@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/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/context.tsx","../src/infinite-list.ts","../src/keys.ts","../src/profiles.ts","../src/connect-machine.ts","../src/connections.ts","../src/Connect.tsx","../src/upload-bytes.ts","../src/media.ts","../src/posts.ts","../src/preview/use-resolved-media.ts","../src/preview/x/XPreviewActions.tsx","../src/preview/x/entities.ts","../src/preview/x/to-tweet.ts","../src/preview/x/XPostPreview.tsx","../src/preview/linkedin/theme.ts","../src/preview/linkedin/EngagementBar.tsx","../src/preview/linkedin/Header.tsx","../src/preview/linkedin/ImageMosaic.tsx","../src/preview/linkedin/Media.tsx","../src/preview/linkedin/PostBody.tsx","../src/preview/linkedin/LinkedInPostPreview.tsx"],"names":["useRef","useEffect","useQuery","useMutation","pWaitFor","useState","useCallback","useMemo","jsx","ROW","ACTIONS","FiRepeat","jsxs","PLACEHOLDER_AVATAR","Fragment","memo"],"mappings":"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","file":"index.js","sourcesContent":["import {\n createContext,\n createElement,\n useContext,\n useEffect,\n useMemo,\n useRef,\n} from 'react';\nimport type { ReactNode } from 'react';\n\nimport { QueryClient } from '@tanstack/react-query';\n\nimport { createPostrunClient } from '@postrun/js';\nimport type { PostrunClient } from '@postrun/js';\n\n/**\n * The value every hook and component reads from context: the typed SDK client\n * plus a private TanStack `QueryClient` that powers caching, dedup, and\n * revalidation. Hooks pass this `queryClient` explicitly to `useQuery` /\n * `useMutation`, so it stays fully isolated from any QueryClient the host app\n * runs of its own — no `QueryClientProvider` setup required from the customer.\n */\nexport interface PostrunContextValue {\n client: PostrunClient;\n queryClient: QueryClient;\n}\n\n/** Sensible defaults: treat data as fresh briefly to avoid refetch storms. */\nfunction createDefaultQueryClient(): QueryClient {\n return new QueryClient({\n defaultOptions: {\n queries: { staleTime: 30_000 },\n },\n });\n}\n\nconst PostrunContext = createContext<PostrunContextValue | null>(null);\nPostrunContext.displayName = 'PostrunContext';\n\nexport interface PostrunProviderProps {\n /**\n * Returns a valid short-lived scoped token. The host app's backend mints it\n * from a secret `pr_` key (`POST /v1/tokens`); the secret never reaches the\n * browser. Called per request — cache and refresh before `exp` inside here.\n */\n getToken: () => string | Promise<string>;\n /** Override the API base URL (defaults to the production gateway). */\n baseUrl?: string;\n /**\n * Bring your own TanStack `QueryClient` (advanced: shared DevTools, custom\n * defaults, tests). Omit it and a private, isolated one is created for you.\n */\n queryClient?: QueryClient;\n children: ReactNode;\n}\n\nexport function PostrunProvider({\n getToken,\n baseUrl,\n queryClient,\n children,\n}: PostrunProviderProps) {\n // Keep the latest `getToken` in a ref so the client can always call the\n // freshest closure WITHOUT being rebuilt when callers pass a new arrow each\n // render (the common case). The client is constructed once per `baseUrl`.\n const getTokenRef = useRef(getToken);\n useEffect(() => {\n getTokenRef.current = getToken;\n }, [getToken]);\n\n const client = useMemo(\n () =>\n createPostrunClient({ getToken: () => getTokenRef.current(), baseUrl }),\n [baseUrl],\n );\n\n const resolvedQueryClient = useMemo(\n () => queryClient ?? createDefaultQueryClient(),\n [queryClient],\n );\n\n const value = useMemo<PostrunContextValue>(\n () => ({ client, queryClient: resolvedQueryClient }),\n [client, resolvedQueryClient],\n );\n\n return createElement(PostrunContext.Provider, { value }, children);\n}\n\n/** Access the configured Postrun client. Throws if used outside a provider. */\nexport function usePostrun(): PostrunContextValue {\n const value = useContext(PostrunContext);\n\n if (value === null) {\n throw new Error('usePostrun must be used within a <PostrunProvider>.');\n }\n\n return value;\n}\n","import { useInfiniteQuery } from '@tanstack/react-query';\nimport type { QueryKey } from '@tanstack/react-query';\n\nimport { usePostrun } from './context';\n\n/**\n * The offset-pagination envelope every Postrun list endpoint returns. The helper\n * only needs these fields; the concrete page type comes from the SDK response\n * (e.g. `PostList`), which satisfies this structurally — nothing is redeclared.\n */\ninterface PageEnvelope<TItem> {\n data: TItem[];\n total: number;\n offset: number;\n has_more: boolean;\n}\n\n/** A flattened, append-style (\"load more\") view over a paginated list endpoint. */\nexport interface InfiniteList<TItem> {\n /** Every item loaded so far, flattened across all fetched pages. */\n items: TItem[];\n /** Total items matching the filter (from the first page's envelope). */\n total: number;\n /** Fetch the next page and append it. No-op once `hasMore` is false. */\n loadMore: () => void;\n /** Whether another page exists beyond what's loaded. */\n hasMore: boolean;\n /** The first page is loading (no items yet). */\n isLoading: boolean;\n /** A `loadMore()` is in flight (items are already shown). */\n isLoadingMore: boolean;\n /** The last error, or null. Narrow with `instanceof PostrunError`. */\n error: Error | null;\n /** Refetch from the first page (re-runs every loaded page). */\n refetch: () => void;\n}\n\n/**\n * Turn an offset-paginated Postrun list endpoint into a clean append-style\n * `{ items, loadMore, hasMore, … }` surface — the \"Load more\" / infinite-scroll\n * shape a feed or calendar wants.\n *\n * Built on TanStack `useInfiniteQuery`, so page accumulation is its job and never\n * hand-rolled. The next offset is read from the envelope itself\n * (`offset + data.length`), so it stays correct regardless of page size.\n * `fetchPage` supplies the resource-specific SDK call; the page type is inferred\n * from its return, so item types are derived, never redeclared.\n */\nexport function useInfiniteList<TItem>(args: {\n queryKey: QueryKey;\n fetchPage: (page: {\n limit: number;\n offset: number;\n }) => Promise<PageEnvelope<TItem>>;\n /** Items per page (default 20, the API's own default). */\n limit?: number;\n enabled?: boolean;\n}): InfiniteList<TItem> {\n const { queryClient } = usePostrun();\n const limit = args.limit ?? 20;\n\n const query = useInfiniteQuery(\n {\n queryKey: args.queryKey,\n queryFn: ({ pageParam }) => args.fetchPage({ limit, offset: pageParam }),\n initialPageParam: 0,\n getNextPageParam: (last) =>\n last.has_more ? last.offset + last.data.length : undefined,\n enabled: args.enabled,\n },\n queryClient,\n );\n\n return {\n items: query.data?.pages.flatMap((page) => page.data) ?? [],\n total: query.data?.pages[0]?.total ?? 0,\n loadMore: () => {\n void query.fetchNextPage();\n },\n hasMore: query.hasNextPage,\n isLoading: query.isLoading,\n isLoadingMore: query.isFetchingNextPage,\n error: query.error,\n refetch: () => {\n void query.refetch();\n },\n };\n}\n","import type {\n ConnectionKind,\n ConnectionStatus,\n ListMediaQuery,\n ListPostsQuery,\n ListProfilesQuery,\n} from '@postrun/js';\n\n/** The connection-list filter that keys the cache (social/ads + lifecycle). */\nexport interface ConnectionsFilter {\n kind?: ConnectionKind;\n status?: ConnectionStatus;\n}\n\n/** Root namespace so our cache never collides with the host app's own queries. */\nconst ROOT = 'postrun';\n\n/**\n * Query-key factory for profiles. Hierarchical so a mutation can invalidate at\n * the right granularity: `lists()` after a create, `detail(id)` after an update.\n */\nexport const profileKeys = {\n all: [ROOT, 'profiles'] as const,\n lists: () => [...profileKeys.all, 'list'] as const,\n list: (query?: ListProfilesQuery) =>\n [...profileKeys.lists(), query ?? {}] as const,\n // Nested under lists() so a create/update/delete invalidating lists() also\n // refreshes the infinite cache; distinct tail so the two cache shapes (a\n // single Page vs accumulated pages) never collide on one key. The filter omits\n // limit/offset — the infinite hook owns pagination, so they never key the cache.\n infinite: (query?: Omit<ListProfilesQuery, 'limit' | 'offset'>) =>\n [...profileKeys.lists(), 'infinite', query ?? {}] as const,\n details: () => [...profileKeys.all, 'detail'] as const,\n detail: (id: string) => [...profileKeys.details(), id] as const,\n};\n\n/** Query-key factory for posts (list filtered by query; detail by id). */\nexport const postKeys = {\n all: [ROOT, 'posts'] as const,\n lists: () => [...postKeys.all, 'list'] as const,\n list: (query?: ListPostsQuery) => [...postKeys.lists(), query ?? {}] as const,\n // Nested under lists() so a create/update/delete invalidating lists() also\n // refreshes the infinite cache; distinct tail so the two cache shapes (a\n // single Page vs accumulated pages) never collide on one key. The filter omits\n // limit/offset — the infinite hook owns pagination, so they never key the cache.\n infinite: (query?: Omit<ListPostsQuery, 'limit' | 'offset'>) =>\n [...postKeys.lists(), 'infinite', query ?? {}] as const,\n details: () => [...postKeys.all, 'detail'] as const,\n detail: (id: string) => [...postKeys.details(), id] as const,\n};\n\n/** Query-key factory for media assets (list filtered by query; detail by id). */\nexport const mediaKeys = {\n all: [ROOT, 'media'] as const,\n lists: () => [...mediaKeys.all, 'list'] as const,\n list: (query?: ListMediaQuery) => [...mediaKeys.lists(), query ?? {}] as const,\n // Nested under lists() so an upload/update/delete invalidating lists() also\n // refreshes the infinite cache; distinct tail so the two cache shapes (a\n // single Page vs accumulated pages) never collide on one key. The filter omits\n // limit/offset — the infinite hook owns pagination, so they never key the cache.\n infinite: (query?: Omit<ListMediaQuery, 'limit' | 'offset'>) =>\n [...mediaKeys.lists(), 'infinite', query ?? {}] as const,\n details: () => [...mediaKeys.all, 'detail'] as const,\n detail: (id: string) => [...mediaKeys.details(), id] as const,\n};\n\n/** Query-key factory for connections (lists keyed by owning profile). */\nexport const connectionKeys = {\n all: [ROOT, 'connections'] as const,\n lists: () => [...connectionKeys.all, 'list'] as const,\n list: (profileId: string, filter?: ConnectionsFilter) =>\n [...connectionKeys.lists(), profileId, filter ?? {}] as const,\n details: () => [...connectionKeys.all, 'detail'] as const,\n detail: (id: string) => [...connectionKeys.details(), id] as const,\n accounts: (id: string) => [...connectionKeys.all, 'accounts', id] as const,\n};\n","import { useMutation, useQuery } from '@tanstack/react-query';\n\nimport {\n profilesCreate,\n profilesDelete,\n profilesGet,\n profilesList,\n profilesUpdate,\n} from '@postrun/js';\nimport type {\n CreateProfileInput,\n ListProfilesQuery,\n Profile,\n UpdateProfileInput,\n} from '@postrun/js';\n\nimport { usePostrun } from './context';\nimport { useInfiniteList } from './infinite-list';\nimport { profileKeys } from './keys';\n\n/**\n * List the account's profiles (client/brand workspaces), filtered and paginated.\n * `data` is the typed `ProfileList` envelope — inferred straight from the SDK\n * call, never hand-typed. Caching, dedup, and revalidation come from the\n * provider's private QueryClient.\n */\nexport function useProfiles(query?: ListProfilesQuery) {\n const { client, queryClient } = usePostrun();\n return useQuery(\n {\n queryKey: profileKeys.list(query),\n queryFn: async () =>\n (await profilesList({ client, query })).data,\n },\n queryClient,\n );\n}\n\n/**\n * List profiles with append-style (\"load more\") pagination. Returns\n * `{ items, loadMore, hasMore, isLoading, isLoadingMore, total }`: render\n * `items`, call `loadMore()` while `hasMore`. `pageSize` defaults to 20. Filters\n * match `useProfiles` minus paging, which the hook owns. Shares list-cache\n * invalidation with the other profile hooks.\n */\nexport function useProfilesInfinite(\n filters?: Omit<ListProfilesQuery, 'limit' | 'offset'>,\n options?: { pageSize?: number },\n) {\n const { client } = usePostrun();\n return useInfiniteList<Profile>({\n queryKey: profileKeys.infinite(filters),\n limit: options?.pageSize,\n fetchPage: async ({ limit, offset }) =>\n (await profilesList({ client, query: { ...filters, limit, offset } }))\n .data,\n });\n}\n\n/** Retrieve a single profile by id. Disabled until an id is provided. */\nexport function useProfile(id: string) {\n const { client, queryClient } = usePostrun();\n return useQuery(\n {\n queryKey: profileKeys.detail(id),\n queryFn: async () =>\n (await profilesGet({ client, path: { id } })).data,\n enabled: Boolean(id),\n },\n queryClient,\n );\n}\n\n/** Create a profile; on success the profile lists are refetched. */\nexport function useCreateProfile() {\n const { client, queryClient } = usePostrun();\n return useMutation(\n {\n mutationFn: async (body: CreateProfileInput) =>\n (await profilesCreate({ client, body })).data,\n onSuccess: () =>\n queryClient.invalidateQueries({ queryKey: profileKeys.lists() }),\n },\n queryClient,\n );\n}\n\n/** Update a profile by id; on success the lists and that profile are refreshed. */\nexport function useUpdateProfile() {\n const { client, queryClient } = usePostrun();\n return useMutation(\n {\n mutationFn: async ({ id, ...body }: { id: string } & UpdateProfileInput) =>\n (await profilesUpdate({ client, path: { id }, body })).data,\n onSuccess: (_result, { id }) => {\n queryClient.invalidateQueries({ queryKey: profileKeys.lists() });\n queryClient.invalidateQueries({ queryKey: profileKeys.detail(id) });\n },\n },\n queryClient,\n );\n}\n\n/** Delete a profile by id; on success the lists refresh and its detail is dropped. */\nexport function useDeleteProfile() {\n const { client, queryClient } = usePostrun();\n return useMutation(\n {\n mutationFn: async (id: string) =>\n (await profilesDelete({ client, path: { id } })).data,\n onSuccess: (_result, id) => {\n queryClient.invalidateQueries({ queryKey: profileKeys.lists() });\n queryClient.removeQueries({ queryKey: profileKeys.detail(id) });\n },\n },\n queryClient,\n );\n}\n","import { AuthError } from '@nangohq/frontend';\nimport pWaitFor, { TimeoutError } from 'p-wait-for';\n\nimport { PostrunError } from '@postrun/js';\nimport type { Connection, DiscoverableAccountList } from '@postrun/js';\n\n/**\n * The pure orchestration behind the embedded (no-redirect) connect flow. It is\n * the in-app twin of the hosted `/connect` runner's machine, sharing its exact\n * shape — grant → correlate by the Nango `connectionId` → discover → pick →\n * select — and its two invariants:\n *\n * 1. It NEVER throws: every path resolves to one typed `ConnectOutcome`, so the\n * hook can map it straight to a UI state and a seam can't crash a host app.\n * 2. Correlation is EXACT: `nango.auth()` resolves with the Nango `connectionId`,\n * the SAME value the auth webhook stores as `nango_connection_id`. We poll the\n * connections list filtered by that id, so the row this grant produced is found\n * unambiguously — a concurrent connect on the same profile can't be mis-picked.\n *\n * All seams (the Nango grant, the host's account picker, the four API calls) are\n * INJECTED, so the whole machine unit-tests without a DOM, a network, or a real\n * `nango.auth()`. The hook (`useConnect`) wires the real seams onto it.\n */\n\n/** One account offered for selection — the element type of the accounts list. */\nexport type DiscoverableAccount = DiscoverableAccountList['data'][number];\n\n/** Why a connect attempt ended in `error` — actionable reasons for the host. */\nexport type ConnectErrorReason =\n | 'popup_blocked' // the browser blocked the OAuth popup\n | 'auth_failed' // the Nango grant failed (bad token, validation, unknown)\n | 'connection_not_found' // we couldn't read back the connection the grant made\n | 'select_failed' // discovery/selection failed (and isn't reauth)\n | 'reauth_required'; // the grant must be reconnected before an account binds\n\n/**\n * The single outcome of a connect attempt. `active` carries the activated\n * connection (so the host can call `onConnected`); `connected_pending` means the\n * grant succeeded but no account is bound yet (slow webhook, out-of-band binding,\n * or no reachable accounts) — the host refetches its list, it is NOT an error.\n */\nexport type ConnectOutcome =\n | { status: 'active'; connection: Connection }\n | { status: 'connected_pending' }\n | { status: 'cancelled' }\n | { status: 'error'; reason: ConnectErrorReason };\n\nexport interface ConnectMachineDeps {\n /** Run the Nango OAuth grant; resolves the Nango `connectionId`, or rejects\n * with a typed `AuthError`. The hook fires `nango.auth()` synchronously in the\n * click and hands the in-flight promise here. */\n readonly authorize: () => Promise<string>;\n /** Resolve the user's chosen external account id — the host app's picker. */\n readonly chooseAccount: (accounts: DiscoverableAccount[]) => Promise<string>;\n /** List this profile's connections filtered by the Nango `connectionId`. */\n readonly listByNangoConnectionId: (\n nangoConnectionId: string,\n ) => Promise<Connection[]>;\n /** Discover the accounts reachable through a pending connection's grant. */\n readonly discoverAccounts: (\n connectionId: string,\n ) => Promise<DiscoverableAccount[]>;\n /** Activate a pending connection with the chosen account; resolves the row. */\n readonly selectAccount: (\n connectionId: string,\n externalAccountId: string,\n ) => Promise<Connection>;\n readonly pollIntervalMs: number;\n readonly pollTimeoutMs: number;\n}\n\nconst PENDING: ConnectOutcome = { status: 'connected_pending' };\nconst CANCELLED: ConnectOutcome = { status: 'cancelled' };\nconst active = (connection: Connection): ConnectOutcome => ({\n status: 'active',\n connection,\n});\nconst failed = (reason: ConnectErrorReason): ConnectOutcome => ({\n status: 'error',\n reason,\n});\n\n/** Map a Nango `AuthError` onto the typed outcome. Exhaustive (no `default`), so\n * a new `AuthErrorType` in a future Nango release is a compile error here, not a\n * silently-swallowed failure. */\nfunction outcomeForAuthError(error: AuthError): ConnectOutcome {\n switch (error.type) {\n case 'window_closed':\n return CANCELLED;\n case 'blocked_by_browser':\n return failed('popup_blocked');\n case 'missing_auth_token':\n case 'invalid_host_url':\n case 'missing_credentials':\n case 'connection_test_failed':\n case 'missing_connect_session_token':\n case 'connection_validation_failed':\n case 'resource_capped':\n case 'unknown_error':\n return failed('auth_failed');\n }\n}\n\n/** The Nango grant step. Resolves the `connectionId` (our correlation key), or\n * the typed outcome to surface when the grant did not complete. Never throws —\n * an `AuthError` maps to its outcome, any other rejection to `auth_failed`. */\nasync function grant(\n authorize: () => Promise<string>,\n): Promise<\n { ok: true; connectionId: string } | { ok: false; outcome: ConnectOutcome }\n> {\n try {\n return { ok: true, connectionId: await authorize() };\n } catch (error) {\n if (error instanceof AuthError) {\n return { ok: false, outcome: outcomeForAuthError(error) };\n }\n\n return { ok: false, outcome: failed('auth_failed') };\n }\n}\n\n/** Poll (bounded) for the connection THIS grant created — the list is filtered\n * server-side by the Nango `connectionId`, so any returned row is the grant's\n * row. Resolves the row, or `null` if it never appears within the timeout (a\n * slow webhook, not an error). */\nasync function awaitGrantedConnection(\n deps: ConnectMachineDeps,\n nangoConnectionId: string,\n): Promise<Connection | null> {\n try {\n return await pWaitFor<Connection>(\n async () => {\n const rows = await deps.listByNangoConnectionId(nangoConnectionId);\n const match = rows[0];\n\n return match ? pWaitFor.resolveWith(match) : false;\n },\n { interval: deps.pollIntervalMs, timeout: deps.pollTimeoutMs },\n );\n } catch (error) {\n if (error instanceof TimeoutError) {\n return null;\n }\n\n throw error;\n }\n}\n\n/** Bind a granted PENDING connection: discover → pick → select. Discovery\n * `not_implemented` (the platform binds out-of-band) or no reachable accounts →\n * `connected_pending`; a reauth-required select → `reauth_required`; any other\n * select failure → `select_failed`. Never throws a `PostrunError`. */\nasync function bindPendingConnection(\n deps: ConnectMachineDeps,\n connection: Connection,\n): Promise<ConnectOutcome> {\n let accounts: DiscoverableAccount[];\n\n try {\n accounts = await deps.discoverAccounts(connection.id);\n } catch (error) {\n if (error instanceof PostrunError && error.code === 'not_implemented') {\n return PENDING;\n }\n\n throw error;\n }\n\n // Nothing to pick or select: the grant landed but the connection stays PENDING\n // (the user must fix their platform access and reconnect), so don't hand `[]`\n // to the picker.\n if (accounts.length === 0) {\n return PENDING;\n }\n\n const chosen = await deps.chooseAccount(accounts);\n\n try {\n return active(await deps.selectAccount(connection.id, chosen));\n } catch (error) {\n if (error instanceof PostrunError) {\n return error.code === 'connection_reauth_required'\n ? failed('reauth_required')\n : failed('select_failed');\n }\n\n throw error;\n }\n}\n\n/**\n * Run the embedded connect flow to a single typed outcome. Never throws.\n */\nexport async function runEmbeddedConnect(\n deps: ConnectMachineDeps,\n): Promise<ConnectOutcome> {\n const granted = await grant(deps.authorize);\n\n if (!granted.ok) {\n return granted.outcome;\n }\n\n let connection: Connection | null;\n\n try {\n connection = await awaitGrantedConnection(deps, granted.connectionId);\n } catch {\n // A polling READ error (not a timeout) means we can't confirm the row landed.\n return failed('connection_not_found');\n }\n\n // Slow webhook: the grant succeeded but the row isn't visible yet. The host\n // refetches its list, so this is `connected_pending`, not an error.\n if (connection === null) {\n return PENDING;\n }\n\n // Single-account platforms (and an already-resolved race) land ACTIVE already.\n if (connection.external_account_id !== null) {\n return active(connection);\n }\n\n try {\n return await bindPendingConnection(deps, connection);\n } catch {\n // A non-`PostrunError` throw mid-bind (e.g. an unexpected network error) is\n // surfaced as a typed failure, never swallowed.\n return failed('select_failed');\n }\n}\n","import Nango from '@nangohq/frontend';\nimport { useMutation, useQuery } from '@tanstack/react-query';\nimport { useCallback, useEffect, useRef, useState } from 'react';\n\nimport {\n connectionsConnect,\n connectionsDelete,\n connectionsGet,\n connectionsListAccounts,\n connectionsListByProfile,\n connectionsSelect,\n} from '@postrun/js';\nimport type {\n ConnectablePlatform,\n Connection,\n SelectAccountInput,\n} from '@postrun/js';\n\nimport {\n type ConnectErrorReason,\n type ConnectOutcome,\n type DiscoverableAccount,\n runEmbeddedConnect,\n} from './connect-machine';\nimport { usePostrun } from './context';\nimport { connectionKeys } from './keys';\nimport type { ConnectionsFilter } from './keys';\n\n/** Poll cadence for reading back the connection a grant created (the row is\n * written out-of-band by the Nango auth webhook). Mirrors the hosted runner. */\nconst POLL_INTERVAL_MS = 1500;\nconst POLL_TIMEOUT_MS = 15_000;\n\nexport interface UseConnectParams {\n /** The profile to attach the new connection to. */\n profileId: string;\n /** The platform to connect (X, LinkedIn, Meta, …). */\n platform: ConnectablePlatform;\n /** Called once a connection is fully ACTIVE (an account is bound). */\n onConnected?: (connection: Connection) => void;\n}\n\n/**\n * The connect flow's UI state. `connected_pending` is a TERMINAL success state —\n * the grant landed but no account is bound yet (a slow webhook, an out-of-band\n * binding, or no reachable accounts); the host shows \"almost there\" and refetches\n * its connections list. It is NOT an error and must not hang in `connecting`.\n */\nexport type ConnectState =\n | { phase: 'preparing' } // pre-minting the Nango session (button not ready)\n | { phase: 'idle' } // session held; ready to start on a click\n | { phase: 'connecting' } // popup open / polling / binding\n | { phase: 'picking'; accounts: DiscoverableAccount[] } // host renders a picker\n | { phase: 'active'; connection: Connection }\n | { phase: 'connected_pending' }\n | { phase: 'cancelled' }\n | { phase: 'error'; reason: ConnectErrorReason };\n\nexport interface UseConnectResult {\n /** The current flow state — drive your button + picker + status off `phase`. */\n state: ConnectState;\n /**\n * Start the OAuth flow. MUST be called directly in the user's click handler\n * (no `await` before it): it opens the OAuth popup synchronously, so the\n * browser keeps it inside the user gesture. A no-op until the session is ready\n * (state `preparing`) — disable the button until `phase` is `idle`.\n */\n start: () => void;\n /** When `phase` is `picking`, activate the connection with the chosen account. */\n select: (externalAccountId: string) => void;\n /** Return to a fresh, ready state (re-mints the session) — e.g. a \"try again\". */\n reset: () => void;\n}\n\ninterface HeldSession {\n readonly token: string;\n readonly providerConfigKey: string;\n readonly host: string;\n}\n\n/**\n * Embedded one-click connect — the customer's OWN button drives the whole OAuth\n * flow IN-APP (no redirect to our hosted page). `nango.auth()` opens a popup that\n * resolves in-page, then the account picker (for multi-account platforms) renders\n * inside the host app via `state.accounts` + `select()`. White-label, one click.\n *\n * The Plaid pattern: the Nango session is PRE-MINTED on mount (and on `reset`),\n * because `nango.auth()` opens its popup synchronously — minting in the click\n * would push `window.open` out of the user gesture and the browser would block\n * the popup. `start()` therefore fires `nango.auth()` with the already-held token\n * and zero `await` before it.\n *\n * The hosted `/connect` page remains the fallback for callers NOT using this SDK\n * (a plain link to `hosted_connect_url`); this hook never redirects.\n */\nexport function useConnect({\n profileId,\n platform,\n onConnected,\n}: UseConnectParams): UseConnectResult {\n const { client } = usePostrun();\n const [state, setState] = useState<ConnectState>({ phase: 'preparing' });\n const [remintNonce, setRemintNonce] = useState(0);\n\n const sessionRef = useRef<HeldSession | null>(null);\n // The pending account pick — BOTH halves: `resolve` is called by `select()`,\n // `reject` by `abandonFlow()` so a machine awaiting the picker UNWINDS to a\n // typed outcome (never hangs/leaks) if the flow is torn down mid-pick.\n const pickRef = useRef<{\n resolve: (externalAccountId: string) => void;\n reject: (reason: Error) => void;\n } | null>(null);\n // One flow at a time. `inFlight` no-ops a re-entrant `start()` (a double click\n // must never open a second popup or race a second machine). `flowGen` is bumped\n // whenever a flow is abandoned, so a stale machine's terminal `.then` is\n // suppressed — no `setState`/`onConnected` after unmount or a profile switch.\n const inFlightRef = useRef(false);\n const flowGenRef = useRef(0);\n\n // Keep the latest `onConnected` in a ref so `start` needn't depend on it (and\n // re-create) when callers pass a fresh arrow each render.\n const onConnectedRef = useRef(onConnected);\n useEffect(() => {\n onConnectedRef.current = onConnected;\n }, [onConnected]);\n\n // Tear down any in-flight flow: bump the generation (its terminal `.then` is\n // ignored) and REJECT a pending pick (a machine awaiting the picker unwinds\n // instead of leaking). Stable — touches refs only.\n const abandonFlow = useCallback(() => {\n flowGenRef.current += 1;\n inFlightRef.current = false;\n const pick = pickRef.current;\n pickRef.current = null;\n pick?.reject(new Error('connect flow abandoned'));\n }, []);\n\n // Pre-mint the session before any click (and on every `reset`). An async mint\n // in the click would break the synchronous `window.open` gesture.\n useEffect(() => {\n let abandoned = false;\n setState({ phase: 'preparing' });\n sessionRef.current = null;\n\n connectionsConnect({ client, path: { id: profileId }, body: { platform } })\n .then(({ data }) => {\n if (abandoned || !data) return;\n sessionRef.current = {\n token: data.connect_session_token,\n providerConfigKey: data.provider_config_key,\n host: data.nango_host,\n };\n setState({ phase: 'idle' });\n })\n .catch(() => {\n if (!abandoned) setState({ phase: 'error', reason: 'auth_failed' });\n });\n\n return () => {\n abandoned = true;\n // reset / unmount / profile|platform change → abandon any in-flight flow\n // (rejects a pending pick; suppresses a stale machine's terminal setState).\n abandonFlow();\n };\n }, [client, profileId, platform, remintNonce, abandonFlow]);\n\n const start = useCallback(() => {\n const session = sessionRef.current;\n // No-op if not ready (host disables the button until 'idle') OR a flow is\n // already running (a re-entrant click must not open a second popup).\n if (!session || inFlightRef.current) return;\n\n inFlightRef.current = true;\n const gen = flowGenRef.current;\n const isCurrent = () => flowGenRef.current === gen;\n\n setState({ phase: 'connecting' });\n\n void runEmbeddedConnect({\n // Nango lives INSIDE `authorize` so a SYNCHRONOUS throw (invalid host /\n // missing token — the Nango SDK throws `AuthError` synchronously) becomes a\n // promise rejection that `grant()` maps to `auth_failed`, never an uncaught\n // throw escaping the click and wedging `inFlightRef`. Gesture timing still\n // holds: `authorize()` is invoked SYNCHRONOUSLY down the\n // start → runEmbeddedConnect → grant chain (each `await`'s operand is\n // evaluated before it suspends), so `nango.auth()`'s `window.open` fires\n // inside the user gesture, with no `await` before it.\n authorize: async () => {\n const nango = new Nango({\n host: session.host,\n connectSessionToken: session.token,\n });\n const result = await nango.auth(session.providerConfigKey, {\n detectClosedAuthWindow: true,\n });\n return result.connectionId;\n },\n chooseAccount: (accounts) =>\n new Promise<string>((resolve, reject) => {\n // Abandoned before reaching the picker (reset / unmount / profile\n // change while still connecting): reject so the machine unwinds, and\n // DON'T touch `pickRef`/state — a newer flow owns them now.\n if (!isCurrent()) {\n reject(new Error('connect flow abandoned'));\n return;\n }\n pickRef.current = { resolve, reject };\n setState({ phase: 'picking', accounts });\n }),\n listByNangoConnectionId: async (nangoConnectionId) => {\n const { data } = await connectionsListByProfile({\n client,\n path: { id: profileId },\n query: { nango_connection_id: nangoConnectionId },\n });\n return data?.data ?? [];\n },\n discoverAccounts: async (connectionId) => {\n const { data } = await connectionsListAccounts({\n client,\n path: { id: connectionId },\n });\n return data?.data ?? [];\n },\n selectAccount: async (connectionId, externalAccountId) => {\n const { data } = await connectionsSelect({\n client,\n path: { id: connectionId },\n body: { external_account_id: externalAccountId },\n });\n // A 2xx with no body shouldn't happen; treat it as a select failure\n // (the machine maps the throw to `select_failed`) rather than cast.\n if (!data) throw new Error('select returned no connection');\n return data;\n },\n pollIntervalMs: POLL_INTERVAL_MS,\n pollTimeoutMs: POLL_TIMEOUT_MS,\n }).then((outcome: ConnectOutcome) => {\n // Abandoned (reset / unmount / profile switch): a newer flow owns the\n // state and `pickRef` — leave both untouched and fire nothing.\n if (!isCurrent()) return;\n\n inFlightRef.current = false;\n pickRef.current = null;\n\n switch (outcome.status) {\n case 'active':\n setState({ phase: 'active', connection: outcome.connection });\n onConnectedRef.current?.(outcome.connection);\n return;\n case 'connected_pending':\n setState({ phase: 'connected_pending' });\n return;\n case 'cancelled':\n setState({ phase: 'cancelled' });\n return;\n case 'error':\n setState({ phase: 'error', reason: outcome.reason });\n return;\n }\n });\n }, [client, profileId]);\n\n const select = useCallback((externalAccountId: string) => {\n const pick = pickRef.current;\n if (!pick) return; // not in the picking phase\n\n pickRef.current = null;\n setState({ phase: 'connecting' }); // working again while the account binds\n pick.resolve(externalAccountId);\n }, []);\n\n const reset = useCallback(() => {\n // Bump the nonce → the pre-mint effect re-runs; its cleanup calls\n // `abandonFlow()` (rejecting any pending pick) and a fresh session is minted.\n setRemintNonce((n) => n + 1);\n }, []);\n\n return { state, start, select, reset };\n}\n\n/**\n * List a profile's connected accounts. Pass a `filter` to narrow by `kind`\n * (`posting` = social, `ads`) or `status` — e.g. a composer fetches\n * `{ kind: 'posting' }` to show only the social accounts it can publish to.\n */\nexport function useConnections(profileId: string, filter?: ConnectionsFilter) {\n const { client, queryClient } = usePostrun();\n return useQuery(\n {\n queryKey: connectionKeys.list(profileId, filter),\n queryFn: async () =>\n (\n await connectionsListByProfile({\n client,\n path: { id: profileId },\n query: filter,\n })\n ).data,\n enabled: Boolean(profileId),\n },\n queryClient,\n );\n}\n\n/** Retrieve a single connection by id. */\nexport function useConnection(id: string) {\n const { client, queryClient } = usePostrun();\n return useQuery(\n {\n queryKey: connectionKeys.detail(id),\n queryFn: async () =>\n (await connectionsGet({ client, path: { id } })).data,\n enabled: Boolean(id),\n },\n queryClient,\n );\n}\n\n/** List the accounts discoverable on a pending connection (for selection). */\nexport function useDiscoverableAccounts(id: string) {\n const { client, queryClient } = usePostrun();\n return useQuery(\n {\n queryKey: connectionKeys.accounts(id),\n queryFn: async () =>\n (await connectionsListAccounts({ client, path: { id } })).data,\n enabled: Boolean(id),\n },\n queryClient,\n );\n}\n\n/** Select an account on a pending connection, activating it. */\nexport function useSelectAccount() {\n const { client, queryClient } = usePostrun();\n return useMutation(\n {\n mutationFn: async ({ id, ...body }: { id: string } & SelectAccountInput) =>\n (await connectionsSelect({ client, path: { id }, body })).data,\n onSuccess: (_result, { id }) => {\n queryClient.invalidateQueries({ queryKey: connectionKeys.lists() });\n queryClient.invalidateQueries({ queryKey: connectionKeys.detail(id) });\n queryClient.invalidateQueries({ queryKey: connectionKeys.accounts(id) });\n },\n },\n queryClient,\n );\n}\n\n/** Disconnect (delete) a connection by id. */\nexport function useDisconnect() {\n const { client, queryClient } = usePostrun();\n return useMutation(\n {\n mutationFn: async (id: string) =>\n (await connectionsDelete({ client, path: { id } })).data,\n onSuccess: (_result, id) => {\n queryClient.invalidateQueries({ queryKey: connectionKeys.lists() });\n queryClient.removeQueries({ queryKey: connectionKeys.detail(id) });\n },\n },\n queryClient,\n );\n}\n","'use client';\n\nimport type { ReactNode } from 'react';\n\nimport type { ConnectablePlatform, Connection } from '@postrun/js';\n\nimport type { ConnectState } from './connections';\nimport { useConnect } from './connections';\n\n/** The flow state + actions handed to your render-prop. */\nexport interface ConnectRenderApi {\n /** The current flow state — switch on `state.phase` to render your UI. */\n state: ConnectState;\n /**\n * Begin connecting. Call this DIRECTLY from your button's `onClick` — it opens\n * the OAuth popup synchronously, so don't `await` anything before it. A no-op\n * until the session is ready (`state.phase === 'preparing'`).\n */\n start: () => void;\n /** When `state.phase === 'picking'`, activate with the chosen account id. */\n select: (externalAccountId: string) => void;\n /** Reset to a fresh, ready state (e.g. a \"try again\" after an error/cancel). */\n reset: () => void;\n}\n\nexport interface ConnectProps {\n /** The profile to attach the new connection to. */\n profileId: string;\n /** The platform to connect (X, LinkedIn, Meta, …). */\n platform: ConnectablePlatform;\n /** Called once a connection is fully ACTIVE (an account is bound). */\n onConnected?: (connection: Connection) => void;\n /** Render your own button + picker + status from the flow state. */\n children: (api: ConnectRenderApi) => ReactNode;\n}\n\n/**\n * Headless one-click connect. Wraps `useConnect` and hands you the flow state +\n * actions via a render-prop, so you own EVERY pixel (your button, your account\n * picker, your brand marks, your styling) while the SDK runs the embedded OAuth\n * popup + account binding — no redirect, no second click.\n *\n * ```tsx\n * <Connect profileId={id} platform=\"x\" onConnected={refetch}>\n * {({ state, start, select }) =>\n * state.phase === 'picking' ? (\n * <ul>\n * {state.accounts.map((a) => (\n * <li key={a.external_account_id}>\n * <button onClick={() => select(a.external_account_id)}>\n * {a.name ?? a.external_account_id}\n * </button>\n * </li>\n * ))}\n * </ul>\n * ) : (\n * <button onClick={start} disabled={state.phase !== 'idle'}>\n * Connect X\n * </button>\n * )\n * }\n * </Connect>\n * ```\n *\n * The trigger MUST call `start()` directly in the click (it opens the popup\n * synchronously). Mount `<Connect>` inside a `<PostrunProvider>`.\n */\nexport function Connect({\n profileId,\n platform,\n onConnected,\n children,\n}: ConnectProps): ReactNode {\n const api = useConnect({ profileId, platform, onConnected });\n return children(api);\n}\n","import axios, { isAxiosError } from 'axios';\n\nimport type { UploadTarget } from '@postrun/js';\n\n/** A failed direct-to-storage upload, carrying the HTTP status (0 = network). */\nexport class UploadError extends Error {\n readonly status: number;\n\n constructor(status: number, message: string) {\n super(message);\n this.name = 'UploadError';\n this.status = status;\n }\n}\n\nexport interface UploadBytesOptions {\n /** Fraction uploaded, 0..1. Called as bytes flow and once with 1 on success. */\n onProgress?: (fraction: number) => void;\n /** Abort the in-flight upload. */\n signal?: AbortSignal;\n}\n\n/**\n * PUT a file's bytes to a signed upload target, with progress and cancellation.\n * axios drives the XHR (the Fetch API can't report upload progress in browsers);\n * retry/poll are composed on top via p-retry/p-wait-for.\n */\nexport async function uploadBytes(\n target: UploadTarget,\n file: Blob,\n options: UploadBytesOptions = {},\n): Promise<void> {\n const { onProgress, signal } = options;\n\n try {\n await axios.request({\n method: target.method,\n url: target.url,\n data: file,\n headers: target.headers,\n signal,\n onUploadProgress: (event) => {\n if (event.total) {\n onProgress?.(event.loaded / event.total);\n }\n },\n });\n onProgress?.(1);\n } catch (error) {\n // A cancellation propagates as-is so callers (and p-retry) treat it as abort.\n if (signal?.aborted) {\n throw error;\n }\n if (isAxiosError(error)) {\n const status = error.response?.status ?? 0;\n throw new UploadError(\n status,\n status ? `Upload failed (HTTP ${status}).` : 'Upload failed: network error.',\n );\n }\n throw error;\n }\n}\n","import { useMutation, useQuery } from '@tanstack/react-query';\nimport pLimit from 'p-limit';\nimport pRetry, { AbortError } from 'p-retry';\nimport pWaitFor from 'p-wait-for';\nimport { useCallback, useRef, useState } from 'react';\n\nimport {\n mediaCreate,\n mediaDelete,\n mediaGet,\n mediaList,\n mediaUpdate,\n} from '@postrun/js';\nimport type {\n ListMediaQuery,\n MediaKind,\n MediaResource,\n MediaTarget,\n Metadata,\n PostrunClient,\n UpdateMediaInput,\n} from '@postrun/js';\n\nimport { usePostrun } from './context';\nimport { useInfiniteList } from './infinite-list';\nimport { mediaKeys } from './keys';\nimport { UploadError, uploadBytes } from './upload-bytes';\n\n/**\n * Poll the asset until it settles (ready/failed), respecting cancellation.\n * `onTick` fires with each fetched resource so callers can surface the live\n * `progress.{stage,percent}` the API reports during processing.\n */\nasync function pollUntilSettled(\n client: PostrunClient,\n id: string,\n signal: AbortSignal,\n onTick?: (resource: MediaResource) => void,\n): Promise<MediaResource> {\n let latest: MediaResource | undefined;\n await pWaitFor(\n async () => {\n if (signal.aborted) {\n throw new DOMException('Upload aborted', 'AbortError');\n }\n latest = (await mediaGet({ client, path: { id } })).data;\n onTick?.(latest);\n return latest.status === 'ready' || latest.status === 'failed';\n },\n { interval: 1500, timeout: 300_000 },\n );\n\n if (!latest) {\n throw new Error('Media polling returned no result.');\n }\n return latest;\n}\n\nexport type MediaUploadStatus =\n | 'idle'\n | 'uploading'\n | 'processing'\n | 'ready'\n | 'failed';\n\nexport interface MediaUploadOptions {\n /** Profile that owns the asset. */\n profileId: string;\n /** Platforms to validate + render for (omit to add later via useUpdateMedia). */\n targets?: MediaTarget[];\n /** Optional override — omit and the API auto-detects the kind from the bytes. */\n kind?: MediaKind;\n /**\n * Optional override — omit and the API auto-detects the MIME from the bytes.\n * Still useful for a legacy Office binary (.doc/.ppt) whose magic bytes can't be\n * disambiguated by the server sniff.\n */\n contentType?: string;\n /** Store as-is with zero processing. */\n raw?: boolean;\n altText?: string;\n externalId?: string;\n metadata?: Metadata;\n}\n\n/**\n * The core single-file upload pipeline used by `useMediaUpload` for every file\n * (single or batched) so the create → PUT-with-retry → poll-until-settled\n * sequence lives in exactly one place. Pure orchestration — no React state; the\n * caller passes an `AbortSignal` and callbacks so it can drive its own UI. Throws\n * on a hard failure / abort; returns the settled `MediaResource` (which may itself\n * be `failed`).\n */\nasync function runUpload(\n client: PostrunClient,\n file: File,\n options: MediaUploadOptions,\n signal: AbortSignal,\n callbacks: {\n onProgress: (fraction: number) => void;\n onProcessing: () => void;\n onPoll?: (resource: MediaResource) => void;\n },\n): Promise<MediaResource> {\n // The API auto-detects `kind` + `content_type` from the uploaded bytes\n // (magic-number sniff). Both ride as PURE OPTIONAL OVERRIDES — `undefined` when\n // the caller omits them, so the server detects; never fabricated client-side.\n const created = (\n await mediaCreate({\n client,\n body: {\n profile_id: options.profileId,\n kind: options.kind,\n content_type: options.contentType,\n targets: options.targets,\n raw: options.raw,\n alt_text: options.altText,\n external_id: options.externalId,\n metadata: options.metadata,\n },\n })\n ).data;\n\n if (created.upload) {\n const target = created.upload;\n await pRetry(\n async () => {\n try {\n await uploadBytes(target, file, {\n onProgress: callbacks.onProgress,\n signal,\n });\n } catch (uploadError) {\n // A client error (e.g. an expired signed URL) won't fix on retry.\n if (\n uploadError instanceof UploadError &&\n uploadError.status >= 400 &&\n uploadError.status < 500\n ) {\n throw new AbortError(uploadError);\n }\n throw uploadError;\n }\n },\n { retries: 3, signal },\n );\n }\n\n callbacks.onProcessing();\n return pollUntilSettled(client, created.id, signal, callbacks.onPoll);\n}\n\n/** One file's slot in an upload — its own live status, progress, and settled\n * asset. `status` is never `idle` (an item exists only once uploading). */\nexport interface MediaUploadItem {\n /** Stable local id (NOT the asset id) — use as the React key and for `remove`. */\n id: string;\n file: File;\n status: Exclude<MediaUploadStatus, 'idle'>;\n /** 0–1 client-side BYTE-upload bar. `media.progress.{stage,percent}` is the\n * live SERVER pipeline bar. */\n progress: number;\n media: MediaResource | null;\n error: unknown;\n}\n\nexport interface UseMediaUploadResult {\n /** Every file added, in add-order, with its live state. */\n items: readonly MediaUploadItem[];\n /** The settled-ready assets, in item order — what you attach to a post. */\n ready: readonly MediaResource[];\n /** True while any item is still uploading or processing. */\n isUploading: boolean;\n /**\n * Upload ONE file or MANY under `options`, gated by `concurrency`. The reactive\n * `items` update live for UI; the returned promise is for imperative flows —\n * it resolves to the settled (`ready`|`failed`) resources for THIS batch, in\n * add-order, EXCLUDING any item removed/aborted mid-flight. Single-file usage:\n * `const [asset] = await add(file, opts)`.\n */\n add: (\n files: File | FileList | readonly File[],\n options: MediaUploadOptions,\n ) => Promise<MediaResource[]>;\n /** Drop an item by local id — aborts it if still in flight. */\n remove: (id: string) => void;\n /** Abort everything and clear the list. */\n reset: () => void;\n}\n\nexport interface UseMediaUploadOptions {\n /**\n * How many files upload at once; the rest queue (default 3). Fixed for the\n * hook's lifetime — set it once when you call the hook.\n */\n concurrency?: number;\n}\n\n/** Normalize the accepted input (one File, a FileList, or an array) to a File[]. */\nfunction toFileArray(files: File | FileList | readonly File[]): File[] {\n if (files instanceof File) return [files];\n return Array.from(files);\n}\n\n/**\n * Upload one OR many files and get back platform-validated assets. The hook owns\n * the whole journey per file: create the asset (the API auto-detects\n * kind/content_type from the bytes), PUT the bytes with live `progress` + retry,\n * poll until processing settles, and expose `media.per_platform` (per-target\n * status, url, warnings,\n * errors). Every file gets its own `MediaUploadItem` slot in `items`; `ready` is\n * the settled assets to attach to a post; `remove`/`reset` abort in-flight work.\n * Uploads run through ONE shared `p-limit` gate so only `concurrency` (default 3)\n * are in flight at once — global across `add` calls, not per-call.\n *\n * Single-file usage: `const [asset] = await add(file, opts)` (or read `ready[0]`).\n */\nexport function useMediaUpload(\n options?: UseMediaUploadOptions,\n): UseMediaUploadResult {\n const { client, queryClient } = usePostrun();\n const [items, setItems] = useState<readonly MediaUploadItem[]>([]);\n // Local-id → controller, so `remove`/`reset` can abort an in-flight upload.\n const controllers = useRef<Map<string, AbortController>>(new Map());\n // One shared concurrency gate for the hook's lifetime — files queued across\n // multiple `add` calls all funnel through it, so the cap is global, not per-add.\n const limitRef = useRef<ReturnType<typeof pLimit> | null>(null);\n if (!limitRef.current) {\n limitRef.current = pLimit(options?.concurrency ?? 3);\n }\n\n const patch = useCallback(\n (id: string, changes: Partial<MediaUploadItem>) => {\n setItems((current) =>\n current.map((item) =>\n item.id === id ? { ...item, ...changes } : item,\n ),\n );\n },\n [],\n );\n\n const add = useCallback(\n (\n files: File | FileList | readonly File[],\n uploadOptions: MediaUploadOptions,\n ): Promise<MediaResource[]> => {\n const queued: MediaUploadItem[] = toFileArray(files).map((file) => ({\n id: crypto.randomUUID(),\n file,\n status: 'uploading',\n progress: 0,\n media: null,\n error: null,\n }));\n\n setItems((current) => [...current, ...queued]);\n\n const limit = limitRef.current;\n if (!limit) {\n return Promise.resolve([]);\n }\n\n // Each item resolves to its settled resource, or `null` if it was\n // removed/aborted mid-flight. These per-item promises NEVER reject, so the\n // batch `Promise.all` can't leave a hanging/unhandled rejection.\n const settlements = queued.map((item) => {\n const controller = new AbortController();\n controllers.current.set(item.id, controller);\n\n return limit(() => {\n // Removed while still queued behind the gate — skip the work entirely.\n if (controller.signal.aborted) {\n throw new DOMException('Upload aborted', 'AbortError');\n }\n return runUpload(client, item.file, uploadOptions, controller.signal, {\n onProgress: (progress) => patch(item.id, { progress }),\n onProcessing: () => patch(item.id, { status: 'processing' }),\n // Live server progress (stage + percent) each poll tick.\n onPoll: (media) => patch(item.id, { media }),\n });\n })\n .then((settled): MediaResource => {\n patch(item.id, {\n status: settled.status === 'failed' ? 'failed' : 'ready',\n media: settled,\n progress: 1,\n });\n queryClient.setQueryData(mediaKeys.detail(settled.id), settled);\n void queryClient.invalidateQueries({ queryKey: mediaKeys.lists() });\n return settled;\n })\n .catch((error: unknown): MediaResource | null => {\n // An aborted item was removed — its slot is already gone; resolve to\n // null so the batch promise drops it instead of hanging or rejecting.\n if (controller.signal.aborted) {\n return null;\n }\n patch(item.id, { status: 'failed', error });\n return null;\n })\n .finally(() => {\n controllers.current.delete(item.id);\n });\n });\n\n return Promise.all(settlements).then((results) =>\n results.filter((result): result is MediaResource => result !== null),\n );\n },\n [client, queryClient, patch],\n );\n\n const remove = useCallback((id: string) => {\n controllers.current.get(id)?.abort();\n controllers.current.delete(id);\n setItems((current) => current.filter((item) => item.id !== id));\n }, []);\n\n const reset = useCallback(() => {\n controllers.current.forEach((controller) => controller.abort());\n controllers.current.clear();\n setItems([]);\n }, []);\n\n const ready = items.flatMap((item) =>\n item.status === 'ready' && item.media ? [item.media] : [],\n );\n const isUploading = items.some(\n (item) => item.status === 'uploading' || item.status === 'processing',\n );\n\n return { items, ready, isUploading, add, remove, reset };\n}\n\n/** Retrieve a media asset; auto-polls while it is still uploading/processing. */\nexport function useMedia(id: string) {\n const { client, queryClient } = usePostrun();\n return useQuery(\n {\n queryKey: mediaKeys.detail(id),\n queryFn: async () =>\n (await mediaGet({ client, path: { id } })).data,\n enabled: Boolean(id),\n refetchInterval: (query) => {\n const current = query.state.data;\n return current?.status === 'uploading' || current?.status === 'processing'\n ? 2000\n : false;\n },\n },\n queryClient,\n );\n}\n\n/**\n * List media assets under the account, newest first. Filter by `profile_id`,\n * `status`, `kind`, your own `external_id`, or `metadata` (exact-match\n * containment), with offset `limit`/`offset` pagination. Returns one page; use\n * `useMediaInfinite` for a load-more feed.\n */\nexport function useMediaList(query?: ListMediaQuery) {\n const { client, queryClient } = usePostrun();\n return useQuery(\n {\n queryKey: mediaKeys.list(query),\n queryFn: async () => (await mediaList({ client, query })).data,\n },\n queryClient,\n );\n}\n\n/**\n * Load-more / infinite-scroll view over the media list — same filters as\n * `useMediaList` minus pagination, which the helper drives. Returns\n * `{ items, total, loadMore, hasMore, … }`.\n */\nexport function useMediaInfinite(\n filters?: Omit<ListMediaQuery, 'limit' | 'offset'>,\n options?: { pageSize?: number },\n) {\n const { client } = usePostrun();\n return useInfiniteList<MediaResource>({\n queryKey: mediaKeys.infinite(filters),\n limit: options?.pageSize,\n fetchPage: async ({ limit, offset }) =>\n (await mediaList({ client, query: { ...filters, limit, offset } })).data,\n });\n}\n\n/** Update a media asset: alt text / metadata / external_id, or extend targets. */\nexport function useUpdateMedia() {\n const { client, queryClient } = usePostrun();\n return useMutation(\n {\n mutationFn: async ({ id, ...body }: { id: string } & UpdateMediaInput) =>\n (await mediaUpdate({ client, path: { id }, body })).data,\n onSuccess: (result, { id }) => {\n queryClient.setQueryData(mediaKeys.detail(id), result);\n void queryClient.invalidateQueries({ queryKey: mediaKeys.lists() });\n },\n },\n queryClient,\n );\n}\n\n/** Delete a media asset and its stored renditions. */\nexport function useDeleteMedia() {\n const { client, queryClient } = usePostrun();\n return useMutation(\n {\n mutationFn: async (id: string) =>\n (await mediaDelete({ client, path: { id } })).data,\n onSuccess: (_result, id) => {\n queryClient.removeQueries({ queryKey: mediaKeys.detail(id) });\n void queryClient.invalidateQueries({ queryKey: mediaKeys.lists() });\n },\n },\n queryClient,\n );\n}\n","import { useMutation, useQuery } from '@tanstack/react-query';\n\nimport {\n buildCreatePost,\n isPostPlatform,\n postsCreate,\n postsDelete,\n postsGet,\n postsList,\n postsUpdate,\n} from '@postrun/js';\nimport type {\n ComposePostInput,\n ListPostsQuery,\n Post,\n UpdatePostInput,\n} from '@postrun/js';\n\n/**\n * The calendar/queue filter surface — a date window over `schedule_at` plus a\n * derived-status multi-select, scoped to an optional profile. Picked straight\n * from the generated `ListPostsQuery` contract (no hand-typed shapes), so it\n * can never drift from the API. Pagination still rides through via `usePosts`.\n */\nexport type CalendarFilters = Pick<\n ListPostsQuery,\n 'profile_id' | 'scheduled_after' | 'scheduled_before' | 'status'\n>;\n\nimport { useConnections } from './connections';\nimport { usePostrun } from './context';\nimport { useInfiniteList } from './infinite-list';\nimport { postKeys } from './keys';\n\n/**\n * A post's status as it appears on the RESPONSE (not the list `status` filter) —\n * the value a live poll actually inspects. Sourced from `Post['status']` so the\n * predicate below is type-correct against `query.state.data?.status`, and a\n * future contract change to the status set surfaces at compile time here.\n */\ntype PostResponseStatus = Post['status'];\n\n/**\n * Statuses that are still moving on their own and warrant polling: `scheduled`\n * (fires at its time with no user action → must be caught transitioning) and\n * `publishing` (mid-flight by definition). Everything else is terminal and stops\n * the poll: `published` / `failed` (end states), `partially_published` (no\n * further automatic movement), and `draft` (only an explicit update — which\n * already invalidates lists — moves it). Modelling in-flight as the small set\n * means any future status defaults to \"terminal/stop\" — the safe, no-runaway\n * default.\n */\nconst IN_FLIGHT: ReadonlySet<PostResponseStatus> = new Set([\n 'scheduled',\n 'publishing',\n]);\n\nconst isLivePostStatus = (status: PostResponseStatus): boolean =>\n IN_FLIGHT.has(status);\n\n/** Per-hook live-poll control: live is on by default; `{ live: false }` opts out. */\nexport interface LiveOptions {\n /** Auto-poll while a post is in-flight (default `true`). Set `false` for one-shot. */\n live?: boolean;\n}\n\n/**\n * List posts — the calendar/queue data, filtered (profile_id / external_id /\n * metadata) and paginated. `data` is the typed `PostList` envelope, with each\n * post's derived status (draft / scheduled / publishing / published / failed).\n */\nexport function usePosts(query?: ListPostsQuery) {\n const { client, queryClient } = usePostrun();\n return useQuery(\n {\n queryKey: postKeys.list(query),\n queryFn: async () =>\n (await postsList({ client, query })).data,\n },\n queryClient,\n );\n}\n\n/**\n * List posts with append-style (\"load more\") pagination — the calendar/queue\n * feed. Returns `{ items, loadMore, hasMore, isLoading, isLoadingMore, total }`:\n * render `items`, call `loadMore()` (on a button or scroll end) while `hasMore`.\n * `pageSize` defaults to 20. Filters are the same as `usePosts` minus paging,\n * which the hook owns. Shares list-cache invalidation with the other post hooks,\n * so a create/update/delete refreshes it automatically.\n */\nexport function usePostsInfinite(\n filters?: Omit<ListPostsQuery, 'limit' | 'offset'>,\n options?: { pageSize?: number },\n) {\n const { client } = usePostrun();\n return useInfiniteList<Post>({\n queryKey: postKeys.infinite(filters),\n limit: options?.pageSize,\n fetchPage: async ({ limit, offset }) =>\n (await postsList({ client, query: { ...filters, limit, offset } })).data,\n });\n}\n\n/**\n * Calendar/queue view — list posts in a `schedule_at` date window, optionally\n * narrowed to a profile and to one or more derived statuses (e.g. only\n * `scheduled` + `failed`). Forwards the date-range + multi-status filters (and\n * any `limit`/`offset`) to the generated `postsList` and returns the same typed\n * `PostList` envelope. It shares the `postKeys.list(filters)` cache identity with\n * `usePosts` but owns its own self-terminating poll: while ANY post in the\n * window is in-flight it refetches (5s — a list is heavier than one detail), and\n * stops once every item is terminal (or the window is empty). `live` is a\n * separate option, never mixed into the API filter object; default-on, opt out\n * with `{ live: false }`.\n */\nexport function useCalendar(\n filters?: CalendarFilters & Pick<ListPostsQuery, 'limit' | 'offset'>,\n options?: LiveOptions,\n) {\n const { client, queryClient } = usePostrun();\n return useQuery(\n {\n queryKey: postKeys.list(filters),\n queryFn: async () => (await postsList({ client, query: filters })).data,\n refetchInterval: (query) => {\n if (options?.live === false) return false;\n const posts = query.state.data?.data ?? [];\n return posts.some((post) => isLivePostStatus(post.status)) ? 5000 : false;\n },\n },\n queryClient,\n );\n}\n\n/**\n * Retrieve a single post by id (its variants, schedule, and derived status).\n * Auto-polls (2s) while the post is in-flight (`scheduled` / `publishing`) and\n * stops once it reaches a terminal status — so a scheduled post visibly\n * transitions with no manual refetch. `live` is on by default; pass\n * `{ live: false }` to force a one-shot.\n */\nexport function usePost(id: string, options?: LiveOptions) {\n const { client, queryClient } = usePostrun();\n return useQuery(\n {\n queryKey: postKeys.detail(id),\n queryFn: async () =>\n (await postsGet({ client, path: { id } })).data,\n enabled: Boolean(id),\n refetchInterval: (query) => {\n if (options?.live === false) return false;\n const status = query.state.data?.status;\n return status && isLivePostStatus(status) ? 2000 : false;\n },\n },\n queryClient,\n );\n}\n\n/**\n * Compose and create a post. Resolves the profile's connections, builds the full\n * variant set from `{ content, channels }` (per the `buildCreatePost` rules), and\n * sends it — the customer never assembles variants or passes a `connection_id`.\n * `connectedChannels` is the set of posting platforms this profile can reach.\n */\nexport function useCreatePost(profileId: string) {\n const { client, queryClient } = usePostrun();\n const connections = useConnections(profileId);\n const connected = connections.data?.data ?? [];\n\n const mutation = useMutation(\n {\n mutationFn: async (input: Omit<ComposePostInput, 'profileId'>) =>\n (\n await postsCreate({\n client,\n body: buildCreatePost({ ...input, profileId }, connected),\n })\n ).data,\n onSuccess: () =>\n queryClient.invalidateQueries({ queryKey: postKeys.lists() }),\n },\n queryClient,\n );\n\n return {\n create: mutation.mutateAsync,\n isPending: mutation.isPending,\n error: mutation.error,\n data: mutation.data,\n reset: mutation.reset,\n // The profile's connections must load before `create` can resolve a channel;\n // gate on this so a call during loading isn't mislabeled \"not connected\".\n isReady: connections.isSuccess,\n connectedChannels: connected\n .map((connection) => connection.platform)\n .filter(isPostPlatform),\n };\n}\n\n/**\n * Update a post by id. Pass a light edit directly (`{ schedule_at }`,\n * `{ tags }`, …) or a rebuilt body from `buildUpdatePost(input, connections)`\n * for content edits (the API's PATCH replaces the variant set).\n */\nexport function useUpdatePost(postId: string) {\n const { client, queryClient } = usePostrun();\n return useMutation(\n {\n mutationFn: async (body: UpdatePostInput) =>\n (await postsUpdate({ client, path: { id: postId }, body })).data,\n onSuccess: (result) => {\n queryClient.invalidateQueries({ queryKey: postKeys.lists() });\n queryClient.setQueryData(postKeys.detail(postId), result);\n },\n },\n queryClient,\n );\n}\n\n/** Delete a post by id; on success the lists refresh and its detail is dropped. */\nexport function useDeletePost() {\n const { client, queryClient } = usePostrun();\n return useMutation(\n {\n mutationFn: async (id: string) =>\n (await postsDelete({ client, path: { id } })).data,\n onSuccess: (_result, id) => {\n queryClient.invalidateQueries({ queryKey: postKeys.lists() });\n queryClient.removeQueries({ queryKey: postKeys.detail(id) });\n },\n },\n queryClient,\n );\n}\n","'use client';\n\nimport { useEffect, useMemo, useState } from 'react';\n\nimport type { PreviewMedia, ResolvedMedia } from './types';\n\n/**\n * Shared media resolution for every platform preview. URL-backed items resolve\n * SYNCHRONOUSLY (the common, processed-asset path — no first-paint flash);\n * compose-time `File` items get an object URL minted in an effect and revoked on\n * change/unmount. Keyed on a content signature, so the resolved array is stable\n * across parent re-renders that don't change the media — the heavy work (object\n * URLs) never churns and downstream mapping stays memoized. Alt text falls back\n * to the variant media's `alt_text_override`.\n */\n\n/** Per-item alt-text fallback source (the variant's media refs). */\nexport type AltFallbacks =\n | readonly { alt_text_override?: string | null }[]\n | undefined;\n\nfunction fileKey(file: File | undefined): string {\n return file ? `${file.name}:${file.size}:${file.lastModified}` : '';\n}\n\n/** A content signature so object-URL work only re-runs when the media actually\n * changes — not on every parent re-render that passes a new array. */\nexport function mediaSignature(\n media: readonly PreviewMedia[] | undefined,\n): string {\n return (media ?? [])\n .map((item) => {\n const source = item.url ?? fileKey(item.file);\n const size = `${item.width ?? ''}x${item.height ?? ''}`;\n return `${item.kind}|${source}|${item.posterUrl ?? ''}|${size}|${item.alt ?? ''}`;\n })\n .join('§');\n}\n\n/** Stable string of the per-item alt fallbacks, for memo keying. */\nexport function altSignatureOf(media: AltFallbacks): string {\n return (media ?? []).map((m) => m?.alt_text_override ?? '').join('§');\n}\n\nexport function useResolvedMedia(\n media: readonly PreviewMedia[] | undefined,\n altFallbacks: AltFallbacks,\n altSignature: string,\n): ResolvedMedia[] {\n const signature = mediaSignature(media);\n const [objectUrls, setObjectUrls] = useState<Record<number, string>>({});\n\n useEffect(() => {\n const created: string[] = [];\n const next: Record<number, string> = {};\n (media ?? []).forEach((item, index) => {\n if (!item.url && item.file) {\n const url = URL.createObjectURL(item.file);\n created.push(url);\n next[index] = url;\n }\n });\n setObjectUrls(next);\n return () => {\n for (const url of created) {\n URL.revokeObjectURL(url);\n }\n };\n // `signature` captures every File identity that needs an object URL.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [signature]);\n\n return useMemo(\n () =>\n (media ?? []).flatMap((item, index): ResolvedMedia[] => {\n const src = item.url ?? objectUrls[index];\n if (!src) {\n return [];\n }\n return [\n {\n kind: item.kind,\n src,\n width: item.width,\n height: item.height,\n alt: item.alt ?? altFallbacks?.[index]?.alt_text_override ?? undefined,\n posterSrc: item.posterUrl,\n },\n ];\n }),\n // `signature` + `altSignature` capture the content; `objectUrls` flips once\n // File blobs resolve. Referencing `media`/`altFallbacks` directly is safe.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [signature, altSignature, objectUrls],\n );\n}\n","import type { CSSProperties } from 'react';\nimport type { IconType } from 'react-icons';\nimport {\n FiBarChart2,\n FiHeart,\n FiMessageCircle,\n FiRepeat,\n FiShare,\n} from 'react-icons/fi';\n\n/**\n * A static, honest action row for the X preview: reply, repost, like, views, and\n * share — real Feather icons (via react-icons), NO fabricated counts and no\n * outbound links (a draft hasn't been engaged with). We render our own row rather\n * than react-tweet's `TweetActions` because that one prints a `0` like-count,\n * which would be a lie on an unpublished post.\n *\n * Color inherits react-tweet's CSS variable, so it matches the card in light and\n * dark and restyles with the same variable the rest of the card uses.\n */\n\nconst ROW: CSSProperties = {\n display: 'flex',\n justifyContent: 'space-between',\n maxWidth: 425,\n marginTop: 12,\n color: 'var(--tweet-color-gray-secondary, #536471)',\n};\n\nconst ACTIONS: { label: string; Icon: IconType }[] = [\n { label: 'Reply', Icon: FiMessageCircle },\n { label: 'Repost', Icon: FiRepeat },\n { label: 'Like', Icon: FiHeart },\n { label: 'Views', Icon: FiBarChart2 },\n { label: 'Share', Icon: FiShare },\n];\n\nexport function XPreviewActions() {\n return (\n <div style={ROW}>\n {ACTIONS.map(({ label, Icon }) => (\n <Icon key={label} size={18} aria-label={label} role=\"img\" />\n ))}\n </div>\n );\n}\n","import twitterText from 'twitter-text';\nimport type { TweetEntities } from 'react-tweet/api';\n\n// twitter-text's ESM entry exposes a single default object (no named exports),\n// so a default import is the only form that resolves across bundlers — named\n// imports compile under @types but break in esbuild/rollup at the consumer.\nconst {\n extractCashtagsWithIndices,\n extractHashtagsWithIndices,\n extractMentionsWithIndices,\n extractUrlsWithIndices,\n modifyIndicesFromUTF16ToUnicode,\n} = twitterText;\n\n/**\n * Extract the X text entities (hashtags, @mentions, URLs, $cashtags) from a post\n * body, in the shape `react-tweet`'s `enrichTweet` consumes to rebuild the rich\n * body. Indices come straight from `twitter-text` — the reference implementation\n * X itself uses — so highlighting matches the real platform exactly (Unicode,\n * punctuation boundaries, and all). We never hand-roll the parsing.\n *\n * Fields X's syndication payload carries that a compose-time preview cannot know\n * (a mention's numeric `id_str` / display `name`) are filled with honest stand-ins\n * (`screen_name`), which is all the renderer needs to draw the entity.\n */\nexport function extractEntities(text: string): TweetEntities {\n const hashtags = extractHashtagsWithIndices(text);\n const mentions = extractMentionsWithIndices(text);\n const urls = extractUrlsWithIndices(text);\n const cashtags = extractCashtagsWithIndices(text);\n\n // twitter-text's regex indices are UTF-16; react-tweet slices `Array.from(text)`\n // (codepoint-aware), so convert in place — otherwise any astral char (emoji)\n // before an entity shifts every later highlight. Converting one combined array\n // keeps the per-list references in sync (the helper mutates `.indices`).\n modifyIndicesFromUTF16ToUnicode(text, [\n ...hashtags,\n ...mentions,\n ...urls,\n ...cashtags,\n ]);\n\n return {\n hashtags: hashtags.map((h) => ({ text: h.hashtag, indices: h.indices })),\n user_mentions: mentions.map((m) => ({\n id_str: '',\n name: m.screenName,\n screen_name: m.screenName,\n indices: m.indices,\n })),\n urls: urls.map((u) => ({\n display_url: u.url,\n expanded_url: u.url,\n url: u.url,\n indices: u.indices,\n })),\n symbols: cashtags.map((c) => ({ text: c.cashtag, indices: c.indices })),\n };\n}\n","import type { XPostVariant } from '@postrun/js';\nimport type {\n MediaAnimatedGif,\n MediaDetails,\n MediaPhoto,\n MediaVideo,\n QuotedTweet,\n Tweet,\n TweetUser,\n VideoInfo,\n} from 'react-tweet/api';\n\nimport type { ResolvedMedia, XPreviewAuthor } from '../types';\nimport { extractEntities } from './entities';\n\n/**\n * Maps a Postrun X variant (+ the customer-supplied author/media) into the\n * `Tweet` object `react-tweet` renders. This is the whole \"schema → exact X\n * preview\" brain: a PURE function, no DOM, no network, no `File` handling (the\n * component resolves pixels to URLs before calling this). Every field\n * `react-tweet` reads is filled with a real value — no casts — and engagement\n * metrics are honest zeros (a draft has no likes).\n */\n\n/** Quoted-card content with media already resolved. */\nexport interface ResolvedQuotedTweet {\n author: XPreviewAuthor;\n body?: string;\n media?: ResolvedMedia[];\n}\n\nexport interface ToTweetInput {\n variant: XPostVariant;\n author: XPreviewAuthor;\n media?: ResolvedMedia[];\n quotedTweet?: ResolvedQuotedTweet;\n /** The replied-to account's handle (our schema only stores the parent id). */\n replyToHandle?: string;\n}\n\n/** Neutral placeholder avatar (a grey circle) for when no avatar is supplied —\n * keeps the header from showing a broken image. */\nconst PLACEHOLDER_AVATAR =\n 'data:image/svg+xml;utf8,' +\n encodeURIComponent(\n '<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"48\" height=\"48\">' +\n '<circle cx=\"24\" cy=\"24\" r=\"24\" fill=\"#cfd9de\"/></svg>',\n );\n\n/** Fallback pixel dimensions when the customer doesn't know the asset's size —\n * a 3:2 frame keeps react-tweet's aspect-ratio math from dividing by zero. */\nconst FALLBACK_WIDTH = 1200;\nconst FALLBACK_HEIGHT = 800;\n\n/** Length in Unicode codepoints (astral-aware), matching how react-tweet slices\n * the body via `Array.from(text)`. */\nfunction codepointLength(text: string): number {\n return Array.from(text).length;\n}\n\nfunction buildUser(author: XPreviewAuthor): TweetUser {\n const verified = author.verified ?? false;\n return {\n id_str: '',\n name: author.name,\n profile_image_url_https: author.avatarUrl ?? PLACEHOLDER_AVATAR,\n profile_image_shape: 'Circle',\n screen_name: author.handle,\n verified: false,\n is_blue_verified: verified,\n };\n}\n\n/** The fields shared by every media kind, contextually typed (derived from\n * `MediaPhoto`) so tuple/literal fields infer correctly without a cast. */\nfunction mediaBase(\n src: string,\n width?: number,\n height?: number,\n): Omit<MediaPhoto, 'type' | 'ext_alt_text'> {\n const w = width ?? FALLBACK_WIDTH;\n const h = height ?? FALLBACK_HEIGHT;\n const size = { h, w, resize: 'fit' };\n return {\n display_url: '',\n expanded_url: '',\n ext_media_availability: { status: 'available' },\n ext_media_color: { palette: [] },\n indices: [0, 0],\n media_url_https: src,\n original_info: { height: h, width: w, focus_rects: [] },\n sizes: { large: size, medium: size, small: size, thumb: size },\n url: src,\n };\n}\n\nfunction buildPhoto(media: ResolvedMedia): MediaPhoto {\n return {\n ...mediaBase(media.src, media.width, media.height),\n type: 'photo',\n ext_alt_text: media.alt,\n };\n}\n\nfunction buildVideo(media: ResolvedMedia): MediaVideo | MediaAnimatedGif {\n const poster = media.posterSrc ?? media.src;\n const videoInfo: VideoInfo = {\n aspect_ratio: [media.width ?? 16, media.height ?? 9],\n variants: [{ content_type: 'video/mp4', url: media.src }],\n };\n const base = mediaBase(poster, media.width, media.height);\n return media.kind === 'gif'\n ? { ...base, type: 'animated_gif', video_info: videoInfo }\n : { ...base, type: 'video', video_info: videoInfo };\n}\n\nfunction buildMediaDetails(media: readonly ResolvedMedia[]): MediaDetails[] {\n return media.map((item) =>\n item.kind === 'image' ? buildPhoto(item) : buildVideo(item),\n );\n}\n\n/** The static, draft-honest scaffolding every synthesized tweet shares. */\nfunction tweetScaffold(): Pick<\n Tweet,\n | 'lang'\n | 'created_at'\n | 'edit_control'\n | 'isEdited'\n | 'isStaleEdit'\n | 'favorite_count'\n | 'conversation_count'\n | 'news_action_type'\n> {\n return {\n lang: 'en',\n created_at: '',\n edit_control: {\n edit_tweet_ids: [],\n editable_until_msecs: '0',\n is_edit_eligible: false,\n edits_remaining: '0',\n },\n isEdited: false,\n isStaleEdit: false,\n favorite_count: 0,\n conversation_count: 0,\n news_action_type: 'conversation',\n };\n}\n\nfunction buildQuoted(\n quote: ResolvedQuotedTweet | undefined,\n hasQuoteId: boolean,\n): QuotedTweet | undefined {\n if (!quote && !hasQuoteId) {\n return undefined;\n }\n\n const author = quote?.author ?? { name: 'Quoted post', handle: '' };\n const body = quote?.body ?? '';\n const media = quote?.media ?? [];\n\n return {\n lang: 'en',\n created_at: '',\n display_text_range: [0, codepointLength(body)],\n entities: extractEntities(body),\n id_str: '',\n text: body,\n user: buildUser(author),\n edit_control: {\n edit_tweet_ids: [],\n editable_until_msecs: '0',\n is_edit_eligible: false,\n edits_remaining: '0',\n },\n isEdited: false,\n isStaleEdit: false,\n reply_count: 0,\n retweet_count: 0,\n favorite_count: 0,\n self_thread: { id_str: '' },\n ...(media.length > 0 ? { mediaDetails: buildMediaDetails(media) } : {}),\n };\n}\n\nexport function toTweet(input: ToTweetInput): Tweet {\n const { variant, author, media = [], quotedTweet, replyToHandle } = input;\n const text = variant.body ?? '';\n const mediaDetails = buildMediaDetails(media);\n const quoted = buildQuoted(\n quotedTweet,\n variant.settings?.quote_tweet_id !== undefined,\n );\n const reply = variant.settings?.reply;\n\n return {\n __typename: 'Tweet',\n ...tweetScaffold(),\n // Codepoint length, not `text.length` (UTF-16) — react-tweet renders the\n // body off `Array.from(text)`, so emoji must not shift the range.\n display_text_range: [0, codepointLength(text)],\n entities: extractEntities(text),\n id_str: '',\n text,\n user: buildUser(author),\n ...(mediaDetails.length > 0 ? { mediaDetails } : {}),\n ...(quoted ? { quoted_tweet: quoted } : {}),\n // Both the handle AND the parent id are needed: enrichTweet builds the\n // reply link as `…/${screen_name}/status/${status_id_str}`, so omitting the\n // id yields a `/status/undefined` href.\n ...(reply && replyToHandle\n ? {\n in_reply_to_screen_name: replyToHandle,\n in_reply_to_status_id_str: reply.in_reply_to_tweet_id,\n }\n : {}),\n };\n}\n","'use client';\n\nimport type { XPostVariant } from '@postrun/js';\nimport { memo, useMemo } from 'react';\nimport type { CSSProperties } from 'react';\nimport {\n QuotedTweet,\n TweetBody,\n TweetContainer,\n TweetHeader,\n TweetInReplyTo,\n TweetMedia,\n type TwitterComponents,\n enrichTweet,\n} from 'react-tweet';\n\nimport type {\n PreviewMedia,\n XPreviewAuthor,\n XPreviewQuotedTweet,\n} from '../types';\nimport { altSignatureOf, useResolvedMedia } from '../use-resolved-media';\nimport { XPreviewActions } from './XPreviewActions';\nimport { toTweet } from './to-tweet';\n\nexport interface XPostPreviewProps {\n /** The X variant from our schema — the content source, untouched. */\n variant: XPostVariant;\n /** Author identity (not stored on our connection — supplied by you). */\n author: XPreviewAuthor;\n /** Resolved media pixels (URLs or compose-time File blobs). */\n media?: PreviewMedia[];\n /** Content for the quoted card when `settings.quote_tweet_id` is set. */\n quotedTweet?: XPreviewQuotedTweet;\n /** The replied-to account's handle (our schema only stores the parent id). */\n replyToHandle?: string;\n /** Color scheme. `auto` (default) inherits the host's theme. */\n theme?: 'light' | 'dark' | 'auto';\n /** Show the static action row (icons, no counts). Default true. */\n showActions?: boolean;\n /** Class applied to the wrapper — your hook for sizing, shadows, etc. */\n className?: string;\n /** Inline styles on the wrapper — e.g. react-tweet CSS variables\n * (`{ ['--tweet-container-margin']: '0' }`). */\n style?: CSSProperties;\n /** Override react-tweet's internal pieces (e.g. `next/image` avatars). */\n components?: TwitterComponents;\n}\n\n/**\n * A faithful, pixel-accurate preview of how an X post will look once published,\n * rendered straight from a Postrun X variant. Built on `react-tweet` (the same\n * card X itself ships), so you write zero card UI — pass the schema, render the\n * preview. Fully customizable: restyle via `className`/`style` (CSS variables)\n * or swap internals via `components`; theme light/dark/auto.\n */\nfunction XPostPreviewImpl({\n variant,\n author,\n media,\n quotedTweet,\n replyToHandle,\n theme = 'auto',\n showActions = true,\n className,\n style,\n components,\n}: XPostPreviewProps) {\n const resolvedMedia = useResolvedMedia(\n media,\n variant.media,\n altSignatureOf(variant.media),\n );\n const resolvedQuotedMedia = useResolvedMedia(quotedTweet?.media, undefined, '');\n\n const tweet = useMemo(() => {\n const resolvedQuoted = quotedTweet\n ? {\n author: quotedTweet.author,\n body: quotedTweet.body,\n media: resolvedQuotedMedia,\n }\n : undefined;\n\n return enrichTweet(\n toTweet({\n variant,\n author,\n media: resolvedMedia,\n quotedTweet: resolvedQuoted,\n replyToHandle,\n }),\n );\n }, [\n variant,\n author,\n resolvedMedia,\n quotedTweet,\n resolvedQuotedMedia,\n replyToHandle,\n ]);\n\n return (\n <div\n data-theme={theme === 'auto' ? undefined : theme}\n className={className}\n style={style}\n >\n <TweetContainer>\n <TweetHeader tweet={tweet} components={components} />\n {tweet.in_reply_to_screen_name ? <TweetInReplyTo tweet={tweet} /> : null}\n <TweetBody tweet={tweet} />\n {tweet.mediaDetails?.length ? (\n <TweetMedia tweet={tweet} components={components} />\n ) : null}\n {tweet.quoted_tweet ? <QuotedTweet tweet={tweet.quoted_tweet} /> : null}\n {showActions ? <XPreviewActions /> : null}\n </TweetContainer>\n </div>\n );\n}\n\n/** Memoized: re-renders only when its props change (the resolved-media hook\n * already absorbs unstable media arrays). */\nexport const XPostPreview = memo(XPostPreviewImpl);\n","'use client';\n\nimport { useEffect, useState } from 'react';\n\n/**\n * LinkedIn preview theming. Unlike the X preview (which inherits react-tweet's\n * CSS), we own the LinkedIn card, so we expose a small set of CSS custom\n * properties on the wrapper. The resolved palette sets their default values;\n * a customer can override any of them via `style`/`className`. Components read\n * `var(--pr-li-*)`, so restyling needs no fork.\n */\n\nexport type LinkedInTheme = 'light' | 'dark' | 'auto';\n\nexport const LI_VAR = {\n bg: '--pr-li-bg',\n text: '--pr-li-text',\n muted: '--pr-li-muted',\n border: '--pr-li-border',\n accent: '--pr-li-accent',\n};\n\ninterface Palette {\n bg: string;\n text: string;\n muted: string;\n border: string;\n accent: string;\n}\n\nconst LIGHT: Palette = {\n bg: '#ffffff',\n text: 'rgba(0,0,0,0.9)',\n muted: 'rgba(0,0,0,0.6)',\n border: 'rgba(0,0,0,0.08)',\n accent: 'rgb(10,102,194)',\n};\n\nconst DARK: Palette = {\n bg: '#1b1f23',\n text: 'rgba(255,255,255,0.9)',\n muted: 'rgba(255,255,255,0.6)',\n border: 'rgba(255,255,255,0.15)',\n accent: 'rgb(112,181,249)',\n};\n\n/** A CSS `var(...)` reference to one of the LinkedIn theme variables. */\nexport function varRef(name: string): string {\n return `var(${name})`;\n}\n\n/** The CSS custom-property declarations for a resolved scheme. Typed as a plain\n * string record (React's `CSSProperties` doesn't model `--custom` keys); it is\n * spread into the card's `style`, where React forwards it to the DOM. */\nexport function paletteVars(dark: boolean): Record<string, string> {\n const p = dark ? DARK : LIGHT;\n return {\n '--pr-li-bg': p.bg,\n '--pr-li-text': p.text,\n '--pr-li-muted': p.muted,\n '--pr-li-border': p.border,\n '--pr-li-accent': p.accent,\n };\n}\n\n/** Track the OS color scheme for `theme=\"auto\"`. Starts light (SSR-safe, no\n * hydration mismatch) and updates after mount. */\nexport function usePrefersDark(): boolean {\n const [dark, setDark] = useState(false);\n\n useEffect(() => {\n if (typeof window === 'undefined' || !window.matchMedia) {\n return;\n }\n const mq = window.matchMedia('(prefers-color-scheme: dark)');\n setDark(mq.matches);\n const onChange = (event: MediaQueryListEvent) => setDark(event.matches);\n mq.addEventListener('change', onChange);\n return () => mq.removeEventListener('change', onChange);\n }, []);\n\n return dark;\n}\n\n/** Resolve whether the card should render dark for a given theme prop. */\nexport function useIsDark(theme: LinkedInTheme): boolean {\n const prefersDark = usePrefersDark();\n if (theme === 'auto') {\n return prefersDark;\n }\n return theme === 'dark';\n}\n","import type { CSSProperties } from 'react';\nimport type { IconType } from 'react-icons';\nimport { FiMessageSquare, FiRepeat, FiSend, FiThumbsUp } from 'react-icons/fi';\n\nimport { LI_VAR, varRef } from './theme';\n\n/**\n * The static LinkedIn action bar — Like / Comment / Repost / Send. Real Feather\n * icons (via react-icons) + labels, no fabricated reaction counts (a draft has\n * none). Honest, like the X preview's footer.\n */\n\nconst ROW: CSSProperties = {\n display: 'flex',\n justifyContent: 'space-around',\n borderTop: `1px solid ${varRef(LI_VAR.border)}`,\n marginTop: 8,\n padding: '4px 8px',\n};\n\nconst ITEM: CSSProperties = {\n display: 'flex',\n alignItems: 'center',\n gap: 6,\n padding: '8px',\n color: varRef(LI_VAR.muted),\n fontSize: 14,\n fontWeight: 600,\n};\n\nconst ACTIONS: { label: string; Icon: IconType }[] = [\n { label: 'Like', Icon: FiThumbsUp },\n { label: 'Comment', Icon: FiMessageSquare },\n { label: 'Repost', Icon: FiRepeat },\n { label: 'Send', Icon: FiSend },\n];\n\nexport function EngagementBar() {\n return (\n <div style={ROW}>\n {ACTIONS.map(({ label, Icon }) => (\n <span key={label} style={ITEM}>\n <Icon size={20} aria-hidden />\n {label}\n </span>\n ))}\n </div>\n );\n}\n","import { FiGlobe, FiUsers } from 'react-icons/fi';\nimport { LuBadgeCheck } from 'react-icons/lu';\n\nimport type { LinkedInPreviewAuthor } from '../types';\nimport { LI_VAR, varRef } from './theme';\n\n/**\n * The LinkedIn post header: avatar, actor name (+ optional verified badge),\n * one-line headline, then a muted row with a relative time and the audience icon\n * (globe = public, people = connections-only). Real Feather/Lucide icons via\n * react-icons — no hand-drawn paths.\n */\n\nexport type LinkedInVisibility = 'PUBLIC' | 'CONNECTIONS';\n\nconst PLACEHOLDER_AVATAR =\n 'data:image/svg+xml;utf8,' +\n encodeURIComponent(\n '<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"48\" height=\"48\">' +\n '<circle cx=\"24\" cy=\"24\" r=\"24\" fill=\"#9aa6b2\"/></svg>',\n );\n\nexport interface HeaderProps {\n author: LinkedInPreviewAuthor;\n visibility: LinkedInVisibility;\n /** Relative time label, e.g. \"Now\". */\n time?: string;\n}\n\nexport function Header({ author, visibility, time = 'Now' }: HeaderProps) {\n return (\n <div style={{ display: 'flex', gap: 8, padding: '12px 16px 0' }}>\n <img\n src={author.avatarUrl ?? PLACEHOLDER_AVATAR}\n alt=\"\"\n width={48}\n height={48}\n style={{ width: 48, height: 48, borderRadius: '50%', objectFit: 'cover', flex: '0 0 auto' }}\n />\n <div style={{ minWidth: 0, display: 'flex', flexDirection: 'column' }}>\n <span\n style={{\n display: 'flex',\n alignItems: 'center',\n fontSize: 14,\n fontWeight: 600,\n color: varRef(LI_VAR.text),\n lineHeight: 1.3,\n }}\n >\n {author.name}\n {author.verified ? (\n <LuBadgeCheck\n size={16}\n aria-label=\"Verified\"\n role=\"img\"\n style={{ color: varRef(LI_VAR.accent), marginLeft: 3, flex: '0 0 auto' }}\n />\n ) : null}\n </span>\n {author.headline ? (\n <span style={{ fontSize: 12, color: varRef(LI_VAR.muted), lineHeight: 1.3 }}>\n {author.headline}\n </span>\n ) : null}\n <span\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 4,\n fontSize: 12,\n color: varRef(LI_VAR.muted),\n lineHeight: 1.3,\n }}\n >\n {time} •{' '}\n {visibility === 'PUBLIC' ? (\n <FiGlobe size={13} aria-label=\"Public\" role=\"img\" />\n ) : (\n <FiUsers size={13} aria-label=\"Connections\" role=\"img\" />\n )}\n </span>\n </div>\n </div>\n );\n}\n","import type { CSSProperties } from 'react';\n\nimport type { ResolvedMedia } from '../types';\n\n/**\n * LinkedIn's image layout: a single full-bleed image, or the 2/3/4 mosaic with a\n * \"+N\" overlay on the fourth tile when there are more than four. Edge-to-edge,\n * 2px gutters — matching the in-feed look.\n */\n\nconst MAX_TILES = 4;\nconst MOSAIC_HEIGHT = 272;\n\nconst GRID_BASE: CSSProperties = {\n display: 'grid',\n gap: 2,\n height: MOSAIC_HEIGHT,\n overflow: 'hidden',\n};\n\n/** Grid template for a given visible-tile count (2, 3 or 4). */\nfunction gridStyle(tiles: number): CSSProperties {\n if (tiles === 2) {\n return { ...GRID_BASE, gridTemplateColumns: '1fr 1fr' };\n }\n if (tiles === 3) {\n // One tall image on the left, two stacked on the right.\n return {\n ...GRID_BASE,\n gridTemplateColumns: '1fr 1fr',\n gridTemplateRows: '1fr 1fr',\n gridTemplateAreas: '\"a b\" \"a c\"',\n };\n }\n return {\n ...GRID_BASE,\n gridTemplateColumns: '1fr 1fr',\n gridTemplateRows: '1fr 1fr',\n };\n}\n\nconst IMG_STYLE: CSSProperties = {\n width: '100%',\n height: '100%',\n objectFit: 'cover',\n display: 'block',\n};\n\nconst AREAS = ['a', 'b', 'c'];\n\nfunction Tile({\n item,\n area,\n overlay,\n}: {\n item: ResolvedMedia;\n area?: string;\n overlay?: number;\n}) {\n return (\n <div style={{ position: 'relative', gridArea: area, overflow: 'hidden' }}>\n <img src={item.src} alt={item.alt ?? ''} style={IMG_STYLE} />\n {overlay ? (\n <div\n aria-hidden={false}\n style={{\n position: 'absolute',\n inset: 0,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n background: 'rgba(0,0,0,0.5)',\n color: '#fff',\n fontSize: 28,\n fontWeight: 600,\n }}\n >\n {`+${overlay}`}\n </div>\n ) : null}\n </div>\n );\n}\n\nexport interface ImageMosaicProps {\n media: readonly ResolvedMedia[];\n}\n\nexport function ImageMosaic({ media }: ImageMosaicProps) {\n if (media.length === 0) {\n return null;\n }\n\n if (media.length === 1) {\n const only = media[0]!;\n return (\n <img\n src={only.src}\n alt={only.alt ?? ''}\n style={{ width: '100%', height: 'auto', display: 'block' }}\n />\n );\n }\n\n const tiles = media.slice(0, MAX_TILES);\n const hidden = media.length - MAX_TILES;\n\n return (\n <div style={gridStyle(tiles.length)}>\n {tiles.map((item, index) => (\n <Tile\n key={item.src + index}\n item={item}\n area={tiles.length === 3 ? AREAS[index] : undefined}\n overlay={\n hidden > 0 && index === MAX_TILES - 1 ? hidden : undefined\n }\n />\n ))}\n </div>\n );\n}\n","import type { ResolvedMedia } from '../types';\nimport { ImageMosaic } from './ImageMosaic';\n\n/**\n * The media area of a LinkedIn post (v1: images + video). A post carries either\n * a video or images; a video wins if present and renders as a playable element\n * with its poster, otherwise the image mosaic. Edge-to-edge, like the feed.\n */\n\nfunction VideoTile({ item }: { item: ResolvedMedia }) {\n return (\n <video\n src={item.src}\n poster={item.posterSrc}\n controls\n style={{ width: '100%', display: 'block', background: '#000' }}\n />\n );\n}\n\nexport interface MediaProps {\n media: readonly ResolvedMedia[];\n}\n\nexport function Media({ media }: MediaProps) {\n if (media.length === 0) {\n return null;\n }\n\n const video = media.find(\n (item) => item.kind === 'video' || item.kind === 'gif',\n );\n if (video) {\n return <VideoTile item={video} />;\n }\n\n const images = media.filter((item) => item.kind === 'image');\n return <ImageMosaic media={images} />;\n}\n","'use client';\n\nimport { Fragment, useState } from 'react';\nimport type { CSSProperties, ReactNode } from 'react';\n\n/**\n * The LinkedIn post body: entity-highlighted text with the platform's faithful\n * \"…more\" fold. LinkedIn truncates a long post to a few lines with an inline\n * \"…more\" toggle; we mirror that. Hashtags, URLs, and supplied @mention names\n * render in the accent color, exactly as they appear in-feed.\n */\n\n/** Roughly the in-feed fold point — long posts collapse here behind \"…more\". */\nconst FOLD_CHARS = 200;\n\nexport interface PostBodyColors {\n accent: string;\n muted: string;\n}\n\nexport interface PostBodyProps {\n text: string;\n /** Names to highlight as @mentions (from `settings.mentions[].name`). */\n mentionNames?: readonly string[];\n colors: PostBodyColors;\n}\n\nconst BODY_STYLE: CSSProperties = {\n whiteSpace: 'pre-wrap',\n wordBreak: 'break-word',\n fontSize: 14,\n lineHeight: 1.43,\n};\n\n/** Truncate to at most `max` characters, backing up to the last word boundary. */\nfunction truncateAtWord(text: string, max: number): string {\n if (text.length <= max) {\n return text;\n }\n const slice = text.slice(0, max);\n const lastSpace = slice.lastIndexOf(' ');\n return slice.slice(0, lastSpace > 0 ? lastSpace : max);\n}\n\n/** Escape a string for safe use inside a RegExp. */\nfunction escapeRegExp(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\n/** Build the tokenizer: hashtags, URLs, then any supplied mention names. */\nfunction buildPattern(mentionNames: readonly string[]): RegExp {\n const mentionAlt = mentionNames\n .filter((name) => name.trim().length > 0)\n .map(escapeRegExp)\n .join('|');\n const parts = [\n 'https?:\\\\/\\\\/[^\\\\s]+', // urls\n '#[\\\\p{L}\\\\p{N}_]+', // hashtags (unicode-aware)\n ...(mentionAlt ? [mentionAlt] : []),\n ];\n return new RegExp(`(${parts.join('|')})`, 'gu');\n}\n\nfunction linkStyle(color: string): CSSProperties {\n return { color, textDecoration: 'none', fontWeight: 500 };\n}\n\n/** Split text into plain runs and highlighted entity nodes. */\nfunction linkify(\n text: string,\n colors: PostBodyColors,\n mentionNames: readonly string[],\n): ReactNode[] {\n const pattern = buildPattern(mentionNames);\n const nodes: ReactNode[] = [];\n let lastIndex = 0;\n let key = 0;\n\n for (const match of text.matchAll(pattern)) {\n const token = match[0];\n const start = match.index;\n if (start > lastIndex) {\n nodes.push(\n <Fragment key={key++}>{text.slice(lastIndex, start)}</Fragment>,\n );\n }\n if (token.startsWith('http')) {\n nodes.push(\n <a\n key={key++}\n href={token}\n style={linkStyle(colors.accent)}\n target=\"_blank\"\n rel=\"noreferrer\"\n >\n {token}\n </a>,\n );\n } else if (token.startsWith('#')) {\n nodes.push(\n <a key={key++} href=\"#\" style={linkStyle(colors.accent)}>\n {token}\n </a>,\n );\n } else {\n nodes.push(\n <span key={key++} style={linkStyle(colors.accent)}>\n {token}\n </span>,\n );\n }\n lastIndex = start + token.length;\n }\n\n if (lastIndex < text.length) {\n nodes.push(<Fragment key={key++}>{text.slice(lastIndex)}</Fragment>);\n }\n return nodes;\n}\n\nexport function PostBody({ text, mentionNames = [], colors }: PostBodyProps) {\n const [expanded, setExpanded] = useState(false);\n const isLong = text.length > FOLD_CHARS;\n const shown = isLong && !expanded ? truncateAtWord(text, FOLD_CHARS) : text;\n\n return (\n <div style={BODY_STYLE}>\n {linkify(shown, colors, mentionNames)}\n {isLong && !expanded ? (\n <>\n {'…'}{' '}\n <button\n type=\"button\"\n onClick={() => setExpanded(true)}\n style={{\n background: 'none',\n border: 'none',\n padding: 0,\n cursor: 'pointer',\n color: colors.muted,\n fontWeight: 600,\n fontSize: 14,\n }}\n >\n more\n </button>\n </>\n ) : null}\n </div>\n );\n}\n","'use client';\n\nimport type { LinkedInPostVariant } from '@postrun/js';\nimport { memo } from 'react';\nimport type { CSSProperties } from 'react';\n\nimport type { LinkedInPreviewAuthor, PreviewMedia } from '../types';\nimport { altSignatureOf, useResolvedMedia } from '../use-resolved-media';\nimport { EngagementBar } from './EngagementBar';\nimport { Header } from './Header';\nimport type { LinkedInVisibility } from './Header';\nimport { Media } from './Media';\nimport { PostBody } from './PostBody';\nimport {\n LI_VAR,\n type LinkedInTheme,\n paletteVars,\n useIsDark,\n varRef,\n} from './theme';\n\n/**\n * A faithful, schema-driven preview of how a LinkedIn post will look in-feed,\n * rendered straight from a Postrun LinkedIn variant. Clean-room components (no\n * dependency to \"buy\" exists for LinkedIn), mirroring the real feed card: header\n * with headline + audience icon, an entity-highlighted body with the \"…more\"\n * fold, the 1/2/3/4/+N image mosaic (or a video), and a static action bar.\n *\n * v1 renders text + images + video. The richer `content_kind`s (article, poll,\n * document) degrade gracefully to the text/media card and arrive next.\n *\n * Customize via `theme` (light/dark/auto), `className`/`style`, or by overriding\n * the `--pr-li-*` CSS variables the card reads.\n */\nexport interface LinkedInPostPreviewProps {\n /** The LinkedIn variant from our schema — the content source, untouched. */\n variant: LinkedInPostVariant;\n /** Author identity (LinkedIn stores no avatar/headline on our connection). */\n author: LinkedInPreviewAuthor;\n /** Resolved media pixels (URLs or compose-time File blobs). */\n media?: PreviewMedia[];\n /** Color scheme. `auto` (default) follows the OS preference. */\n theme?: LinkedInTheme;\n /** Relative time label shown in the header. Default \"Now\". */\n time?: string;\n /** Show the static action bar (Like/Comment/Repost/Send). Default true. */\n showActions?: boolean;\n /** Class applied to the card — your hook for sizing, shadows, etc. */\n className?: string;\n /** Inline styles on the card — including `--pr-li-*` variable overrides. */\n style?: CSSProperties;\n}\n\nconst FONT_STACK =\n '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif';\n\nfunction LinkedInPostPreviewImpl({\n variant,\n author,\n media,\n theme = 'auto',\n time,\n showActions = true,\n className,\n style,\n}: LinkedInPostPreviewProps) {\n const dark = useIsDark(theme);\n const resolvedMedia = useResolvedMedia(\n media,\n variant.media,\n altSignatureOf(variant.media),\n );\n\n const visibility: LinkedInVisibility =\n variant.settings?.visibility ?? 'PUBLIC';\n const mentionNames = (variant.settings?.mentions ?? []).map((m) => m.name);\n const bodyColors = {\n accent: varRef(LI_VAR.accent),\n muted: varRef(LI_VAR.muted),\n };\n\n const cardStyle: CSSProperties = {\n ...paletteVars(dark),\n background: varRef(LI_VAR.bg),\n color: varRef(LI_VAR.text),\n border: `1px solid ${varRef(LI_VAR.border)}`,\n borderRadius: 10,\n maxWidth: 552,\n overflow: 'hidden',\n fontFamily: FONT_STACK,\n ...style,\n };\n\n return (\n <div className={className} style={cardStyle}>\n <Header author={author} visibility={visibility} time={time} />\n {variant.body ? (\n <div style={{ padding: '8px 16px 0' }}>\n <PostBody\n text={variant.body}\n mentionNames={mentionNames}\n colors={bodyColors}\n />\n </div>\n ) : null}\n {resolvedMedia.length > 0 ? (\n <div style={{ marginTop: 12 }}>\n <Media media={resolvedMedia} />\n </div>\n ) : null}\n {showActions ? <EngagementBar /> : null}\n </div>\n );\n}\n\n/** Memoized: re-renders only when its props change (the resolved-media hook\n * absorbs unstable media arrays). */\nexport const LinkedInPostPreview = memo(LinkedInPostPreviewImpl);\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/context.tsx","../src/infinite-list.ts","../src/keys.ts","../src/profiles.ts","../src/connect-machine.ts","../src/connections.ts","../src/Connect.tsx","../src/upload-bytes.ts","../src/media.ts","../src/posts.ts","../src/preview/use-resolved-media.ts","../src/preview/x/XPreviewActions.tsx","../src/preview/x/entities.ts","../src/preview/x/to-tweet.ts","../src/preview/x/XPostPreview.tsx","../src/preview/linkedin/theme.ts","../src/preview/linkedin/EngagementBar.tsx","../src/preview/linkedin/Header.tsx","../src/preview/linkedin/ImageMosaic.tsx","../src/preview/linkedin/Media.tsx","../src/preview/linkedin/PostBody.tsx","../src/preview/linkedin/LinkedInPostPreview.tsx"],"names":["useRef","useEffect","useQuery","useMutation","pWaitFor","useState","useCallback","useMemo","jsx","ROW","ACTIONS","FiRepeat","jsxs","PLACEHOLDER_AVATAR","Fragment","memo"],"mappings":"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","file":"index.js","sourcesContent":["import {\n createContext,\n createElement,\n useContext,\n useEffect,\n useMemo,\n useRef,\n} from 'react';\nimport type { ReactNode } from 'react';\n\nimport { QueryClient } from '@tanstack/react-query';\n\nimport { createPostrunClient } from '@postrun/js';\nimport type { PostrunClient } from '@postrun/js';\n\n/**\n * The value every hook and component reads from context: the typed SDK client\n * plus a private TanStack `QueryClient` that powers caching, dedup, and\n * revalidation. Hooks pass this `queryClient` explicitly to `useQuery` /\n * `useMutation`, so it stays fully isolated from any QueryClient the host app\n * runs of its own — no `QueryClientProvider` setup required from the customer.\n */\nexport interface PostrunContextValue {\n client: PostrunClient;\n queryClient: QueryClient;\n}\n\n/** Sensible defaults: treat data as fresh briefly to avoid refetch storms. */\nfunction createDefaultQueryClient(): QueryClient {\n return new QueryClient({\n defaultOptions: {\n queries: { staleTime: 30_000 },\n },\n });\n}\n\nconst PostrunContext = createContext<PostrunContextValue | null>(null);\nPostrunContext.displayName = 'PostrunContext';\n\nexport interface PostrunProviderProps {\n /**\n * Returns a valid short-lived scoped token. The host app's backend mints it\n * from a secret `pr_` key (`POST /v1/tokens`); the secret never reaches the\n * browser. Called per request — cache and refresh before `exp` inside here.\n */\n getToken: () => string | Promise<string>;\n /** Override the API base URL (defaults to the production gateway). */\n baseUrl?: string;\n /**\n * Bring your own TanStack `QueryClient` (advanced: shared DevTools, custom\n * defaults, tests). Omit it and a private, isolated one is created for you.\n */\n queryClient?: QueryClient;\n children: ReactNode;\n}\n\nexport function PostrunProvider({\n getToken,\n baseUrl,\n queryClient,\n children,\n}: PostrunProviderProps) {\n // Keep the latest `getToken` in a ref so the client can always call the\n // freshest closure WITHOUT being rebuilt when callers pass a new arrow each\n // render (the common case). The client is constructed once per `baseUrl`.\n const getTokenRef = useRef(getToken);\n useEffect(() => {\n getTokenRef.current = getToken;\n }, [getToken]);\n\n const client = useMemo(\n () =>\n createPostrunClient({ getToken: () => getTokenRef.current(), baseUrl }),\n [baseUrl],\n );\n\n const resolvedQueryClient = useMemo(\n () => queryClient ?? createDefaultQueryClient(),\n [queryClient],\n );\n\n const value = useMemo<PostrunContextValue>(\n () => ({ client, queryClient: resolvedQueryClient }),\n [client, resolvedQueryClient],\n );\n\n return createElement(PostrunContext.Provider, { value }, children);\n}\n\n/** Access the configured Postrun client. Throws if used outside a provider. */\nexport function usePostrun(): PostrunContextValue {\n const value = useContext(PostrunContext);\n\n if (value === null) {\n throw new Error('usePostrun must be used within a <PostrunProvider>.');\n }\n\n return value;\n}\n","import { useInfiniteQuery } from '@tanstack/react-query';\nimport type { QueryKey } from '@tanstack/react-query';\n\nimport { usePostrun } from './context';\n\n/**\n * The offset-pagination envelope every Postrun list endpoint returns. The helper\n * only needs these fields; the concrete page type comes from the SDK response\n * (e.g. `PostList`), which satisfies this structurally — nothing is redeclared.\n */\ninterface PageEnvelope<TItem> {\n data: TItem[];\n total: number;\n offset: number;\n has_more: boolean;\n}\n\n/** A flattened, append-style (\"load more\") view over a paginated list endpoint. */\nexport interface InfiniteList<TItem> {\n /** Every item loaded so far, flattened across all fetched pages. */\n items: TItem[];\n /** Total items matching the filter (from the first page's envelope). */\n total: number;\n /** Fetch the next page and append it. No-op once `hasMore` is false. */\n loadMore: () => void;\n /** Whether another page exists beyond what's loaded. */\n hasMore: boolean;\n /** The first page is loading (no items yet). */\n isLoading: boolean;\n /** A `loadMore()` is in flight (items are already shown). */\n isLoadingMore: boolean;\n /** The last error, or null. Narrow with `instanceof PostrunError`. */\n error: Error | null;\n /** Refetch from the first page (re-runs every loaded page). */\n refetch: () => void;\n}\n\n/**\n * Turn an offset-paginated Postrun list endpoint into a clean append-style\n * `{ items, loadMore, hasMore, … }` surface — the \"Load more\" / infinite-scroll\n * shape a feed or calendar wants.\n *\n * Built on TanStack `useInfiniteQuery`, so page accumulation is its job and never\n * hand-rolled. The next offset is read from the envelope itself\n * (`offset + data.length`), so it stays correct regardless of page size.\n * `fetchPage` supplies the resource-specific SDK call; the page type is inferred\n * from its return, so item types are derived, never redeclared.\n */\nexport function useInfiniteList<TItem>(args: {\n queryKey: QueryKey;\n fetchPage: (page: {\n limit: number;\n offset: number;\n }) => Promise<PageEnvelope<TItem>>;\n /** Items per page (default 20, the API's own default). */\n limit?: number;\n enabled?: boolean;\n}): InfiniteList<TItem> {\n const { queryClient } = usePostrun();\n const limit = args.limit ?? 20;\n\n const query = useInfiniteQuery(\n {\n queryKey: args.queryKey,\n queryFn: ({ pageParam }) => args.fetchPage({ limit, offset: pageParam }),\n initialPageParam: 0,\n getNextPageParam: (last) =>\n last.has_more ? last.offset + last.data.length : undefined,\n enabled: args.enabled,\n },\n queryClient,\n );\n\n return {\n items: query.data?.pages.flatMap((page) => page.data) ?? [],\n total: query.data?.pages[0]?.total ?? 0,\n loadMore: () => {\n void query.fetchNextPage();\n },\n hasMore: query.hasNextPage,\n isLoading: query.isLoading,\n isLoadingMore: query.isFetchingNextPage,\n error: query.error,\n refetch: () => {\n void query.refetch();\n },\n };\n}\n","import type {\n ConnectionKind,\n ConnectionStatus,\n ListMediaQuery,\n ListPostsQuery,\n ListProfilesQuery,\n} from '@postrun/js';\n\n/** The connection-list filter that keys the cache (social/ads + lifecycle). */\nexport interface ConnectionsFilter {\n kind?: ConnectionKind;\n status?: ConnectionStatus;\n}\n\n/** Root namespace so our cache never collides with the host app's own queries. */\nconst ROOT = 'postrun';\n\n/**\n * Query-key factory for profiles. Hierarchical so a mutation can invalidate at\n * the right granularity: `lists()` after a create, `detail(id)` after an update.\n */\nexport const profileKeys = {\n all: [ROOT, 'profiles'] as const,\n lists: () => [...profileKeys.all, 'list'] as const,\n list: (query?: ListProfilesQuery) =>\n [...profileKeys.lists(), query ?? {}] as const,\n // Nested under lists() so a create/update/delete invalidating lists() also\n // refreshes the infinite cache; distinct tail so the two cache shapes (a\n // single Page vs accumulated pages) never collide on one key. The filter omits\n // limit/offset — the infinite hook owns pagination, so they never key the cache.\n infinite: (query?: Omit<ListProfilesQuery, 'limit' | 'offset'>) =>\n [...profileKeys.lists(), 'infinite', query ?? {}] as const,\n details: () => [...profileKeys.all, 'detail'] as const,\n detail: (id: string) => [...profileKeys.details(), id] as const,\n};\n\n/** Query-key factory for posts (list filtered by query; detail by id). */\nexport const postKeys = {\n all: [ROOT, 'posts'] as const,\n lists: () => [...postKeys.all, 'list'] as const,\n list: (query?: ListPostsQuery) => [...postKeys.lists(), query ?? {}] as const,\n // Nested under lists() so a create/update/delete invalidating lists() also\n // refreshes the infinite cache; distinct tail so the two cache shapes (a\n // single Page vs accumulated pages) never collide on one key. The filter omits\n // limit/offset — the infinite hook owns pagination, so they never key the cache.\n infinite: (query?: Omit<ListPostsQuery, 'limit' | 'offset'>) =>\n [...postKeys.lists(), 'infinite', query ?? {}] as const,\n details: () => [...postKeys.all, 'detail'] as const,\n detail: (id: string) => [...postKeys.details(), id] as const,\n};\n\n/** Query-key factory for media assets (list filtered by query; detail by id). */\nexport const mediaKeys = {\n all: [ROOT, 'media'] as const,\n lists: () => [...mediaKeys.all, 'list'] as const,\n list: (query?: ListMediaQuery) => [...mediaKeys.lists(), query ?? {}] as const,\n // Nested under lists() so an upload/update/delete invalidating lists() also\n // refreshes the infinite cache; distinct tail so the two cache shapes (a\n // single Page vs accumulated pages) never collide on one key. The filter omits\n // limit/offset — the infinite hook owns pagination, so they never key the cache.\n infinite: (query?: Omit<ListMediaQuery, 'limit' | 'offset'>) =>\n [...mediaKeys.lists(), 'infinite', query ?? {}] as const,\n details: () => [...mediaKeys.all, 'detail'] as const,\n detail: (id: string) => [...mediaKeys.details(), id] as const,\n};\n\n/** Query-key factory for connections (lists keyed by owning profile). */\nexport const connectionKeys = {\n all: [ROOT, 'connections'] as const,\n lists: () => [...connectionKeys.all, 'list'] as const,\n list: (profileId: string, filter?: ConnectionsFilter) =>\n [...connectionKeys.lists(), profileId, filter ?? {}] as const,\n details: () => [...connectionKeys.all, 'detail'] as const,\n detail: (id: string) => [...connectionKeys.details(), id] as const,\n accounts: (id: string) => [...connectionKeys.all, 'accounts', id] as const,\n};\n","import { useMutation, useQuery } from '@tanstack/react-query';\n\nimport {\n profilesCreate,\n profilesDelete,\n profilesGet,\n profilesList,\n profilesUpdate,\n} from '@postrun/js';\nimport type {\n CreateProfileInput,\n ListProfilesQuery,\n Profile,\n UpdateProfileInput,\n} from '@postrun/js';\n\nimport { usePostrun } from './context';\nimport { useInfiniteList } from './infinite-list';\nimport { profileKeys } from './keys';\n\n/**\n * List the account's profiles (client/brand workspaces), filtered and paginated.\n * `data` is the typed `ProfileList` envelope — inferred straight from the SDK\n * call, never hand-typed. Caching, dedup, and revalidation come from the\n * provider's private QueryClient.\n */\nexport function useProfiles(query?: ListProfilesQuery) {\n const { client, queryClient } = usePostrun();\n return useQuery(\n {\n queryKey: profileKeys.list(query),\n queryFn: async () =>\n (await profilesList({ client, query })).data,\n },\n queryClient,\n );\n}\n\n/**\n * List profiles with append-style (\"load more\") pagination. Returns\n * `{ items, loadMore, hasMore, isLoading, isLoadingMore, total }`: render\n * `items`, call `loadMore()` while `hasMore`. `pageSize` defaults to 20. Filters\n * match `useProfiles` minus paging, which the hook owns. Shares list-cache\n * invalidation with the other profile hooks.\n */\nexport function useProfilesInfinite(\n filters?: Omit<ListProfilesQuery, 'limit' | 'offset'>,\n options?: { pageSize?: number },\n) {\n const { client } = usePostrun();\n return useInfiniteList<Profile>({\n queryKey: profileKeys.infinite(filters),\n limit: options?.pageSize,\n fetchPage: async ({ limit, offset }) =>\n (await profilesList({ client, query: { ...filters, limit, offset } }))\n .data,\n });\n}\n\n/** Retrieve a single profile by id. Disabled until an id is provided. */\nexport function useProfile(id: string) {\n const { client, queryClient } = usePostrun();\n return useQuery(\n {\n queryKey: profileKeys.detail(id),\n queryFn: async () =>\n (await profilesGet({ client, path: { id } })).data,\n enabled: Boolean(id),\n },\n queryClient,\n );\n}\n\n/** Create a profile; on success the profile lists are refetched. */\nexport function useCreateProfile() {\n const { client, queryClient } = usePostrun();\n return useMutation(\n {\n mutationFn: async (body: CreateProfileInput) =>\n (await profilesCreate({ client, body })).data,\n onSuccess: () =>\n queryClient.invalidateQueries({ queryKey: profileKeys.lists() }),\n },\n queryClient,\n );\n}\n\n/** Update a profile by id; on success the lists and that profile are refreshed. */\nexport function useUpdateProfile() {\n const { client, queryClient } = usePostrun();\n return useMutation(\n {\n mutationFn: async ({ id, ...body }: { id: string } & UpdateProfileInput) =>\n (await profilesUpdate({ client, path: { id }, body })).data,\n onSuccess: (_result, { id }) => {\n queryClient.invalidateQueries({ queryKey: profileKeys.lists() });\n queryClient.invalidateQueries({ queryKey: profileKeys.detail(id) });\n },\n },\n queryClient,\n );\n}\n\n/** Delete a profile by id; on success the lists refresh and its detail is dropped. */\nexport function useDeleteProfile() {\n const { client, queryClient } = usePostrun();\n return useMutation(\n {\n mutationFn: async (id: string) =>\n (await profilesDelete({ client, path: { id } })).data,\n onSuccess: (_result, id) => {\n queryClient.invalidateQueries({ queryKey: profileKeys.lists() });\n queryClient.removeQueries({ queryKey: profileKeys.detail(id) });\n },\n },\n queryClient,\n );\n}\n","import { AuthError } from '@nangohq/frontend';\nimport pWaitFor, { TimeoutError } from 'p-wait-for';\n\nimport { PostrunError } from '@postrun/js';\nimport type { Connection, DiscoverableAccountList } from '@postrun/js';\n\n/**\n * The pure orchestration behind the embedded (no-redirect) connect flow. It is\n * the in-app twin of the hosted `/connect` runner's machine, sharing its exact\n * shape — grant → correlate by the Nango `connectionId` → discover → pick →\n * select — and its two invariants:\n *\n * 1. It NEVER throws: every path resolves to one typed `ConnectOutcome`, so the\n * hook can map it straight to a UI state and a seam can't crash a host app.\n * 2. Correlation is EXACT: `nango.auth()` resolves with the Nango `connectionId`,\n * the SAME value the auth webhook stores as `nango_connection_id`. We poll the\n * connections list filtered by that id, so the row this grant produced is found\n * unambiguously — a concurrent connect on the same profile can't be mis-picked.\n *\n * All seams (the Nango grant, the host's account picker, the four API calls) are\n * INJECTED, so the whole machine unit-tests without a DOM, a network, or a real\n * `nango.auth()`. The hook (`useConnect`) wires the real seams onto it.\n */\n\n/** One account offered for selection — the element type of the accounts list. */\nexport type DiscoverableAccount = DiscoverableAccountList['data'][number];\n\n/** Why a connect attempt ended in `error` — actionable reasons for the host. */\nexport type ConnectErrorReason =\n | 'prepare_failed' // couldn't mint the connect session (BEFORE any OAuth popup)\n | 'popup_blocked' // the browser blocked the OAuth popup\n | 'auth_failed' // the Nango grant failed (bad token, validation, unknown)\n | 'connection_not_found' // we couldn't read back the connection the grant made\n | 'select_failed' // discovery/selection failed (and isn't reauth)\n | 'reauth_required'; // the grant must be reconnected before an account binds\n\n/**\n * The single outcome of a connect attempt. `active` carries the activated\n * connection (so the host can call `onConnected`); `connected_pending` means the\n * grant succeeded but no account is bound yet (slow webhook, out-of-band binding,\n * or no reachable accounts) — the host refetches its list, it is NOT an error.\n */\nexport type ConnectOutcome =\n | { status: 'active'; connection: Connection }\n | { status: 'connected_pending' }\n | { status: 'cancelled' }\n | { status: 'error'; reason: ConnectErrorReason };\n\nexport interface ConnectMachineDeps {\n /** Run the Nango OAuth grant; resolves the Nango `connectionId`, or rejects\n * with a typed `AuthError`. The hook fires `nango.auth()` synchronously in the\n * click and hands the in-flight promise here. */\n readonly authorize: () => Promise<string>;\n /** Resolve the user's chosen external account id — the host app's picker. */\n readonly chooseAccount: (accounts: DiscoverableAccount[]) => Promise<string>;\n /** List this profile's connections filtered by the Nango `connectionId`. */\n readonly listByNangoConnectionId: (\n nangoConnectionId: string,\n ) => Promise<Connection[]>;\n /** Discover the accounts reachable through a pending connection's grant. */\n readonly discoverAccounts: (\n connectionId: string,\n ) => Promise<DiscoverableAccount[]>;\n /** Activate a pending connection with the chosen account; resolves the row. */\n readonly selectAccount: (\n connectionId: string,\n externalAccountId: string,\n ) => Promise<Connection>;\n readonly pollIntervalMs: number;\n readonly pollTimeoutMs: number;\n}\n\nconst PENDING: ConnectOutcome = { status: 'connected_pending' };\nconst CANCELLED: ConnectOutcome = { status: 'cancelled' };\nconst active = (connection: Connection): ConnectOutcome => ({\n status: 'active',\n connection,\n});\nconst failed = (reason: ConnectErrorReason): ConnectOutcome => ({\n status: 'error',\n reason,\n});\n\n/** Map a Nango `AuthError` onto the typed outcome. Exhaustive (no `default`), so\n * a new `AuthErrorType` in a future Nango release is a compile error here, not a\n * silently-swallowed failure. */\nfunction outcomeForAuthError(error: AuthError): ConnectOutcome {\n switch (error.type) {\n case 'window_closed':\n return CANCELLED;\n case 'blocked_by_browser':\n return failed('popup_blocked');\n case 'missing_auth_token':\n case 'invalid_host_url':\n case 'missing_credentials':\n case 'connection_test_failed':\n case 'missing_connect_session_token':\n case 'connection_validation_failed':\n case 'resource_capped':\n case 'unknown_error':\n return failed('auth_failed');\n }\n}\n\n/** The Nango grant step. Resolves the `connectionId` (our correlation key), or\n * the typed outcome to surface when the grant did not complete. Never throws —\n * an `AuthError` maps to its outcome, any other rejection to `auth_failed`. */\nasync function grant(\n authorize: () => Promise<string>,\n): Promise<\n { ok: true; connectionId: string } | { ok: false; outcome: ConnectOutcome }\n> {\n try {\n return { ok: true, connectionId: await authorize() };\n } catch (error) {\n if (error instanceof AuthError) {\n return { ok: false, outcome: outcomeForAuthError(error) };\n }\n\n return { ok: false, outcome: failed('auth_failed') };\n }\n}\n\n/** Poll (bounded) for the connection THIS grant created — the list is filtered\n * server-side by the Nango `connectionId`, so any returned row is the grant's\n * row. Resolves the row, or `null` if it never appears within the timeout (a\n * slow webhook, not an error). */\nasync function awaitGrantedConnection(\n deps: ConnectMachineDeps,\n nangoConnectionId: string,\n): Promise<Connection | null> {\n try {\n return await pWaitFor<Connection>(\n async () => {\n const rows = await deps.listByNangoConnectionId(nangoConnectionId);\n const match = rows[0];\n\n return match ? pWaitFor.resolveWith(match) : false;\n },\n { interval: deps.pollIntervalMs, timeout: deps.pollTimeoutMs },\n );\n } catch (error) {\n if (error instanceof TimeoutError) {\n return null;\n }\n\n throw error;\n }\n}\n\n/** Bind a granted PENDING connection: discover → pick → select. Discovery\n * `not_implemented` (the platform binds out-of-band) or no reachable accounts →\n * `connected_pending`; a reauth-required select → `reauth_required`; any other\n * select failure → `select_failed`. Never throws a `PostrunError`. */\nasync function bindPendingConnection(\n deps: ConnectMachineDeps,\n connection: Connection,\n): Promise<ConnectOutcome> {\n let accounts: DiscoverableAccount[];\n\n try {\n accounts = await deps.discoverAccounts(connection.id);\n } catch (error) {\n if (error instanceof PostrunError && error.code === 'not_implemented') {\n return PENDING;\n }\n\n throw error;\n }\n\n // Nothing to pick or select: the grant landed but the connection stays PENDING\n // (the user must fix their platform access and reconnect), so don't hand `[]`\n // to the picker.\n if (accounts.length === 0) {\n return PENDING;\n }\n\n const chosen = await deps.chooseAccount(accounts);\n\n try {\n return active(await deps.selectAccount(connection.id, chosen));\n } catch (error) {\n if (error instanceof PostrunError) {\n return error.code === 'connection_reauth_required'\n ? failed('reauth_required')\n : failed('select_failed');\n }\n\n throw error;\n }\n}\n\n/**\n * Run the embedded connect flow to a single typed outcome. Never throws.\n */\nexport async function runEmbeddedConnect(\n deps: ConnectMachineDeps,\n): Promise<ConnectOutcome> {\n const granted = await grant(deps.authorize);\n\n if (!granted.ok) {\n return granted.outcome;\n }\n\n let connection: Connection | null;\n\n try {\n connection = await awaitGrantedConnection(deps, granted.connectionId);\n } catch {\n // A polling READ error (not a timeout) means we can't confirm the row landed.\n return failed('connection_not_found');\n }\n\n // Slow webhook: the grant succeeded but the row isn't visible yet. The host\n // refetches its list, so this is `connected_pending`, not an error.\n if (connection === null) {\n return PENDING;\n }\n\n // Single-account platforms (and an already-resolved race) land ACTIVE already.\n if (connection.external_account_id !== null) {\n return active(connection);\n }\n\n try {\n return await bindPendingConnection(deps, connection);\n } catch {\n // A non-`PostrunError` throw mid-bind (e.g. an unexpected network error) is\n // surfaced as a typed failure, never swallowed.\n return failed('select_failed');\n }\n}\n","import Nango from '@nangohq/frontend';\nimport { useMutation, useQuery } from '@tanstack/react-query';\nimport { useCallback, useEffect, useRef, useState } from 'react';\n\nimport {\n connectionsConnect,\n connectionsDelete,\n connectionsGet,\n connectionsListAccounts,\n connectionsListByProfile,\n connectionsSelect,\n} from '@postrun/js';\nimport type {\n ConnectablePlatform,\n Connection,\n SelectAccountInput,\n} from '@postrun/js';\n\nimport {\n type ConnectErrorReason,\n type ConnectOutcome,\n type DiscoverableAccount,\n runEmbeddedConnect,\n} from './connect-machine';\nimport { usePostrun } from './context';\nimport { connectionKeys } from './keys';\nimport type { ConnectionsFilter } from './keys';\n\n/** Poll cadence for reading back the connection a grant created (the row is\n * written out-of-band by the Nango auth webhook). Mirrors the hosted runner. */\nconst POLL_INTERVAL_MS = 1500;\nconst POLL_TIMEOUT_MS = 15_000;\n\nexport interface UseConnectParams {\n /** The profile to attach the new connection to. */\n profileId: string;\n /** The platform to connect (X, LinkedIn, Meta, …). */\n platform: ConnectablePlatform;\n /** Called once a connection is fully ACTIVE (an account is bound). The\n * connections list is auto-refetched too, so you rarely need to act here. */\n onConnected?: (connection: Connection) => void;\n /** Called when the connect SUCCEEDS — `active` OR `connected_pending` (the\n * grant landed but the account binds out-of-band / via a slow webhook). Use\n * this to close your UI and let the auto-refetched list show the result;\n * `onConnected` additionally hands you the bound connection on `active`. */\n onSuccess?: () => void;\n /** Called when the attempt fails, with the typed reason. */\n onError?: (reason: ConnectErrorReason) => void;\n /** Called when the user closes the OAuth popup without finishing. The hook\n * stays in the `cancelled` phase; call `reset()` to re-arm for another try. */\n onCancelled?: () => void;\n /**\n * Pre-mint the Nango session on mount (default `true`). Keep it `true` for a\n * dedicated \"Connect X\" button. Set it `false` for a MULTI-platform picker —\n * then call `prepare()` on the platform button's `onPointerEnter`/`onFocus` so\n * only the platform the user is about to click mints a session (not all of\n * them on open). The popup still needs a pre-minted session, so prepare on\n * intent, not on click.\n */\n prepareOnMount?: boolean;\n}\n\n/**\n * The connect flow's UI state. `connected_pending` is a TERMINAL success state —\n * the grant landed but no account is bound yet (a slow webhook, an out-of-band\n * binding, or no reachable accounts); the host shows \"almost there\" and refetches\n * its connections list. It is NOT an error and must not hang in `connecting`.\n */\nexport type ConnectState =\n | { phase: 'preparing' } // no session held yet — minting, or awaiting `prepare()`\n | { phase: 'idle' } // session held; ready to start on a click\n | { phase: 'connecting' } // popup open / polling / binding\n | { phase: 'picking'; accounts: DiscoverableAccount[] } // host renders a picker\n | { phase: 'active'; connection: Connection }\n | { phase: 'connected_pending' }\n | { phase: 'cancelled' }\n | { phase: 'error'; reason: ConnectErrorReason };\n\nexport interface UseConnectResult {\n /** The current flow state — drive your button + picker + status off `phase`. */\n state: ConnectState;\n /**\n * Start the OAuth flow. MUST be called directly in the user's click handler\n * (no `await` before it): it opens the OAuth popup synchronously, so the\n * browser keeps it inside the user gesture. If the session isn't ready yet\n * (`phase` !== `idle`) it kicks `prepare()` and no-ops the popup, so the next\n * click works — prepare on intent (hover/focus) to make the first click open.\n */\n start: () => void;\n /**\n * Mint the Nango session ahead of the click. Idempotent (a no-op if a session\n * is already held or a mint is in flight). Only needed with\n * `prepareOnMount: false` — call it on the button's `onPointerEnter`/`onFocus`.\n */\n prepare: () => void;\n /** When `phase` is `picking`, activate the connection with the chosen account. */\n select: (externalAccountId: string) => void;\n /** Return to a fresh, ready state (re-mints the session) — e.g. a \"try again\". */\n reset: () => void;\n}\n\ninterface HeldSession {\n readonly token: string;\n readonly providerConfigKey: string;\n readonly host: string;\n}\n\n/**\n * Embedded one-click connect — the customer's OWN button drives the whole OAuth\n * flow IN-APP (no redirect to our hosted page). `nango.auth()` opens a popup that\n * resolves in-page, then the account picker (for multi-account platforms) renders\n * inside the host app via `state.accounts` + `select()`. White-label, one click.\n *\n * The Plaid pattern: the Nango session is PRE-MINTED on mount (and on `reset`),\n * because `nango.auth()` opens its popup synchronously — minting in the click\n * would push `window.open` out of the user gesture and the browser would block\n * the popup. `start()` therefore fires `nango.auth()` with the already-held token\n * and zero `await` before it.\n *\n * The hosted `/connect` page remains the fallback for callers NOT using this SDK\n * (a plain link to `hosted_connect_url`); this hook never redirects.\n */\nexport function useConnect({\n profileId,\n platform,\n onConnected,\n onSuccess,\n onError,\n onCancelled,\n prepareOnMount = true,\n}: UseConnectParams): UseConnectResult {\n const { client, queryClient } = usePostrun();\n const [state, setState] = useState<ConnectState>({ phase: 'preparing' });\n const [remintNonce, setRemintNonce] = useState(0);\n\n const sessionRef = useRef<HeldSession | null>(null);\n // The pending account pick — BOTH halves: `resolve` is called by `select()`,\n // `reject` by `abandonFlow()` so a machine awaiting the picker UNWINDS to a\n // typed outcome (never hangs/leaks) if the flow is torn down mid-pick.\n const pickRef = useRef<{\n resolve: (externalAccountId: string) => void;\n reject: (reason: Error) => void;\n } | null>(null);\n // One flow at a time. `inFlight` no-ops a re-entrant `start()` (a double click\n // must never open a second popup or race a second machine). `flowGen` is bumped\n // whenever a flow is abandoned, so a stale machine's terminal `.then` is\n // suppressed — no `setState`/`onConnected` after unmount or a profile switch.\n const inFlightRef = useRef(false);\n const flowGenRef = useRef(0);\n // A mint in flight (so `prepare()` is idempotent), and a generation bumped when\n // the held session goes stale (profile/platform/reset/unmount) so a late mint\n // can't apply its result onto a newer session.\n const preparingRef = useRef(false);\n const prepareGenRef = useRef(0);\n\n // Latest callbacks in refs so the memoised `start`/`prepare` needn't depend on\n // them (and re-create) when callers pass fresh arrows each render.\n const onConnectedRef = useRef(onConnected);\n const onSuccessRef = useRef(onSuccess);\n const onErrorRef = useRef(onError);\n const onCancelledRef = useRef(onCancelled);\n useEffect(() => {\n onConnectedRef.current = onConnected;\n onSuccessRef.current = onSuccess;\n onErrorRef.current = onError;\n onCancelledRef.current = onCancelled;\n });\n\n // Tear down any in-flight flow: bump the generation (its terminal `.then` is\n // ignored) and REJECT a pending pick (a machine awaiting the picker unwinds\n // instead of leaking). Stable — touches refs only.\n const abandonFlow = useCallback(() => {\n flowGenRef.current += 1;\n inFlightRef.current = false;\n const pick = pickRef.current;\n pickRef.current = null;\n pick?.reject(new Error('connect flow abandoned'));\n }, []);\n\n // Mint the Nango session ahead of the click — `nango.auth()` opens its popup\n // synchronously, so an async mint in the click would break the gesture.\n // Idempotent: a held session or an in-flight mint short-circuits.\n const prepare = useCallback(() => {\n if (sessionRef.current || preparingRef.current) return;\n preparingRef.current = true;\n const gen = prepareGenRef.current;\n setState({ phase: 'preparing' });\n\n // A mint failure (request rejected, OR a 2xx with no body) — clear the\n // in-flight flag (so a retry is possible, never a stuck `preparing`) and\n // surface a typed `prepare_failed`. Distinct from `auth_failed`: the OAuth\n // popup never opened; we couldn't even get a session.\n const failPrepare = () => {\n preparingRef.current = false;\n setState({ phase: 'error', reason: 'prepare_failed' });\n onErrorRef.current?.('prepare_failed');\n };\n\n connectionsConnect({ client, path: { id: profileId }, body: { platform } })\n .then(({ data }) => {\n if (prepareGenRef.current !== gen) return;\n if (!data) {\n failPrepare();\n return;\n }\n preparingRef.current = false;\n sessionRef.current = {\n token: data.connect_session_token,\n providerConfigKey: data.provider_config_key,\n host: data.nango_host,\n };\n setState({ phase: 'idle' });\n })\n .catch(() => {\n if (prepareGenRef.current !== gen) return;\n failPrepare();\n });\n }, [client, profileId, platform]);\n\n // On mount and on every profile/platform/reset change: invalidate the held\n // session + any in-flight mint + any running flow, then (when `prepareOnMount`)\n // mint eagerly. With `prepareOnMount: false` we sit in `preparing` until the\n // host calls `prepare()` — the picker-on-intent path.\n useEffect(() => {\n prepareGenRef.current += 1;\n preparingRef.current = false;\n sessionRef.current = null;\n setState({ phase: 'preparing' });\n\n if (prepareOnMount) prepare();\n\n return () => {\n prepareGenRef.current += 1; // a late mint must not apply after teardown\n abandonFlow();\n };\n }, [profileId, platform, remintNonce, prepareOnMount, prepare, abandonFlow]);\n\n const start = useCallback(() => {\n const session = sessionRef.current;\n // Not minted yet (no prior intent): kick a mint so the NEXT click works. We\n // can't open the popup now (no token) and an async mint would break the\n // gesture — prepare on intent (hover/focus) to make the FIRST click open.\n if (!session) {\n prepare();\n return;\n }\n // A flow is already running — a re-entrant click must not open a 2nd popup.\n if (inFlightRef.current) return;\n\n inFlightRef.current = true;\n const gen = flowGenRef.current;\n const isCurrent = () => flowGenRef.current === gen;\n\n setState({ phase: 'connecting' });\n\n void runEmbeddedConnect({\n // Nango lives INSIDE `authorize` so a SYNCHRONOUS throw (invalid host /\n // missing token — the Nango SDK throws `AuthError` synchronously) becomes a\n // promise rejection that `grant()` maps to `auth_failed`, never an uncaught\n // throw escaping the click and wedging `inFlightRef`. Gesture timing still\n // holds: `authorize()` is invoked SYNCHRONOUSLY down the\n // start → runEmbeddedConnect → grant chain (each `await`'s operand is\n // evaluated before it suspends), so `nango.auth()`'s `window.open` fires\n // inside the user gesture, with no `await` before it.\n authorize: async () => {\n const nango = new Nango({\n host: session.host,\n connectSessionToken: session.token,\n });\n const result = await nango.auth(session.providerConfigKey, {\n detectClosedAuthWindow: true,\n });\n return result.connectionId;\n },\n chooseAccount: (accounts) =>\n new Promise<string>((resolve, reject) => {\n // Abandoned before reaching the picker (reset / unmount / profile\n // change while still connecting): reject so the machine unwinds, and\n // DON'T touch `pickRef`/state — a newer flow owns them now.\n if (!isCurrent()) {\n reject(new Error('connect flow abandoned'));\n return;\n }\n pickRef.current = { resolve, reject };\n setState({ phase: 'picking', accounts });\n }),\n listByNangoConnectionId: async (nangoConnectionId) => {\n const { data } = await connectionsListByProfile({\n client,\n path: { id: profileId },\n query: { nango_connection_id: nangoConnectionId },\n });\n return data?.data ?? [];\n },\n discoverAccounts: async (connectionId) => {\n const { data } = await connectionsListAccounts({\n client,\n path: { id: connectionId },\n });\n return data?.data ?? [];\n },\n selectAccount: async (connectionId, externalAccountId) => {\n const { data } = await connectionsSelect({\n client,\n path: { id: connectionId },\n body: { external_account_id: externalAccountId },\n });\n // A 2xx with no body shouldn't happen; treat it as a select failure\n // (the machine maps the throw to `select_failed`) rather than cast.\n if (!data) throw new Error('select returned no connection');\n return data;\n },\n pollIntervalMs: POLL_INTERVAL_MS,\n pollTimeoutMs: POLL_TIMEOUT_MS,\n }).then((outcome: ConnectOutcome) => {\n // Abandoned (reset / unmount / profile switch): a newer flow owns the\n // state and `pickRef` — leave both untouched and fire nothing.\n if (!isCurrent()) return;\n\n inFlightRef.current = false;\n pickRef.current = null;\n\n switch (outcome.status) {\n case 'active':\n setState({ phase: 'active', connection: outcome.connection });\n // The new connection exists — refetch any connections list so the host\n // sees it without wiring its own refetch.\n void queryClient.invalidateQueries({ queryKey: connectionKeys.lists() });\n onConnectedRef.current?.(outcome.connection);\n onSuccessRef.current?.();\n return;\n case 'connected_pending':\n setState({ phase: 'connected_pending' });\n // The grant landed; the row is written by the webhook (maybe not yet).\n // Refetch the list ONCE so it shows as soon as it's there; the host can\n // refetch again from its own layer if it's still pending.\n void queryClient.invalidateQueries({ queryKey: connectionKeys.lists() });\n onSuccessRef.current?.();\n return;\n case 'cancelled':\n setState({ phase: 'cancelled' });\n onCancelledRef.current?.();\n return;\n case 'error':\n setState({ phase: 'error', reason: outcome.reason });\n onErrorRef.current?.(outcome.reason);\n return;\n }\n });\n }, [client, profileId, prepare, queryClient]);\n\n const select = useCallback((externalAccountId: string) => {\n const pick = pickRef.current;\n if (!pick) return; // not in the picking phase\n\n pickRef.current = null;\n setState({ phase: 'connecting' }); // working again while the account binds\n pick.resolve(externalAccountId);\n }, []);\n\n const reset = useCallback(() => {\n // Bump the nonce → the prepare effect re-runs; its cleanup abandons any flow\n // and a fresh session is minted (or awaits `prepare()` if not on-mount).\n setRemintNonce((n) => n + 1);\n }, []);\n\n return { state, start, prepare, select, reset };\n}\n\n/**\n * List a profile's connected accounts. Pass a `filter` to narrow by `kind`\n * (`posting` = social, `ads`) or `status` — e.g. a composer fetches\n * `{ kind: 'posting' }` to show only the social accounts it can publish to.\n */\nexport function useConnections(profileId: string, filter?: ConnectionsFilter) {\n const { client, queryClient } = usePostrun();\n return useQuery(\n {\n queryKey: connectionKeys.list(profileId, filter),\n queryFn: async () =>\n (\n await connectionsListByProfile({\n client,\n path: { id: profileId },\n query: filter,\n })\n ).data,\n enabled: Boolean(profileId),\n },\n queryClient,\n );\n}\n\n/** Retrieve a single connection by id. */\nexport function useConnection(id: string) {\n const { client, queryClient } = usePostrun();\n return useQuery(\n {\n queryKey: connectionKeys.detail(id),\n queryFn: async () =>\n (await connectionsGet({ client, path: { id } })).data,\n enabled: Boolean(id),\n },\n queryClient,\n );\n}\n\n/** List the accounts discoverable on a pending connection (for selection). */\nexport function useDiscoverableAccounts(id: string) {\n const { client, queryClient } = usePostrun();\n return useQuery(\n {\n queryKey: connectionKeys.accounts(id),\n queryFn: async () =>\n (await connectionsListAccounts({ client, path: { id } })).data,\n enabled: Boolean(id),\n },\n queryClient,\n );\n}\n\n/** Select an account on a pending connection, activating it. */\nexport function useSelectAccount() {\n const { client, queryClient } = usePostrun();\n return useMutation(\n {\n mutationFn: async ({ id, ...body }: { id: string } & SelectAccountInput) =>\n (await connectionsSelect({ client, path: { id }, body })).data,\n onSuccess: (_result, { id }) => {\n queryClient.invalidateQueries({ queryKey: connectionKeys.lists() });\n queryClient.invalidateQueries({ queryKey: connectionKeys.detail(id) });\n queryClient.invalidateQueries({ queryKey: connectionKeys.accounts(id) });\n },\n },\n queryClient,\n );\n}\n\n/** Disconnect (delete) a connection by id. */\nexport function useDisconnect() {\n const { client, queryClient } = usePostrun();\n return useMutation(\n {\n mutationFn: async (id: string) =>\n (await connectionsDelete({ client, path: { id } })).data,\n onSuccess: (_result, id) => {\n queryClient.invalidateQueries({ queryKey: connectionKeys.lists() });\n queryClient.removeQueries({ queryKey: connectionKeys.detail(id) });\n },\n },\n queryClient,\n );\n}\n","'use client';\n\nimport type { ReactNode } from 'react';\n\nimport type { ConnectablePlatform, Connection } from '@postrun/js';\n\nimport type { ConnectErrorReason } from './connect-machine';\nimport type { ConnectState, UseConnectParams } from './connections';\nimport { useConnect } from './connections';\n\n/** The flow state + actions handed to your render-prop. */\nexport interface ConnectRenderApi {\n /** The current flow state — switch on `state.phase` to render your UI. */\n state: ConnectState;\n /**\n * Begin connecting. Call this DIRECTLY from your button's `onClick` — it opens\n * the OAuth popup synchronously, so don't `await` anything before it.\n */\n start: () => void;\n /**\n * Mint the session ahead of the click — only needed with\n * `prepareOnMount={false}` (a multi-platform picker): call it on the button's\n * `onPointerEnter`/`onFocus`.\n */\n prepare: () => void;\n /** When `state.phase === 'picking'`, activate with the chosen account id. */\n select: (externalAccountId: string) => void;\n /** Reset to a fresh, ready state (e.g. a \"try again\" after an error/cancel). */\n reset: () => void;\n}\n\nexport interface ConnectProps {\n /** The profile to attach the new connection to. */\n profileId: string;\n /** The platform to connect (X, LinkedIn, Meta, …). */\n platform: ConnectablePlatform;\n /** Called once a connection is fully ACTIVE (an account is bound). */\n onConnected?: (connection: Connection) => void;\n /** Called when the connect succeeds — `active` OR `connected_pending`. */\n onSuccess?: () => void;\n /** Called when the attempt fails, with the typed reason. */\n onError?: (reason: ConnectErrorReason) => void;\n /** Called when the user closes the OAuth popup without finishing. */\n onCancelled?: () => void;\n /** Pre-mint on mount (default `true`). Set `false` for a multi-platform picker\n * and call `prepare()` on intent — see {@link UseConnectParams.prepareOnMount}. */\n prepareOnMount?: boolean;\n /** Render your own button + picker + status from the flow state. */\n children: (api: ConnectRenderApi) => ReactNode;\n}\n\n/**\n * Headless one-click connect. Wraps `useConnect` and hands you the flow state +\n * actions via a render-prop, so you own EVERY pixel (your button, your account\n * picker, your brand marks, your styling) while the SDK runs the embedded OAuth\n * popup + account binding — no redirect, no second click.\n *\n * ```tsx\n * <Connect profileId={id} platform=\"x\" onConnected={refetch}>\n * {({ state, start, select }) =>\n * state.phase === 'picking' ? (\n * <ul>\n * {state.accounts.map((a) => (\n * <li key={a.external_account_id}>\n * <button onClick={() => select(a.external_account_id)}>\n * {a.name ?? a.external_account_id}\n * </button>\n * </li>\n * ))}\n * </ul>\n * ) : (\n * <button onClick={start} disabled={state.phase !== 'idle'}>\n * Connect X\n * </button>\n * )\n * }\n * </Connect>\n * ```\n *\n * The trigger MUST call `start()` directly in the click (it opens the popup\n * synchronously). Mount `<Connect>` inside a `<PostrunProvider>`.\n */\nexport function Connect({\n profileId,\n platform,\n onConnected,\n onSuccess,\n onError,\n onCancelled,\n prepareOnMount,\n children,\n}: ConnectProps): ReactNode {\n const api = useConnect({\n profileId,\n platform,\n onConnected,\n onSuccess,\n onError,\n onCancelled,\n prepareOnMount,\n });\n return children(api);\n}\n","import axios, { isAxiosError } from 'axios';\n\nimport type { UploadTarget } from '@postrun/js';\n\n/** A failed direct-to-storage upload, carrying the HTTP status (0 = network). */\nexport class UploadError extends Error {\n readonly status: number;\n\n constructor(status: number, message: string) {\n super(message);\n this.name = 'UploadError';\n this.status = status;\n }\n}\n\nexport interface UploadBytesOptions {\n /** Fraction uploaded, 0..1. Called as bytes flow and once with 1 on success. */\n onProgress?: (fraction: number) => void;\n /** Abort the in-flight upload. */\n signal?: AbortSignal;\n}\n\n/**\n * PUT a file's bytes to a signed upload target, with progress and cancellation.\n * axios drives the XHR (the Fetch API can't report upload progress in browsers);\n * retry/poll are composed on top via p-retry/p-wait-for.\n */\nexport async function uploadBytes(\n target: UploadTarget,\n file: Blob,\n options: UploadBytesOptions = {},\n): Promise<void> {\n const { onProgress, signal } = options;\n\n try {\n await axios.request({\n method: target.method,\n url: target.url,\n data: file,\n headers: target.headers,\n signal,\n onUploadProgress: (event) => {\n if (event.total) {\n onProgress?.(event.loaded / event.total);\n }\n },\n });\n onProgress?.(1);\n } catch (error) {\n // A cancellation propagates as-is so callers (and p-retry) treat it as abort.\n if (signal?.aborted) {\n throw error;\n }\n if (isAxiosError(error)) {\n const status = error.response?.status ?? 0;\n throw new UploadError(\n status,\n status ? `Upload failed (HTTP ${status}).` : 'Upload failed: network error.',\n );\n }\n throw error;\n }\n}\n","import { useMutation, useQuery } from '@tanstack/react-query';\nimport pLimit from 'p-limit';\nimport pRetry, { AbortError } from 'p-retry';\nimport pWaitFor from 'p-wait-for';\nimport { useCallback, useRef, useState } from 'react';\n\nimport {\n mediaCreate,\n mediaDelete,\n mediaGet,\n mediaList,\n mediaUpdate,\n} from '@postrun/js';\nimport type {\n ListMediaQuery,\n MediaKind,\n MediaResource,\n MediaTarget,\n Metadata,\n PostrunClient,\n UpdateMediaInput,\n} from '@postrun/js';\n\nimport { usePostrun } from './context';\nimport { useInfiniteList } from './infinite-list';\nimport { mediaKeys } from './keys';\nimport { UploadError, uploadBytes } from './upload-bytes';\n\n/**\n * Poll the asset until it settles (ready/failed), respecting cancellation.\n * `onTick` fires with each fetched resource so callers can surface the live\n * `progress.{stage,percent}` the API reports during processing.\n */\nasync function pollUntilSettled(\n client: PostrunClient,\n id: string,\n signal: AbortSignal,\n onTick?: (resource: MediaResource) => void,\n): Promise<MediaResource> {\n let latest: MediaResource | undefined;\n await pWaitFor(\n async () => {\n if (signal.aborted) {\n throw new DOMException('Upload aborted', 'AbortError');\n }\n latest = (await mediaGet({ client, path: { id } })).data;\n onTick?.(latest);\n return latest.status === 'ready' || latest.status === 'failed';\n },\n { interval: 1500, timeout: 300_000 },\n );\n\n if (!latest) {\n throw new Error('Media polling returned no result.');\n }\n return latest;\n}\n\nexport type MediaUploadStatus =\n | 'idle'\n | 'uploading'\n | 'processing'\n | 'ready'\n | 'failed';\n\nexport interface MediaUploadOptions {\n /** Profile that owns the asset. */\n profileId: string;\n /** Platforms to validate + render for (omit to add later via useUpdateMedia). */\n targets?: MediaTarget[];\n /** Optional override — omit and the API auto-detects the kind from the bytes. */\n kind?: MediaKind;\n /**\n * Optional override — omit and the API auto-detects the MIME from the bytes.\n * Still useful for a legacy Office binary (.doc/.ppt) whose magic bytes can't be\n * disambiguated by the server sniff.\n */\n contentType?: string;\n /** Store as-is with zero processing. */\n raw?: boolean;\n altText?: string;\n externalId?: string;\n metadata?: Metadata;\n}\n\n/**\n * The core single-file upload pipeline used by `useMediaUpload` for every file\n * (single or batched) so the create → PUT-with-retry → poll-until-settled\n * sequence lives in exactly one place. Pure orchestration — no React state; the\n * caller passes an `AbortSignal` and callbacks so it can drive its own UI. Throws\n * on a hard failure / abort; returns the settled `MediaResource` (which may itself\n * be `failed`).\n */\nasync function runUpload(\n client: PostrunClient,\n file: File,\n options: MediaUploadOptions,\n signal: AbortSignal,\n callbacks: {\n onProgress: (fraction: number) => void;\n onProcessing: () => void;\n onPoll?: (resource: MediaResource) => void;\n },\n): Promise<MediaResource> {\n // The API auto-detects `kind` + `content_type` from the uploaded bytes\n // (magic-number sniff). Both ride as PURE OPTIONAL OVERRIDES — `undefined` when\n // the caller omits them, so the server detects; never fabricated client-side.\n const created = (\n await mediaCreate({\n client,\n body: {\n profile_id: options.profileId,\n kind: options.kind,\n content_type: options.contentType,\n targets: options.targets,\n raw: options.raw,\n alt_text: options.altText,\n external_id: options.externalId,\n metadata: options.metadata,\n },\n })\n ).data;\n\n if (created.upload) {\n const target = created.upload;\n await pRetry(\n async () => {\n try {\n await uploadBytes(target, file, {\n onProgress: callbacks.onProgress,\n signal,\n });\n } catch (uploadError) {\n // A client error (e.g. an expired signed URL) won't fix on retry.\n if (\n uploadError instanceof UploadError &&\n uploadError.status >= 400 &&\n uploadError.status < 500\n ) {\n throw new AbortError(uploadError);\n }\n throw uploadError;\n }\n },\n { retries: 3, signal },\n );\n }\n\n callbacks.onProcessing();\n return pollUntilSettled(client, created.id, signal, callbacks.onPoll);\n}\n\n/** One file's slot in an upload — its own live status, progress, and settled\n * asset. `status` is never `idle` (an item exists only once uploading). */\nexport interface MediaUploadItem {\n /** Stable local id (NOT the asset id) — use as the React key and for `remove`. */\n id: string;\n file: File;\n status: Exclude<MediaUploadStatus, 'idle'>;\n /** 0–1 client-side BYTE-upload bar. `media.progress.{stage,percent}` is the\n * live SERVER pipeline bar. */\n progress: number;\n media: MediaResource | null;\n error: unknown;\n}\n\nexport interface UseMediaUploadResult {\n /** Every file added, in add-order, with its live state. */\n items: readonly MediaUploadItem[];\n /** The settled-ready assets, in item order — what you attach to a post. */\n ready: readonly MediaResource[];\n /** True while any item is still uploading or processing. */\n isUploading: boolean;\n /**\n * Upload ONE file or MANY under `options`, gated by `concurrency`. The reactive\n * `items` update live for UI; the returned promise is for imperative flows —\n * it resolves to the settled (`ready`|`failed`) resources for THIS batch, in\n * add-order, EXCLUDING any item removed/aborted mid-flight. Single-file usage:\n * `const [asset] = await add(file, opts)`.\n */\n add: (\n files: File | FileList | readonly File[],\n options: MediaUploadOptions,\n ) => Promise<MediaResource[]>;\n /** Drop an item by local id — aborts it if still in flight. */\n remove: (id: string) => void;\n /** Abort everything and clear the list. */\n reset: () => void;\n}\n\nexport interface UseMediaUploadOptions {\n /**\n * How many files upload at once; the rest queue (default 3). Fixed for the\n * hook's lifetime — set it once when you call the hook.\n */\n concurrency?: number;\n}\n\n/** Normalize the accepted input (one File, a FileList, or an array) to a File[]. */\nfunction toFileArray(files: File | FileList | readonly File[]): File[] {\n if (files instanceof File) return [files];\n return Array.from(files);\n}\n\n/**\n * Upload one OR many files and get back platform-validated assets. The hook owns\n * the whole journey per file: create the asset (the API auto-detects\n * kind/content_type from the bytes), PUT the bytes with live `progress` + retry,\n * poll until processing settles, and expose `media.per_platform` (per-target\n * status, url, warnings,\n * errors). Every file gets its own `MediaUploadItem` slot in `items`; `ready` is\n * the settled assets to attach to a post; `remove`/`reset` abort in-flight work.\n * Uploads run through ONE shared `p-limit` gate so only `concurrency` (default 3)\n * are in flight at once — global across `add` calls, not per-call.\n *\n * Single-file usage: `const [asset] = await add(file, opts)` (or read `ready[0]`).\n */\nexport function useMediaUpload(\n options?: UseMediaUploadOptions,\n): UseMediaUploadResult {\n const { client, queryClient } = usePostrun();\n const [items, setItems] = useState<readonly MediaUploadItem[]>([]);\n // Local-id → controller, so `remove`/`reset` can abort an in-flight upload.\n const controllers = useRef<Map<string, AbortController>>(new Map());\n // One shared concurrency gate for the hook's lifetime — files queued across\n // multiple `add` calls all funnel through it, so the cap is global, not per-add.\n const limitRef = useRef<ReturnType<typeof pLimit> | null>(null);\n if (!limitRef.current) {\n limitRef.current = pLimit(options?.concurrency ?? 3);\n }\n\n const patch = useCallback(\n (id: string, changes: Partial<MediaUploadItem>) => {\n setItems((current) =>\n current.map((item) =>\n item.id === id ? { ...item, ...changes } : item,\n ),\n );\n },\n [],\n );\n\n const add = useCallback(\n (\n files: File | FileList | readonly File[],\n uploadOptions: MediaUploadOptions,\n ): Promise<MediaResource[]> => {\n const queued: MediaUploadItem[] = toFileArray(files).map((file) => ({\n id: crypto.randomUUID(),\n file,\n status: 'uploading',\n progress: 0,\n media: null,\n error: null,\n }));\n\n setItems((current) => [...current, ...queued]);\n\n const limit = limitRef.current;\n if (!limit) {\n return Promise.resolve([]);\n }\n\n // Each item resolves to its settled resource, or `null` if it was\n // removed/aborted mid-flight. These per-item promises NEVER reject, so the\n // batch `Promise.all` can't leave a hanging/unhandled rejection.\n const settlements = queued.map((item) => {\n const controller = new AbortController();\n controllers.current.set(item.id, controller);\n\n return limit(() => {\n // Removed while still queued behind the gate — skip the work entirely.\n if (controller.signal.aborted) {\n throw new DOMException('Upload aborted', 'AbortError');\n }\n return runUpload(client, item.file, uploadOptions, controller.signal, {\n onProgress: (progress) => patch(item.id, { progress }),\n onProcessing: () => patch(item.id, { status: 'processing' }),\n // Live server progress (stage + percent) each poll tick.\n onPoll: (media) => patch(item.id, { media }),\n });\n })\n .then((settled): MediaResource => {\n patch(item.id, {\n status: settled.status === 'failed' ? 'failed' : 'ready',\n media: settled,\n progress: 1,\n });\n queryClient.setQueryData(mediaKeys.detail(settled.id), settled);\n void queryClient.invalidateQueries({ queryKey: mediaKeys.lists() });\n return settled;\n })\n .catch((error: unknown): MediaResource | null => {\n // An aborted item was removed — its slot is already gone; resolve to\n // null so the batch promise drops it instead of hanging or rejecting.\n if (controller.signal.aborted) {\n return null;\n }\n patch(item.id, { status: 'failed', error });\n return null;\n })\n .finally(() => {\n controllers.current.delete(item.id);\n });\n });\n\n return Promise.all(settlements).then((results) =>\n results.filter((result): result is MediaResource => result !== null),\n );\n },\n [client, queryClient, patch],\n );\n\n const remove = useCallback((id: string) => {\n controllers.current.get(id)?.abort();\n controllers.current.delete(id);\n setItems((current) => current.filter((item) => item.id !== id));\n }, []);\n\n const reset = useCallback(() => {\n controllers.current.forEach((controller) => controller.abort());\n controllers.current.clear();\n setItems([]);\n }, []);\n\n const ready = items.flatMap((item) =>\n item.status === 'ready' && item.media ? [item.media] : [],\n );\n const isUploading = items.some(\n (item) => item.status === 'uploading' || item.status === 'processing',\n );\n\n return { items, ready, isUploading, add, remove, reset };\n}\n\n/** Retrieve a media asset; auto-polls while it is still uploading/processing. */\nexport function useMedia(id: string) {\n const { client, queryClient } = usePostrun();\n return useQuery(\n {\n queryKey: mediaKeys.detail(id),\n queryFn: async () =>\n (await mediaGet({ client, path: { id } })).data,\n enabled: Boolean(id),\n refetchInterval: (query) => {\n const current = query.state.data;\n return current?.status === 'uploading' || current?.status === 'processing'\n ? 2000\n : false;\n },\n },\n queryClient,\n );\n}\n\n/**\n * List media assets under the account, newest first. Filter by `profile_id`,\n * `status`, `kind`, your own `external_id`, or `metadata` (exact-match\n * containment), with offset `limit`/`offset` pagination. Returns one page; use\n * `useMediaInfinite` for a load-more feed.\n */\nexport function useMediaList(query?: ListMediaQuery) {\n const { client, queryClient } = usePostrun();\n return useQuery(\n {\n queryKey: mediaKeys.list(query),\n queryFn: async () => (await mediaList({ client, query })).data,\n },\n queryClient,\n );\n}\n\n/**\n * Load-more / infinite-scroll view over the media list — same filters as\n * `useMediaList` minus pagination, which the helper drives. Returns\n * `{ items, total, loadMore, hasMore, … }`.\n */\nexport function useMediaInfinite(\n filters?: Omit<ListMediaQuery, 'limit' | 'offset'>,\n options?: { pageSize?: number },\n) {\n const { client } = usePostrun();\n return useInfiniteList<MediaResource>({\n queryKey: mediaKeys.infinite(filters),\n limit: options?.pageSize,\n fetchPage: async ({ limit, offset }) =>\n (await mediaList({ client, query: { ...filters, limit, offset } })).data,\n });\n}\n\n/** Update a media asset: alt text / metadata / external_id, or extend targets. */\nexport function useUpdateMedia() {\n const { client, queryClient } = usePostrun();\n return useMutation(\n {\n mutationFn: async ({ id, ...body }: { id: string } & UpdateMediaInput) =>\n (await mediaUpdate({ client, path: { id }, body })).data,\n onSuccess: (result, { id }) => {\n queryClient.setQueryData(mediaKeys.detail(id), result);\n void queryClient.invalidateQueries({ queryKey: mediaKeys.lists() });\n },\n },\n queryClient,\n );\n}\n\n/** Delete a media asset and its stored renditions. */\nexport function useDeleteMedia() {\n const { client, queryClient } = usePostrun();\n return useMutation(\n {\n mutationFn: async (id: string) =>\n (await mediaDelete({ client, path: { id } })).data,\n onSuccess: (_result, id) => {\n queryClient.removeQueries({ queryKey: mediaKeys.detail(id) });\n void queryClient.invalidateQueries({ queryKey: mediaKeys.lists() });\n },\n },\n queryClient,\n );\n}\n","import { useMutation, useQuery } from '@tanstack/react-query';\n\nimport {\n buildCreatePost,\n isPostPlatform,\n postsCreate,\n postsDelete,\n postsGet,\n postsList,\n postsUpdate,\n} from '@postrun/js';\nimport type {\n ComposePostInput,\n ListPostsQuery,\n Post,\n UpdatePostInput,\n} from '@postrun/js';\n\n/**\n * The calendar/queue filter surface — a date window over `schedule_at` plus a\n * derived-status multi-select, scoped to an optional profile. Picked straight\n * from the generated `ListPostsQuery` contract (no hand-typed shapes), so it\n * can never drift from the API. Pagination still rides through via `usePosts`.\n */\nexport type CalendarFilters = Pick<\n ListPostsQuery,\n 'profile_id' | 'scheduled_after' | 'scheduled_before' | 'status'\n>;\n\nimport { useConnections } from './connections';\nimport { usePostrun } from './context';\nimport { useInfiniteList } from './infinite-list';\nimport { postKeys } from './keys';\n\n/**\n * A post's status as it appears on the RESPONSE (not the list `status` filter) —\n * the value a live poll actually inspects. Sourced from `Post['status']` so the\n * predicate below is type-correct against `query.state.data?.status`, and a\n * future contract change to the status set surfaces at compile time here.\n */\ntype PostResponseStatus = Post['status'];\n\n/**\n * Statuses that are still moving on their own and warrant polling: `scheduled`\n * (fires at its time with no user action → must be caught transitioning) and\n * `publishing` (mid-flight by definition). Everything else is terminal and stops\n * the poll: `published` / `failed` (end states), `partially_published` (no\n * further automatic movement), and `draft` (only an explicit update — which\n * already invalidates lists — moves it). Modelling in-flight as the small set\n * means any future status defaults to \"terminal/stop\" — the safe, no-runaway\n * default.\n */\nconst IN_FLIGHT: ReadonlySet<PostResponseStatus> = new Set([\n 'scheduled',\n 'publishing',\n]);\n\nconst isLivePostStatus = (status: PostResponseStatus): boolean =>\n IN_FLIGHT.has(status);\n\n/** Per-hook live-poll control: live is on by default; `{ live: false }` opts out. */\nexport interface LiveOptions {\n /** Auto-poll while a post is in-flight (default `true`). Set `false` for one-shot. */\n live?: boolean;\n}\n\n/**\n * List posts — the calendar/queue data, filtered (profile_id / external_id /\n * metadata) and paginated. `data` is the typed `PostList` envelope, with each\n * post's derived status (draft / scheduled / publishing / published / failed).\n */\nexport function usePosts(query?: ListPostsQuery) {\n const { client, queryClient } = usePostrun();\n return useQuery(\n {\n queryKey: postKeys.list(query),\n queryFn: async () =>\n (await postsList({ client, query })).data,\n },\n queryClient,\n );\n}\n\n/**\n * List posts with append-style (\"load more\") pagination — the calendar/queue\n * feed. Returns `{ items, loadMore, hasMore, isLoading, isLoadingMore, total }`:\n * render `items`, call `loadMore()` (on a button or scroll end) while `hasMore`.\n * `pageSize` defaults to 20. Filters are the same as `usePosts` minus paging,\n * which the hook owns. Shares list-cache invalidation with the other post hooks,\n * so a create/update/delete refreshes it automatically.\n */\nexport function usePostsInfinite(\n filters?: Omit<ListPostsQuery, 'limit' | 'offset'>,\n options?: { pageSize?: number },\n) {\n const { client } = usePostrun();\n return useInfiniteList<Post>({\n queryKey: postKeys.infinite(filters),\n limit: options?.pageSize,\n fetchPage: async ({ limit, offset }) =>\n (await postsList({ client, query: { ...filters, limit, offset } })).data,\n });\n}\n\n/**\n * Calendar/queue view — list posts in a `schedule_at` date window, optionally\n * narrowed to a profile and to one or more derived statuses (e.g. only\n * `scheduled` + `failed`). Forwards the date-range + multi-status filters (and\n * any `limit`/`offset`) to the generated `postsList` and returns the same typed\n * `PostList` envelope. It shares the `postKeys.list(filters)` cache identity with\n * `usePosts` but owns its own self-terminating poll: while ANY post in the\n * window is in-flight it refetches (5s — a list is heavier than one detail), and\n * stops once every item is terminal (or the window is empty). `live` is a\n * separate option, never mixed into the API filter object; default-on, opt out\n * with `{ live: false }`.\n */\nexport function useCalendar(\n filters?: CalendarFilters & Pick<ListPostsQuery, 'limit' | 'offset'>,\n options?: LiveOptions,\n) {\n const { client, queryClient } = usePostrun();\n return useQuery(\n {\n queryKey: postKeys.list(filters),\n queryFn: async () => (await postsList({ client, query: filters })).data,\n refetchInterval: (query) => {\n if (options?.live === false) return false;\n const posts = query.state.data?.data ?? [];\n return posts.some((post) => isLivePostStatus(post.status)) ? 5000 : false;\n },\n },\n queryClient,\n );\n}\n\n/**\n * Retrieve a single post by id (its variants, schedule, and derived status).\n * Auto-polls (2s) while the post is in-flight (`scheduled` / `publishing`) and\n * stops once it reaches a terminal status — so a scheduled post visibly\n * transitions with no manual refetch. `live` is on by default; pass\n * `{ live: false }` to force a one-shot.\n */\nexport function usePost(id: string, options?: LiveOptions) {\n const { client, queryClient } = usePostrun();\n return useQuery(\n {\n queryKey: postKeys.detail(id),\n queryFn: async () =>\n (await postsGet({ client, path: { id } })).data,\n enabled: Boolean(id),\n refetchInterval: (query) => {\n if (options?.live === false) return false;\n const status = query.state.data?.status;\n return status && isLivePostStatus(status) ? 2000 : false;\n },\n },\n queryClient,\n );\n}\n\n/**\n * Compose and create a post. Resolves the profile's connections, builds the full\n * variant set from `{ content, channels }` (per the `buildCreatePost` rules), and\n * sends it — the customer never assembles variants or passes a `connection_id`.\n * `connectedChannels` is the set of posting platforms this profile can reach.\n */\nexport function useCreatePost(profileId: string) {\n const { client, queryClient } = usePostrun();\n const connections = useConnections(profileId);\n const connected = connections.data?.data ?? [];\n\n const mutation = useMutation(\n {\n mutationFn: async (input: Omit<ComposePostInput, 'profileId'>) =>\n (\n await postsCreate({\n client,\n body: buildCreatePost({ ...input, profileId }, connected),\n })\n ).data,\n onSuccess: () =>\n queryClient.invalidateQueries({ queryKey: postKeys.lists() }),\n },\n queryClient,\n );\n\n return {\n create: mutation.mutateAsync,\n isPending: mutation.isPending,\n error: mutation.error,\n data: mutation.data,\n reset: mutation.reset,\n // The profile's connections must load before `create` can resolve a channel;\n // gate on this so a call during loading isn't mislabeled \"not connected\".\n isReady: connections.isSuccess,\n connectedChannels: connected\n .map((connection) => connection.platform)\n .filter(isPostPlatform),\n };\n}\n\n/**\n * Update a post by id. Pass a light edit directly (`{ schedule_at }`,\n * `{ tags }`, …) or a rebuilt body from `buildUpdatePost(input, connections)`\n * for content edits (the API's PATCH replaces the variant set).\n */\nexport function useUpdatePost(postId: string) {\n const { client, queryClient } = usePostrun();\n return useMutation(\n {\n mutationFn: async (body: UpdatePostInput) =>\n (await postsUpdate({ client, path: { id: postId }, body })).data,\n onSuccess: (result) => {\n queryClient.invalidateQueries({ queryKey: postKeys.lists() });\n queryClient.setQueryData(postKeys.detail(postId), result);\n },\n },\n queryClient,\n );\n}\n\n/** Delete a post by id; on success the lists refresh and its detail is dropped. */\nexport function useDeletePost() {\n const { client, queryClient } = usePostrun();\n return useMutation(\n {\n mutationFn: async (id: string) =>\n (await postsDelete({ client, path: { id } })).data,\n onSuccess: (_result, id) => {\n queryClient.invalidateQueries({ queryKey: postKeys.lists() });\n queryClient.removeQueries({ queryKey: postKeys.detail(id) });\n },\n },\n queryClient,\n );\n}\n","'use client';\n\nimport { useEffect, useMemo, useState } from 'react';\n\nimport type { PreviewMedia, ResolvedMedia } from './types';\n\n/**\n * Shared media resolution for every platform preview. URL-backed items resolve\n * SYNCHRONOUSLY (the common, processed-asset path — no first-paint flash);\n * compose-time `File` items get an object URL minted in an effect and revoked on\n * change/unmount. Keyed on a content signature, so the resolved array is stable\n * across parent re-renders that don't change the media — the heavy work (object\n * URLs) never churns and downstream mapping stays memoized. Alt text falls back\n * to the variant media's `alt_text_override`.\n */\n\n/** Per-item alt-text fallback source (the variant's media refs). */\nexport type AltFallbacks =\n | readonly { alt_text_override?: string | null }[]\n | undefined;\n\nfunction fileKey(file: File | undefined): string {\n return file ? `${file.name}:${file.size}:${file.lastModified}` : '';\n}\n\n/** A content signature so object-URL work only re-runs when the media actually\n * changes — not on every parent re-render that passes a new array. */\nexport function mediaSignature(\n media: readonly PreviewMedia[] | undefined,\n): string {\n return (media ?? [])\n .map((item) => {\n const source = item.url ?? fileKey(item.file);\n const size = `${item.width ?? ''}x${item.height ?? ''}`;\n return `${item.kind}|${source}|${item.posterUrl ?? ''}|${size}|${item.alt ?? ''}`;\n })\n .join('§');\n}\n\n/** Stable string of the per-item alt fallbacks, for memo keying. */\nexport function altSignatureOf(media: AltFallbacks): string {\n return (media ?? []).map((m) => m?.alt_text_override ?? '').join('§');\n}\n\nexport function useResolvedMedia(\n media: readonly PreviewMedia[] | undefined,\n altFallbacks: AltFallbacks,\n altSignature: string,\n): ResolvedMedia[] {\n const signature = mediaSignature(media);\n const [objectUrls, setObjectUrls] = useState<Record<number, string>>({});\n\n useEffect(() => {\n const created: string[] = [];\n const next: Record<number, string> = {};\n (media ?? []).forEach((item, index) => {\n if (!item.url && item.file) {\n const url = URL.createObjectURL(item.file);\n created.push(url);\n next[index] = url;\n }\n });\n setObjectUrls(next);\n return () => {\n for (const url of created) {\n URL.revokeObjectURL(url);\n }\n };\n // `signature` captures every File identity that needs an object URL.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [signature]);\n\n return useMemo(\n () =>\n (media ?? []).flatMap((item, index): ResolvedMedia[] => {\n const src = item.url ?? objectUrls[index];\n if (!src) {\n return [];\n }\n return [\n {\n kind: item.kind,\n src,\n width: item.width,\n height: item.height,\n alt: item.alt ?? altFallbacks?.[index]?.alt_text_override ?? undefined,\n posterSrc: item.posterUrl,\n },\n ];\n }),\n // `signature` + `altSignature` capture the content; `objectUrls` flips once\n // File blobs resolve. Referencing `media`/`altFallbacks` directly is safe.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [signature, altSignature, objectUrls],\n );\n}\n","import type { CSSProperties } from 'react';\nimport type { IconType } from 'react-icons';\nimport {\n FiBarChart2,\n FiHeart,\n FiMessageCircle,\n FiRepeat,\n FiShare,\n} from 'react-icons/fi';\n\n/**\n * A static, honest action row for the X preview: reply, repost, like, views, and\n * share — real Feather icons (via react-icons), NO fabricated counts and no\n * outbound links (a draft hasn't been engaged with). We render our own row rather\n * than react-tweet's `TweetActions` because that one prints a `0` like-count,\n * which would be a lie on an unpublished post.\n *\n * Color inherits react-tweet's CSS variable, so it matches the card in light and\n * dark and restyles with the same variable the rest of the card uses.\n */\n\nconst ROW: CSSProperties = {\n display: 'flex',\n justifyContent: 'space-between',\n maxWidth: 425,\n marginTop: 12,\n color: 'var(--tweet-color-gray-secondary, #536471)',\n};\n\nconst ACTIONS: { label: string; Icon: IconType }[] = [\n { label: 'Reply', Icon: FiMessageCircle },\n { label: 'Repost', Icon: FiRepeat },\n { label: 'Like', Icon: FiHeart },\n { label: 'Views', Icon: FiBarChart2 },\n { label: 'Share', Icon: FiShare },\n];\n\nexport function XPreviewActions() {\n return (\n <div style={ROW}>\n {ACTIONS.map(({ label, Icon }) => (\n <Icon key={label} size={18} aria-label={label} role=\"img\" />\n ))}\n </div>\n );\n}\n","import twitterText from 'twitter-text';\nimport type { TweetEntities } from 'react-tweet/api';\n\n// twitter-text's ESM entry exposes a single default object (no named exports),\n// so a default import is the only form that resolves across bundlers — named\n// imports compile under @types but break in esbuild/rollup at the consumer.\nconst {\n extractCashtagsWithIndices,\n extractHashtagsWithIndices,\n extractMentionsWithIndices,\n extractUrlsWithIndices,\n modifyIndicesFromUTF16ToUnicode,\n} = twitterText;\n\n/**\n * Extract the X text entities (hashtags, @mentions, URLs, $cashtags) from a post\n * body, in the shape `react-tweet`'s `enrichTweet` consumes to rebuild the rich\n * body. Indices come straight from `twitter-text` — the reference implementation\n * X itself uses — so highlighting matches the real platform exactly (Unicode,\n * punctuation boundaries, and all). We never hand-roll the parsing.\n *\n * Fields X's syndication payload carries that a compose-time preview cannot know\n * (a mention's numeric `id_str` / display `name`) are filled with honest stand-ins\n * (`screen_name`), which is all the renderer needs to draw the entity.\n */\nexport function extractEntities(text: string): TweetEntities {\n const hashtags = extractHashtagsWithIndices(text);\n const mentions = extractMentionsWithIndices(text);\n const urls = extractUrlsWithIndices(text);\n const cashtags = extractCashtagsWithIndices(text);\n\n // twitter-text's regex indices are UTF-16; react-tweet slices `Array.from(text)`\n // (codepoint-aware), so convert in place — otherwise any astral char (emoji)\n // before an entity shifts every later highlight. Converting one combined array\n // keeps the per-list references in sync (the helper mutates `.indices`).\n modifyIndicesFromUTF16ToUnicode(text, [\n ...hashtags,\n ...mentions,\n ...urls,\n ...cashtags,\n ]);\n\n return {\n hashtags: hashtags.map((h) => ({ text: h.hashtag, indices: h.indices })),\n user_mentions: mentions.map((m) => ({\n id_str: '',\n name: m.screenName,\n screen_name: m.screenName,\n indices: m.indices,\n })),\n urls: urls.map((u) => ({\n display_url: u.url,\n expanded_url: u.url,\n url: u.url,\n indices: u.indices,\n })),\n symbols: cashtags.map((c) => ({ text: c.cashtag, indices: c.indices })),\n };\n}\n","import type { XPostVariant } from '@postrun/js';\nimport type {\n MediaAnimatedGif,\n MediaDetails,\n MediaPhoto,\n MediaVideo,\n QuotedTweet,\n Tweet,\n TweetUser,\n VideoInfo,\n} from 'react-tweet/api';\n\nimport type { ResolvedMedia, XPreviewAuthor } from '../types';\nimport { extractEntities } from './entities';\n\n/**\n * Maps a Postrun X variant (+ the customer-supplied author/media) into the\n * `Tweet` object `react-tweet` renders. This is the whole \"schema → exact X\n * preview\" brain: a PURE function, no DOM, no network, no `File` handling (the\n * component resolves pixels to URLs before calling this). Every field\n * `react-tweet` reads is filled with a real value — no casts — and engagement\n * metrics are honest zeros (a draft has no likes).\n */\n\n/** Quoted-card content with media already resolved. */\nexport interface ResolvedQuotedTweet {\n author: XPreviewAuthor;\n body?: string;\n media?: ResolvedMedia[];\n}\n\nexport interface ToTweetInput {\n variant: XPostVariant;\n author: XPreviewAuthor;\n media?: ResolvedMedia[];\n quotedTweet?: ResolvedQuotedTweet;\n /** The replied-to account's handle (our schema only stores the parent id). */\n replyToHandle?: string;\n}\n\n/** Neutral placeholder avatar (a grey circle) for when no avatar is supplied —\n * keeps the header from showing a broken image. */\nconst PLACEHOLDER_AVATAR =\n 'data:image/svg+xml;utf8,' +\n encodeURIComponent(\n '<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"48\" height=\"48\">' +\n '<circle cx=\"24\" cy=\"24\" r=\"24\" fill=\"#cfd9de\"/></svg>',\n );\n\n/** Fallback pixel dimensions when the customer doesn't know the asset's size —\n * a 3:2 frame keeps react-tweet's aspect-ratio math from dividing by zero. */\nconst FALLBACK_WIDTH = 1200;\nconst FALLBACK_HEIGHT = 800;\n\n/** Length in Unicode codepoints (astral-aware), matching how react-tweet slices\n * the body via `Array.from(text)`. */\nfunction codepointLength(text: string): number {\n return Array.from(text).length;\n}\n\nfunction buildUser(author: XPreviewAuthor): TweetUser {\n const verified = author.verified ?? false;\n return {\n id_str: '',\n name: author.name,\n profile_image_url_https: author.avatarUrl ?? PLACEHOLDER_AVATAR,\n profile_image_shape: 'Circle',\n screen_name: author.handle,\n verified: false,\n is_blue_verified: verified,\n };\n}\n\n/** The fields shared by every media kind, contextually typed (derived from\n * `MediaPhoto`) so tuple/literal fields infer correctly without a cast. */\nfunction mediaBase(\n src: string,\n width?: number,\n height?: number,\n): Omit<MediaPhoto, 'type' | 'ext_alt_text'> {\n const w = width ?? FALLBACK_WIDTH;\n const h = height ?? FALLBACK_HEIGHT;\n const size = { h, w, resize: 'fit' };\n return {\n display_url: '',\n expanded_url: '',\n ext_media_availability: { status: 'available' },\n ext_media_color: { palette: [] },\n indices: [0, 0],\n media_url_https: src,\n original_info: { height: h, width: w, focus_rects: [] },\n sizes: { large: size, medium: size, small: size, thumb: size },\n url: src,\n };\n}\n\nfunction buildPhoto(media: ResolvedMedia): MediaPhoto {\n return {\n ...mediaBase(media.src, media.width, media.height),\n type: 'photo',\n ext_alt_text: media.alt,\n };\n}\n\nfunction buildVideo(media: ResolvedMedia): MediaVideo | MediaAnimatedGif {\n const poster = media.posterSrc ?? media.src;\n const videoInfo: VideoInfo = {\n aspect_ratio: [media.width ?? 16, media.height ?? 9],\n variants: [{ content_type: 'video/mp4', url: media.src }],\n };\n const base = mediaBase(poster, media.width, media.height);\n return media.kind === 'gif'\n ? { ...base, type: 'animated_gif', video_info: videoInfo }\n : { ...base, type: 'video', video_info: videoInfo };\n}\n\nfunction buildMediaDetails(media: readonly ResolvedMedia[]): MediaDetails[] {\n return media.map((item) =>\n item.kind === 'image' ? buildPhoto(item) : buildVideo(item),\n );\n}\n\n/** The static, draft-honest scaffolding every synthesized tweet shares. */\nfunction tweetScaffold(): Pick<\n Tweet,\n | 'lang'\n | 'created_at'\n | 'edit_control'\n | 'isEdited'\n | 'isStaleEdit'\n | 'favorite_count'\n | 'conversation_count'\n | 'news_action_type'\n> {\n return {\n lang: 'en',\n created_at: '',\n edit_control: {\n edit_tweet_ids: [],\n editable_until_msecs: '0',\n is_edit_eligible: false,\n edits_remaining: '0',\n },\n isEdited: false,\n isStaleEdit: false,\n favorite_count: 0,\n conversation_count: 0,\n news_action_type: 'conversation',\n };\n}\n\nfunction buildQuoted(\n quote: ResolvedQuotedTweet | undefined,\n hasQuoteId: boolean,\n): QuotedTweet | undefined {\n if (!quote && !hasQuoteId) {\n return undefined;\n }\n\n const author = quote?.author ?? { name: 'Quoted post', handle: '' };\n const body = quote?.body ?? '';\n const media = quote?.media ?? [];\n\n return {\n lang: 'en',\n created_at: '',\n display_text_range: [0, codepointLength(body)],\n entities: extractEntities(body),\n id_str: '',\n text: body,\n user: buildUser(author),\n edit_control: {\n edit_tweet_ids: [],\n editable_until_msecs: '0',\n is_edit_eligible: false,\n edits_remaining: '0',\n },\n isEdited: false,\n isStaleEdit: false,\n reply_count: 0,\n retweet_count: 0,\n favorite_count: 0,\n self_thread: { id_str: '' },\n ...(media.length > 0 ? { mediaDetails: buildMediaDetails(media) } : {}),\n };\n}\n\nexport function toTweet(input: ToTweetInput): Tweet {\n const { variant, author, media = [], quotedTweet, replyToHandle } = input;\n const text = variant.body ?? '';\n const mediaDetails = buildMediaDetails(media);\n const quoted = buildQuoted(\n quotedTweet,\n variant.settings?.quote_tweet_id !== undefined,\n );\n const reply = variant.settings?.reply;\n\n return {\n __typename: 'Tweet',\n ...tweetScaffold(),\n // Codepoint length, not `text.length` (UTF-16) — react-tweet renders the\n // body off `Array.from(text)`, so emoji must not shift the range.\n display_text_range: [0, codepointLength(text)],\n entities: extractEntities(text),\n id_str: '',\n text,\n user: buildUser(author),\n ...(mediaDetails.length > 0 ? { mediaDetails } : {}),\n ...(quoted ? { quoted_tweet: quoted } : {}),\n // Both the handle AND the parent id are needed: enrichTweet builds the\n // reply link as `…/${screen_name}/status/${status_id_str}`, so omitting the\n // id yields a `/status/undefined` href.\n ...(reply && replyToHandle\n ? {\n in_reply_to_screen_name: replyToHandle,\n in_reply_to_status_id_str: reply.in_reply_to_tweet_id,\n }\n : {}),\n };\n}\n","'use client';\n\nimport type { XPostVariant } from '@postrun/js';\nimport { memo, useMemo } from 'react';\nimport type { CSSProperties } from 'react';\nimport {\n QuotedTweet,\n TweetBody,\n TweetContainer,\n TweetHeader,\n TweetInReplyTo,\n TweetMedia,\n type TwitterComponents,\n enrichTweet,\n} from 'react-tweet';\n\nimport type {\n PreviewMedia,\n XPreviewAuthor,\n XPreviewQuotedTweet,\n} from '../types';\nimport { altSignatureOf, useResolvedMedia } from '../use-resolved-media';\nimport { XPreviewActions } from './XPreviewActions';\nimport { toTweet } from './to-tweet';\n\nexport interface XPostPreviewProps {\n /** The X variant from our schema — the content source, untouched. */\n variant: XPostVariant;\n /** Author identity (not stored on our connection — supplied by you). */\n author: XPreviewAuthor;\n /** Resolved media pixels (URLs or compose-time File blobs). */\n media?: PreviewMedia[];\n /** Content for the quoted card when `settings.quote_tweet_id` is set. */\n quotedTweet?: XPreviewQuotedTweet;\n /** The replied-to account's handle (our schema only stores the parent id). */\n replyToHandle?: string;\n /** Color scheme. `auto` (default) inherits the host's theme. */\n theme?: 'light' | 'dark' | 'auto';\n /** Show the static action row (icons, no counts). Default true. */\n showActions?: boolean;\n /** Class applied to the wrapper — your hook for sizing, shadows, etc. */\n className?: string;\n /** Inline styles on the wrapper — e.g. react-tweet CSS variables\n * (`{ ['--tweet-container-margin']: '0' }`). */\n style?: CSSProperties;\n /** Override react-tweet's internal pieces (e.g. `next/image` avatars). */\n components?: TwitterComponents;\n}\n\n/**\n * A faithful, pixel-accurate preview of how an X post will look once published,\n * rendered straight from a Postrun X variant. Built on `react-tweet` (the same\n * card X itself ships), so you write zero card UI — pass the schema, render the\n * preview. Fully customizable: restyle via `className`/`style` (CSS variables)\n * or swap internals via `components`; theme light/dark/auto.\n */\nfunction XPostPreviewImpl({\n variant,\n author,\n media,\n quotedTweet,\n replyToHandle,\n theme = 'auto',\n showActions = true,\n className,\n style,\n components,\n}: XPostPreviewProps) {\n const resolvedMedia = useResolvedMedia(\n media,\n variant.media,\n altSignatureOf(variant.media),\n );\n const resolvedQuotedMedia = useResolvedMedia(quotedTweet?.media, undefined, '');\n\n const tweet = useMemo(() => {\n const resolvedQuoted = quotedTweet\n ? {\n author: quotedTweet.author,\n body: quotedTweet.body,\n media: resolvedQuotedMedia,\n }\n : undefined;\n\n return enrichTweet(\n toTweet({\n variant,\n author,\n media: resolvedMedia,\n quotedTweet: resolvedQuoted,\n replyToHandle,\n }),\n );\n }, [\n variant,\n author,\n resolvedMedia,\n quotedTweet,\n resolvedQuotedMedia,\n replyToHandle,\n ]);\n\n return (\n <div\n data-theme={theme === 'auto' ? undefined : theme}\n className={className}\n style={style}\n >\n <TweetContainer>\n <TweetHeader tweet={tweet} components={components} />\n {tweet.in_reply_to_screen_name ? <TweetInReplyTo tweet={tweet} /> : null}\n <TweetBody tweet={tweet} />\n {tweet.mediaDetails?.length ? (\n <TweetMedia tweet={tweet} components={components} />\n ) : null}\n {tweet.quoted_tweet ? <QuotedTweet tweet={tweet.quoted_tweet} /> : null}\n {showActions ? <XPreviewActions /> : null}\n </TweetContainer>\n </div>\n );\n}\n\n/** Memoized: re-renders only when its props change (the resolved-media hook\n * already absorbs unstable media arrays). */\nexport const XPostPreview = memo(XPostPreviewImpl);\n","'use client';\n\nimport { useEffect, useState } from 'react';\n\n/**\n * LinkedIn preview theming. Unlike the X preview (which inherits react-tweet's\n * CSS), we own the LinkedIn card, so we expose a small set of CSS custom\n * properties on the wrapper. The resolved palette sets their default values;\n * a customer can override any of them via `style`/`className`. Components read\n * `var(--pr-li-*)`, so restyling needs no fork.\n */\n\nexport type LinkedInTheme = 'light' | 'dark' | 'auto';\n\nexport const LI_VAR = {\n bg: '--pr-li-bg',\n text: '--pr-li-text',\n muted: '--pr-li-muted',\n border: '--pr-li-border',\n accent: '--pr-li-accent',\n};\n\ninterface Palette {\n bg: string;\n text: string;\n muted: string;\n border: string;\n accent: string;\n}\n\nconst LIGHT: Palette = {\n bg: '#ffffff',\n text: 'rgba(0,0,0,0.9)',\n muted: 'rgba(0,0,0,0.6)',\n border: 'rgba(0,0,0,0.08)',\n accent: 'rgb(10,102,194)',\n};\n\nconst DARK: Palette = {\n bg: '#1b1f23',\n text: 'rgba(255,255,255,0.9)',\n muted: 'rgba(255,255,255,0.6)',\n border: 'rgba(255,255,255,0.15)',\n accent: 'rgb(112,181,249)',\n};\n\n/** A CSS `var(...)` reference to one of the LinkedIn theme variables. */\nexport function varRef(name: string): string {\n return `var(${name})`;\n}\n\n/** The CSS custom-property declarations for a resolved scheme. Typed as a plain\n * string record (React's `CSSProperties` doesn't model `--custom` keys); it is\n * spread into the card's `style`, where React forwards it to the DOM. */\nexport function paletteVars(dark: boolean): Record<string, string> {\n const p = dark ? DARK : LIGHT;\n return {\n '--pr-li-bg': p.bg,\n '--pr-li-text': p.text,\n '--pr-li-muted': p.muted,\n '--pr-li-border': p.border,\n '--pr-li-accent': p.accent,\n };\n}\n\n/** Track the OS color scheme for `theme=\"auto\"`. Starts light (SSR-safe, no\n * hydration mismatch) and updates after mount. */\nexport function usePrefersDark(): boolean {\n const [dark, setDark] = useState(false);\n\n useEffect(() => {\n if (typeof window === 'undefined' || !window.matchMedia) {\n return;\n }\n const mq = window.matchMedia('(prefers-color-scheme: dark)');\n setDark(mq.matches);\n const onChange = (event: MediaQueryListEvent) => setDark(event.matches);\n mq.addEventListener('change', onChange);\n return () => mq.removeEventListener('change', onChange);\n }, []);\n\n return dark;\n}\n\n/** Resolve whether the card should render dark for a given theme prop. */\nexport function useIsDark(theme: LinkedInTheme): boolean {\n const prefersDark = usePrefersDark();\n if (theme === 'auto') {\n return prefersDark;\n }\n return theme === 'dark';\n}\n","import type { CSSProperties } from 'react';\nimport type { IconType } from 'react-icons';\nimport { FiMessageSquare, FiRepeat, FiSend, FiThumbsUp } from 'react-icons/fi';\n\nimport { LI_VAR, varRef } from './theme';\n\n/**\n * The static LinkedIn action bar — Like / Comment / Repost / Send. Real Feather\n * icons (via react-icons) + labels, no fabricated reaction counts (a draft has\n * none). Honest, like the X preview's footer.\n */\n\nconst ROW: CSSProperties = {\n display: 'flex',\n justifyContent: 'space-around',\n borderTop: `1px solid ${varRef(LI_VAR.border)}`,\n marginTop: 8,\n padding: '4px 8px',\n};\n\nconst ITEM: CSSProperties = {\n display: 'flex',\n alignItems: 'center',\n gap: 6,\n padding: '8px',\n color: varRef(LI_VAR.muted),\n fontSize: 14,\n fontWeight: 600,\n};\n\nconst ACTIONS: { label: string; Icon: IconType }[] = [\n { label: 'Like', Icon: FiThumbsUp },\n { label: 'Comment', Icon: FiMessageSquare },\n { label: 'Repost', Icon: FiRepeat },\n { label: 'Send', Icon: FiSend },\n];\n\nexport function EngagementBar() {\n return (\n <div style={ROW}>\n {ACTIONS.map(({ label, Icon }) => (\n <span key={label} style={ITEM}>\n <Icon size={20} aria-hidden />\n {label}\n </span>\n ))}\n </div>\n );\n}\n","import { FiGlobe, FiUsers } from 'react-icons/fi';\nimport { LuBadgeCheck } from 'react-icons/lu';\n\nimport type { LinkedInPreviewAuthor } from '../types';\nimport { LI_VAR, varRef } from './theme';\n\n/**\n * The LinkedIn post header: avatar, actor name (+ optional verified badge),\n * one-line headline, then a muted row with a relative time and the audience icon\n * (globe = public, people = connections-only). Real Feather/Lucide icons via\n * react-icons — no hand-drawn paths.\n */\n\nexport type LinkedInVisibility = 'PUBLIC' | 'CONNECTIONS';\n\nconst PLACEHOLDER_AVATAR =\n 'data:image/svg+xml;utf8,' +\n encodeURIComponent(\n '<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"48\" height=\"48\">' +\n '<circle cx=\"24\" cy=\"24\" r=\"24\" fill=\"#9aa6b2\"/></svg>',\n );\n\nexport interface HeaderProps {\n author: LinkedInPreviewAuthor;\n visibility: LinkedInVisibility;\n /** Relative time label, e.g. \"Now\". */\n time?: string;\n}\n\nexport function Header({ author, visibility, time = 'Now' }: HeaderProps) {\n return (\n <div style={{ display: 'flex', gap: 8, padding: '12px 16px 0' }}>\n <img\n src={author.avatarUrl ?? PLACEHOLDER_AVATAR}\n alt=\"\"\n width={48}\n height={48}\n style={{ width: 48, height: 48, borderRadius: '50%', objectFit: 'cover', flex: '0 0 auto' }}\n />\n <div style={{ minWidth: 0, display: 'flex', flexDirection: 'column' }}>\n <span\n style={{\n display: 'flex',\n alignItems: 'center',\n fontSize: 14,\n fontWeight: 600,\n color: varRef(LI_VAR.text),\n lineHeight: 1.3,\n }}\n >\n {author.name}\n {author.verified ? (\n <LuBadgeCheck\n size={16}\n aria-label=\"Verified\"\n role=\"img\"\n style={{ color: varRef(LI_VAR.accent), marginLeft: 3, flex: '0 0 auto' }}\n />\n ) : null}\n </span>\n {author.headline ? (\n <span style={{ fontSize: 12, color: varRef(LI_VAR.muted), lineHeight: 1.3 }}>\n {author.headline}\n </span>\n ) : null}\n <span\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: 4,\n fontSize: 12,\n color: varRef(LI_VAR.muted),\n lineHeight: 1.3,\n }}\n >\n {time} •{' '}\n {visibility === 'PUBLIC' ? (\n <FiGlobe size={13} aria-label=\"Public\" role=\"img\" />\n ) : (\n <FiUsers size={13} aria-label=\"Connections\" role=\"img\" />\n )}\n </span>\n </div>\n </div>\n );\n}\n","import type { CSSProperties } from 'react';\n\nimport type { ResolvedMedia } from '../types';\n\n/**\n * LinkedIn's image layout: a single full-bleed image, or the 2/3/4 mosaic with a\n * \"+N\" overlay on the fourth tile when there are more than four. Edge-to-edge,\n * 2px gutters — matching the in-feed look.\n */\n\nconst MAX_TILES = 4;\nconst MOSAIC_HEIGHT = 272;\n\nconst GRID_BASE: CSSProperties = {\n display: 'grid',\n gap: 2,\n height: MOSAIC_HEIGHT,\n overflow: 'hidden',\n};\n\n/** Grid template for a given visible-tile count (2, 3 or 4). */\nfunction gridStyle(tiles: number): CSSProperties {\n if (tiles === 2) {\n return { ...GRID_BASE, gridTemplateColumns: '1fr 1fr' };\n }\n if (tiles === 3) {\n // One tall image on the left, two stacked on the right.\n return {\n ...GRID_BASE,\n gridTemplateColumns: '1fr 1fr',\n gridTemplateRows: '1fr 1fr',\n gridTemplateAreas: '\"a b\" \"a c\"',\n };\n }\n return {\n ...GRID_BASE,\n gridTemplateColumns: '1fr 1fr',\n gridTemplateRows: '1fr 1fr',\n };\n}\n\nconst IMG_STYLE: CSSProperties = {\n width: '100%',\n height: '100%',\n objectFit: 'cover',\n display: 'block',\n};\n\nconst AREAS = ['a', 'b', 'c'];\n\nfunction Tile({\n item,\n area,\n overlay,\n}: {\n item: ResolvedMedia;\n area?: string;\n overlay?: number;\n}) {\n return (\n <div style={{ position: 'relative', gridArea: area, overflow: 'hidden' }}>\n <img src={item.src} alt={item.alt ?? ''} style={IMG_STYLE} />\n {overlay ? (\n <div\n aria-hidden={false}\n style={{\n position: 'absolute',\n inset: 0,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n background: 'rgba(0,0,0,0.5)',\n color: '#fff',\n fontSize: 28,\n fontWeight: 600,\n }}\n >\n {`+${overlay}`}\n </div>\n ) : null}\n </div>\n );\n}\n\nexport interface ImageMosaicProps {\n media: readonly ResolvedMedia[];\n}\n\nexport function ImageMosaic({ media }: ImageMosaicProps) {\n if (media.length === 0) {\n return null;\n }\n\n if (media.length === 1) {\n const only = media[0]!;\n return (\n <img\n src={only.src}\n alt={only.alt ?? ''}\n style={{ width: '100%', height: 'auto', display: 'block' }}\n />\n );\n }\n\n const tiles = media.slice(0, MAX_TILES);\n const hidden = media.length - MAX_TILES;\n\n return (\n <div style={gridStyle(tiles.length)}>\n {tiles.map((item, index) => (\n <Tile\n key={item.src + index}\n item={item}\n area={tiles.length === 3 ? AREAS[index] : undefined}\n overlay={\n hidden > 0 && index === MAX_TILES - 1 ? hidden : undefined\n }\n />\n ))}\n </div>\n );\n}\n","import type { ResolvedMedia } from '../types';\nimport { ImageMosaic } from './ImageMosaic';\n\n/**\n * The media area of a LinkedIn post (v1: images + video). A post carries either\n * a video or images; a video wins if present and renders as a playable element\n * with its poster, otherwise the image mosaic. Edge-to-edge, like the feed.\n */\n\nfunction VideoTile({ item }: { item: ResolvedMedia }) {\n return (\n <video\n src={item.src}\n poster={item.posterSrc}\n controls\n style={{ width: '100%', display: 'block', background: '#000' }}\n />\n );\n}\n\nexport interface MediaProps {\n media: readonly ResolvedMedia[];\n}\n\nexport function Media({ media }: MediaProps) {\n if (media.length === 0) {\n return null;\n }\n\n const video = media.find(\n (item) => item.kind === 'video' || item.kind === 'gif',\n );\n if (video) {\n return <VideoTile item={video} />;\n }\n\n const images = media.filter((item) => item.kind === 'image');\n return <ImageMosaic media={images} />;\n}\n","'use client';\n\nimport { Fragment, useState } from 'react';\nimport type { CSSProperties, ReactNode } from 'react';\n\n/**\n * The LinkedIn post body: entity-highlighted text with the platform's faithful\n * \"…more\" fold. LinkedIn truncates a long post to a few lines with an inline\n * \"…more\" toggle; we mirror that. Hashtags, URLs, and supplied @mention names\n * render in the accent color, exactly as they appear in-feed.\n */\n\n/** Roughly the in-feed fold point — long posts collapse here behind \"…more\". */\nconst FOLD_CHARS = 200;\n\nexport interface PostBodyColors {\n accent: string;\n muted: string;\n}\n\nexport interface PostBodyProps {\n text: string;\n /** Names to highlight as @mentions (from `settings.mentions[].name`). */\n mentionNames?: readonly string[];\n colors: PostBodyColors;\n}\n\nconst BODY_STYLE: CSSProperties = {\n whiteSpace: 'pre-wrap',\n wordBreak: 'break-word',\n fontSize: 14,\n lineHeight: 1.43,\n};\n\n/** Truncate to at most `max` characters, backing up to the last word boundary. */\nfunction truncateAtWord(text: string, max: number): string {\n if (text.length <= max) {\n return text;\n }\n const slice = text.slice(0, max);\n const lastSpace = slice.lastIndexOf(' ');\n return slice.slice(0, lastSpace > 0 ? lastSpace : max);\n}\n\n/** Escape a string for safe use inside a RegExp. */\nfunction escapeRegExp(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\n/** Build the tokenizer: hashtags, URLs, then any supplied mention names. */\nfunction buildPattern(mentionNames: readonly string[]): RegExp {\n const mentionAlt = mentionNames\n .filter((name) => name.trim().length > 0)\n .map(escapeRegExp)\n .join('|');\n const parts = [\n 'https?:\\\\/\\\\/[^\\\\s]+', // urls\n '#[\\\\p{L}\\\\p{N}_]+', // hashtags (unicode-aware)\n ...(mentionAlt ? [mentionAlt] : []),\n ];\n return new RegExp(`(${parts.join('|')})`, 'gu');\n}\n\nfunction linkStyle(color: string): CSSProperties {\n return { color, textDecoration: 'none', fontWeight: 500 };\n}\n\n/** Split text into plain runs and highlighted entity nodes. */\nfunction linkify(\n text: string,\n colors: PostBodyColors,\n mentionNames: readonly string[],\n): ReactNode[] {\n const pattern = buildPattern(mentionNames);\n const nodes: ReactNode[] = [];\n let lastIndex = 0;\n let key = 0;\n\n for (const match of text.matchAll(pattern)) {\n const token = match[0];\n const start = match.index;\n if (start > lastIndex) {\n nodes.push(\n <Fragment key={key++}>{text.slice(lastIndex, start)}</Fragment>,\n );\n }\n if (token.startsWith('http')) {\n nodes.push(\n <a\n key={key++}\n href={token}\n style={linkStyle(colors.accent)}\n target=\"_blank\"\n rel=\"noreferrer\"\n >\n {token}\n </a>,\n );\n } else if (token.startsWith('#')) {\n nodes.push(\n <a key={key++} href=\"#\" style={linkStyle(colors.accent)}>\n {token}\n </a>,\n );\n } else {\n nodes.push(\n <span key={key++} style={linkStyle(colors.accent)}>\n {token}\n </span>,\n );\n }\n lastIndex = start + token.length;\n }\n\n if (lastIndex < text.length) {\n nodes.push(<Fragment key={key++}>{text.slice(lastIndex)}</Fragment>);\n }\n return nodes;\n}\n\nexport function PostBody({ text, mentionNames = [], colors }: PostBodyProps) {\n const [expanded, setExpanded] = useState(false);\n const isLong = text.length > FOLD_CHARS;\n const shown = isLong && !expanded ? truncateAtWord(text, FOLD_CHARS) : text;\n\n return (\n <div style={BODY_STYLE}>\n {linkify(shown, colors, mentionNames)}\n {isLong && !expanded ? (\n <>\n {'…'}{' '}\n <button\n type=\"button\"\n onClick={() => setExpanded(true)}\n style={{\n background: 'none',\n border: 'none',\n padding: 0,\n cursor: 'pointer',\n color: colors.muted,\n fontWeight: 600,\n fontSize: 14,\n }}\n >\n more\n </button>\n </>\n ) : null}\n </div>\n );\n}\n","'use client';\n\nimport type { LinkedInPostVariant } from '@postrun/js';\nimport { memo } from 'react';\nimport type { CSSProperties } from 'react';\n\nimport type { LinkedInPreviewAuthor, PreviewMedia } from '../types';\nimport { altSignatureOf, useResolvedMedia } from '../use-resolved-media';\nimport { EngagementBar } from './EngagementBar';\nimport { Header } from './Header';\nimport type { LinkedInVisibility } from './Header';\nimport { Media } from './Media';\nimport { PostBody } from './PostBody';\nimport {\n LI_VAR,\n type LinkedInTheme,\n paletteVars,\n useIsDark,\n varRef,\n} from './theme';\n\n/**\n * A faithful, schema-driven preview of how a LinkedIn post will look in-feed,\n * rendered straight from a Postrun LinkedIn variant. Clean-room components (no\n * dependency to \"buy\" exists for LinkedIn), mirroring the real feed card: header\n * with headline + audience icon, an entity-highlighted body with the \"…more\"\n * fold, the 1/2/3/4/+N image mosaic (or a video), and a static action bar.\n *\n * v1 renders text + images + video. The richer `content_kind`s (article, poll,\n * document) degrade gracefully to the text/media card and arrive next.\n *\n * Customize via `theme` (light/dark/auto), `className`/`style`, or by overriding\n * the `--pr-li-*` CSS variables the card reads.\n */\nexport interface LinkedInPostPreviewProps {\n /** The LinkedIn variant from our schema — the content source, untouched. */\n variant: LinkedInPostVariant;\n /** Author identity (LinkedIn stores no avatar/headline on our connection). */\n author: LinkedInPreviewAuthor;\n /** Resolved media pixels (URLs or compose-time File blobs). */\n media?: PreviewMedia[];\n /** Color scheme. `auto` (default) follows the OS preference. */\n theme?: LinkedInTheme;\n /** Relative time label shown in the header. Default \"Now\". */\n time?: string;\n /** Show the static action bar (Like/Comment/Repost/Send). Default true. */\n showActions?: boolean;\n /** Class applied to the card — your hook for sizing, shadows, etc. */\n className?: string;\n /** Inline styles on the card — including `--pr-li-*` variable overrides. */\n style?: CSSProperties;\n}\n\nconst FONT_STACK =\n '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif';\n\nfunction LinkedInPostPreviewImpl({\n variant,\n author,\n media,\n theme = 'auto',\n time,\n showActions = true,\n className,\n style,\n}: LinkedInPostPreviewProps) {\n const dark = useIsDark(theme);\n const resolvedMedia = useResolvedMedia(\n media,\n variant.media,\n altSignatureOf(variant.media),\n );\n\n const visibility: LinkedInVisibility =\n variant.settings?.visibility ?? 'PUBLIC';\n const mentionNames = (variant.settings?.mentions ?? []).map((m) => m.name);\n const bodyColors = {\n accent: varRef(LI_VAR.accent),\n muted: varRef(LI_VAR.muted),\n };\n\n const cardStyle: CSSProperties = {\n ...paletteVars(dark),\n background: varRef(LI_VAR.bg),\n color: varRef(LI_VAR.text),\n border: `1px solid ${varRef(LI_VAR.border)}`,\n borderRadius: 10,\n maxWidth: 552,\n overflow: 'hidden',\n fontFamily: FONT_STACK,\n ...style,\n };\n\n return (\n <div className={className} style={cardStyle}>\n <Header author={author} visibility={visibility} time={time} />\n {variant.body ? (\n <div style={{ padding: '8px 16px 0' }}>\n <PostBody\n text={variant.body}\n mentionNames={mentionNames}\n colors={bodyColors}\n />\n </div>\n ) : null}\n {resolvedMedia.length > 0 ? (\n <div style={{ marginTop: 12 }}>\n <Media media={resolvedMedia} />\n </div>\n ) : null}\n {showActions ? <EngagementBar /> : null}\n </div>\n );\n}\n\n/** Memoized: re-renders only when its props change (the resolved-media hook\n * absorbs unstable media arrays). */\nexport const LinkedInPostPreview = memo(LinkedInPostPreviewImpl);\n"]}
|