@postrun/react 0.2.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 +82 -5
- package/dist/index.cjs +419 -109
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +266 -82
- package/dist/index.d.ts +266 -82
- package/dist/index.js +417 -110
- package/dist/index.js.map +1 -1
- package/package.json +4 -2
package/dist/index.d.cts
CHANGED
|
@@ -2,7 +2,7 @@ import * as react from 'react';
|
|
|
2
2
|
import { ReactNode, CSSProperties } from 'react';
|
|
3
3
|
import * as _tanstack_react_query from '@tanstack/react-query';
|
|
4
4
|
import { QueryClient, QueryKey } from '@tanstack/react-query';
|
|
5
|
-
import { PostrunClient, ListProfilesQuery, ConnectionKind, ConnectionStatus, ListMediaQuery, ListPostsQuery, ConnectablePlatform, MediaTarget, MediaKind, Metadata,
|
|
5
|
+
import { PostrunClient, ListProfilesQuery, DiscoverableAccountList, Connection, ConnectionKind, ConnectionStatus, ListMediaQuery, ListPostsQuery, ConnectablePlatform, MediaResource, MediaTarget, MediaKind, Metadata, ComposePostInput, XPostVariant, LinkedInPostVariant } from '@postrun/js';
|
|
6
6
|
import { TwitterComponents } from 'react-tweet';
|
|
7
7
|
|
|
8
8
|
/**
|
|
@@ -191,6 +191,45 @@ declare function useDeleteProfile(): _tanstack_react_query.UseMutationResult<{
|
|
|
191
191
|
deleted: true;
|
|
192
192
|
}, Error, string, unknown>;
|
|
193
193
|
|
|
194
|
+
/**
|
|
195
|
+
* The pure orchestration behind the embedded (no-redirect) connect flow. It is
|
|
196
|
+
* the in-app twin of the hosted `/connect` runner's machine, sharing its exact
|
|
197
|
+
* shape — grant → correlate by the Nango `connectionId` → discover → pick →
|
|
198
|
+
* select — and its two invariants:
|
|
199
|
+
*
|
|
200
|
+
* 1. It NEVER throws: every path resolves to one typed `ConnectOutcome`, so the
|
|
201
|
+
* hook can map it straight to a UI state and a seam can't crash a host app.
|
|
202
|
+
* 2. Correlation is EXACT: `nango.auth()` resolves with the Nango `connectionId`,
|
|
203
|
+
* the SAME value the auth webhook stores as `nango_connection_id`. We poll the
|
|
204
|
+
* connections list filtered by that id, so the row this grant produced is found
|
|
205
|
+
* unambiguously — a concurrent connect on the same profile can't be mis-picked.
|
|
206
|
+
*
|
|
207
|
+
* All seams (the Nango grant, the host's account picker, the four API calls) are
|
|
208
|
+
* INJECTED, so the whole machine unit-tests without a DOM, a network, or a real
|
|
209
|
+
* `nango.auth()`. The hook (`useConnect`) wires the real seams onto it.
|
|
210
|
+
*/
|
|
211
|
+
/** One account offered for selection — the element type of the accounts list. */
|
|
212
|
+
type DiscoverableAccount = DiscoverableAccountList['data'][number];
|
|
213
|
+
/** Why a connect attempt ended in `error` — actionable reasons for the host. */
|
|
214
|
+
type ConnectErrorReason = 'prepare_failed' | 'popup_blocked' | 'auth_failed' | 'connection_not_found' | 'select_failed' | 'reauth_required';
|
|
215
|
+
/**
|
|
216
|
+
* The single outcome of a connect attempt. `active` carries the activated
|
|
217
|
+
* connection (so the host can call `onConnected`); `connected_pending` means the
|
|
218
|
+
* grant succeeded but no account is bound yet (slow webhook, out-of-band binding,
|
|
219
|
+
* or no reachable accounts) — the host refetches its list, it is NOT an error.
|
|
220
|
+
*/
|
|
221
|
+
type ConnectOutcome = {
|
|
222
|
+
status: 'active';
|
|
223
|
+
connection: Connection;
|
|
224
|
+
} | {
|
|
225
|
+
status: 'connected_pending';
|
|
226
|
+
} | {
|
|
227
|
+
status: 'cancelled';
|
|
228
|
+
} | {
|
|
229
|
+
status: 'error';
|
|
230
|
+
reason: ConnectErrorReason;
|
|
231
|
+
};
|
|
232
|
+
|
|
194
233
|
/** The connection-list filter that keys the cache (social/ads + lifecycle). */
|
|
195
234
|
interface ConnectionsFilter {
|
|
196
235
|
kind?: ConnectionKind;
|
|
@@ -294,24 +333,93 @@ declare const connectionKeys: {
|
|
|
294
333
|
accounts: (id: string) => readonly ["postrun", "connections", "accounts", string];
|
|
295
334
|
};
|
|
296
335
|
|
|
297
|
-
interface
|
|
336
|
+
interface UseConnectParams {
|
|
298
337
|
/** The profile to attach the new connection to. */
|
|
299
338
|
profileId: string;
|
|
300
339
|
/** The platform to connect (X, LinkedIn, Meta, …). */
|
|
301
340
|
platform: ConnectablePlatform;
|
|
341
|
+
/** Called once a connection is fully ACTIVE (an account is bound). The
|
|
342
|
+
* connections list is auto-refetched too, so you rarely need to act here. */
|
|
343
|
+
onConnected?: (connection: Connection) => void;
|
|
344
|
+
/** Called when the attempt fails, with the typed reason. */
|
|
345
|
+
onError?: (reason: ConnectErrorReason) => void;
|
|
346
|
+
/** Called when the user closes the OAuth popup without finishing. The hook
|
|
347
|
+
* stays in the `cancelled` phase; call `reset()` to re-arm for another try. */
|
|
348
|
+
onCancelled?: () => void;
|
|
349
|
+
/**
|
|
350
|
+
* Pre-mint the Nango session on mount (default `true`). Keep it `true` for a
|
|
351
|
+
* dedicated "Connect X" button. Set it `false` for a MULTI-platform picker —
|
|
352
|
+
* then call `prepare()` on the platform button's `onPointerEnter`/`onFocus` so
|
|
353
|
+
* only the platform the user is about to click mints a session (not all of
|
|
354
|
+
* them on open). The popup still needs a pre-minted session, so prepare on
|
|
355
|
+
* intent, not on click.
|
|
356
|
+
*/
|
|
357
|
+
prepareOnMount?: boolean;
|
|
358
|
+
}
|
|
359
|
+
/**
|
|
360
|
+
* The connect flow's UI state. `connected_pending` is a TERMINAL success state —
|
|
361
|
+
* the grant landed but no account is bound yet (a slow webhook, an out-of-band
|
|
362
|
+
* binding, or no reachable accounts); the host shows "almost there" and refetches
|
|
363
|
+
* its connections list. It is NOT an error and must not hang in `connecting`.
|
|
364
|
+
*/
|
|
365
|
+
type ConnectState = {
|
|
366
|
+
phase: 'preparing';
|
|
367
|
+
} | {
|
|
368
|
+
phase: 'idle';
|
|
369
|
+
} | {
|
|
370
|
+
phase: 'connecting';
|
|
371
|
+
} | {
|
|
372
|
+
phase: 'picking';
|
|
373
|
+
accounts: DiscoverableAccount[];
|
|
374
|
+
} | {
|
|
375
|
+
phase: 'active';
|
|
376
|
+
connection: Connection;
|
|
377
|
+
} | {
|
|
378
|
+
phase: 'connected_pending';
|
|
379
|
+
} | {
|
|
380
|
+
phase: 'cancelled';
|
|
381
|
+
} | {
|
|
382
|
+
phase: 'error';
|
|
383
|
+
reason: ConnectErrorReason;
|
|
384
|
+
};
|
|
385
|
+
interface UseConnectResult {
|
|
386
|
+
/** The current flow state — drive your button + picker + status off `phase`. */
|
|
387
|
+
state: ConnectState;
|
|
388
|
+
/**
|
|
389
|
+
* Start the OAuth flow. MUST be called directly in the user's click handler
|
|
390
|
+
* (no `await` before it): it opens the OAuth popup synchronously, so the
|
|
391
|
+
* browser keeps it inside the user gesture. If the session isn't ready yet
|
|
392
|
+
* (`phase` !== `idle`) it kicks `prepare()` and no-ops the popup, so the next
|
|
393
|
+
* click works — prepare on intent (hover/focus) to make the first click open.
|
|
394
|
+
*/
|
|
395
|
+
start: () => void;
|
|
396
|
+
/**
|
|
397
|
+
* Mint the Nango session ahead of the click. Idempotent (a no-op if a session
|
|
398
|
+
* is already held or a mint is in flight). Only needed with
|
|
399
|
+
* `prepareOnMount: false` — call it on the button's `onPointerEnter`/`onFocus`.
|
|
400
|
+
*/
|
|
401
|
+
prepare: () => void;
|
|
402
|
+
/** When `phase` is `picking`, activate the connection with the chosen account. */
|
|
403
|
+
select: (externalAccountId: string) => void;
|
|
404
|
+
/** Return to a fresh, ready state (re-mints the session) — e.g. a "try again". */
|
|
405
|
+
reset: () => void;
|
|
302
406
|
}
|
|
303
407
|
/**
|
|
304
|
-
*
|
|
305
|
-
*
|
|
306
|
-
*
|
|
307
|
-
*
|
|
308
|
-
*
|
|
408
|
+
* Embedded one-click connect — the customer's OWN button drives the whole OAuth
|
|
409
|
+
* flow IN-APP (no redirect to our hosted page). `nango.auth()` opens a popup that
|
|
410
|
+
* resolves in-page, then the account picker (for multi-account platforms) renders
|
|
411
|
+
* inside the host app via `state.accounts` + `select()`. White-label, one click.
|
|
412
|
+
*
|
|
413
|
+
* The Plaid pattern: the Nango session is PRE-MINTED on mount (and on `reset`),
|
|
414
|
+
* because `nango.auth()` opens its popup synchronously — minting in the click
|
|
415
|
+
* would push `window.open` out of the user gesture and the browser would block
|
|
416
|
+
* the popup. `start()` therefore fires `nango.auth()` with the already-held token
|
|
417
|
+
* and zero `await` before it.
|
|
418
|
+
*
|
|
419
|
+
* The hosted `/connect` page remains the fallback for callers NOT using this SDK
|
|
420
|
+
* (a plain link to `hosted_connect_url`); this hook never redirects.
|
|
309
421
|
*/
|
|
310
|
-
declare function useConnect():
|
|
311
|
-
hosted_connect_url: string;
|
|
312
|
-
connect_token: string;
|
|
313
|
-
expires_at: string;
|
|
314
|
-
}, Error, ConnectParams, unknown>;
|
|
422
|
+
declare function useConnect({ profileId, platform, onConnected, onError, onCancelled, prepareOnMount, }: UseConnectParams): UseConnectResult;
|
|
315
423
|
/**
|
|
316
424
|
* List a profile's connected accounts. Pass a `filter` to narrow by `kind`
|
|
317
425
|
* (`posting` = social, `ads`) or `status` — e.g. a composer fetches
|
|
@@ -404,15 +512,89 @@ declare function useDisconnect(): _tanstack_react_query.UseMutationResult<{
|
|
|
404
512
|
deleted: true;
|
|
405
513
|
}, Error, string, unknown>;
|
|
406
514
|
|
|
515
|
+
/** The flow state + actions handed to your render-prop. */
|
|
516
|
+
interface ConnectRenderApi {
|
|
517
|
+
/** The current flow state — switch on `state.phase` to render your UI. */
|
|
518
|
+
state: ConnectState;
|
|
519
|
+
/**
|
|
520
|
+
* Begin connecting. Call this DIRECTLY from your button's `onClick` — it opens
|
|
521
|
+
* the OAuth popup synchronously, so don't `await` anything before it.
|
|
522
|
+
*/
|
|
523
|
+
start: () => void;
|
|
524
|
+
/**
|
|
525
|
+
* Mint the session ahead of the click — only needed with
|
|
526
|
+
* `prepareOnMount={false}` (a multi-platform picker): call it on the button's
|
|
527
|
+
* `onPointerEnter`/`onFocus`.
|
|
528
|
+
*/
|
|
529
|
+
prepare: () => void;
|
|
530
|
+
/** When `state.phase === 'picking'`, activate with the chosen account id. */
|
|
531
|
+
select: (externalAccountId: string) => void;
|
|
532
|
+
/** Reset to a fresh, ready state (e.g. a "try again" after an error/cancel). */
|
|
533
|
+
reset: () => void;
|
|
534
|
+
}
|
|
535
|
+
interface ConnectProps {
|
|
536
|
+
/** The profile to attach the new connection to. */
|
|
537
|
+
profileId: string;
|
|
538
|
+
/** The platform to connect (X, LinkedIn, Meta, …). */
|
|
539
|
+
platform: ConnectablePlatform;
|
|
540
|
+
/** Called once a connection is fully ACTIVE (an account is bound). */
|
|
541
|
+
onConnected?: (connection: Connection) => void;
|
|
542
|
+
/** Called when the attempt fails, with the typed reason. */
|
|
543
|
+
onError?: (reason: ConnectErrorReason) => void;
|
|
544
|
+
/** Called when the user closes the OAuth popup without finishing. */
|
|
545
|
+
onCancelled?: () => void;
|
|
546
|
+
/** Pre-mint on mount (default `true`). Set `false` for a multi-platform picker
|
|
547
|
+
* and call `prepare()` on intent — see {@link UseConnectParams.prepareOnMount}. */
|
|
548
|
+
prepareOnMount?: boolean;
|
|
549
|
+
/** Render your own button + picker + status from the flow state. */
|
|
550
|
+
children: (api: ConnectRenderApi) => ReactNode;
|
|
551
|
+
}
|
|
552
|
+
/**
|
|
553
|
+
* Headless one-click connect. Wraps `useConnect` and hands you the flow state +
|
|
554
|
+
* actions via a render-prop, so you own EVERY pixel (your button, your account
|
|
555
|
+
* picker, your brand marks, your styling) while the SDK runs the embedded OAuth
|
|
556
|
+
* popup + account binding — no redirect, no second click.
|
|
557
|
+
*
|
|
558
|
+
* ```tsx
|
|
559
|
+
* <Connect profileId={id} platform="x" onConnected={refetch}>
|
|
560
|
+
* {({ state, start, select }) =>
|
|
561
|
+
* state.phase === 'picking' ? (
|
|
562
|
+
* <ul>
|
|
563
|
+
* {state.accounts.map((a) => (
|
|
564
|
+
* <li key={a.external_account_id}>
|
|
565
|
+
* <button onClick={() => select(a.external_account_id)}>
|
|
566
|
+
* {a.name ?? a.external_account_id}
|
|
567
|
+
* </button>
|
|
568
|
+
* </li>
|
|
569
|
+
* ))}
|
|
570
|
+
* </ul>
|
|
571
|
+
* ) : (
|
|
572
|
+
* <button onClick={start} disabled={state.phase !== 'idle'}>
|
|
573
|
+
* Connect X
|
|
574
|
+
* </button>
|
|
575
|
+
* )
|
|
576
|
+
* }
|
|
577
|
+
* </Connect>
|
|
578
|
+
* ```
|
|
579
|
+
*
|
|
580
|
+
* The trigger MUST call `start()` directly in the click (it opens the popup
|
|
581
|
+
* synchronously). Mount `<Connect>` inside a `<PostrunProvider>`.
|
|
582
|
+
*/
|
|
583
|
+
declare function Connect({ profileId, platform, onConnected, onError, onCancelled, prepareOnMount, children, }: ConnectProps): ReactNode;
|
|
584
|
+
|
|
407
585
|
type MediaUploadStatus = 'idle' | 'uploading' | 'processing' | 'ready' | 'failed';
|
|
408
586
|
interface MediaUploadOptions {
|
|
409
587
|
/** Profile that owns the asset. */
|
|
410
588
|
profileId: string;
|
|
411
589
|
/** Platforms to validate + render for (omit to add later via useUpdateMedia). */
|
|
412
590
|
targets?: MediaTarget[];
|
|
413
|
-
/**
|
|
591
|
+
/** Optional override — omit and the API auto-detects the kind from the bytes. */
|
|
414
592
|
kind?: MediaKind;
|
|
415
|
-
/**
|
|
593
|
+
/**
|
|
594
|
+
* Optional override — omit and the API auto-detects the MIME from the bytes.
|
|
595
|
+
* Still useful for a legacy Office binary (.doc/.ppt) whose magic bytes can't be
|
|
596
|
+
* disambiguated by the server sniff.
|
|
597
|
+
*/
|
|
416
598
|
contentType?: string;
|
|
417
599
|
/** Store as-is with zero processing. */
|
|
418
600
|
raw?: boolean;
|
|
@@ -420,74 +602,60 @@ interface MediaUploadOptions {
|
|
|
420
602
|
externalId?: string;
|
|
421
603
|
metadata?: Metadata;
|
|
422
604
|
}
|
|
423
|
-
/**
|
|
424
|
-
*
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
cancel: () => void | undefined;
|
|
433
|
-
reset: () => void;
|
|
434
|
-
status: MediaUploadStatus;
|
|
605
|
+
/** One file's slot in an upload — its own live status, progress, and settled
|
|
606
|
+
* asset. `status` is never `idle` (an item exists only once uploading). */
|
|
607
|
+
interface MediaUploadItem {
|
|
608
|
+
/** Stable local id (NOT the asset id) — use as the React key and for `remove`. */
|
|
609
|
+
id: string;
|
|
610
|
+
file: File;
|
|
611
|
+
status: Exclude<MediaUploadStatus, 'idle'>;
|
|
612
|
+
/** 0–1 client-side BYTE-upload bar. `media.progress.{stage,percent}` is the
|
|
613
|
+
* live SERVER pipeline bar. */
|
|
435
614
|
progress: number;
|
|
436
|
-
media:
|
|
437
|
-
id: string;
|
|
438
|
-
object: "media";
|
|
439
|
-
profile_id: string;
|
|
440
|
-
kind: "image" | "video" | "gif" | "document" | null;
|
|
441
|
-
content_type: string | null;
|
|
442
|
-
status: "uploading" | "processing" | "ready" | "failed";
|
|
443
|
-
raw: boolean;
|
|
444
|
-
error: {
|
|
445
|
-
code: "media_unprobeable" | "media_format_indeterminate" | "media_too_large" | "media_aspect_ratio_unsupported" | "media_resolution_too_low" | "media_gif_unsupported" | "media_format_recompressed" | "media_resolution_downscaled" | "video_container_unsupported" | "video_codec_unsupported" | "video_audio_codec_unsupported" | "video_too_large" | "video_too_small" | "video_dimensions_unsupported" | "video_dimensions_too_large" | "video_fps_unsupported" | "video_fps_too_low" | "video_aspect_unsupported" | "video_duration_too_short" | "video_duration_exceeds_max" | "video_transform_failed" | "media_fetch_failed" | "document_format_unsupported" | "document_too_large" | "document_too_many_pages" | "media_unsupported";
|
|
446
|
-
message: string;
|
|
447
|
-
hint?: string;
|
|
448
|
-
allowed?: Array<string>;
|
|
449
|
-
got?: string;
|
|
450
|
-
} | null;
|
|
451
|
-
source: {
|
|
452
|
-
format: string;
|
|
453
|
-
bytes: number;
|
|
454
|
-
width: number | null;
|
|
455
|
-
height: number | null;
|
|
456
|
-
duration_ms: number | null;
|
|
457
|
-
} | null;
|
|
458
|
-
alt_text: string | null;
|
|
459
|
-
per_platform: {
|
|
460
|
-
[key: string]: {
|
|
461
|
-
status: "processing" | "ready" | "failed";
|
|
462
|
-
url: string | null;
|
|
463
|
-
width: number | null;
|
|
464
|
-
height: number | null;
|
|
465
|
-
bytes: number | null;
|
|
466
|
-
warnings: Array<{
|
|
467
|
-
code: "media_unprobeable" | "media_format_indeterminate" | "media_too_large" | "media_aspect_ratio_unsupported" | "media_resolution_too_low" | "media_gif_unsupported" | "media_format_recompressed" | "media_resolution_downscaled" | "video_container_unsupported" | "video_codec_unsupported" | "video_audio_codec_unsupported" | "video_too_large" | "video_too_small" | "video_dimensions_unsupported" | "video_dimensions_too_large" | "video_fps_unsupported" | "video_fps_too_low" | "video_aspect_unsupported" | "video_duration_too_short" | "video_duration_exceeds_max" | "video_transform_failed" | "media_fetch_failed" | "document_format_unsupported" | "document_too_large" | "document_too_many_pages" | "media_unsupported";
|
|
468
|
-
message: string;
|
|
469
|
-
hint?: string;
|
|
470
|
-
allowed?: Array<string>;
|
|
471
|
-
got?: string;
|
|
472
|
-
}>;
|
|
473
|
-
errors: Array<{
|
|
474
|
-
code: "media_unprobeable" | "media_format_indeterminate" | "media_too_large" | "media_aspect_ratio_unsupported" | "media_resolution_too_low" | "media_gif_unsupported" | "media_format_recompressed" | "media_resolution_downscaled" | "video_container_unsupported" | "video_codec_unsupported" | "video_audio_codec_unsupported" | "video_too_large" | "video_too_small" | "video_dimensions_unsupported" | "video_dimensions_too_large" | "video_fps_unsupported" | "video_fps_too_low" | "video_aspect_unsupported" | "video_duration_too_short" | "video_duration_exceeds_max" | "video_transform_failed" | "media_fetch_failed" | "document_format_unsupported" | "document_too_large" | "document_too_many_pages" | "media_unsupported";
|
|
475
|
-
message: string;
|
|
476
|
-
hint?: string;
|
|
477
|
-
allowed?: Array<string>;
|
|
478
|
-
got?: string;
|
|
479
|
-
}>;
|
|
480
|
-
};
|
|
481
|
-
};
|
|
482
|
-
external_id: string | null;
|
|
483
|
-
metadata: {
|
|
484
|
-
[key: string]: string | number | boolean;
|
|
485
|
-
};
|
|
486
|
-
created_at: string;
|
|
487
|
-
updated_at: string;
|
|
488
|
-
} | null;
|
|
615
|
+
media: MediaResource | null;
|
|
489
616
|
error: unknown;
|
|
490
|
-
}
|
|
617
|
+
}
|
|
618
|
+
interface UseMediaUploadResult {
|
|
619
|
+
/** Every file added, in add-order, with its live state. */
|
|
620
|
+
items: readonly MediaUploadItem[];
|
|
621
|
+
/** The settled-ready assets, in item order — what you attach to a post. */
|
|
622
|
+
ready: readonly MediaResource[];
|
|
623
|
+
/** True while any item is still uploading or processing. */
|
|
624
|
+
isUploading: boolean;
|
|
625
|
+
/**
|
|
626
|
+
* Upload ONE file or MANY under `options`, gated by `concurrency`. The reactive
|
|
627
|
+
* `items` update live for UI; the returned promise is for imperative flows —
|
|
628
|
+
* it resolves to the settled (`ready`|`failed`) resources for THIS batch, in
|
|
629
|
+
* add-order, EXCLUDING any item removed/aborted mid-flight. Single-file usage:
|
|
630
|
+
* `const [asset] = await add(file, opts)`.
|
|
631
|
+
*/
|
|
632
|
+
add: (files: File | FileList | readonly File[], options: MediaUploadOptions) => Promise<MediaResource[]>;
|
|
633
|
+
/** Drop an item by local id — aborts it if still in flight. */
|
|
634
|
+
remove: (id: string) => void;
|
|
635
|
+
/** Abort everything and clear the list. */
|
|
636
|
+
reset: () => void;
|
|
637
|
+
}
|
|
638
|
+
interface UseMediaUploadOptions {
|
|
639
|
+
/**
|
|
640
|
+
* How many files upload at once; the rest queue (default 3). Fixed for the
|
|
641
|
+
* hook's lifetime — set it once when you call the hook.
|
|
642
|
+
*/
|
|
643
|
+
concurrency?: number;
|
|
644
|
+
}
|
|
645
|
+
/**
|
|
646
|
+
* Upload one OR many files and get back platform-validated assets. The hook owns
|
|
647
|
+
* the whole journey per file: create the asset (the API auto-detects
|
|
648
|
+
* kind/content_type from the bytes), PUT the bytes with live `progress` + retry,
|
|
649
|
+
* poll until processing settles, and expose `media.per_platform` (per-target
|
|
650
|
+
* status, url, warnings,
|
|
651
|
+
* errors). Every file gets its own `MediaUploadItem` slot in `items`; `ready` is
|
|
652
|
+
* the settled assets to attach to a post; `remove`/`reset` abort in-flight work.
|
|
653
|
+
* Uploads run through ONE shared `p-limit` gate so only `concurrency` (default 3)
|
|
654
|
+
* are in flight at once — global across `add` calls, not per-call.
|
|
655
|
+
*
|
|
656
|
+
* Single-file usage: `const [asset] = await add(file, opts)` (or read `ready[0]`).
|
|
657
|
+
*/
|
|
658
|
+
declare function useMediaUpload(options?: UseMediaUploadOptions): UseMediaUploadResult;
|
|
491
659
|
/** Retrieve a media asset; auto-polls while it is still uploading/processing. */
|
|
492
660
|
declare function useMedia(id: string): _tanstack_react_query.UseQueryResult<NoInfer<{
|
|
493
661
|
id: string;
|
|
@@ -496,6 +664,10 @@ declare function useMedia(id: string): _tanstack_react_query.UseQueryResult<NoIn
|
|
|
496
664
|
kind: "image" | "video" | "gif" | "document" | null;
|
|
497
665
|
content_type: string | null;
|
|
498
666
|
status: "uploading" | "processing" | "ready" | "failed";
|
|
667
|
+
progress: {
|
|
668
|
+
stage: "queued" | "analyzing" | "transcoding" | "done";
|
|
669
|
+
percent: number;
|
|
670
|
+
};
|
|
499
671
|
raw: boolean;
|
|
500
672
|
error: {
|
|
501
673
|
code: "media_unprobeable" | "media_format_indeterminate" | "media_too_large" | "media_aspect_ratio_unsupported" | "media_resolution_too_low" | "media_gif_unsupported" | "media_format_recompressed" | "media_resolution_downscaled" | "video_container_unsupported" | "video_codec_unsupported" | "video_audio_codec_unsupported" | "video_too_large" | "video_too_small" | "video_dimensions_unsupported" | "video_dimensions_too_large" | "video_fps_unsupported" | "video_fps_too_low" | "video_aspect_unsupported" | "video_duration_too_short" | "video_duration_exceeds_max" | "video_transform_failed" | "media_fetch_failed" | "document_format_unsupported" | "document_too_large" | "document_too_many_pages" | "media_unsupported";
|
|
@@ -557,6 +729,10 @@ declare function useMediaList(query?: ListMediaQuery): _tanstack_react_query.Use
|
|
|
557
729
|
kind: "image" | "video" | "gif" | "document" | null;
|
|
558
730
|
content_type: string | null;
|
|
559
731
|
status: "uploading" | "processing" | "ready" | "failed";
|
|
732
|
+
progress: {
|
|
733
|
+
stage: "queued" | "analyzing" | "transcoding" | "done";
|
|
734
|
+
percent: number;
|
|
735
|
+
};
|
|
560
736
|
raw: boolean;
|
|
561
737
|
error: {
|
|
562
738
|
code: "media_unprobeable" | "media_format_indeterminate" | "media_too_large" | "media_aspect_ratio_unsupported" | "media_resolution_too_low" | "media_gif_unsupported" | "media_format_recompressed" | "media_resolution_downscaled" | "video_container_unsupported" | "video_codec_unsupported" | "video_audio_codec_unsupported" | "video_too_large" | "video_too_small" | "video_dimensions_unsupported" | "video_dimensions_too_large" | "video_fps_unsupported" | "video_fps_too_low" | "video_aspect_unsupported" | "video_duration_too_short" | "video_duration_exceeds_max" | "video_transform_failed" | "media_fetch_failed" | "document_format_unsupported" | "document_too_large" | "document_too_many_pages" | "media_unsupported";
|
|
@@ -622,6 +798,10 @@ declare function useMediaInfinite(filters?: Omit<ListMediaQuery, 'limit' | 'offs
|
|
|
622
798
|
kind: "image" | "video" | "gif" | "document" | null;
|
|
623
799
|
content_type: string | null;
|
|
624
800
|
status: "uploading" | "processing" | "ready" | "failed";
|
|
801
|
+
progress: {
|
|
802
|
+
stage: "queued" | "analyzing" | "transcoding" | "done";
|
|
803
|
+
percent: number;
|
|
804
|
+
};
|
|
625
805
|
raw: boolean;
|
|
626
806
|
error: {
|
|
627
807
|
code: "media_unprobeable" | "media_format_indeterminate" | "media_too_large" | "media_aspect_ratio_unsupported" | "media_resolution_too_low" | "media_gif_unsupported" | "media_format_recompressed" | "media_resolution_downscaled" | "video_container_unsupported" | "video_codec_unsupported" | "video_audio_codec_unsupported" | "video_too_large" | "video_too_small" | "video_dimensions_unsupported" | "video_dimensions_too_large" | "video_fps_unsupported" | "video_fps_too_low" | "video_aspect_unsupported" | "video_duration_too_short" | "video_duration_exceeds_max" | "video_transform_failed" | "media_fetch_failed" | "document_format_unsupported" | "document_too_large" | "document_too_many_pages" | "media_unsupported";
|
|
@@ -676,6 +856,10 @@ declare function useUpdateMedia(): _tanstack_react_query.UseMutationResult<{
|
|
|
676
856
|
kind: "image" | "video" | "gif" | "document" | null;
|
|
677
857
|
content_type: string | null;
|
|
678
858
|
status: "uploading" | "processing" | "ready" | "failed";
|
|
859
|
+
progress: {
|
|
860
|
+
stage: "queued" | "analyzing" | "transcoding" | "done";
|
|
861
|
+
percent: number;
|
|
862
|
+
};
|
|
679
863
|
raw: boolean;
|
|
680
864
|
error: {
|
|
681
865
|
code: "media_unprobeable" | "media_format_indeterminate" | "media_too_large" | "media_aspect_ratio_unsupported" | "media_resolution_too_low" | "media_gif_unsupported" | "media_format_recompressed" | "media_resolution_downscaled" | "video_container_unsupported" | "video_codec_unsupported" | "video_audio_codec_unsupported" | "video_too_large" | "video_too_small" | "video_dimensions_unsupported" | "video_dimensions_too_large" | "video_fps_unsupported" | "video_fps_too_low" | "video_aspect_unsupported" | "video_duration_too_short" | "video_duration_exceeds_max" | "video_transform_failed" | "media_fetch_failed" | "document_format_unsupported" | "document_too_large" | "document_too_many_pages" | "media_unsupported";
|
|
@@ -1089,7 +1273,7 @@ declare function useCreatePost(profileId: string): {
|
|
|
1089
1273
|
} | undefined;
|
|
1090
1274
|
reset: () => void;
|
|
1091
1275
|
isReady: boolean;
|
|
1092
|
-
connectedChannels: ("x" | "linkedin" | "facebook_page" | "
|
|
1276
|
+
connectedChannels: ("x" | "linkedin" | "facebook_page" | "instagram" | "tiktok")[];
|
|
1093
1277
|
};
|
|
1094
1278
|
/**
|
|
1095
1279
|
* Update a post by id. Pass a light edit directly (`{ schedule_at }`,
|
|
@@ -1443,4 +1627,4 @@ declare function LinkedInPostPreviewImpl({ variant, author, media, theme, time,
|
|
|
1443
1627
|
* absorbs unstable media arrays). */
|
|
1444
1628
|
declare const LinkedInPostPreview: react.MemoExoticComponent<typeof LinkedInPostPreviewImpl>;
|
|
1445
1629
|
|
|
1446
|
-
export { type CalendarFilters, type
|
|
1630
|
+
export { type CalendarFilters, Connect, type ConnectErrorReason, type ConnectOutcome, type ConnectProps, type ConnectRenderApi, type ConnectState, type ConnectionsFilter, type DiscoverableAccount, type InfiniteList, LinkedInPostPreview, type LinkedInPostPreviewProps, type LinkedInPreviewAuthor, type LiveOptions, type MediaUploadItem, type MediaUploadOptions, type MediaUploadStatus, type PostrunContextValue, PostrunProvider, type PostrunProviderProps, type PreviewMedia, type PreviewMediaKind, UploadError, type UseConnectParams, type UseConnectResult, type UseMediaUploadOptions, type UseMediaUploadResult, XPostPreview, type XPostPreviewProps, type XPreviewAuthor, type XPreviewMedia, type XPreviewQuotedTweet, connectionKeys, mediaKeys, postKeys, profileKeys, useCalendar, useConnect, useConnection, useConnections, useCreatePost, useCreateProfile, useDeleteMedia, useDeletePost, useDeleteProfile, useDisconnect, useDiscoverableAccounts, useInfiniteList, useMedia, useMediaInfinite, useMediaList, useMediaUpload, usePost, usePostrun, usePosts, usePostsInfinite, useProfile, useProfiles, useProfilesInfinite, useSelectAccount, useUpdateMedia, useUpdatePost, useUpdateProfile };
|