@postrun/react 2.0.0 → 2.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/dist/index.d.cts CHANGED
@@ -3,7 +3,7 @@ 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
5
  import { PostrunClient, ListProfilesQuery, DiscoverableAccountList, Connection, ConnectionKind, ConnectionStatus, ListMediaQuery, ListPostsQuery, ConnectablePlatform, MediaResource, MediaTarget, MediaKind, Metadata, ComposePostInput, PostValidation, XPostVariant, LinkedInPostVariant } from '@postrun/js';
6
- export { PostValidation, ValidationIssue } from '@postrun/js';
6
+ export { PostValidation, PostVariant, PostVariantError, TikTokCreatorInfo, ValidationIssue } from '@postrun/js';
7
7
  import { TwitterComponents } from 'react-tweet';
8
8
 
9
9
  /**
@@ -333,6 +333,11 @@ declare const connectionKeys: {
333
333
  detail: (id: string) => readonly ["postrun", "connections", "detail", string];
334
334
  accounts: (id: string) => readonly ["postrun", "connections", "accounts", string];
335
335
  };
336
+ /** Query-key factory for TikTok reads (creator info keyed by connection id). */
337
+ declare const tiktokKeys: {
338
+ all: readonly ["postrun", "tiktok"];
339
+ creatorInfo: (connectionId: string) => readonly ["postrun", "tiktok", "creator-info", string];
340
+ };
336
341
 
337
342
  interface UseConnectParams {
338
343
  /** The profile to attach the new connection to. */
@@ -1181,6 +1186,25 @@ declare function usePost(id: string, options?: LiveOptions): _tanstack_react_que
1181
1186
  * variant set from `{ content, channels }` (per the `buildCreatePost` rules), and
1182
1187
  * sends it — the customer never assembles variants or passes a `connection_id`.
1183
1188
  * `connectedChannels` is the set of posting platforms this profile can reach.
1189
+ *
1190
+ * ## Reading the publish outcome (do NOT stop at "it returned")
1191
+ * On `publish: 'now'` the API returns the created post with a rollup `status` and
1192
+ * a per-variant `status` + typed `error`. A 201 does NOT mean every platform
1193
+ * published — one can silently fail while another succeeds. Surface the outcome
1194
+ * via the derived fields, never assume success from a resolved `create`:
1195
+ *
1196
+ * - **`status`** — the rollup (`published | partially_published | failed |
1197
+ * draft | scheduled`), `undefined` until the first `create` resolves.
1198
+ * - **`isPublished`** — `true` ONLY when `status === 'published'`. This is the
1199
+ * one "fully published" state; `partially_published` and `failed` are NOT
1200
+ * success. Branch on this, not on the promise resolving.
1201
+ * - **`failedVariants`** — the variants that failed, each with its typed
1202
+ * `error` (`{ code, message }`); `[]` when none. Render "X failed: <message>".
1203
+ *
1204
+ * `create` still resolves with the FULL `Post` (read everything if you need to),
1205
+ * and it NEVER throws on a failed/partial publish — a throw would discard the
1206
+ * platforms that DID publish. A transport error (network / 4xx) still surfaces
1207
+ * via `error` (and rejects `create`), exactly as before.
1184
1208
  */
1185
1209
  declare function useCreatePost(profileId: string): {
1186
1210
  create: _tanstack_react_query.UseMutateAsyncFunction<{
@@ -1280,8 +1304,40 @@ declare function useCreatePost(profileId: string): {
1280
1304
  executed: boolean;
1281
1305
  } | undefined;
1282
1306
  reset: () => void;
1307
+ status: "draft" | "scheduled" | "publishing" | "partially_published" | "published" | "failed" | undefined;
1308
+ isPublished: boolean;
1309
+ failedVariants: {
1310
+ id: string;
1311
+ object: "post_variant";
1312
+ connection_id: string | null;
1313
+ platform: "x" | "linkedin" | "facebook_page" | "instagram" | "tiktok";
1314
+ post_type: "text" | "single_image" | "multi_image" | "video" | "reel" | "carousel";
1315
+ body: string | null;
1316
+ status: "draft" | "scheduled" | "publishing" | "published" | "failed";
1317
+ settings: {
1318
+ [key: string]: unknown;
1319
+ };
1320
+ schedule_at: string | null;
1321
+ result: {
1322
+ platform_post_id: string;
1323
+ permalink: string | null;
1324
+ published_at: string;
1325
+ } | null;
1326
+ error: {
1327
+ code: string;
1328
+ message: string;
1329
+ } | null;
1330
+ media: Array<{
1331
+ media_id: string;
1332
+ position: number;
1333
+ crop_box: {
1334
+ [key: string]: unknown;
1335
+ } | null;
1336
+ alt_text_override: string | null;
1337
+ }>;
1338
+ }[];
1283
1339
  isReady: boolean;
1284
- connectedChannels: ("x" | "linkedin" | "facebook_page" | "instagram" | "tiktok")[];
1340
+ connectedChannels: ("tiktok" | "x" | "linkedin" | "facebook_page" | "instagram")[];
1285
1341
  };
1286
1342
  /**
1287
1343
  * Validate a composed post WITHOUT saving or publishing it — the read-scoped
@@ -1300,7 +1356,7 @@ declare function useValidatePost(profileId: string): {
1300
1356
  validate: (input: Omit<ComposePostInput, "profileId">) => Promise<PostValidation>;
1301
1357
  publishable: boolean | undefined;
1302
1358
  issues: {
1303
- code: "unauthorized" | "forbidden" | "not_found" | "conflict" | "validation_failed" | "rate_limited" | "internal_error" | "idempotency_key_invalid" | "idempotency_key_reused" | "idempotency_request_in_progress" | "account_not_available" | "connection_reauth_required" | "connection_not_pending" | "not_implemented" | "connection_discovery_failed" | "media_processing" | "not_publishable" | "invalid_connection" | "invalid_media" | "profile_scope_invalid" | "media_unprobeable" | "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_format_indeterminate" | "media_count_invalid" | "body_too_long" | "content_missing" | "content_conflict" | "content_incomplete" | "content_kind_mismatch" | "media_type_mismatch" | "tag_limit_exceeded" | "reel_field_on_non_reel" | "field_placement_invalid" | "media_not_ready" | "media_failed" | "media_unsupported" | "media_kind_mismatch" | "variant_unparseable" | "publishing_unavailable" | "x_duplicate_content" | "x_not_authorized" | "x_rate_limited" | "x_publish_failed" | "x_media_upload_failed" | "linkedin_duplicate_content" | "linkedin_auth_expired" | "linkedin_permission_denied" | "linkedin_media_processing" | "linkedin_media_upload_failed" | "linkedin_publish_failed" | "instagram_media_processing" | "instagram_container_expired" | "instagram_container_failed" | "instagram_rate_limited" | "instagram_not_authorized" | "instagram_publish_failed" | "facebook_reel_processing" | "facebook_reel_failed" | "facebook_rate_limited" | "facebook_not_authorized" | "facebook_publish_failed" | "tiktok_privacy_not_allowed" | "tiktok_duration_exceeds_max" | "tiktok_media_processing" | "tiktok_not_authorized" | "tiktok_rate_limited" | "tiktok_publish_failed" | "connection_platform_mismatch" | "connection_removed";
1359
+ code: "unauthorized" | "forbidden" | "not_found" | "conflict" | "validation_failed" | "rate_limited" | "internal_error" | "idempotency_key_invalid" | "idempotency_key_reused" | "idempotency_request_in_progress" | "account_not_available" | "connection_reauth_required" | "connection_not_pending" | "not_implemented" | "connection_discovery_failed" | "tiktok_creator_info_unavailable" | "media_processing" | "not_publishable" | "invalid_connection" | "invalid_media" | "profile_scope_invalid" | "media_unprobeable" | "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_format_indeterminate" | "media_count_invalid" | "body_too_long" | "content_missing" | "content_conflict" | "content_incomplete" | "content_kind_mismatch" | "media_type_mismatch" | "tag_limit_exceeded" | "reel_field_on_non_reel" | "field_placement_invalid" | "media_not_ready" | "media_failed" | "media_unsupported" | "media_kind_mismatch" | "variant_unparseable" | "publishing_unavailable" | "x_duplicate_content" | "x_not_authorized" | "x_access_not_permitted" | "x_rate_limited" | "x_publish_failed" | "x_media_upload_failed" | "linkedin_duplicate_content" | "linkedin_auth_expired" | "linkedin_permission_denied" | "linkedin_rate_limited" | "linkedin_media_processing" | "linkedin_media_failed" | "linkedin_media_upload_failed" | "linkedin_publish_failed" | "instagram_media_processing" | "instagram_container_expired" | "instagram_container_failed" | "instagram_rate_limited" | "instagram_not_authorized" | "instagram_publish_failed" | "facebook_reel_processing" | "facebook_reel_failed" | "facebook_rate_limited" | "facebook_not_authorized" | "facebook_publish_failed" | "tiktok_privacy_not_allowed" | "tiktok_duration_exceeds_max" | "tiktok_media_processing" | "tiktok_not_authorized" | "tiktok_rate_limited" | "tiktok_publish_failed" | "post_publish_failed" | "post_partially_published" | "connection_platform_mismatch" | "connection_removed";
1304
1360
  message: string;
1305
1361
  hint?: string;
1306
1362
  allowed?: Array<string>;
@@ -1311,7 +1367,7 @@ declare function useValidatePost(profileId: string): {
1311
1367
  isPending: boolean;
1312
1368
  error: Error | null;
1313
1369
  isReady: boolean;
1314
- connectedChannels: ("x" | "linkedin" | "facebook_page" | "instagram" | "tiktok")[];
1370
+ connectedChannels: ("tiktok" | "x" | "linkedin" | "facebook_page" | "instagram")[];
1315
1371
  };
1316
1372
  /**
1317
1373
  * Update a post by id. Pass a light edit directly (`{ schedule_at }`,
@@ -1517,6 +1573,36 @@ declare function useDeletePost(): _tanstack_react_query.UseMutationResult<{
1517
1573
  deleted: true;
1518
1574
  }, Error, string, unknown>;
1519
1575
 
1576
+ /**
1577
+ * Fetch a TikTok connection's live creator info — the data TikTok's Content
1578
+ * Posting policy REQUIRES the publishing UI to render before a post: the
1579
+ * `creator` (nickname + avatar), the `privacy_options` to offer (with NO default
1580
+ * selected — render each with `tiktokPrivacyLabel`), the positive `interaction`
1581
+ * (allowed) flags for the Comment/Duet/Stitch toggles, and the per-account video
1582
+ * length cap (`max_video_duration_sec`).
1583
+ *
1584
+ * Pass the id of the TikTok connection the composer is posting through, or `null`
1585
+ * when none is selected yet — the query is DISABLED while `connectionId` is null
1586
+ * (no request fires). The host knows which connection is TikTok (it picked it), so
1587
+ * only call this for a TikTok connection; a non-TikTok id surfaces a 404 as
1588
+ * `error` (the API never leaks the platform). Returns the standard react-query
1589
+ * result — read `data` (the creator info), `isLoading`, and `error`.
1590
+ */
1591
+ declare function useTikTokCreatorInfo(connectionId: string | null): _tanstack_react_query.UseQueryResult<NoInfer<{
1592
+ creator: {
1593
+ nickname: string;
1594
+ username: string;
1595
+ avatar_url: string | null;
1596
+ };
1597
+ privacy_options: Array<"PUBLIC_TO_EVERYONE" | "MUTUAL_FOLLOW_FRIENDS" | "FOLLOWER_OF_CREATOR" | "SELF_ONLY">;
1598
+ interaction: {
1599
+ comment: boolean;
1600
+ duet: boolean;
1601
+ stitch: boolean;
1602
+ };
1603
+ max_video_duration_sec: number;
1604
+ }>, Error>;
1605
+
1520
1606
  /**
1521
1607
  * Public input types for the post-preview components. These describe data the
1522
1608
  * CUSTOMER supplies for presentation — NOT shapes from our OpenAPI contract — so
@@ -1665,4 +1751,4 @@ declare function LinkedInPostPreviewImpl({ variant, author, media, theme, time,
1665
1751
  * absorbs unstable media arrays). */
1666
1752
  declare const LinkedInPostPreview: react.MemoExoticComponent<typeof LinkedInPostPreviewImpl>;
1667
1753
 
1668
- 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, useValidatePost };
1754
+ 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, tiktokKeys, useCalendar, useConnect, useConnection, useConnections, useCreatePost, useCreateProfile, useDeleteMedia, useDeletePost, useDeleteProfile, useDisconnect, useDiscoverableAccounts, useInfiniteList, useMedia, useMediaInfinite, useMediaList, useMediaUpload, usePost, usePostrun, usePosts, usePostsInfinite, useProfile, useProfiles, useProfilesInfinite, useSelectAccount, useTikTokCreatorInfo, useUpdateMedia, useUpdatePost, useUpdateProfile, useValidatePost };
package/dist/index.d.ts CHANGED
@@ -3,7 +3,7 @@ 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
5
  import { PostrunClient, ListProfilesQuery, DiscoverableAccountList, Connection, ConnectionKind, ConnectionStatus, ListMediaQuery, ListPostsQuery, ConnectablePlatform, MediaResource, MediaTarget, MediaKind, Metadata, ComposePostInput, PostValidation, XPostVariant, LinkedInPostVariant } from '@postrun/js';
6
- export { PostValidation, ValidationIssue } from '@postrun/js';
6
+ export { PostValidation, PostVariant, PostVariantError, TikTokCreatorInfo, ValidationIssue } from '@postrun/js';
7
7
  import { TwitterComponents } from 'react-tweet';
8
8
 
9
9
  /**
@@ -333,6 +333,11 @@ declare const connectionKeys: {
333
333
  detail: (id: string) => readonly ["postrun", "connections", "detail", string];
334
334
  accounts: (id: string) => readonly ["postrun", "connections", "accounts", string];
335
335
  };
336
+ /** Query-key factory for TikTok reads (creator info keyed by connection id). */
337
+ declare const tiktokKeys: {
338
+ all: readonly ["postrun", "tiktok"];
339
+ creatorInfo: (connectionId: string) => readonly ["postrun", "tiktok", "creator-info", string];
340
+ };
336
341
 
337
342
  interface UseConnectParams {
338
343
  /** The profile to attach the new connection to. */
@@ -1181,6 +1186,25 @@ declare function usePost(id: string, options?: LiveOptions): _tanstack_react_que
1181
1186
  * variant set from `{ content, channels }` (per the `buildCreatePost` rules), and
1182
1187
  * sends it — the customer never assembles variants or passes a `connection_id`.
1183
1188
  * `connectedChannels` is the set of posting platforms this profile can reach.
1189
+ *
1190
+ * ## Reading the publish outcome (do NOT stop at "it returned")
1191
+ * On `publish: 'now'` the API returns the created post with a rollup `status` and
1192
+ * a per-variant `status` + typed `error`. A 201 does NOT mean every platform
1193
+ * published — one can silently fail while another succeeds. Surface the outcome
1194
+ * via the derived fields, never assume success from a resolved `create`:
1195
+ *
1196
+ * - **`status`** — the rollup (`published | partially_published | failed |
1197
+ * draft | scheduled`), `undefined` until the first `create` resolves.
1198
+ * - **`isPublished`** — `true` ONLY when `status === 'published'`. This is the
1199
+ * one "fully published" state; `partially_published` and `failed` are NOT
1200
+ * success. Branch on this, not on the promise resolving.
1201
+ * - **`failedVariants`** — the variants that failed, each with its typed
1202
+ * `error` (`{ code, message }`); `[]` when none. Render "X failed: <message>".
1203
+ *
1204
+ * `create` still resolves with the FULL `Post` (read everything if you need to),
1205
+ * and it NEVER throws on a failed/partial publish — a throw would discard the
1206
+ * platforms that DID publish. A transport error (network / 4xx) still surfaces
1207
+ * via `error` (and rejects `create`), exactly as before.
1184
1208
  */
1185
1209
  declare function useCreatePost(profileId: string): {
1186
1210
  create: _tanstack_react_query.UseMutateAsyncFunction<{
@@ -1280,8 +1304,40 @@ declare function useCreatePost(profileId: string): {
1280
1304
  executed: boolean;
1281
1305
  } | undefined;
1282
1306
  reset: () => void;
1307
+ status: "draft" | "scheduled" | "publishing" | "partially_published" | "published" | "failed" | undefined;
1308
+ isPublished: boolean;
1309
+ failedVariants: {
1310
+ id: string;
1311
+ object: "post_variant";
1312
+ connection_id: string | null;
1313
+ platform: "x" | "linkedin" | "facebook_page" | "instagram" | "tiktok";
1314
+ post_type: "text" | "single_image" | "multi_image" | "video" | "reel" | "carousel";
1315
+ body: string | null;
1316
+ status: "draft" | "scheduled" | "publishing" | "published" | "failed";
1317
+ settings: {
1318
+ [key: string]: unknown;
1319
+ };
1320
+ schedule_at: string | null;
1321
+ result: {
1322
+ platform_post_id: string;
1323
+ permalink: string | null;
1324
+ published_at: string;
1325
+ } | null;
1326
+ error: {
1327
+ code: string;
1328
+ message: string;
1329
+ } | null;
1330
+ media: Array<{
1331
+ media_id: string;
1332
+ position: number;
1333
+ crop_box: {
1334
+ [key: string]: unknown;
1335
+ } | null;
1336
+ alt_text_override: string | null;
1337
+ }>;
1338
+ }[];
1283
1339
  isReady: boolean;
1284
- connectedChannels: ("x" | "linkedin" | "facebook_page" | "instagram" | "tiktok")[];
1340
+ connectedChannels: ("tiktok" | "x" | "linkedin" | "facebook_page" | "instagram")[];
1285
1341
  };
1286
1342
  /**
1287
1343
  * Validate a composed post WITHOUT saving or publishing it — the read-scoped
@@ -1300,7 +1356,7 @@ declare function useValidatePost(profileId: string): {
1300
1356
  validate: (input: Omit<ComposePostInput, "profileId">) => Promise<PostValidation>;
1301
1357
  publishable: boolean | undefined;
1302
1358
  issues: {
1303
- code: "unauthorized" | "forbidden" | "not_found" | "conflict" | "validation_failed" | "rate_limited" | "internal_error" | "idempotency_key_invalid" | "idempotency_key_reused" | "idempotency_request_in_progress" | "account_not_available" | "connection_reauth_required" | "connection_not_pending" | "not_implemented" | "connection_discovery_failed" | "media_processing" | "not_publishable" | "invalid_connection" | "invalid_media" | "profile_scope_invalid" | "media_unprobeable" | "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_format_indeterminate" | "media_count_invalid" | "body_too_long" | "content_missing" | "content_conflict" | "content_incomplete" | "content_kind_mismatch" | "media_type_mismatch" | "tag_limit_exceeded" | "reel_field_on_non_reel" | "field_placement_invalid" | "media_not_ready" | "media_failed" | "media_unsupported" | "media_kind_mismatch" | "variant_unparseable" | "publishing_unavailable" | "x_duplicate_content" | "x_not_authorized" | "x_rate_limited" | "x_publish_failed" | "x_media_upload_failed" | "linkedin_duplicate_content" | "linkedin_auth_expired" | "linkedin_permission_denied" | "linkedin_media_processing" | "linkedin_media_upload_failed" | "linkedin_publish_failed" | "instagram_media_processing" | "instagram_container_expired" | "instagram_container_failed" | "instagram_rate_limited" | "instagram_not_authorized" | "instagram_publish_failed" | "facebook_reel_processing" | "facebook_reel_failed" | "facebook_rate_limited" | "facebook_not_authorized" | "facebook_publish_failed" | "tiktok_privacy_not_allowed" | "tiktok_duration_exceeds_max" | "tiktok_media_processing" | "tiktok_not_authorized" | "tiktok_rate_limited" | "tiktok_publish_failed" | "connection_platform_mismatch" | "connection_removed";
1359
+ code: "unauthorized" | "forbidden" | "not_found" | "conflict" | "validation_failed" | "rate_limited" | "internal_error" | "idempotency_key_invalid" | "idempotency_key_reused" | "idempotency_request_in_progress" | "account_not_available" | "connection_reauth_required" | "connection_not_pending" | "not_implemented" | "connection_discovery_failed" | "tiktok_creator_info_unavailable" | "media_processing" | "not_publishable" | "invalid_connection" | "invalid_media" | "profile_scope_invalid" | "media_unprobeable" | "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_format_indeterminate" | "media_count_invalid" | "body_too_long" | "content_missing" | "content_conflict" | "content_incomplete" | "content_kind_mismatch" | "media_type_mismatch" | "tag_limit_exceeded" | "reel_field_on_non_reel" | "field_placement_invalid" | "media_not_ready" | "media_failed" | "media_unsupported" | "media_kind_mismatch" | "variant_unparseable" | "publishing_unavailable" | "x_duplicate_content" | "x_not_authorized" | "x_access_not_permitted" | "x_rate_limited" | "x_publish_failed" | "x_media_upload_failed" | "linkedin_duplicate_content" | "linkedin_auth_expired" | "linkedin_permission_denied" | "linkedin_rate_limited" | "linkedin_media_processing" | "linkedin_media_failed" | "linkedin_media_upload_failed" | "linkedin_publish_failed" | "instagram_media_processing" | "instagram_container_expired" | "instagram_container_failed" | "instagram_rate_limited" | "instagram_not_authorized" | "instagram_publish_failed" | "facebook_reel_processing" | "facebook_reel_failed" | "facebook_rate_limited" | "facebook_not_authorized" | "facebook_publish_failed" | "tiktok_privacy_not_allowed" | "tiktok_duration_exceeds_max" | "tiktok_media_processing" | "tiktok_not_authorized" | "tiktok_rate_limited" | "tiktok_publish_failed" | "post_publish_failed" | "post_partially_published" | "connection_platform_mismatch" | "connection_removed";
1304
1360
  message: string;
1305
1361
  hint?: string;
1306
1362
  allowed?: Array<string>;
@@ -1311,7 +1367,7 @@ declare function useValidatePost(profileId: string): {
1311
1367
  isPending: boolean;
1312
1368
  error: Error | null;
1313
1369
  isReady: boolean;
1314
- connectedChannels: ("x" | "linkedin" | "facebook_page" | "instagram" | "tiktok")[];
1370
+ connectedChannels: ("tiktok" | "x" | "linkedin" | "facebook_page" | "instagram")[];
1315
1371
  };
1316
1372
  /**
1317
1373
  * Update a post by id. Pass a light edit directly (`{ schedule_at }`,
@@ -1517,6 +1573,36 @@ declare function useDeletePost(): _tanstack_react_query.UseMutationResult<{
1517
1573
  deleted: true;
1518
1574
  }, Error, string, unknown>;
1519
1575
 
1576
+ /**
1577
+ * Fetch a TikTok connection's live creator info — the data TikTok's Content
1578
+ * Posting policy REQUIRES the publishing UI to render before a post: the
1579
+ * `creator` (nickname + avatar), the `privacy_options` to offer (with NO default
1580
+ * selected — render each with `tiktokPrivacyLabel`), the positive `interaction`
1581
+ * (allowed) flags for the Comment/Duet/Stitch toggles, and the per-account video
1582
+ * length cap (`max_video_duration_sec`).
1583
+ *
1584
+ * Pass the id of the TikTok connection the composer is posting through, or `null`
1585
+ * when none is selected yet — the query is DISABLED while `connectionId` is null
1586
+ * (no request fires). The host knows which connection is TikTok (it picked it), so
1587
+ * only call this for a TikTok connection; a non-TikTok id surfaces a 404 as
1588
+ * `error` (the API never leaks the platform). Returns the standard react-query
1589
+ * result — read `data` (the creator info), `isLoading`, and `error`.
1590
+ */
1591
+ declare function useTikTokCreatorInfo(connectionId: string | null): _tanstack_react_query.UseQueryResult<NoInfer<{
1592
+ creator: {
1593
+ nickname: string;
1594
+ username: string;
1595
+ avatar_url: string | null;
1596
+ };
1597
+ privacy_options: Array<"PUBLIC_TO_EVERYONE" | "MUTUAL_FOLLOW_FRIENDS" | "FOLLOWER_OF_CREATOR" | "SELF_ONLY">;
1598
+ interaction: {
1599
+ comment: boolean;
1600
+ duet: boolean;
1601
+ stitch: boolean;
1602
+ };
1603
+ max_video_duration_sec: number;
1604
+ }>, Error>;
1605
+
1520
1606
  /**
1521
1607
  * Public input types for the post-preview components. These describe data the
1522
1608
  * CUSTOMER supplies for presentation — NOT shapes from our OpenAPI contract — so
@@ -1665,4 +1751,4 @@ declare function LinkedInPostPreviewImpl({ variant, author, media, theme, time,
1665
1751
  * absorbs unstable media arrays). */
1666
1752
  declare const LinkedInPostPreview: react.MemoExoticComponent<typeof LinkedInPostPreviewImpl>;
1667
1753
 
1668
- 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, useValidatePost };
1754
+ 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, tiktokKeys, useCalendar, useConnect, useConnection, useConnections, useCreatePost, useCreateProfile, useDeleteMedia, useDeletePost, useDeleteProfile, useDisconnect, useDiscoverableAccounts, useInfiniteList, useMedia, useMediaInfinite, useMediaList, useMediaUpload, usePost, usePostrun, usePosts, usePostsInfinite, useProfile, useProfiles, useProfilesInfinite, useSelectAccount, useTikTokCreatorInfo, useUpdateMedia, useUpdatePost, useUpdateProfile, useValidatePost };
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import { createContext, memo, useMemo, useState, useEffect, Fragment as Fragment$1, useRef, createElement, useContext, useCallback } from 'react';
3
3
  import { useInfiniteQuery, useQuery, useMutation, QueryClient } from '@tanstack/react-query';
4
- import { createPostrunClient, profilesList, profilesGet, profilesCreate, profilesUpdate, profilesDelete, connectionsConnect, connectionsListByProfile, connectionsGet, connectionsListAccounts, connectionsSelect, connectionsDelete, mediaGet, mediaList, mediaUpdate, mediaDelete, postsList, postsGet, postsCreate, buildCreatePost, isPostPlatform, postsValidate, postsUpdate, postsDelete, mediaCreate, PostrunError } from '@postrun/js';
4
+ import { createPostrunClient, profilesList, profilesGet, profilesCreate, profilesUpdate, profilesDelete, connectionsConnect, connectionsListByProfile, connectionsGet, connectionsListAccounts, connectionsSelect, connectionsDelete, mediaGet, mediaList, mediaUpdate, mediaDelete, postsList, postsGet, postsCreate, buildCreatePost, isPostPlatform, failedVariants, isPublished, postsValidate, postsUpdate, postsDelete, tiktokCreatorInfo, mediaCreate, PostrunError } from '@postrun/js';
5
5
  import Nango, { AuthError } from '@nangohq/frontend';
6
6
  import pWaitFor, { TimeoutError } from 'p-wait-for';
7
7
  import pLimit from 'p-limit';
@@ -129,6 +129,10 @@ var connectionKeys = {
129
129
  detail: (id) => [...connectionKeys.details(), id],
130
130
  accounts: (id) => [...connectionKeys.all, "accounts", id]
131
131
  };
132
+ var tiktokKeys = {
133
+ all: [ROOT, "tiktok"],
134
+ creatorInfo: (connectionId) => [...tiktokKeys.all, "creator-info", connectionId]
135
+ };
132
136
 
133
137
  // src/profiles.ts
134
138
  function useProfiles(query) {
@@ -878,12 +882,18 @@ function useCreatePost(profileId) {
878
882
  },
879
883
  queryClient
880
884
  );
885
+ const post = mutation.data;
881
886
  return {
882
887
  create: mutation.mutateAsync,
883
888
  isPending: mutation.isPending,
884
889
  error: mutation.error,
885
- data: mutation.data,
890
+ data: post,
886
891
  reset: mutation.reset,
892
+ // Derived publish outcome (see the JSDoc above) — `undefined`/`false`/`[]`
893
+ // until the first create resolves; computed from the returned post only.
894
+ status: post?.status,
895
+ isPublished: post ? isPublished(post) : false,
896
+ failedVariants: post ? failedVariants(post) : [],
887
897
  // The profile's connections must load before `create` can resolve a channel;
888
898
  // gate on this so a call during loading isn't mislabeled "not connected".
889
899
  isReady: connections.isSuccess,
@@ -947,6 +957,19 @@ function useDeletePost() {
947
957
  queryClient
948
958
  );
949
959
  }
960
+ function useTikTokCreatorInfo(connectionId) {
961
+ const { client, queryClient } = usePostrun();
962
+ return useQuery(
963
+ {
964
+ // `connectionId ?? ''` only ever keys the cache when the query is enabled
965
+ // (a non-null id), so the empty fallback is never used to fetch.
966
+ queryKey: tiktokKeys.creatorInfo(connectionId ?? ""),
967
+ queryFn: async () => (await tiktokCreatorInfo({ client, path: { id: connectionId ?? "" } })).data,
968
+ enabled: connectionId !== null
969
+ },
970
+ queryClient
971
+ );
972
+ }
950
973
  function fileKey(file) {
951
974
  return file ? `${file.name}:${file.size}:${file.lastModified}` : "";
952
975
  }
@@ -1662,6 +1685,6 @@ function LinkedInPostPreviewImpl({
1662
1685
  }
1663
1686
  var LinkedInPostPreview = memo(LinkedInPostPreviewImpl);
1664
1687
 
1665
- export { Connect, LinkedInPostPreview, PostrunProvider, UploadError, XPostPreview, 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, useValidatePost };
1688
+ export { Connect, LinkedInPostPreview, PostrunProvider, UploadError, XPostPreview, connectionKeys, mediaKeys, postKeys, profileKeys, tiktokKeys, useCalendar, useConnect, useConnection, useConnections, useCreatePost, useCreateProfile, useDeleteMedia, useDeletePost, useDeleteProfile, useDisconnect, useDiscoverableAccounts, useInfiniteList, useMedia, useMediaInfinite, useMediaList, useMediaUpload, usePost, usePostrun, usePosts, usePostsInfinite, useProfile, useProfiles, useProfilesInfinite, useSelectAccount, useTikTokCreatorInfo, useUpdateMedia, useUpdatePost, useUpdateProfile, useValidatePost };
1666
1689
  //# sourceMappingURL=index.js.map
1667
1690
  //# sourceMappingURL=index.js.map