@fluid-app/portal-sdk 0.1.435 → 0.1.436
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{OrdersScreen-3noAB3V0.mjs → OrdersScreen-CSrHqOH8.mjs} +1 -1
- package/dist/{OrdersScreen-B54rTEGH.cjs → OrdersScreen-CZ3axJB8.cjs} +1 -1
- package/dist/{OrdersScreen-9Z-E37j-.mjs → OrdersScreen-DBM1hhgf.mjs} +3 -5
- package/dist/OrdersScreen-DBM1hhgf.mjs.map +1 -0
- package/dist/{OrdersScreen-CouE0MT7.cjs → OrdersScreen-Dc9dnk6h.cjs} +3 -5
- package/dist/OrdersScreen-Dc9dnk6h.cjs.map +1 -0
- package/dist/adapters/orders-api-adapter.d.ts.map +1 -1
- package/dist/index.cjs +3 -3
- package/dist/index.mjs +3 -3
- package/dist/translation-adapter-DObP7Ra9.mjs.map +1 -1
- package/dist/translation-adapter-QvJmka5w.cjs.map +1 -1
- package/package.json +12 -12
- package/dist/OrdersScreen-9Z-E37j-.mjs.map +0 -1
- package/dist/OrdersScreen-CouE0MT7.cjs.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"translation-adapter-DObP7Ra9.mjs","names":["portalTenantContent.dam_query","portalTenantContent.dam_assets_destroy","portalTenantContent.dam_assets_discard","portalTenantContent.dam_asset_paths_create","portalTenantContent.media_list","portalTenantContent.media_create","portalTenantContent.media_show","portalTenantContent.media_update","portalTenantContent.media_destroy","portalTenantContent.media_products_list","portalTenantContent.media_products_add","portalTenantContent.media_products_remove","portalTenantContent.playlists_list","portalTenantContent.playlists_create","portalTenantContent.playlists_show","portalTenantContent.playlists_update","portalTenantContent.playlists_destroy","portalTenantContent.playlists_items_list","portalTenantContent.playlists_items_add","portalTenantContent.playlists_items_remove","portalTenantContent.playlists_items_reorder","portalTenantContent.shares_list","portalTenantContent.shares_create","portalTenantContent.pages_list","portalTenantContent.pages_show","portalTenant.enrollment_packs_list","portalTenant.enrollment_packs_show","portalTenantContent.dam_assets_list","portalTenantContent.dam_assets_create","portalTenantContent.dam_asset_paths_list","portalTenantContent.dam_asset_paths_create","portalTenantContent.content_media_by_visits","portalTenantContent.content_media_by_shares","portalTenantContent.content_playlists_by_visits","portalTenantContent.content_playlists_by_shares","portalTenantContent.content_pages_by_visits","portalTenantContent.content_pages_by_shares"],"sources":["../../../api-clients/portal-tenant/src/namespaces/portal_tenant.ts","../../../api-clients/portal-tenant-content/src/namespaces/portal_tenant_content.ts","../../../shareables/core/src/context.tsx","../../../shareables/core/src/hooks/use-product-media-counts.ts","../../../shareables/core/src/hooks/use-media-mutations.ts","../../../shareables/core/src/utils.ts","../../../shareables/core/src/hooks/use-playlist-mutations.ts","../../../file-picker/core/src/file-picker-api-context.ts","../../../file-picker/core/src/schemas/dam.ts","../../../file-picker/api-client/src/api/url-proxy.ts","../src/adapters/file-picker-api-adapter.ts","../src/adapters/content-api-adapter.ts","../src/content/PortalContentApiProvider.tsx","../../../shareables/core/src/translation-dictionary.ts","../../../shareables/core/src/translation-adapter.ts"],"sourcesContent":["/**\n * Generated API client functions for portal_tenant\n *\n * DO NOT EDIT THIS FILE DIRECTLY\n * This file is auto-generated. To update:\n * 1. Update the OpenAPI spec file\n * 2. Run: pnpm generate\n */\n\nimport type { FetchClient } from \"../lib/fetch-client\";\nimport type { operations } from \"../generated/portal-tenant\";\n\n// ============================================================================\n// address_fields\n// ============================================================================\n\n/**\n * Get address fields for a country\n * Returns the address field configuration for a given country code, including field names, localized labels, and whether each field is required. Use the optional language_iso query parameter to receive labels in a specific locale; defaults to English.\n *\n * @param client - Fetch client instance\n * @param country_code - country_code\n * @param [params] - params\n */\nexport async function address_fields_show(\n client: FetchClient,\n country_code: string | number,\n params?: operations[\"address_fields_show\"][\"parameters\"][\"query\"],\n): Promise<\n operations[\"address_fields_show\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/countries/${country_code}/address_fields`, params);\n}\n\n// ============================================================================\n// account\n// ============================================================================\n\n/**\n * Get current account\n * Returns the authenticated member's account profile and company context. This is the primary endpoint the SPA calls to check auth status and display user information.\n *\n * @param client - Fetch client instance\n \n */\nexport async function account_show(\n client: FetchClient,\n): Promise<\n operations[\"account_show\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/account`);\n}\n\n/**\n * Update current account\n * Updates the authenticated member's profile fields such as name, phone, bio, avatar, and social links.\n *\n * @param client - Fetch client instance\n * @param body - body\n */\nexport async function account_update(\n client: FetchClient,\n body: operations[\"account_update\"][\"requestBody\"][\"content\"][\"application/json\"],\n): Promise<\n operations[\"account_update\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.patch(`/api/account`, body);\n}\n\n// ============================================================================\n// store\n// ============================================================================\n\n/**\n * Get store branding and feature flags\n * Returns the tenant company's store branding (logo, icon, app store URLs) and feature flags such as whether subscription bundling is enabled.\n *\n * @param client - Fetch client instance\n \n */\nexport async function store_show(\n client: FetchClient,\n): Promise<\n operations[\"store_show\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/store`);\n}\n\n// ============================================================================\n// app\n// ============================================================================\n\n/**\n * Get the app manifest\n * Returns the rendered manifest for the tenant company's active FluidOS definition, matched against the current user's country, rank, and roles.\n *\n * @param client - Fetch client instance\n \n */\nexport async function app_manifest_show(\n client: FetchClient,\n): Promise<\n operations[\"app_manifest_show\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/app/manifest`);\n}\n\n// ============================================================================\n// calendar_events\n// ============================================================================\n\n/**\n * List calendar events\n * Returns a paginated list of upcoming and ongoing calendar events for the tenant company, optionally filtered by the authenticated member's country when one is set.\n *\n * @param client - Fetch client instance\n * @param [params] - params\n */\nexport async function calendar_events_list(\n client: FetchClient,\n params?: operations[\"calendar_events_list\"][\"parameters\"][\"query\"],\n): Promise<\n operations[\"calendar_events_list\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/calendar/events`, params);\n}\n\n// ============================================================================\n// activities\n// ============================================================================\n\n/**\n * List recent activities\n * Returns a paginated list of recent activities for the authenticated member, ordered by most recent first. Each activity includes pre-computed user_name and target_name fields ready for direct rendering by the portal SPA. When `days_ago` is provided, the response is restricted to that rolling window and `meta.pagination.total_count` is populated.\n *\n * @param client - Fetch client instance\n * @param [params] - params\n */\nexport async function activities_list(\n client: FetchClient,\n params?: operations[\"activities_list\"][\"parameters\"][\"query\"],\n): Promise<\n operations[\"activities_list\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/activities`, params);\n}\n\n// ============================================================================\n// catch_ups\n// ============================================================================\n\n/**\n * List catch-up suggestions\n * Returns a paginated list of catch-up suggestions for the authenticated member. Limited to suggestions with at least one pending action that have not expired.\n *\n * @param client - Fetch client instance\n * @param [params] - params\n */\nexport async function catch_ups_list(\n client: FetchClient,\n params?: operations[\"catch_ups_list\"][\"parameters\"][\"query\"],\n): Promise<\n operations[\"catch_ups_list\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/catch_ups`, params);\n}\n\n/**\n * Get a catch-up suggestion\n * Returns a single catch-up suggestion by id, scoped to the authenticated member. Returns 404 when the catch-up belongs to a different member.\n *\n * @param client - Fetch client instance\n * @param id - id\n */\nexport async function catch_ups_show(\n client: FetchClient,\n id: string | number,\n): Promise<\n operations[\"catch_ups_show\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/catch_ups/${id}`);\n}\n\n// ============================================================================\n// orders\n// ============================================================================\n\n/**\n * List orders\n * Returns a paginated list of orders placed through the tenant company, optionally filtered by status.\n *\n * @param client - Fetch client instance\n * @param [params] - params\n */\nexport async function orders_list(\n client: FetchClient,\n params?: operations[\"orders_list\"][\"parameters\"][\"query\"],\n): Promise<\n operations[\"orders_list\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/orders`, params);\n}\n\n/**\n * Get an order\n * Returns a single order by token with its line items.\n *\n * @param client - Fetch client instance\n * @param token - token\n */\nexport async function orders_show(\n client: FetchClient,\n token: string | number,\n): Promise<\n operations[\"orders_show\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/orders/${token}`);\n}\n\n// ============================================================================\n// products\n// ============================================================================\n\n/**\n * List products\n * Returns a paginated list of products available in the tenant company's catalog. Supports sorting and filtering by title, product type, collection, and stock availability.\n *\n * @param client - Fetch client instance\n * @param [params] - params\n */\nexport async function products_list(\n client: FetchClient,\n params?: operations[\"products_list\"][\"parameters\"][\"query\"],\n): Promise<\n operations[\"products_list\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/products`, params);\n}\n\n/**\n * Get a product\n * Returns a single product by ID with its variants.\n *\n * @param client - Fetch client instance\n * @param id - id\n */\nexport async function products_show(\n client: FetchClient,\n id: string | number,\n): Promise<\n operations[\"products_show\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/products/${id}`);\n}\n\n/**\n * Search products\n * Searches the tenant company's product catalog by keyword, returning paginated results.\n *\n * @param client - Fetch client instance\n * @param [params] - params\n */\nexport async function products_search(\n client: FetchClient,\n params?: operations[\"products_search\"][\"parameters\"][\"query\"],\n): Promise<\n operations[\"products_search\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/products/search`, params);\n}\n\n/**\n * List product media\n * Returns all media (images, videos) attached to a product.\n *\n * @param client - Fetch client instance\n * @param id - id\n */\nexport async function products_media_list(\n client: FetchClient,\n id: string | number,\n): Promise<\n operations[\"products_media_list\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/products/${id}/media`);\n}\n\n// ============================================================================\n// enrollment_packs\n// ============================================================================\n\n/**\n * List enrollment packs\n * Returns a paginated list of active, non-discarded enrollment packs scoped to the current portal tenant's company. Each pack carries an empty `products` array — fetch a single pack via `/api/enrollment_packs/{id}` to load its visible products.\n *\n * @param client - Fetch client instance\n * @param [params] - params\n */\nexport async function enrollment_packs_list(\n client: FetchClient,\n params?: operations[\"enrollment_packs_list\"][\"parameters\"][\"query\"],\n): Promise<\n operations[\"enrollment_packs_list\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/enrollment_packs`, params);\n}\n\n/**\n * Get an enrollment pack\n * Returns a single active, non-discarded enrollment pack scoped to the current portal tenant's company.\n *\n * @param client - Fetch client instance\n * @param id - id\n */\nexport async function enrollment_packs_show(\n client: FetchClient,\n id: string | number,\n): Promise<\n operations[\"enrollment_packs_show\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/enrollment_packs/${id}`);\n}\n\n// ============================================================================\n// subscriptions\n// ============================================================================\n\n/**\n * List subscription bundles\n * Returns the runtime bundle groupings for the authenticated customer's active subscriptions. Bundles are computed at request time by grouping subscriptions that share customer, address (physical only), volume rep, next bill date, and digital flag — they have no persistent id. The response is unpaginated; customers typically have a small number of bundles.\n *\n * @param client - Fetch client instance\n \n */\nexport async function subscription_bundles_list(\n client: FetchClient,\n): Promise<\n operations[\"subscription_bundles_list\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/subscription_bundles`);\n}\n\n/**\n * List subscriptions\n * Returns a paginated list of the member's active and historical subscriptions. Supports filtering by lifecycle state and a free-text search across product and plan names.\n *\n * @param client - Fetch client instance\n * @param [params] - params\n */\nexport async function subscriptions_list(\n client: FetchClient,\n params?: operations[\"subscriptions_list\"][\"parameters\"][\"query\"],\n): Promise<\n operations[\"subscriptions_list\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/subscriptions`, params);\n}\n\n/**\n * Get a subscription\n * Returns a single subscription by its token.\n *\n * @param client - Fetch client instance\n * @param token - token\n */\nexport async function subscriptions_show(\n client: FetchClient,\n token: string | number,\n): Promise<\n operations[\"subscriptions_show\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/subscriptions/${token}`);\n}\n\n/**\n * Update a subscription\n * Updates a subscription's default payment method or quantity.\n *\n * @param client - Fetch client instance\n * @param token - token\n * @param body - body\n */\nexport async function subscriptions_update(\n client: FetchClient,\n token: string | number,\n body: operations[\"subscriptions_update\"][\"requestBody\"][\"content\"][\"application/json\"],\n): Promise<\n operations[\"subscriptions_update\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.put(`/api/subscriptions/${token}`, body);\n}\n\n/**\n * List subscription discounts\n * Returns active and historical discount attachments for a visible subscription, newest first.\n *\n * @param client - Fetch client instance\n * @param token - token\n */\nexport async function subscription_discounts_list(\n client: FetchClient,\n token: string | number,\n): Promise<\n operations[\"subscription_discounts_list\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/subscriptions/${token}/discounts`);\n}\n\n/**\n * Attach a subscription discount\n * Attaches an eligible discount to a visible subscription.\n *\n * @param client - Fetch client instance\n * @param token - token\n * @param body - body\n */\nexport async function subscription_discounts_attach(\n client: FetchClient,\n token: string | number,\n body: operations[\"subscription_discounts_attach\"][\"requestBody\"][\"content\"][\"application/json\"],\n): Promise<\n operations[\"subscription_discounts_attach\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.post(`/api/subscriptions/${token}/discounts`, body);\n}\n\n/**\n * Remove a subscription discount\n * Soft-removes a visible subscription discount attachment.\n *\n * @param client - Fetch client instance\n * @param token - token\n * @param id - id\n * @param [body] - body\n */\nexport async function subscription_discounts_remove(\n client: FetchClient,\n token: string | number,\n id: string | number,\n body?: NonNullable<\n operations[\"subscription_discounts_remove\"][\"requestBody\"]\n >[\"content\"][\"application/json\"],\n): Promise<\n operations[\"subscription_discounts_remove\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.delete(`/api/subscriptions/${token}/discounts/${id}`, { body });\n}\n\n/**\n * Pause a subscription\n * Pauses billing on an active subscription. When neither `next_bill_date` nor `number_of_orders` is provided, the subscription is paused indefinitely. Specifying both is rejected.\n *\n * @param client - Fetch client instance\n * @param token - token\n * @param [body] - body\n */\nexport async function subscriptions_pause(\n client: FetchClient,\n token: string | number,\n body?: NonNullable<\n operations[\"subscriptions_pause\"][\"requestBody\"]\n >[\"content\"][\"application/json\"],\n): Promise<\n operations[\"subscriptions_pause\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.post(`/api/subscriptions/${token}/pause`, body);\n}\n\n/**\n * Resume a subscription\n * Resumes billing on a paused subscription or restores normal scheduled billing for an exhausted past-due subscription without charging immediately. Paused subscriptions use the supplied next bill date, or the plan's next date when omitted. Exhausted subscriptions preserve a future bill date; a stale date is moved into the future using the subscription plan cadence.\n *\n * @param client - Fetch client instance\n * @param token - token\n * @param [body] - body\n */\nexport async function subscriptions_resume(\n client: FetchClient,\n token: string | number,\n body?: NonNullable<\n operations[\"subscriptions_resume\"][\"requestBody\"]\n >[\"content\"][\"application/json\"],\n): Promise<\n operations[\"subscriptions_resume\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.post(`/api/subscriptions/${token}/resume`, body);\n}\n\n/**\n * Preview a failed-cycle waiver\n * Returns the authoritative future billing and shipping timestamps that would be restored if the exhausted failed cycle were waived. An ineligible subscription returns 200 with eligible false and null dates.\n *\n * @param client - Fetch client instance\n * @param token - token\n */\nexport async function subscriptions_failed_cycle_waiver_preview(\n client: FetchClient,\n token: string | number,\n): Promise<\n operations[\"subscriptions_failed_cycle_waiver_preview\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/subscriptions/${token}/failed-cycle-waiver`);\n}\n\n/**\n * Skip the exhausted failed cycle\n * Waives the missed billing and shipping cycle without collecting payment and without creating an order or shipment. The missed shipment is skipped. The subscription's original billing and shipping cadence and anchors are preserved, and each stored next date is advanced independently only as needed to reach a future local date.\n *\n * @param client - Fetch client instance\n * @param token - token\n * @param [body] - body\n */\nexport async function subscriptions_failed_cycle_waiver_create(\n client: FetchClient,\n token: string | number,\n body?: NonNullable<\n operations[\"subscriptions_failed_cycle_waiver_create\"][\"requestBody\"]\n >[\"content\"][\"application/json\"],\n): Promise<\n operations[\"subscriptions_failed_cycle_waiver_create\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.post(`/api/subscriptions/${token}/failed-cycle-waiver`, body);\n}\n\n/**\n * Skip next billing cycle\n * Skips the next billing cycle for a subscription without pausing it.\n *\n * @param client - Fetch client instance\n * @param token - token\n */\nexport async function subscriptions_skip(\n client: FetchClient,\n token: string | number,\n): Promise<\n operations[\"subscriptions_skip\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.post(`/api/subscriptions/${token}/skip_next_billing`);\n}\n\n/**\n * Cancel a subscription\n * Cancels an active subscription.\n *\n * @param client - Fetch client instance\n * @param token - token\n */\nexport async function subscriptions_cancel(\n client: FetchClient,\n token: string | number,\n): Promise<\n operations[\"subscriptions_cancel\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.post(`/api/subscriptions/${token}/cancel`);\n}\n\n/**\n * Reactivate a subscription\n * Reactivates a previously cancelled subscription.\n *\n * @param client - Fetch client instance\n * @param token - token\n * @param [body] - body\n */\nexport async function subscriptions_reactivate(\n client: FetchClient,\n token: string | number,\n body?: NonNullable<\n operations[\"subscriptions_reactivate\"][\"requestBody\"]\n >[\"content\"][\"application/json\"],\n): Promise<\n operations[\"subscriptions_reactivate\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.post(`/api/subscriptions/${token}/reactivate`, body);\n}\n\n/**\n * Retry billing on a past-due subscription\n * Queues an immediate retry on a past-due subscription against whatever payment method is currently on file. The customer may retry the saved method directly or update the method before making this request.\n\n\nThe endpoint returns 200 for found subscriptions in normal operation, regardless of status — it is intentionally idempotent so the client can call it unconditionally without first checking status. A 422 can still be returned if the server cannot persist the retry state. Use the response's `queued` field to distinguish the two outcomes:\n\n - `queued: true` — the subscription was past_due and a retry is pending. A rapid duplicate preserves the first `next_retry_at` and does not enqueue another attempt.\n - `queued: false` — the subscription was not past_due and no state change occurred. Treat as a no-op.\n *\n * @param client - Fetch client instance\n * @param token - token\n */\nexport async function subscriptions_retry(\n client: FetchClient,\n token: string | number,\n): Promise<\n operations[\"subscriptions_retry\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.post(`/api/subscriptions/${token}/retry`);\n}\n\n// ============================================================================\n// subscription_bundles\n// ============================================================================\n\n/**\n * Create a subscription bundle\n * Bundles two or more existing subscriptions onto a shared bill date, address, and volume rep. All subscriptions must belong to the authenticated customer. Bundles are not persisted entities — the endpoint aligns each subscription's billing attributes so that they share a runtime grouping key.\n *\n * @param client - Fetch client instance\n * @param body - body\n */\nexport async function subscription_bundles_create(\n client: FetchClient,\n body: operations[\"subscription_bundles_create\"][\"requestBody\"][\"content\"][\"application/json\"],\n): Promise<\n operations[\"subscription_bundles_create\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.post(`/api/subscription_bundles/bundle`, body);\n}\n\n// ============================================================================\n// todos\n// ============================================================================\n\n/**\n * List todos\n * Returns a paginated list of tasks scoped to the authenticated member. Filter by completion state via the `state` query parameter; defaults to `incomplete` for backwards compatibility. Incomplete tasks are ordered by due date ascending (nulls last); completed tasks by completion time descending.\n *\n * @param client - Fetch client instance\n * @param [params] - params\n */\nexport async function todos_list(\n client: FetchClient,\n params?: operations[\"todos_list\"][\"parameters\"][\"query\"],\n): Promise<\n operations[\"todos_list\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/todos`, params);\n}\n\n/**\n * Create a todo\n * Creates a todo owned by the authenticated member. `contact_id` is optional — omit it (or send null) to create a standalone todo not attached to a contact, matching mobile widget parity. When `contact_id` is supplied the caller must own the contact.\n *\n * @param client - Fetch client instance\n * @param body - body\n */\nexport async function todos_create(\n client: FetchClient,\n body: operations[\"todos_create\"][\"requestBody\"][\"content\"][\"application/json\"],\n): Promise<\n operations[\"todos_create\"][\"responses\"][201][\"content\"][\"application/json\"]\n> {\n return client.post(`/api/todos`, body);\n}\n\n/**\n * Update a todo\n * Updates the given todo. Any non-empty subset of `body`, `due_at`, `completed`, and `contact_id` is accepted. Sending `completed: true` stamps `completed_at` with the current time; `false` clears it. A non-null `contact_id` must identify a contact owned by the authenticated user in the portal tenant company; `null` clears it. The existing widget call sending only `{ completed }` continues to work unchanged.\n *\n * @param client - Fetch client instance\n * @param id - id\n * @param body - body\n */\nexport async function todos_update(\n client: FetchClient,\n id: string | number,\n body: operations[\"todos_update\"][\"requestBody\"][\"content\"][\"application/json\"],\n): Promise<\n operations[\"todos_update\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.patch(`/api/todos/${id}`, body);\n}\n\n/**\n * Delete a todo\n * Deletes the given todo. Only the owning member can delete. Deleting a todo not visible to the acting member returns 404 (do not leak existence). Soft vs hard delete follows the Task model's existing destroy semantics.\n *\n * @param client - Fetch client instance\n * @param id - id\n */\nexport async function todos_destroy(\n client: FetchClient,\n id: string | number,\n): Promise<\n operations[\"todos_destroy\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.delete(`/api/todos/${id}`);\n}\n\n// ============================================================================\n// carts\n// ============================================================================\n\n/**\n * Claim a cart\n * Assigns the logged-in member as buyer_rep on an unclaimed FairShare cart. Any portal member (rep or customer) can claim. Returns an error if the cart has already been claimed.\n *\n * @param client - Fetch client instance\n * @param token - token\n */\nexport async function carts_claim(\n client: FetchClient,\n token: string | number,\n): Promise<\n operations[\"carts_claim\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.post(`/api/carts/${token}/claim`);\n}\n\n// ============================================================================\n// product_metrics\n// ============================================================================\n\n/**\n * Top products by direct visits\n * Ranked list of the company's products by total visits to the product page (aggregates metrics_product_visits across all visit sources).\n *\n * @param client - Fetch client instance\n * @param [params] - params\n */\nexport async function product_by_visits(\n client: FetchClient,\n params?: operations[\"product_by_visits\"][\"parameters\"][\"query\"],\n): Promise<\n operations[\"product_by_visits\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/products/by-visits`, params);\n}\n\n/**\n * Top products by share-link visits\n * Ranked list of the company's products by click-throughs on rep share links (aggregates metrics_share_shareable_visits where shareable_type='Product').\n *\n * @param client - Fetch client instance\n * @param [params] - params\n */\nexport async function product_by_shares(\n client: FetchClient,\n params?: operations[\"product_by_shares\"][\"parameters\"][\"query\"],\n): Promise<\n operations[\"product_by_shares\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/products/by-shares`, params);\n}\n\n// ============================================================================\n// enrollment_pack_metrics\n// ============================================================================\n\n/**\n * Top enrollment packs by direct visits\n * Ranked list of the company's enrollment packs by total visits to the pack page (aggregates metrics_enrollment_pack_visits across all visit sources).\n *\n * @param client - Fetch client instance\n * @param [params] - params\n */\nexport async function enrollment_pack_by_visits(\n client: FetchClient,\n params?: operations[\"enrollment_pack_by_visits\"][\"parameters\"][\"query\"],\n): Promise<\n operations[\"enrollment_pack_by_visits\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/enrollment_packs/by-visits`, params);\n}\n\n/**\n * Top enrollment packs by share-link visits\n * Ranked list of the company's enrollment packs by click-throughs on rep share links (aggregates metrics_share_shareable_visits where shareable_type='EnrollmentPack').\n *\n * @param client - Fetch client instance\n * @param [params] - params\n */\nexport async function enrollment_pack_by_shares(\n client: FetchClient,\n params?: operations[\"enrollment_pack_by_shares\"][\"parameters\"][\"query\"],\n): Promise<\n operations[\"enrollment_pack_by_shares\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/enrollment_packs/by-shares`, params);\n}\n","/**\n * Generated API client functions for portal_tenant_content\n *\n * DO NOT EDIT THIS FILE DIRECTLY\n * This file is auto-generated. To update:\n * 1. Update the OpenAPI spec file\n * 2. Run: pnpm generate\n */\n\nimport type { FetchClient } from \"../lib/fetch-client\";\nimport type { operations } from \"../generated/portal-tenant-content\";\n\n// ============================================================================\n// content\n// ============================================================================\n\n/**\n * List active languages for the tenant company\n * Returns active languages enabled for the tenant company, sorted by name. Used by the content/translation editor to populate the language switcher.\n *\n * @param client - Fetch client instance\n * @param [params] - params\n */\nexport async function content_languages_list(\n client: FetchClient,\n params?: operations[\"content_languages_list\"][\"parameters\"][\"query\"],\n): Promise<\n operations[\"content_languages_list\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/content/languages`, params);\n}\n\n/**\n * List media (own uploads and company share media)\n * Returns a paginated list of the member's own uploads and company share media. Training and update media are excluded.\n *\n * @param client - Fetch client instance\n * @param [params] - params\n */\nexport async function media_list(\n client: FetchClient,\n params?: operations[\"media_list\"][\"parameters\"][\"query\"],\n): Promise<\n operations[\"media_list\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/content/media`, params);\n}\n\n/**\n * Create a new media item\n * Creates a new media item record.\n *\n * @param client - Fetch client instance\n * @param body - body\n */\nexport async function media_create(\n client: FetchClient,\n body: operations[\"media_create\"][\"requestBody\"][\"content\"][\"application/json\"],\n): Promise<\n operations[\"media_create\"][\"responses\"][201][\"content\"][\"application/json\"]\n> {\n return client.post(`/api/content/media`, body);\n}\n\n/**\n * Get a specific media item\n * Returns a single media item by ID. When language_iso is provided, translatable fields (title, description, url) are returned for that language with no fallback — empty values indicate an untranslated field.\n *\n * @param client - Fetch client instance\n * @param id - id\n * @param [params] - params\n */\nexport async function media_show(\n client: FetchClient,\n id: string | number,\n params?: operations[\"media_show\"][\"parameters\"][\"query\"],\n): Promise<\n operations[\"media_show\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/content/media/${id}`, params);\n}\n\n/**\n * Update a media item (own uploads only)\n * Updates a media item's title, description, status, url, content_format, thumbnail, CTA, and SEO. When language_iso is provided, translatable fields are written against that language's translation row instead of the default locale.\n *\n * @param client - Fetch client instance\n * @param id - id\n * @param body - body\n * @param [params] - params\n */\nexport async function media_update(\n client: FetchClient,\n id: string | number,\n body: operations[\"media_update\"][\"requestBody\"][\"content\"][\"application/json\"],\n params?: operations[\"media_update\"][\"parameters\"][\"query\"],\n): Promise<\n operations[\"media_update\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.patch(`/api/content/media/${id}`, body, { params });\n}\n\n/**\n * Delete a media item (own uploads only)\n * Removes a media item.\n *\n * @param client - Fetch client instance\n * @param id - id\n */\nexport async function media_destroy(\n client: FetchClient,\n id: string | number,\n): Promise<\n operations[\"media_destroy\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.delete(`/api/content/media/${id}`);\n}\n\n/**\n * List products associated with a media item\n * Returns a paginated list of products associated with a media item.\n *\n * @param client - Fetch client instance\n * @param medium_id - medium_id\n * @param [params] - params\n */\nexport async function media_products_list(\n client: FetchClient,\n medium_id: string | number,\n params?: operations[\"media_products_list\"][\"parameters\"][\"query\"],\n): Promise<\n operations[\"media_products_list\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/content/media/${medium_id}/products`, params);\n}\n\n/**\n * Associate a product with a media item\n * Creates a product association for a media item.\n *\n * @param client - Fetch client instance\n * @param medium_id - medium_id\n * @param body - body\n */\nexport async function media_products_add(\n client: FetchClient,\n medium_id: string | number,\n body: operations[\"media_products_add\"][\"requestBody\"][\"content\"][\"application/json\"],\n): Promise<\n operations[\"media_products_add\"][\"responses\"][201][\"content\"][\"application/json\"]\n> {\n return client.post(`/api/content/media/${medium_id}/products`, body);\n}\n\n/**\n * Remove a product association from a media item\n * Removes a single product association from a media item.\n *\n * @param client - Fetch client instance\n * @param medium_id - medium_id\n * @param id - id\n */\nexport async function media_products_remove(\n client: FetchClient,\n medium_id: string | number,\n id: string | number,\n): Promise<\n operations[\"media_products_remove\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.delete(`/api/content/media/${medium_id}/products/${id}`);\n}\n\n/**\n * List playlists with cursor pagination\n * Returns a paginated list of playlists.\n *\n * @param client - Fetch client instance\n * @param [params] - params\n */\nexport async function playlists_list(\n client: FetchClient,\n params?: operations[\"playlists_list\"][\"parameters\"][\"query\"],\n): Promise<\n operations[\"playlists_list\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/content/playlists`, params);\n}\n\n/**\n * Create a new playlist\n * Creates a new playlist.\n *\n * @param client - Fetch client instance\n * @param body - body\n */\nexport async function playlists_create(\n client: FetchClient,\n body: operations[\"playlists_create\"][\"requestBody\"][\"content\"][\"application/json\"],\n): Promise<\n operations[\"playlists_create\"][\"responses\"][201][\"content\"][\"application/json\"]\n> {\n return client.post(`/api/content/playlists`, body);\n}\n\n/**\n * Get a specific playlist\n * Returns a single playlist by ID.\n *\n * @param client - Fetch client instance\n * @param id - id\n */\nexport async function playlists_show(\n client: FetchClient,\n id: string | number,\n): Promise<\n operations[\"playlists_show\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/content/playlists/${id}`);\n}\n\n/**\n * Update a playlist\n * Updates a playlist's title or metadata.\n *\n * @param client - Fetch client instance\n * @param id - id\n * @param body - body\n */\nexport async function playlists_update(\n client: FetchClient,\n id: string | number,\n body: operations[\"playlists_update\"][\"requestBody\"][\"content\"][\"application/json\"],\n): Promise<\n operations[\"playlists_update\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.patch(`/api/content/playlists/${id}`, body);\n}\n\n/**\n * Delete a playlist\n * Removes a playlist.\n *\n * @param client - Fetch client instance\n * @param id - id\n */\nexport async function playlists_destroy(\n client: FetchClient,\n id: string | number,\n): Promise<\n operations[\"playlists_destroy\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.delete(`/api/content/playlists/${id}`);\n}\n\n/**\n * List items in a playlist\n * Returns a paginated list of items in a playlist.\n *\n * @param client - Fetch client instance\n * @param playlist_id - playlist_id\n * @param [params] - params\n */\nexport async function playlists_items_list(\n client: FetchClient,\n playlist_id: string | number,\n params?: operations[\"playlists_items_list\"][\"parameters\"][\"query\"],\n): Promise<\n operations[\"playlists_items_list\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/content/playlists/${playlist_id}/items`, params);\n}\n\n/**\n * Add an item to a playlist\n * Adds a content item (media, page, product, or enrollment_pack) to a playlist.\n *\n * @param client - Fetch client instance\n * @param playlist_id - playlist_id\n * @param body - body\n */\nexport async function playlists_items_add(\n client: FetchClient,\n playlist_id: string | number,\n body: operations[\"playlists_items_add\"][\"requestBody\"][\"content\"][\"application/json\"],\n): Promise<\n operations[\"playlists_items_add\"][\"responses\"][201][\"content\"][\"application/json\"]\n> {\n return client.post(`/api/content/playlists/${playlist_id}/items`, body);\n}\n\n/**\n * Reorder items in a playlist\n * Sets the order of items in a playlist. Items not included in the payload are not moved. Flips the playlist to manual ordering.\n *\n * @param client - Fetch client instance\n * @param playlist_id - playlist_id\n * @param body - body\n */\nexport async function playlists_items_reorder(\n client: FetchClient,\n playlist_id: string | number,\n body: operations[\"playlists_items_reorder\"][\"requestBody\"][\"content\"][\"application/json\"],\n): Promise<\n operations[\"playlists_items_reorder\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.patch(\n `/api/content/playlists/${playlist_id}/items/reorder`,\n body,\n );\n}\n\n/**\n * Remove an item from a playlist\n * Removes a single item from a playlist.\n *\n * @param client - Fetch client instance\n * @param playlist_id - playlist_id\n * @param id - id\n */\nexport async function playlists_items_remove(\n client: FetchClient,\n playlist_id: string | number,\n id: string | number,\n): Promise<\n operations[\"playlists_items_remove\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.delete(`/api/content/playlists/${playlist_id}/items/${id}`);\n}\n\n/**\n * List pages for the company\n * Returns a paginated list of published pages for the authenticated rep's company. Members have read-only access — there is no create, update, or destroy action for pages in the portal BFF. Response shape matches pages_show (PortalTenant::Api::PageBlueprinter).\n *\n * @param client - Fetch client instance\n * @param [params] - params\n */\nexport async function pages_list(\n client: FetchClient,\n params?: operations[\"pages_list\"][\"parameters\"][\"query\"],\n): Promise<\n operations[\"pages_list\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/content/pages`, params);\n}\n\n/**\n * Get a specific page\n * Returns a single page by ID, scoped to the authenticated rep's company. Response is a lean portal-BFF shape rendered by PortalTenant::Api::PageBlueprinter — not the legacy admin shape. Admin-only fields (html_code, application_theme_template, search_engine_optimizer, open_graph, prompts, etc.) are intentionally omitted.\n *\n * @param client - Fetch client instance\n * @param id - id\n * @param [params] - params\n */\nexport async function pages_show(\n client: FetchClient,\n id: string | number,\n params?: operations[\"pages_show\"][\"parameters\"][\"query\"],\n): Promise<\n operations[\"pages_show\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/content/pages/${id}`, params);\n}\n\n/**\n * List share links for the current user\n * Returns a paginated list of share links.\n *\n * @param client - Fetch client instance\n * @param [params] - params\n */\nexport async function shares_list(\n client: FetchClient,\n params?: operations[\"shares_list\"][\"parameters\"][\"query\"],\n): Promise<\n operations[\"shares_list\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/shares`, params);\n}\n\n/**\n * Create a share link\n * Creates a new share link for content.\n *\n * @param client - Fetch client instance\n * @param body - body\n */\nexport async function shares_create(\n client: FetchClient,\n body: operations[\"shares_create\"][\"requestBody\"][\"content\"][\"application/json\"],\n): Promise<\n operations[\"shares_create\"][\"responses\"][201][\"content\"][\"application/json\"]\n> {\n return client.post(`/api/shares`, body);\n}\n\n/**\n * List DAM assets\n * Returns a paginated list of DAM assets for the company.\n *\n * @param client - Fetch client instance\n * @param [params] - params\n */\nexport async function dam_assets_list(\n client: FetchClient,\n params?: operations[\"dam_assets_list\"][\"parameters\"][\"query\"],\n): Promise<\n operations[\"dam_assets_list\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/content/dam/assets`, params);\n}\n\n/**\n * Create a DAM asset\n * Creates a new DAM asset. Supports two modes:\n1. **JSON placeholder** — send `application/json` with `asset[name]` to\n create a placeholder record for later file upload.\n\n2. **File upload** — send `multipart/form-data` with `asset[file]`,\n `asset[name]`, and optionally `asset[description]` and `asset[tags]`\n to upload a file and create the full asset with variants.\n *\n * @param client - Fetch client instance\n * @param body - body\n */\nexport async function dam_assets_create(\n client: FetchClient,\n body: operations[\"dam_assets_create\"][\"requestBody\"][\"content\"][\"application/json\"],\n): Promise<\n operations[\"dam_assets_create\"][\"responses\"][201][\"content\"][\"application/json\"]\n> {\n return client.post(`/api/content/dam/assets`, body);\n}\n\n/**\n * List paths for a DAM asset\n * Returns a paginated list of path aliases for a DAM asset.\n *\n * @param client - Fetch client instance\n * @param asset_code - asset_code\n * @param [params] - params\n */\nexport async function dam_asset_paths_list(\n client: FetchClient,\n asset_code: string | number,\n params?: operations[\"dam_asset_paths_list\"][\"parameters\"][\"query\"],\n): Promise<\n operations[\"dam_asset_paths_list\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/content/dam/assets/${asset_code}/paths`, params);\n}\n\n/**\n * Create a path alias for a DAM asset\n * Creates a new path alias for an existing DAM asset.\n *\n * @param client - Fetch client instance\n * @param asset_code - asset_code\n * @param body - body\n */\nexport async function dam_asset_paths_create(\n client: FetchClient,\n asset_code: string | number,\n body: operations[\"dam_asset_paths_create\"][\"requestBody\"][\"content\"][\"application/json\"],\n): Promise<\n operations[\"dam_asset_paths_create\"][\"responses\"][201][\"content\"][\"application/json\"]\n> {\n return client.post(`/api/content/dam/assets/${asset_code}/paths`, body);\n}\n\n/**\n * Query DAM assets using tree paths and tags\n * Searches and retrieves DAM assets using tree path pattern matching, tag-based variant filtering, wildcard name matching, and partial search. Supports cursor pagination for large result sets.\n *\n * @param client - Fetch client instance\n * @param body - body\n */\nexport async function dam_query(\n client: FetchClient,\n body: operations[\"dam_query\"][\"requestBody\"][\"content\"][\"application/json\"],\n): Promise<\n operations[\"dam_query\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.post(`/api/content/dam/query`, body);\n}\n\n/**\n * Delete a DAM asset\n * Permanently destroys a DAM asset, including its ImageKit storage, variants, and database records.\n *\n * @param client - Fetch client instance\n * @param code - code\n */\nexport async function dam_assets_destroy(\n client: FetchClient,\n code: string | number,\n): Promise<\n operations[\"dam_assets_destroy\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.delete(`/api/content/dam/assets/${code}`);\n}\n\n/**\n * Discard (soft-delete) a DAM asset\n * Soft-deletes a DAM asset. Used to discard an in-progress upload without permanently removing the record.\n *\n * @param client - Fetch client instance\n * @param code - code\n */\nexport async function dam_assets_discard(\n client: FetchClient,\n code: string | number,\n): Promise<\n operations[\"dam_assets_discard\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.patch(`/api/content/dam/assets/${code}/discard`);\n}\n\n/**\n * Toggle favorite status on a content item\n * Toggles the favorite status of a content item for the authenticated member. If the item is not currently favorited, it becomes favorited. If it is already favorited, the favorite is removed.\n *\n * @param client - Fetch client instance\n * @param body - body\n */\nexport async function favorites_toggle(\n client: FetchClient,\n body: operations[\"favorites_toggle\"][\"requestBody\"][\"content\"][\"application/json\"],\n): Promise<\n operations[\"favorites_toggle\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.post(`/api/content/favorites/toggle`, body);\n}\n\n// ============================================================================\n// media_metrics\n// ============================================================================\n\n/**\n * Top media by direct visits\n * Ranked list of the company's media by total visits (aggregates metrics_media_visits across all visit sources).\n *\n * @param client - Fetch client instance\n * @param [params] - params\n */\nexport async function content_media_by_visits(\n client: FetchClient,\n params?: operations[\"content_media_by_visits\"][\"parameters\"][\"query\"],\n): Promise<\n operations[\"content_media_by_visits\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/content/media/by-visits`, params);\n}\n\n/**\n * Top media by share-link visits\n * Ranked list of the company's media by click-throughs on rep share links (aggregates metrics_share_shareable_visits where shareable_type='Medium').\n *\n * @param client - Fetch client instance\n * @param [params] - params\n */\nexport async function content_media_by_shares(\n client: FetchClient,\n params?: operations[\"content_media_by_shares\"][\"parameters\"][\"query\"],\n): Promise<\n operations[\"content_media_by_shares\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/content/media/by-shares`, params);\n}\n\n// ============================================================================\n// playlist_metrics\n// ============================================================================\n\n/**\n * Top playlists by direct visits\n * Ranked list of the company's playlists by total visits (aggregates metrics_library_visits since playlists are stored in the libraries table).\n *\n * @param client - Fetch client instance\n * @param [params] - params\n */\nexport async function content_playlists_by_visits(\n client: FetchClient,\n params?: operations[\"content_playlists_by_visits\"][\"parameters\"][\"query\"],\n): Promise<\n operations[\"content_playlists_by_visits\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/content/playlists/by-visits`, params);\n}\n\n/**\n * Top playlists by share-link visits\n * Ranked list of the company's playlists by click-throughs on rep share links (aggregates metrics_share_shareable_visits where shareable_type='Library').\n *\n * @param client - Fetch client instance\n * @param [params] - params\n */\nexport async function content_playlists_by_shares(\n client: FetchClient,\n params?: operations[\"content_playlists_by_shares\"][\"parameters\"][\"query\"],\n): Promise<\n operations[\"content_playlists_by_shares\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/content/playlists/by-shares`, params);\n}\n\n// ============================================================================\n// page_metrics\n// ============================================================================\n\n/**\n * Top pages by direct visits\n * Ranked list of the company's pages by total visits (aggregates metrics_page_visits across all visit sources).\n *\n * @param client - Fetch client instance\n * @param [params] - params\n */\nexport async function content_pages_by_visits(\n client: FetchClient,\n params?: operations[\"content_pages_by_visits\"][\"parameters\"][\"query\"],\n): Promise<\n operations[\"content_pages_by_visits\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/content/pages/by-visits`, params);\n}\n\n/**\n * Top pages by share-link visits\n * Ranked list of the company's pages by click-throughs on rep share links (aggregates metrics_share_shareable_visits where shareable_type='Page').\n *\n * @param client - Fetch client instance\n * @param [params] - params\n */\nexport async function content_pages_by_shares(\n client: FetchClient,\n params?: operations[\"content_pages_by_shares\"][\"parameters\"][\"query\"],\n): Promise<\n operations[\"content_pages_by_shares\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/content/pages/by-shares`, params);\n}\n","import { createContext, use } from \"react\";\nimport type { FetchClient } from \"@fluid-app/api-client-core\";\n\ninterface ShareablesCoreConfig {\n /**\n * Legacy FetchClient for direct API calls (e.g. products-api-client).\n * Optional — portal-tenant contexts use BFF adapters instead.\n */\n client?: FetchClient;\n user: { id: number } | null;\n /** When true, use rep-scoped API endpoints (e.g. /users/v2025-06/media) */\n repContext?: boolean;\n}\n\nconst ShareablesCoreContext = createContext<ShareablesCoreConfig | null>(null);\n\nexport function ShareablesCoreProvider({\n config,\n children,\n}: {\n config: ShareablesCoreConfig;\n children: React.ReactNode;\n}): React.JSX.Element {\n return (\n <ShareablesCoreContext.Provider value={config}>\n {children}\n </ShareablesCoreContext.Provider>\n );\n}\n\nexport function useShareablesClient(): FetchClient | null {\n const ctx = use(ShareablesCoreContext);\n if (!ctx) {\n throw new Error(\n \"useShareablesClient must be used within a ShareablesCoreProvider\",\n );\n }\n return ctx.client ?? null;\n}\n\nexport function useShareablesUser(): { id: number } | null {\n const ctx = use(ShareablesCoreContext);\n if (!ctx) {\n throw new Error(\n \"useShareablesUser must be used within a ShareablesCoreProvider\",\n );\n }\n return ctx.user;\n}\n\nexport function useRepContext(): boolean {\n const ctx = use(ShareablesCoreContext);\n return ctx?.repContext ?? false;\n}\n","import { useQuery } from \"@tanstack/react-query\";\nimport { useShareablesApi } from \"../shareables-api-context\";\nimport { shareablesKeys } from \"../query-keys\";\nimport type { ContentDomainApi } from \"../content-domain-api\";\nimport type { shareables } from \"../types\";\n\ninterface ProductMediaCountsResult {\n [productId: number]: number;\n}\n\nexport type ProductMediaByProductId = Record<number, shareables.ProductMedia[]>;\n\nfunction getUniqueSortedProductIds(productIds: number[]) {\n return [...new Set(productIds)].toSorted((a, b) => a - b);\n}\n\nasync function fetchProductMediaByProductIds(\n api: ContentDomainApi,\n productIds: number[],\n): Promise<ProductMediaByProductId> {\n const productMediaByProductId: ProductMediaByProductId = {};\n\n const promises = productIds.map(async (productId) => {\n try {\n const response = await api.productMedia.getProductMedia(productId);\n productMediaByProductId[productId] = response.media || [];\n } catch (error) {\n console.warn(`Failed to fetch media for product ${productId}:`, error);\n productMediaByProductId[productId] = [];\n }\n });\n\n await Promise.allSettled(promises);\n return productMediaByProductId;\n}\n\nexport function useProductMediaByProductIds(productIds: number[]) {\n const api = useShareablesApi();\n const normalizedProductIds = getUniqueSortedProductIds(productIds);\n\n return useQuery({\n queryKey: shareablesKeys.productMedia.byProductIds(normalizedProductIds),\n queryFn: () => fetchProductMediaByProductIds(api, normalizedProductIds),\n enabled: normalizedProductIds.length > 0,\n staleTime: 5 * 60 * 1000,\n gcTime: 10 * 60 * 1000,\n });\n}\n\nexport function useProductMediaCounts(productIds: number[]) {\n const api = useShareablesApi();\n const normalizedProductIds = getUniqueSortedProductIds(productIds);\n\n return useQuery({\n queryKey: shareablesKeys.productMedia.byProductIds(normalizedProductIds),\n queryFn: () => fetchProductMediaByProductIds(api, normalizedProductIds),\n select: selectProductMediaCounts,\n enabled: normalizedProductIds.length > 0,\n staleTime: 5 * 60 * 1000,\n gcTime: 10 * 60 * 1000,\n });\n}\n\nfunction selectProductMediaCounts(\n productMediaByProductId: ProductMediaByProductId,\n): ProductMediaCountsResult {\n return Object.fromEntries(\n Object.entries(productMediaByProductId).map(([productId, media]) => [\n Number(productId),\n media.length,\n ]),\n );\n}\n\nexport function useProductMediaCount(productId: number) {\n const api = useShareablesApi();\n\n return useQuery({\n queryKey: shareablesKeys.productMedia.count(productId),\n queryFn: async (): Promise<number> => {\n try {\n const response = await api.productMedia.getProductMedia(productId);\n const mediaArray = response.media || [];\n return mediaArray.length;\n } catch (error) {\n console.warn(\n `Failed to fetch media count for product ${productId}:`,\n error,\n );\n return 0;\n }\n },\n enabled: !!productId,\n staleTime: 5 * 60 * 1000,\n gcTime: 10 * 60 * 1000,\n });\n}\n","import { useMutation, useQueryClient } from \"@tanstack/react-query\";\nimport type { shareables } from \"../types\";\nimport { useShareablesApi } from \"../shareables-api-context\";\nimport { useRepContext } from \"../context\";\nimport { shareablesKeys } from \"../query-keys\";\n\nexport interface UseMediaMutationsOptions {\n onDeleteSuccess?: (id: number) => void;\n onDeleteError?: (error: Error, id: number) => void;\n onDuplicateSuccess?: (newMedia: shareables.MediumResponse) => void;\n onDuplicateError?: (error: Error) => void;\n}\n\nexport const useMediaMutations = (options?: UseMediaMutationsOptions) => {\n const api = useShareablesApi();\n const queryClient = useQueryClient();\n const repContext = useRepContext();\n\n // Delete media mutation with optimistic updates\n const deleteMutation = useMutation({\n mutationFn: (id: number) => {\n return api.media.deleteMedia(id);\n },\n onMutate: async (id: number) => {\n await queryClient.cancelQueries({\n queryKey: shareablesKeys.media.all,\n });\n\n // Optimistically remove from media lists\n const previousData = queryClient.getQueriesData({\n queryKey: shareablesKeys.media.all,\n });\n\n queryClient.setQueriesData<unknown>(\n { queryKey: shareablesKeys.media.all },\n (oldData: unknown) => {\n if (!oldData) return oldData;\n\n // Handle different response formats\n if (Array.isArray(oldData)) {\n return oldData.filter((item: { id: number }) => item.id !== id);\n }\n\n const dataObj = oldData as Record<string, unknown>;\n if (dataObj.data && Array.isArray(dataObj.data)) {\n return {\n ...dataObj,\n data: dataObj.data.filter(\n (item: { id: number }) => item.id !== id,\n ),\n };\n }\n\n if (dataObj.media && Array.isArray(dataObj.media)) {\n return {\n ...dataObj,\n media: dataObj.media.filter(\n (item: { id: number }) => item.id !== id,\n ),\n };\n }\n\n return oldData;\n },\n );\n\n // Remove individual media query — use the id-only prefix so every\n // (repContext, locale) variant of this media's detail cache is\n // cleared, not just the default-locale slot.\n queryClient.removeQueries({\n queryKey: shareablesKeys.media.detailById(id),\n });\n\n return { previousData, id };\n },\n onSuccess: async (_, id) => {\n // Invalidate all media queries to refetch fresh data\n queryClient.invalidateQueries({\n queryKey: shareablesKeys.media.all,\n });\n options?.onDeleteSuccess?.(id);\n },\n onError: (error: Error, _id: number, context) => {\n // Rollback optimistic updates\n if (context?.previousData) {\n context.previousData.forEach(([queryKey, data]) => {\n queryClient.setQueryData(queryKey, data);\n });\n }\n\n console.error(\"Error deleting media:\", error);\n options?.onDeleteError?.(error, _id);\n },\n });\n\n // Duplicate media mutation with optimistic update\n const duplicateMutation = useMutation({\n mutationFn: (mediaData: shareables.MediumUpdate) => {\n return api.media.createMedia(mediaData);\n },\n onMutate: async (mediaData) => {\n await queryClient.cancelQueries({\n queryKey: shareablesKeys.media.all,\n });\n\n // Generate temporary ID for optimistic update\n const tempId = Date.now();\n\n // Create optimistic media object\n const optimisticMedia = {\n id: tempId,\n title: mediaData.title || \"Untitled Media\",\n description: mediaData.description || null,\n media_type: \"share\",\n media_format: null,\n image_url: mediaData.image_url || null,\n video_url: mediaData.video_url || null,\n pdf_url: mediaData.pdf_url || null,\n stripped: mediaData.description || null,\n active: mediaData.active ?? true,\n visibility: mediaData.visibility || null,\n share_link: null,\n views: 0,\n leads: 0,\n watch: null,\n video_status: null,\n duration: null,\n cta_url: mediaData.cta_url || null,\n cta_button_text: mediaData.cta_button_text || null,\n cta_enabled: mediaData.cta_enabled ?? false,\n cta_action_type: mediaData.cta_action_type || null,\n video_shopping_enabled: mediaData.video_shopping_enabled ?? false,\n prompts_enabled: mediaData.prompts_enabled ?? false,\n ranks: [],\n preview_link: null,\n attached_shareables: [],\n subtitles: {},\n user_id: null,\n created_at: new Date().toISOString(),\n };\n\n // Snapshot previous data for rollback\n const previousMediaLists = queryClient.getQueriesData({\n queryKey: shareablesKeys.media.all,\n });\n\n // Optimistically add media to list queries\n queryClient.setQueriesData<unknown>(\n { queryKey: shareablesKeys.media.all },\n (oldData: unknown) => {\n if (!oldData) return [optimisticMedia];\n\n // Handle different response formats\n if (Array.isArray(oldData)) {\n return [optimisticMedia, ...oldData];\n }\n\n const dataObj = oldData as Record<string, unknown>;\n if (dataObj.data && Array.isArray(dataObj.data)) {\n return { ...dataObj, data: [optimisticMedia, ...dataObj.data] };\n }\n\n if (dataObj.media && Array.isArray(dataObj.media)) {\n return { ...dataObj, media: [optimisticMedia, ...dataObj.media] };\n }\n\n return oldData;\n },\n );\n\n // Set optimistic individual media query\n queryClient.setQueryData(\n shareablesKeys.media.detail(tempId, repContext),\n {\n media: optimisticMedia,\n },\n );\n\n return { previousMediaLists, tempId };\n },\n onError: (_error, _mediaData, context) => {\n // Rollback optimistic updates\n if (context) {\n context.previousMediaLists.forEach(([queryKey, data]) => {\n queryClient.setQueryData(queryKey, data);\n });\n\n queryClient.removeQueries({\n queryKey: shareablesKeys.media.detailById(context.tempId),\n });\n }\n\n console.error(\"Error duplicating media:\", _error);\n options?.onDuplicateError?.(_error);\n },\n onSuccess: async (data, _mediaData, context) => {\n const realMediaId = data.id;\n\n if (context) {\n // Remove optimistic data\n queryClient.removeQueries({\n queryKey: shareablesKeys.media.detailById(context.tempId),\n });\n }\n\n // Set real media data\n queryClient.setQueryData(\n shareablesKeys.media.detail(realMediaId, repContext),\n {\n media: data,\n },\n );\n\n options?.onDuplicateSuccess?.(data);\n\n // Invalidate lists to get fresh data\n queryClient.invalidateQueries({\n queryKey: shareablesKeys.media.all,\n predicate: (query) => {\n return query.queryKey.length === 1 && query.queryKey[0] === \"media\";\n },\n });\n },\n });\n\n // Handler functions\n const handleDelete = async (id: number) => {\n try {\n await deleteMutation.mutateAsync(id);\n } catch (error) {\n console.error(\"Delete failed:\", error);\n }\n };\n\n const handleDuplicate = async (mediaData: shareables.MediumUpdate) => {\n try {\n await duplicateMutation.mutateAsync(mediaData);\n } catch (error) {\n console.error(\"Duplicate failed:\", error);\n }\n };\n\n return {\n deleteMutation,\n duplicateMutation,\n handleDelete,\n handleDuplicate,\n };\n};\n\n// ---------------------------------------------------------------------------\n// useCreateMediaMutation — dedicated create (no optimistic duplication logic)\n// ---------------------------------------------------------------------------\n\nexport interface UseCreateMediaOptions {\n onSuccess?: (newMedia: shareables.MediumResponse) => void;\n onError?: (error: Error) => void;\n}\n\nexport const useCreateMediaMutation = (options?: UseCreateMediaOptions) => {\n const api = useShareablesApi();\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: (payload: shareables.MediumUpdate) => {\n return api.media.createMedia(payload);\n },\n onSuccess: (data) => {\n queryClient.invalidateQueries({\n queryKey: shareablesKeys.media.all,\n });\n options?.onSuccess?.(data);\n },\n onError: (error) => {\n console.error(\"Error creating media:\", error);\n options?.onError?.(error as Error);\n },\n });\n};\n","/**\n * Check if an error is a cancellation/abort error from TanStack Query or AbortController.\n */\nexport function isCancellationError(error: unknown): boolean {\n return (\n !!error &&\n typeof error === \"object\" &&\n \"name\" in error &&\n (error.name === \"CancelledError\" || error.name === \"AbortError\")\n );\n}\n","import { useMutation, useQueryClient } from \"@tanstack/react-query\";\nimport type { shareables } from \"../types\";\nimport { useShareablesApi } from \"../shareables-api-context\";\nimport { shareablesKeys } from \"../query-keys\";\nimport { isCancellationError } from \"../utils\";\n\n// ---------------------------------------------------------------------------\n// Types for optimistic updates (internal)\n// ---------------------------------------------------------------------------\n\ninterface PlaylistItemLike {\n id?: number | null;\n order?: number;\n relateable_type?: string | null;\n relateable?: unknown;\n}\n\ntype PlaylistDetailCacheEntry = readonly [readonly unknown[], unknown];\n\nfunction updatePlaylistDetailItems(\n old: unknown,\n updateItems: (items: PlaylistItemLike[]) => PlaylistItemLike[],\n): unknown {\n if (!old || typeof old !== \"object\" || !(\"playlist\" in old)) return old;\n\n const playlistData = old as {\n playlist: { items?: PlaylistItemLike[] };\n };\n return {\n ...playlistData,\n playlist: {\n ...playlistData.playlist,\n items: updateItems(playlistData.playlist.items ?? []),\n },\n };\n}\n\nfunction rollbackPlaylistDetailEntries(\n queryClient: ReturnType<typeof useQueryClient>,\n previousData: PlaylistDetailCacheEntry[] | undefined,\n): void {\n for (const [queryKey, data] of previousData ?? []) {\n queryClient.setQueryData(queryKey, data);\n }\n}\n\n// ---------------------------------------------------------------------------\n// useAddItemToPlaylistMutation\n// ---------------------------------------------------------------------------\n\nexport interface UseAddItemOptions {\n onSuccess?: (playlistId: number) => void;\n onError?: (error: Error, playlistId: number) => void;\n}\n\ninterface AddItemToPlaylistParams {\n playlistId: number;\n newItem: PlaylistItemLike;\n data: { relateable_type: string; relateable_id: number; order: number };\n}\n\nexport const useAddItemToPlaylistMutation = (options?: UseAddItemOptions) => {\n const api = useShareablesApi();\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: ({ playlistId, data }: AddItemToPlaylistParams) => {\n return api.playlists.addItemToPlaylist(playlistId, {\n items: [data],\n });\n },\n onMutate: async ({ playlistId, newItem }: AddItemToPlaylistParams) => {\n const detailPrefix = shareablesKeys.playlists.detailById(playlistId);\n await queryClient.cancelQueries({ queryKey: detailPrefix });\n\n const previousData = queryClient.getQueriesData({\n queryKey: detailPrefix,\n });\n\n queryClient.setQueriesData({ queryKey: detailPrefix }, (old: unknown) =>\n updatePlaylistDetailItems(old, (items) => [...items, newItem]),\n );\n\n return { previousData };\n },\n onSuccess: (_, { playlistId }) => {\n queryClient.invalidateQueries({\n queryKey: shareablesKeys.playlists.detailById(playlistId),\n });\n queryClient.invalidateQueries({\n queryKey: shareablesKeys.playlists.all,\n });\n options?.onSuccess?.(playlistId);\n },\n onError: (error, { playlistId }, context) => {\n // Always rollback optimistic updates first\n rollbackPlaylistDetailEntries(queryClient, context?.previousData);\n\n if (isCancellationError(error)) return;\n\n console.error(\"Error adding item to playlist:\", error);\n options?.onError?.(error as Error, playlistId);\n },\n });\n};\n\n// ---------------------------------------------------------------------------\n// useRemoveItemsFromPlaylistMutation\n// ---------------------------------------------------------------------------\n\nexport interface UseRemoveItemsOptions {\n onSuccess?: (playlistId: number) => void;\n onError?: (error: Error, playlistId: number) => void;\n}\n\ninterface RemoveItemsFromPlaylistParams {\n playlistId: number;\n itemIds: number[];\n}\n\nexport const useRemoveItemsFromPlaylistMutation = (\n options?: UseRemoveItemsOptions,\n) => {\n const api = useShareablesApi();\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: ({ playlistId, itemIds }: RemoveItemsFromPlaylistParams) => {\n return api.playlists.removeItemsFromPlaylist(playlistId, {\n item_ids: itemIds,\n });\n },\n onMutate: async ({\n playlistId,\n itemIds,\n }: RemoveItemsFromPlaylistParams) => {\n const detailPrefix = shareablesKeys.playlists.detailById(playlistId);\n await queryClient.cancelQueries({ queryKey: detailPrefix });\n\n const previousData = queryClient.getQueriesData({\n queryKey: detailPrefix,\n });\n\n queryClient.setQueriesData({ queryKey: detailPrefix }, (old: unknown) =>\n updatePlaylistDetailItems(old, (items) =>\n items.filter((item) => item.id != null && !itemIds.includes(item.id)),\n ),\n );\n\n return { previousData };\n },\n onSuccess: (_, { playlistId }) => {\n queryClient.invalidateQueries({\n queryKey: shareablesKeys.playlists.detailById(playlistId),\n });\n queryClient.invalidateQueries({\n queryKey: shareablesKeys.playlists.all,\n });\n options?.onSuccess?.(playlistId);\n },\n onError: (error, { playlistId }, context) => {\n // Always rollback optimistic updates first\n rollbackPlaylistDetailEntries(queryClient, context?.previousData);\n\n if (isCancellationError(error)) return;\n\n // \"No valid playlist items found\" means the last item was removed — treat as success\n const errorMessage =\n error && typeof error === \"object\" && \"message\" in error\n ? String(error.message)\n : \"\";\n\n if (errorMessage.includes(\"No valid playlist items found\")) {\n queryClient.invalidateQueries({\n queryKey: shareablesKeys.playlists.detailById(playlistId),\n });\n options?.onSuccess?.(playlistId);\n return;\n }\n\n console.error(\"Error removing item from playlist:\", error);\n options?.onError?.(error as Error, playlistId);\n },\n });\n};\n\n// ---------------------------------------------------------------------------\n// useCreatePlaylistMutation\n// ---------------------------------------------------------------------------\n\nexport interface UseCreatePlaylistOptions {\n onSuccess?: (response: shareables.GetPlaylistResponse) => void;\n onError?: (error: Error) => void;\n}\n\nexport const useCreatePlaylistMutation = (\n options?: UseCreatePlaylistOptions,\n) => {\n const api = useShareablesApi();\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: (input: shareables.CreatePlaylistInput) => {\n return api.playlists.createPlaylist(input);\n },\n onSuccess: (createdPlaylist) => {\n queryClient.invalidateQueries({\n queryKey: shareablesKeys.playlists.all,\n });\n options?.onSuccess?.(createdPlaylist);\n },\n onError: (error) => {\n if (isCancellationError(error)) return;\n\n console.error(\"Error creating playlist:\", error);\n options?.onError?.(error as Error);\n },\n });\n};\n\n// ---------------------------------------------------------------------------\n// useUpdatePlaylistMutation\n// ---------------------------------------------------------------------------\n\nexport interface UseUpdatePlaylistOptions {\n onSuccess?: (playlistId: number) => void;\n onError?: (error: Error) => void;\n}\n\ninterface UpdatePlaylistParams {\n playlistId: number;\n data: shareables.UpdatePlaylistInput;\n}\n\nexport const useUpdatePlaylistMutation = (\n options?: UseUpdatePlaylistOptions,\n) => {\n const api = useShareablesApi();\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: ({ playlistId, data }: UpdatePlaylistParams) => {\n return api.playlists.updatePlaylist(playlistId, data);\n },\n onSuccess: (_, { playlistId }) => {\n queryClient.invalidateQueries({\n queryKey: shareablesKeys.playlists.all,\n });\n queryClient.invalidateQueries({\n queryKey: shareablesKeys.playlists.detail(playlistId),\n });\n options?.onSuccess?.(playlistId);\n },\n onError: (error) => {\n if (isCancellationError(error)) return;\n\n console.error(\"Error updating playlist:\", error);\n options?.onError?.(error as Error);\n },\n });\n};\n\n// ---------------------------------------------------------------------------\n// useReorderPlaylistItemsMutation\n// ---------------------------------------------------------------------------\n\nexport interface UseReorderPlaylistItemsOptions {\n onSuccess?: (playlistId: number) => void;\n onError?: (error: Error, playlistId: number) => void;\n}\n\ninterface ReorderPlaylistItemsParams {\n playlistId: number;\n data: shareables.ReorderPlaylistItemsInput;\n}\n\nexport const useReorderPlaylistItemsMutation = (\n options?: UseReorderPlaylistItemsOptions,\n) => {\n const api = useShareablesApi();\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: ({ playlistId, data }: ReorderPlaylistItemsParams) => {\n if (!api.playlists.reorderPlaylistItems) {\n return Promise.resolve();\n }\n return api.playlists.reorderPlaylistItems(playlistId, data);\n },\n onSuccess: (_, { playlistId }) => {\n if (api.playlists.reorderPlaylistItems) {\n queryClient.invalidateQueries({\n queryKey: shareablesKeys.playlists.detail(playlistId),\n });\n }\n options?.onSuccess?.(playlistId);\n },\n onError: (error, { playlistId }) => {\n if (isCancellationError(error)) return;\n\n console.error(\"Error reordering playlist items:\", error);\n options?.onError?.(error as Error, playlistId);\n },\n });\n};\n","import { createContext, useContext, type Provider } from \"react\";\nimport type { FilePickerApi } from \"./schemas/file-picker-api\";\n\nconst FilePickerApiContext = createContext<FilePickerApi | null>(null);\n\nexport const FilePickerApiProvider: Provider<FilePickerApi | null> =\n FilePickerApiContext.Provider;\n\nexport function useFilePickerApi(): FilePickerApi {\n const api = useContext(FilePickerApiContext);\n if (!api) {\n throw new Error(\n \"useFilePickerApi must be used within a FilePickerApiProvider\",\n );\n }\n return api;\n}\n","import { z } from \"zod\";\n\ntype DamVariantApi = {\n id: string;\n url: string | null;\n file_name: string;\n mime_type: string;\n content: any;\n created_at: string;\n updated_at: string;\n default: boolean;\n is_original: boolean;\n is_text: boolean;\n media_type: string;\n processing_status: string;\n tags: string[];\n};\n\nexport const damVariantSchema: z.ZodType<DamVariantApi> = z.object({\n id: z.string(),\n url: z.string().nullable(),\n file_name: z.string(),\n mime_type: z.string(),\n content: z.any().nullable(),\n created_at: z.string(),\n updated_at: z.string(),\n default: z.boolean(),\n is_original: z.boolean(),\n is_text: z.boolean(),\n media_type: z.string(),\n processing_status: z.string(),\n tags: z.array(z.string()),\n});\n\ntype DamAssetApi = {\n id: number;\n canonical_path: string;\n category: string;\n code: string;\n company: string;\n created_at: string;\n default_variant_id: string;\n default_variant_url?: string;\n description: string;\n name: string;\n updated_at: string;\n variants?: DamVariantApi[];\n};\n\nexport const damAssetSchema: z.ZodType<DamAssetApi> = z.object({\n id: z.number(),\n canonical_path: z.string(),\n category: z.string(),\n code: z.string(),\n company: z.string(),\n created_at: z.string(),\n default_variant_id: z.string(),\n default_variant_url: z.string().optional(),\n description: z.string(),\n name: z.string(),\n updated_at: z.string(),\n variants: z.array(damVariantSchema).optional(),\n});\n\ntype DamTreeFolderNode = {\n asset_code?: string | Record<string, unknown>;\n name?: string | Record<string, unknown>;\n category?: string | Record<string, unknown>;\n variants?: unknown[] | Record<string, unknown>;\n [key: string]: unknown;\n};\n\nexport const damTreeFolderNodeSchema: z.ZodType<DamTreeFolderNode> = z\n .object({\n asset_code: z\n .union([z.string(), z.record(z.string(), z.unknown())])\n .optional(),\n name: z.union([z.string(), z.record(z.string(), z.unknown())]).optional(),\n category: z\n .union([z.string(), z.record(z.string(), z.unknown())])\n .optional(),\n variants: z\n .union([z.array(z.unknown()), z.record(z.string(), z.unknown())])\n .optional(),\n })\n .passthrough();\n\nexport const damTreeSchema: z.ZodType<Record<string, any>> = z.record(\n z.string(),\n z.union([\n z.lazy(() => damTreeSchema),\n damAssetSchema,\n damTreeFolderNodeSchema,\n ]),\n);\n\ntype DamQueryResponse = {\n path: string;\n tree: Record<string, any>;\n meta?: { next_cursor?: string; total_count?: number };\n};\n\nexport const damQueryResponseSchema: z.ZodType<DamQueryResponse> = z.object({\n path: z.string(),\n tree: damTreeSchema,\n meta: z\n .object({\n next_cursor: z.string().optional(),\n total_count: z.number().optional(),\n })\n .optional(),\n});\n\ntype DamAssetCreateRequest = {\n asset: {\n file: any;\n name: string;\n description?: string;\n tags?: string;\n };\n};\n\nexport const damAssetCreateRequestSchema: z.ZodType<DamAssetCreateRequest> =\n z.object({\n asset: z.object({\n file: z.any(),\n name: z.string(),\n description: z.string().optional(),\n tags: z.string().optional(),\n }),\n });\n\ntype DamAssetCreateResponse = {\n asset: DamAssetApi;\n meta: { request_id: string; timestamp: string };\n};\n\nexport const damAssetCreateResponseSchema: z.ZodType<DamAssetCreateResponse> =\n z.object({\n asset: damAssetSchema,\n meta: z.object({\n request_id: z.string(),\n timestamp: z.string(),\n }),\n });\n\n// Schema for creating asset with placeholder (for ImageKit direct upload)\ntype DamAssetCreateWithPlaceholderRequest = {\n placeholder_asset: {\n mime_type: string;\n name?: string;\n description?: string;\n };\n skip_autotagging?: boolean;\n};\n\nexport const damAssetCreateWithPlaceholderRequestSchema: z.ZodType<DamAssetCreateWithPlaceholderRequest> =\n z.object({\n placeholder_asset: z.object({\n mime_type: z.string(),\n name: z.string().optional(),\n description: z.string().optional(),\n }),\n skip_autotagging: z.boolean().optional(),\n });\n\n// Schema for creating asset path without file upload (legacy)\ntype DamAssetPathCreateRequest = {\n asset?: {\n file: any;\n name: string;\n description?: string;\n tags?: string;\n };\n text_asset?: {\n file_name: string;\n mime_type: string;\n text: string;\n name?: string;\n description?: string;\n tags?: string;\n };\n placeholder_asset?: {\n mime_type: string;\n name?: string;\n description?: string;\n };\n skip_autotagging?: boolean;\n};\n\nexport const damAssetPathCreateRequestSchema: z.ZodType<DamAssetPathCreateRequest> =\n z.object({\n asset: z\n .object({\n file: z.any(),\n name: z.string(),\n description: z.string().optional(),\n tags: z.string().optional(),\n })\n .optional(),\n text_asset: z\n .object({\n file_name: z.string(),\n mime_type: z.string(),\n text: z.string(),\n name: z.string().optional(),\n description: z.string().optional(),\n tags: z.string().optional(),\n })\n .optional(),\n placeholder_asset: z\n .object({\n mime_type: z.string(),\n name: z.string().optional(),\n description: z.string().optional(),\n })\n .optional(),\n skip_autotagging: z.boolean().optional(),\n });\n\ntype DamAssetPathCreateResponse = {\n asset: { id: number; canonical_path: string; name: string };\n meta: { request_id: string; timestamp: string };\n};\n\nexport const damAssetPathCreateResponseSchema: z.ZodType<DamAssetPathCreateResponse> =\n z.object({\n asset: z.object({\n id: z.number(),\n canonical_path: z.string(),\n name: z.string(),\n }),\n meta: z.object({\n request_id: z.string(),\n timestamp: z.string(),\n }),\n });\n\nexport type { DamVariantApi, DamAssetApi };\nexport type DamTreeApi = z.infer<typeof damTreeSchema>;\nexport type { DamQueryResponse };\nexport type { DamAssetCreateRequest };\nexport type { DamAssetCreateResponse };\nexport type { DamAssetCreateWithPlaceholderRequest };\nexport type { DamAssetPathCreateRequest };\nexport type { DamAssetPathCreateResponse };\n","import { z } from \"zod\";\nimport type { UrlProxyResponse } from \"@fluid-app/file-picker-core\";\n\nexport type { UrlProxyResponse };\n\nconst urlProxyResponseSchema: z.ZodType<UrlProxyResponse> = z.object({\n data: z.string(),\n contentType: z.string(),\n size: z.number(),\n});\n\n/**\n * Proxy a URL fetch through the backend to bypass CORS restrictions.\n * The backend fetches the file and returns it as base64-encoded data.\n *\n * @param url - The URL to fetch\n * @param proxyEndpoint - The proxy endpoint (defaults to \"/api/proxy-url\")\n */\nexport async function proxyUrlFetch(\n url: string,\n proxyEndpoint: string = \"/api/proxy-url\",\n): Promise<UrlProxyResponse> {\n const response = await fetch(proxyEndpoint, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({ url }),\n });\n\n if (!response.ok) {\n const errorData = await response.json().catch(() => ({\n error: \"Failed to proxy URL fetch\",\n }));\n throw new Error(\n (errorData as { error?: string }).error || `HTTP ${response.status}`,\n );\n }\n\n const data: unknown = await response.json();\n return urlProxyResponseSchema.parse(data);\n}\n","import {\n damAssetSchema,\n damQueryResponseSchema,\n type CreateDamAssetParams,\n type CreateDamAssetPathForAssetsParams,\n type DamAssetCreateResponse,\n type DamAssetPathCreateResponse,\n type DamQueryParams,\n type DamQueryResponse,\n type FilePickerApi,\n type UnsplashSearchResponse,\n} from \"@fluid-app/file-picker-core\";\nimport { proxyUrlFetch } from \"@fluid-app/file-picker-api-client\";\nimport type { FetchClient } from \"@fluid-app/portal-tenant-api-client\";\nimport {\n portalTenantContent,\n type operations,\n} from \"@fluid-app/portal-tenant-content-api-client\";\n\n/** BFF create response — derived from the generated OpenAPI types. */\ntype DamAssetCreateBffResponse = Awaited<\n ReturnType<typeof portalTenantContent.dam_assets_create>\n>;\n\n/** BFF asset path create response — derived from the generated OpenAPI types. */\ntype DamAssetPathCreateBffResponse = Awaited<\n ReturnType<typeof portalTenantContent.dam_asset_paths_create>\n>;\n\n/**\n * Maps a BFF DAM asset to the file-picker port's DamAssetCreateResponse shape.\n *\n * The BFF response includes nullable meta.request_id (from Api::Response),\n * while the port schema requires a string. We coalesce to empty string.\n */\nfunction mapCreateResponse(\n response: DamAssetCreateBffResponse,\n): DamAssetCreateResponse {\n const raw = response.asset ?? {};\n return {\n asset: damAssetSchema.parse({\n ...raw,\n canonical_path: raw.canonical_path ?? \"\",\n category: raw.category ?? \"\",\n company: raw.company ?? \"\",\n description: raw.description ?? \"\",\n default_variant_id: raw.default_variant_id ?? \"\",\n }),\n meta: {\n request_id: response.meta?.request_id ?? \"\",\n timestamp: response.meta?.timestamp ?? new Date().toISOString(),\n },\n };\n}\n\n/**\n * Maps a BFF asset path response to the file-picker port's shape.\n */\nfunction mapAssetPathCreateResponse(\n response: DamAssetPathCreateBffResponse,\n): DamAssetPathCreateResponse {\n const assetPath = response.asset_path ?? {};\n return {\n asset: {\n id: assetPath.id ?? 0,\n canonical_path: assetPath.path ?? \"\",\n name: assetPath.asset_code ?? \"\",\n },\n meta: {\n request_id: response.meta?.request_id ?? \"\",\n timestamp: response.meta?.timestamp ?? new Date().toISOString(),\n },\n };\n}\n\n/**\n * Creates a FilePickerApi adapter backed by the portal-tenant BFF's\n * `/api/content/dam/*` endpoints, using cookie-based auth via the\n * provided FetchClient.\n *\n * Unsplash search is not available through the BFF — callers that need\n * Unsplash should use the legacy adapter or provide their own\n * implementation.\n *\n * The `onProgress` callback in `createDamAsset` is not supported — the\n * underlying `fetch` API does not expose upload progress events.\n *\n * URL proxy delegates to the same-origin `/api/proxy-url` endpoint\n * (served by the hosting app, not the BFF) for CORS bypass, identical\n * to the legacy adapter behaviour.\n */\nexport function createFilePickerApiAdapter(client: FetchClient): FilePickerApi {\n return {\n createDamAsset: async (\n params: CreateDamAssetParams,\n ): Promise<DamAssetCreateResponse> => {\n // The generated dam_assets_create uses client.post (JSON body), but\n // file uploads require multipart/form-data. Use requestWithFormData\n // directly, typing the response from the generated operation type.\n const formData = new FormData();\n formData.append(\"asset[file]\", params.file);\n formData.append(\"asset[name]\", params.name);\n\n if (params.description) {\n formData.append(\"asset[description]\", params.description);\n }\n\n if (params.tags && params.tags.length > 0) {\n formData.append(\"asset[tags]\", params.tags.join(\",\"));\n }\n\n const response =\n await client.requestWithFormData<DamAssetCreateBffResponse>(\n \"/api/content/dam/assets\",\n formData,\n { method: \"POST\" },\n );\n\n return mapCreateResponse(response);\n },\n\n queryDamAssets: async (\n params: DamQueryParams,\n ): Promise<DamQueryResponse> => {\n const response = await portalTenantContent.dam_query(\n client,\n params satisfies operations[\"dam_query\"][\"requestBody\"][\"content\"][\"application/json\"],\n );\n return damQueryResponseSchema.parse({\n ...response,\n meta: response.meta\n ? { next_cursor: response.meta.pagination?.next_cursor ?? undefined }\n : undefined,\n });\n },\n\n deleteDamAsset: async (code: string): Promise<unknown> => {\n return portalTenantContent.dam_assets_destroy(client, code);\n },\n\n discardDamAsset: async (code: string): Promise<unknown> => {\n return portalTenantContent.dam_assets_discard(client, code);\n },\n\n createDamAssetPathForAssets: async (\n params: CreateDamAssetPathForAssetsParams,\n ): Promise<DamAssetPathCreateResponse> => {\n const response = await portalTenantContent.dam_asset_paths_create(\n client,\n params.code,\n { asset_path: { path: params.asset_paths.join(\",\") } },\n );\n return mapAssetPathCreateResponse(response);\n },\n\n searchUnsplash: async (\n _query: string,\n _page?: number,\n _perPage?: number,\n ): Promise<UnsplashSearchResponse> => {\n throw new Error(\n \"Unsplash search is not available through the portal-tenant BFF. \" +\n \"Configure an Unsplash access key and use the standard FilePickerApi adapter instead.\",\n );\n },\n\n proxyUrlFetch: (url: string) => proxyUrlFetch(url),\n };\n}\n","/**\n * Portal Content Domain Adapter — Implements ContentDomainApi using the\n * portal-tenant Content BFF endpoints.\n *\n * Follows the composite adapter pattern (see contacts-api-adapter.ts):\n * all sub-factory functions are private; the only public export is the\n * composite `createPortalContentDomainApiAdapter`.\n */\n\nimport type { FetchClient } from \"@fluid-app/api-client-core\";\nimport type {\n ContentMediaApi,\n ContentMediaProductsApi,\n media,\n} from \"@fluid-app/shareables-core/media-api\";\nimport type {\n ContentPlaylistsApi,\n playlists,\n} from \"@fluid-app/shareables-core/playlists-api\";\nimport type {\n ContentSharesApi,\n shares,\n} from \"@fluid-app/shareables-core/shares-api\";\nimport type {\n ContentDamAssetsApi,\n damAssets,\n} from \"@fluid-app/shareables-core/dam-assets-api\";\nimport type {\n ContentMetricsApi,\n metrics,\n} from \"@fluid-app/shareables-core/metrics-api\";\nimport type {\n ContentPagesApi,\n pages,\n} from \"@fluid-app/shareables-core/pages-api\";\nimport type {\n ContentEnrollmentPacksApi,\n enrollmentPacks,\n} from \"@fluid-app/shareables-core/enrollment-packs-api\";\nimport type {\n MediaApi,\n PlaylistsApi,\n FileResourcesApi,\n ProductMediaApi,\n ShareApi,\n} from \"@fluid-app/shareables-core/shareables-api\";\nimport type { ContentDomainApi } from \"@fluid-app/shareables-core/content-domain-api\";\nimport type {\n shareables,\n PlaylistsQuery,\n} from \"@fluid-app/shareables-core/types\";\nimport { portalTenantContent } from \"@fluid-app/portal-tenant-content-api-client\";\nimport { portalTenant } from \"@fluid-app/portal-tenant-api-client\";\n\n// ============================================================================\n// Media — Raw BFF adapter (private)\n// ============================================================================\n\nfunction mapMedia(\n raw: NonNullable<\n Awaited<ReturnType<typeof portalTenantContent.media_show>>[\"media\"]\n >,\n): media.Media {\n return {\n id: raw.id ?? 0,\n title: raw.title ?? \"\",\n description: raw.description ?? null,\n content_format: raw.content_format ?? null,\n status: raw.status ?? \"active\",\n url: raw.url ?? null,\n thumbnail_url: raw.thumbnail_url ?? null,\n owner_type: raw.owner_type ?? \"\",\n cta: raw.cta\n ? {\n enabled: raw.cta.enabled ?? null,\n type: raw.cta.type ?? null,\n button_text: raw.cta.button_text ?? null,\n button_color: raw.cta.button_color ?? null,\n button_description: raw.cta.button_description ?? null,\n action_url: raw.cta.action_url ?? null,\n }\n : null,\n seo: raw.seo\n ? {\n title: raw.seo.title ?? null,\n description: raw.seo.description ?? null,\n image_url: raw.seo.image_url ?? null,\n block_crawler: raw.seo.block_crawler ?? null,\n }\n : null,\n created_at: raw.created_at ?? \"\",\n updated_at: raw.updated_at ?? \"\",\n };\n}\n\nfunction mapMediaMeta(\n raw: Awaited<ReturnType<typeof portalTenantContent.media_list>>[\"meta\"],\n): media.MediaListResponse[\"meta\"] {\n return {\n request_id: raw?.request_id ?? null,\n timestamp: raw?.timestamp ?? \"\",\n pagination: raw?.pagination\n ? {\n cursor: raw.pagination.cursor ?? null,\n limit: raw.pagination.limit,\n next_cursor: raw.pagination.next_cursor ?? null,\n prev_cursor: raw.pagination.prev_cursor ?? null,\n }\n : undefined,\n };\n}\n\nfunction createRawMediaAdapter(client: FetchClient): ContentMediaApi {\n return {\n listMedia: async (params) => {\n const response = await portalTenantContent.media_list(client, {\n \"page[cursor]\": params?.cursor,\n \"page[limit]\": params?.limit,\n \"filter[title]\": params?.[\"filter[title]\"],\n \"filter[ownership]\": params?.[\"filter[ownership]\"],\n \"filter[content_format]\": params?.[\"filter[content_format]\"],\n sort: params?.sort,\n language_iso: params?.language_iso,\n });\n return {\n media: (response.media ?? []).map(mapMedia),\n meta: mapMediaMeta(response.meta),\n };\n },\n\n createMedia: async (body) => {\n const response = await portalTenantContent.media_create(client, {\n media: body,\n });\n if (!response.media) {\n throw new Error(\"Media create response missing media\");\n }\n return {\n media: mapMedia(response.media),\n meta: mapMediaMeta(response.meta),\n };\n },\n\n getMedia: async (id, language_iso) => {\n const response = await portalTenantContent.media_show(\n client,\n id,\n language_iso ? { language_iso } : undefined,\n );\n if (!response.media) {\n throw new Error(\"Media show response missing media\");\n }\n return {\n media: mapMedia(response.media),\n meta: mapMediaMeta(response.meta),\n };\n },\n\n updateMedia: async (id, body, language_iso) => {\n const response = await portalTenantContent.media_update(\n client,\n id,\n { media: body },\n language_iso ? { language_iso } : undefined,\n );\n if (!response.media) {\n throw new Error(\"Media update response missing media\");\n }\n return {\n media: mapMedia(response.media),\n meta: mapMediaMeta(response.meta),\n };\n },\n\n deleteMedia: async (id) => {\n const response = await portalTenantContent.media_destroy(client, id);\n return {\n media: { id: response.media?.id ?? 0 },\n meta: mapMediaMeta(response.meta),\n };\n },\n };\n}\n\n/**\n * Creates a ContentMediaProductsApi adapter backed by the portal-tenant content BFF.\n */\nexport function createPortalTenantMediaProductsAdapter(\n client: FetchClient,\n): ContentMediaProductsApi {\n return {\n listMediaProducts: async (mediumId, params) => {\n const response = await portalTenantContent.media_products_list(\n client,\n mediumId,\n {\n \"page[cursor]\": params?.cursor,\n \"page[limit]\": params?.limit,\n language_iso: params?.language_iso,\n },\n );\n return {\n media_products: (response.media_products ?? []).map((p) => ({\n id: p.id ?? 0,\n name: p.name ?? undefined,\n slug: p.slug ?? null,\n image_url: p.image_url ?? null,\n price: p.price ?? null,\n currency: p.currency ?? null,\n added_at: p.added_at ?? null,\n })),\n meta: mapMediaMeta(response.meta),\n };\n },\n\n addMediaProduct: async (mediumId, body) => {\n const response = await portalTenantContent.media_products_add(\n client,\n mediumId,\n { product: { id: body.id } },\n );\n const p = response.media_product ?? {};\n return {\n media_product: {\n id: p.id ?? 0,\n name: p.name ?? undefined,\n slug: p.slug ?? null,\n image_url: p.image_url ?? null,\n price: p.price ?? null,\n currency: p.currency ?? null,\n added_at: p.added_at ?? null,\n },\n meta: {\n request_id: response.meta?.request_id ?? null,\n timestamp: response.meta?.timestamp ?? \"\",\n },\n };\n },\n\n removeMediaProduct: async (mediumId, productId) => {\n const response = await portalTenantContent.media_products_remove(\n client,\n mediumId,\n productId,\n );\n return {\n media_product: {\n product_id: response.media_product?.product_id ?? 0,\n },\n meta: {\n request_id: response.meta?.request_id ?? null,\n timestamp: response.meta?.timestamp ?? \"\",\n },\n };\n },\n };\n}\n\n// ============================================================================\n// Media — ShareablesApi-compatible adapter (private)\n// ============================================================================\n\nfunction mediaKindFromType(mediaType: string): string | null {\n if (mediaType === \"video\") return \"video\";\n if (mediaType === \"image\") return \"image\";\n if (mediaType === \"document\" || mediaType === \"pdf\") return \"pdf\";\n return null;\n}\n\nfunction toBffMediumResponse(bff: media.Media): shareables.MediumResponse {\n const kind = bff.content_format ?? null;\n const isVideo = kind === \"video\";\n const isPdf = kind === \"pdf\";\n const ctaData = bff.cta;\n const seoData = bff.seo;\n\n return {\n id: bff.id,\n user_id: null,\n owner_type: bff.owner_type ?? null,\n media_type: bff.content_format ?? \"image\",\n media_format: bff.content_format ?? \"image\",\n image_url:\n !isVideo && !isPdf\n ? (bff.url ?? bff.thumbnail_url ?? null)\n : (bff.thumbnail_url ?? null),\n video_url: isVideo ? (bff.url ?? null) : null,\n pdf_url: isPdf ? (bff.url ?? null) : null,\n title: bff.title,\n description: {\n id: null,\n name: null,\n body: bff.description ?? null,\n record_type: null,\n record_id: null,\n created_at: bff.created_at ?? null,\n updated_at: bff.updated_at ?? null,\n locale: null,\n },\n stripped: bff.description ?? null,\n kind,\n active: bff.status === \"active\",\n visibility: null,\n share_link: null,\n views: 0,\n leads: 0,\n watch: null,\n video_status: null,\n duration: null,\n cta_url: ctaData?.action_url ?? null,\n cta_button_text: ctaData?.button_text ?? null,\n cta_enabled: ctaData?.enabled ?? false,\n cta_action_type: ctaData?.type ?? null,\n video_shopping_enabled: false,\n prompts_enabled: false,\n ranks: [],\n preview_link: null,\n attached_shareables: [],\n created_at: bff.created_at,\n settings: {\n cta: ctaData\n ? {\n enabled: ctaData.enabled ?? undefined,\n type: ctaData.type ?? undefined,\n url: ctaData.action_url ?? undefined,\n button_text: ctaData.button_text ?? undefined,\n button_color: ctaData.button_color ?? undefined,\n button_description: ctaData.button_description ?? undefined,\n }\n : null,\n seo: seoData\n ? {\n title: seoData.title ?? undefined,\n description: seoData.description ?? undefined,\n image_url: seoData.image_url ?? undefined,\n block_crawler: seoData.block_crawler ?? undefined,\n }\n : null,\n },\n };\n}\n\nfunction createMediaAdapter(client: FetchClient): MediaApi {\n const portAdapter = createRawMediaAdapter(client);\n const cursorByPage = new Map<number, string>();\n let lastFilterKey = \"\";\n\n return {\n list: async (options) => {\n const response = await portAdapter.listMedia({\n cursor: options?.[\"page[cursor]\"],\n limit: options?.[\"page[limit]\"],\n \"filter[title]\": options?.[\"filter[title]\"],\n \"filter[ownership]\": options?.[\"filter[ownership]\"],\n \"filter[content_format]\": options?.[\"filter[content_format]\"],\n sort: options?.sort,\n language_iso: options?.language_iso,\n });\n return {\n media: response.media.map(toBffMediumResponse),\n nextCursor: response.meta.pagination?.next_cursor ?? null,\n };\n },\n\n getMedia: async (options) => {\n const pageNumber = options?.page ?? 1;\n\n // Clear cursor cache when search/sort/ownership/locale filters change\n const filterKey = `${options?.search_query ?? \"\"}|${options?.sorted_by ?? \"\"}|${options?.ownership ?? \"\"}|${options?.language_iso ?? \"\"}`;\n if (filterKey !== lastFilterKey) {\n cursorByPage.clear();\n lastFilterKey = filterKey;\n }\n\n const cursor = pageNumber > 1 ? cursorByPage.get(pageNumber) : undefined;\n\n // Map UI sort values (\"title_asc\", \"title_desc\") to BFF sort.\n const rawSort = options?.sorted_by;\n let bffSort: \"title_asc\" | \"title_desc\" | undefined;\n if (rawSort === \"title_asc\") {\n bffSort = \"title_asc\";\n } else if (rawSort === \"title_desc\") {\n bffSort = \"title_desc\";\n }\n\n const ownership = options?.ownership;\n const bffOwnership: \"all\" | \"mine\" | \"company\" | undefined =\n ownership === \"all\" || ownership === \"mine\" || ownership === \"company\"\n ? ownership\n : undefined;\n\n const response = await portAdapter.listMedia({\n cursor,\n limit: options?.per_page,\n \"filter[title]\": options?.search_query,\n \"filter[ownership]\": bffOwnership,\n sort: bffSort,\n language_iso: options?.language_iso,\n });\n\n const nextCursor = response.meta.pagination?.next_cursor;\n if (nextCursor) {\n cursorByPage.set(pageNumber + 1, nextCursor);\n }\n\n const transformedItems = response.media.map(toBffMediumResponse);\n\n // Cursor-based pagination doesn't expose a real total. Synthesize\n // a value so `page * PAGE_SIZE < total_count` yields the correct\n // hasNextPage boolean: if there's a next cursor, total exceeds the\n // current offset; otherwise it's exactly the items seen so far.\n const perPage = options?.per_page ?? 24;\n const syntheticTotal = nextCursor\n ? pageNumber * perPage + 1\n : (pageNumber - 1) * perPage + transformedItems.length;\n\n return {\n data: transformedItems,\n status: \"success\",\n media: transformedItems,\n meta: {\n total_count: syntheticTotal,\n current: pageNumber,\n per_page: perPage,\n pages: nextCursor ? pageNumber + 1 : pageNumber,\n next: nextCursor ? pageNumber + 1 : null,\n previous: pageNumber > 1 ? pageNumber - 1 : null,\n },\n };\n },\n\n getMediaById: async (id, language_iso) => {\n const response = await portAdapter.getMedia(id, language_iso);\n const medium = toBffMediumResponse(response.media);\n return {\n data: medium,\n status: \"success\",\n media: medium,\n };\n },\n\n createMedia: async (mediaData) => {\n // Per backend contract: send `content_format` on every POST that\n // includes a `url`, otherwise backend defaults to image_url/kind=\"image\"\n // regardless of the actual asset. The UI derives kind from MIME type\n // (see deriveMediaType in MediaCreateScreen).\n const contentFormat: \"image\" | \"video\" | \"pdf\" | \"ppt\" | undefined =\n mediaData.kind === \"image\" ||\n mediaData.kind === \"video\" ||\n mediaData.kind === \"pdf\" ||\n mediaData.kind === \"ppt\"\n ? mediaData.kind\n : undefined;\n const response = await portAdapter.createMedia({\n title: mediaData.title ?? \"\",\n description: mediaData.description,\n media_type: mediaData.media_type ?? \"image\",\n url:\n mediaData.image_url ??\n mediaData.video_url ??\n mediaData.pdf_url ??\n undefined,\n content_format: contentFormat,\n });\n return toBffMediumResponse(response.media);\n },\n\n updateMedia: async (id, mediaData, language_iso) => {\n const updateBody: media.MediaUpdateBody = {\n title: mediaData.title,\n description: mediaData.description,\n };\n // Map active boolean to status enum\n if (mediaData.active !== undefined) {\n updateBody.status = mediaData.active ? \"active\" : \"draft\";\n }\n // Map replacement media asset URL (image/video/pdf) → BFF single `url`\n const newUrl =\n mediaData.image_url ??\n mediaData.video_url ??\n mediaData.pdf_url ??\n undefined;\n if (newUrl !== undefined) {\n updateBody.url = newUrl;\n }\n // Map UI `kind` (from FilePickerResult) → BFF `content_format`.\n // Per backend contract: must be sent alongside `url` when asset type\n // changes, otherwise backend falls back to medium's stored `kind` and\n // the new URL lands in the wrong column. Runtime-narrow since the\n // source `MediumUpdate.kind` is typed as a broader string.\n if (\n mediaData.kind === \"image\" ||\n mediaData.kind === \"video\" ||\n mediaData.kind === \"pdf\" ||\n mediaData.kind === \"ppt\"\n ) {\n updateBody.content_format = mediaData.kind;\n }\n // Thumbnail override (for video thumbnail captures)\n if (mediaData.thumbnail_url !== undefined) {\n updateBody.thumbnail_url = mediaData.thumbnail_url;\n }\n // Map CTA from settings to top-level.\n // Note: to disable an existing CTA, callers set { enabled: false };\n // sending settings.cta = null is not currently supported by the BFF\n // (MediaUpdate.cta has no null variant), so we only forward when cta\n // is a defined object.\n if (mediaData.settings?.cta) {\n const rawType = mediaData.settings.cta.type;\n // Runtime-narrow CTA type rather than casting — the source type is\n // `string | null | undefined` so an unknown string would otherwise\n // be forwarded unvalidated to the BFF.\n const ctaType =\n rawType === \"link\" ||\n rawType === \"cart\" ||\n rawType === \"email\" ||\n rawType === \"phone\"\n ? rawType\n : undefined;\n updateBody.cta = {\n enabled: mediaData.settings.cta.enabled,\n type: ctaType,\n button_text: mediaData.settings.cta.button_text,\n button_color: mediaData.settings.cta.button_color,\n button_description: mediaData.settings.cta.button_description,\n action_url: mediaData.settings.cta.url,\n };\n }\n // Map SEO from settings to top-level\n if (mediaData.settings?.seo) {\n updateBody.seo = {\n title: mediaData.settings.seo.title,\n description: mediaData.settings.seo.description,\n image_url: mediaData.settings.seo.image_url,\n block_crawler: mediaData.settings.seo.block_crawler ?? undefined,\n };\n }\n const response = await portAdapter.updateMedia(\n id,\n updateBody,\n language_iso,\n );\n return toBffMediumResponse(response.media);\n },\n\n deleteMedia: async (id) => {\n await portAdapter.deleteMedia(id);\n return { success: true };\n },\n };\n}\n\n// ============================================================================\n// Playlists — Raw BFF adapter (private)\n// ============================================================================\n\nfunction mapPlaylist(\n raw: NonNullable<\n Awaited<ReturnType<typeof portalTenantContent.playlists_show>>[\"playlist\"]\n >,\n): playlists.Playlist {\n return {\n id: raw.id ?? 0,\n title: raw.title ?? \"\",\n description: raw.description ?? null,\n items_count: raw.items_count ?? 0,\n user_id: raw.member_id ?? undefined,\n is_favorited: raw.is_favorited,\n image_url: raw.image_url ?? null,\n created_at: raw.created_at ?? \"\",\n updated_at: raw.updated_at ?? \"\",\n };\n}\n\nfunction mapPlaylistItem(\n raw: NonNullable<\n Awaited<\n ReturnType<typeof portalTenantContent.playlists_items_list>\n >[\"playlist_items\"]\n >[number],\n): playlists.PlaylistItem {\n return {\n id: raw.id,\n content_type: raw.content_type,\n content_id: raw.content_id,\n position: raw.position,\n created_at: raw.created_at,\n content: raw.content as playlists.PlaylistItemContent,\n };\n}\n\nfunction mapPlaylistsMeta(\n raw: Awaited<ReturnType<typeof portalTenantContent.playlists_list>>[\"meta\"],\n): playlists.PlaylistsListResponse[\"meta\"] {\n return {\n request_id: raw?.request_id ?? null,\n timestamp: raw?.timestamp ?? \"\",\n pagination: raw?.pagination\n ? {\n cursor: raw.pagination.cursor ?? null,\n limit: raw.pagination.limit,\n next_cursor: raw.pagination.next_cursor ?? null,\n prev_cursor: raw.pagination.prev_cursor ?? null,\n }\n : undefined,\n };\n}\n\nfunction createRawPlaylistsAdapter(client: FetchClient): ContentPlaylistsApi {\n return {\n listPlaylists: async (params) => {\n const response = await portalTenantContent.playlists_list(client, {\n \"page[cursor]\": params?.cursor,\n \"page[limit]\": params?.limit,\n \"filter[title]\": params?.[\"filter[title]\"],\n \"filter[ownership]\": params?.[\"filter[ownership]\"],\n sort: params?.sort,\n });\n return {\n playlists: (response.playlists ?? []).map(mapPlaylist),\n meta: mapPlaylistsMeta(response.meta),\n };\n },\n\n createPlaylist: async (body) => {\n const response = await portalTenantContent.playlists_create(client, {\n playlist: body,\n });\n return {\n playlist: mapPlaylist(response.playlist ?? {}),\n meta: mapPlaylistsMeta(response.meta),\n };\n },\n\n getPlaylist: async (id) => {\n const response = await portalTenantContent.playlists_show(client, id);\n return {\n playlist: mapPlaylist(response.playlist ?? {}),\n meta: mapPlaylistsMeta(response.meta),\n };\n },\n\n updatePlaylist: async (id, body) => {\n const response = await portalTenantContent.playlists_update(client, id, {\n playlist: body,\n });\n return {\n playlist: mapPlaylist(response.playlist ?? {}),\n meta: mapPlaylistsMeta(response.meta),\n };\n },\n\n deletePlaylist: async (id) => {\n const response = await portalTenantContent.playlists_destroy(client, id);\n return {\n playlist: { id: response.playlist?.id ?? 0 },\n meta: mapPlaylistsMeta(response.meta),\n };\n },\n\n listPlaylistItems: async (playlistId, params) => {\n const response = await portalTenantContent.playlists_items_list(\n client,\n playlistId,\n {\n \"page[cursor]\": params?.cursor,\n \"page[limit]\": params?.limit,\n language_iso: params?.language_iso,\n },\n );\n return {\n playlist_items: (response.playlist_items ?? []).map(mapPlaylistItem),\n meta: mapPlaylistsMeta(response.meta),\n };\n },\n\n addPlaylistItem: async (playlistId, body) => {\n const response = await portalTenantContent.playlists_items_add(\n client,\n playlistId,\n { item: body },\n );\n const rawItem = response.playlist_item;\n if (!rawItem) {\n throw new Error(\"Playlist item add response missing playlist_item\");\n }\n return {\n playlist_item: mapPlaylistItem(rawItem),\n meta: mapPlaylistsMeta(response.meta),\n };\n },\n\n removePlaylistItem: async (playlistId, itemId) => {\n const response = await portalTenantContent.playlists_items_remove(\n client,\n playlistId,\n itemId,\n );\n return {\n playlist_item: { id: response.playlist_item?.id ?? 0 },\n meta: mapPlaylistsMeta(response.meta),\n };\n },\n\n reorderPlaylistItems: async (playlistId, body) => {\n const response = await portalTenantContent.playlists_items_reorder(\n client,\n playlistId,\n body,\n );\n return {\n playlist_id: response.playlist_id ?? playlistId,\n meta: mapPlaylistsMeta(response.meta),\n };\n },\n };\n}\n\n// ============================================================================\n// Playlists — ShareablesApi-compatible adapter (private)\n// ============================================================================\n\n// Map BFF content_type ↔ legacy admin polymorphic relateable_type used by the\n// Playlists UI, plus reverse for outgoing add-item payloads.\nconst CONTENT_TYPE_TO_RELATEABLE: Record<\n playlists.ContentType,\n \"Medium\" | \"Page\" | \"Product\" | \"EnrollmentPack\"\n> = {\n media: \"Medium\",\n page: \"Page\",\n product: \"Product\",\n enrollment_pack: \"EnrollmentPack\",\n};\n\nconst RELATEABLE_TO_CONTENT_TYPE: Record<string, playlists.ContentType> = {\n Medium: \"media\",\n Media: \"media\",\n media: \"media\",\n Page: \"page\",\n page: \"page\",\n Product: \"product\",\n product: \"product\",\n EnrollmentPack: \"enrollment_pack\",\n enrollment_pack: \"enrollment_pack\",\n};\n\nfunction firstImageUrl(\n images: Array<{ url?: string | null }> | undefined,\n): string | null {\n return images?.[0]?.url ?? null;\n}\n\nfunction toShareablePlaylistItem(\n item: playlists.PlaylistItem,\n): shareables.PlaylistItem {\n const relateableType = CONTENT_TYPE_TO_RELATEABLE[item.content_type];\n const base: shareables.PlaylistItem = {\n id: item.id,\n order: item.position ?? undefined,\n relateable_type: relateableType,\n relateable: { id: item.content_id },\n };\n\n switch (item.content_type) {\n case \"media\": {\n const c = item.content as playlists.MediaContent;\n const isVideo = c.content_format === \"video\";\n const isPdf = c.content_format === \"pdf\";\n base.title = c.title ?? \"Untitled\";\n base.image_url =\n isVideo || isPdf\n ? (c.thumbnail_url ?? null)\n : (c.url ?? c.thumbnail_url ?? null);\n base.kind = mediaKindFromType(c.content_format ?? \"\");\n base.video_url = isVideo ? (c.url ?? null) : null;\n base.duration = null;\n base.media_format = c.content_format ?? null;\n base.relateable = {\n id: c.id,\n title: c.title,\n image_url: base.image_url,\n media_format: c.content_format ?? null,\n video_url: base.video_url,\n kind: base.kind,\n description: {\n id: null,\n name: null,\n body: c.description ?? null,\n record_type: null,\n record_id: null,\n created_at: c.created_at ?? null,\n updated_at: c.updated_at ?? null,\n locale: null,\n },\n };\n break;\n }\n case \"page\": {\n const c = item.content as playlists.PageContent;\n base.title = c.title ?? \"Untitled\";\n base.image_url = c.image_url ?? null;\n base.relateable = {\n id: c.id,\n title: c.title,\n slug: c.slug ?? null,\n image_url: c.image_url ?? null,\n status: c.status,\n description: {\n id: null,\n name: null,\n body: c.description ?? null,\n record_type: null,\n record_id: null,\n created_at: null,\n updated_at: null,\n locale: null,\n },\n };\n break;\n }\n case \"product\": {\n const c = item.content as playlists.ProductContent;\n const image = firstImageUrl(c.images);\n base.title = c.name;\n base.image_url = image;\n base.relateable = {\n id: c.id,\n title: c.name,\n slug: c.slug ?? null,\n price: c.price ?? null,\n display_price: c.price ?? null,\n image_url: image,\n status: c.status ?? null,\n description: {\n id: null,\n name: null,\n body: c.description ?? null,\n record_type: null,\n record_id: null,\n created_at: c.created_at ?? null,\n updated_at: null,\n locale: null,\n },\n images: (c.images ?? []).map((img) => ({\n image_url: img.url ?? null,\n })),\n };\n break;\n }\n case \"enrollment_pack\": {\n const c = item.content as playlists.EnrollmentPackContent;\n const image = firstImageUrl(c.images);\n base.title = c.title;\n base.image_url = image;\n base.relateable = {\n id: c.id,\n title: c.title,\n slug: c.slug ?? null,\n canonical_url: c.url ?? null,\n image_url: image,\n description: {\n id: null,\n name: null,\n body: c.description ?? null,\n record_type: null,\n record_id: null,\n created_at: null,\n updated_at: null,\n locale: null,\n },\n images: (c.images ?? []).map((img) => ({\n image_url: img.url ?? null,\n })),\n };\n break;\n }\n default: {\n // If a new ContentType literal is added without updating this switch,\n // TypeScript will reject this assignment at compile time. At runtime,\n // unknown discriminators surface as a typed error rather than silently\n // producing a row with no title/image.\n const _exhaustive: never = item.content_type;\n throw new Error(\n `Unhandled playlist item content_type: ${String(_exhaustive)}`,\n );\n }\n }\n\n return base;\n}\n\nfunction toBffPlaylist(\n bff: playlists.Playlist,\n items?: shareables.PlaylistItem[],\n): shareables.Playlist {\n return {\n id: bff.id,\n title: bff.title,\n description: bff.description ?? null,\n image_url: bff.image_url ?? null,\n slug: null,\n active: true,\n user_id: bff.user_id ?? null,\n is_favorited: bff.is_favorited ?? false,\n items: items ?? [],\n items_count: bff.items_count,\n };\n}\n\nfunction createPlaylistsAdapter(client: FetchClient): PlaylistsApi {\n const portAdapter = createRawPlaylistsAdapter(client);\n\n return {\n getPlaylists: async (options?: PlaylistsQuery) => {\n // The UI sends Rails-style sort (\"-title\", \"title\", \"-created_at\")\n // but the BFF expects \"title_asc\", \"title_desc\", etc.\n const rawSort = options?.sort;\n let bffSort:\n | \"title_asc\"\n | \"title_desc\"\n | \"created_at_asc\"\n | \"created_at_desc\"\n | undefined;\n if (rawSort === \"title_asc\" || rawSort === \"title\") {\n bffSort = \"title_asc\";\n } else if (rawSort === \"title_desc\" || rawSort === \"-title\") {\n bffSort = \"title_desc\";\n } else if (rawSort === \"created_at_asc\" || rawSort === \"created_at\") {\n bffSort = \"created_at_asc\";\n } else if (rawSort === \"created_at_desc\" || rawSort === \"-created_at\") {\n bffSort = \"created_at_desc\";\n }\n\n const response = await portAdapter.listPlaylists({\n cursor: options?.[\"page[cursor]\"],\n limit: options?.[\"page[limit]\"],\n \"filter[title]\": options?.[\"filter[title]\"],\n \"filter[ownership]\": options?.[\"filter[ownership]\"],\n sort: bffSort,\n });\n\n return {\n playlists: response.playlists.map((p) => toBffPlaylist(p)),\n meta: {\n request_id: response.meta.request_id ?? \"\",\n timestamp: response.meta.timestamp ?? \"\",\n pagination: {\n cursor: response.meta.pagination?.cursor ?? null,\n limit: response.meta.pagination?.limit ?? 12,\n prev_cursor: response.meta.pagination?.prev_cursor ?? null,\n next_cursor: response.meta.pagination?.next_cursor ?? null,\n total_count: 0,\n total_pages: 0,\n },\n },\n };\n },\n\n getPlaylistById: async (id, language_iso) => {\n // Fetch playlist metadata and all items in parallel.\n // Items are cursor-paginated so we follow next_cursor until exhausted.\n const response = await portAdapter.getPlaylist(id);\n\n const allItems: playlists.PlaylistItem[] = [];\n let cursor: string | undefined;\n const MAX_PAGES = 50; // Safety limit: 50 pages × 100 items = 5,000 items max\n for (let i = 0; i < MAX_PAGES; i++) {\n const page = await portAdapter.listPlaylistItems(id, {\n cursor,\n limit: 100,\n language_iso,\n });\n allItems.push(...page.playlist_items);\n cursor = page.meta.pagination?.next_cursor ?? undefined;\n if (!cursor) break;\n }\n\n const items: shareables.PlaylistItem[] = allItems.map(\n toShareablePlaylistItem,\n );\n\n return {\n playlist: toBffPlaylist(response.playlist, items),\n meta: {\n request_id: response.meta.request_id ?? \"\",\n timestamp: response.meta.timestamp ?? \"\",\n },\n };\n },\n\n createPlaylist: async (data) => {\n const response = await portAdapter.createPlaylist({\n title: data.playlist.title,\n description: data.playlist.description,\n });\n return {\n playlist: toBffPlaylist(response.playlist),\n meta: {\n request_id: response.meta.request_id ?? \"\",\n timestamp: response.meta.timestamp ?? \"\",\n },\n };\n },\n\n updatePlaylist: async (id, data) => {\n const response = await portAdapter.updatePlaylist(id, {\n title: data.playlist.title,\n description: data.playlist.description,\n });\n return {\n playlist: toBffPlaylist(response.playlist),\n meta: {\n request_id: response.meta.request_id ?? \"\",\n timestamp: response.meta.timestamp ?? \"\",\n },\n };\n },\n\n addItemToPlaylist: async (id, data) => {\n // Sequential dispatch — the BFF assigns playlist position by insert\n // order when the request omits an explicit position, and shared\n // explicit positions across concurrent requests would race. for-of\n // ordering keeps the playlist deterministic regardless of caller.\n for (const item of data.items) {\n const contentType = RELATEABLE_TO_CONTENT_TYPE[item.relateable_type];\n if (!contentType) {\n throw new Error(\n `Unsupported relateable_type for playlist item: \"${item.relateable_type}\"`,\n );\n }\n await portAdapter.addPlaylistItem(id, {\n content_type: contentType,\n content_id: item.relateable_id,\n position:\n typeof item.order === \"number\" ? item.order : Number(item.order),\n });\n }\n return {\n id,\n title: \"\",\n description: null,\n image_url: null,\n slug: null,\n active: true,\n user_id: null,\n is_favorited: false,\n items: [],\n items_count: 0,\n } satisfies shareables.Playlist;\n },\n\n removeItemsFromPlaylist: async (playlistId, data) => {\n await Promise.all(\n data.item_ids.map((itemId) =>\n portAdapter.removePlaylistItem(playlistId, itemId),\n ),\n );\n return {\n id: playlistId,\n title: \"\",\n description: null,\n image_url: null,\n slug: null,\n active: true,\n user_id: null,\n is_favorited: false,\n items: [],\n items_count: 0,\n } satisfies shareables.Playlist;\n },\n\n reorderPlaylistItems: async (playlistId, data) => {\n await portAdapter.reorderPlaylistItems(playlistId, {\n items: data.items,\n });\n },\n };\n}\n\n// ============================================================================\n// Shares — Raw BFF adapter (private)\n// ============================================================================\n\nfunction isShareableType(\n value: string | undefined,\n): value is shares.ShareableType {\n return (\n value === \"media\" ||\n value === \"product\" ||\n value === \"library\" ||\n value === \"page\"\n );\n}\n\nfunction mapShare(\n raw: NonNullable<\n Awaited<ReturnType<typeof portalTenantContent.shares_list>>[\"shares\"]\n >[number],\n): shares.Share {\n return {\n id: raw.id ?? 0,\n url: raw.url ?? \"\",\n shareable_type: isShareableType(raw.shareable_type)\n ? raw.shareable_type\n : \"media\",\n shareable_id: raw.shareable_id ?? 0,\n created_at: raw.created_at ?? \"\",\n };\n}\n\nfunction mapSharesMeta(\n raw: Awaited<ReturnType<typeof portalTenantContent.shares_list>>[\"meta\"],\n): shares.SharesListResponse[\"meta\"] {\n return {\n request_id: raw?.request_id ?? null,\n timestamp: raw?.timestamp ?? \"\",\n pagination: raw?.pagination\n ? {\n cursor: raw.pagination.cursor ?? null,\n limit: raw.pagination.limit,\n next_cursor: raw.pagination.next_cursor ?? null,\n prev_cursor: raw.pagination.prev_cursor ?? null,\n }\n : undefined,\n };\n}\n\nfunction createRawSharesAdapter(client: FetchClient): ContentSharesApi {\n return {\n listShares: async (params) => {\n const response = await portalTenantContent.shares_list(client, {\n \"page[cursor]\": params?.cursor,\n \"page[limit]\": params?.limit,\n });\n return {\n shares: (response.shares ?? []).map(mapShare),\n meta: mapSharesMeta(response.meta),\n };\n },\n\n createShare: async (body) => {\n const response = await portalTenantContent.shares_create(client, {\n share: body,\n });\n return {\n share: mapShare(response.share ?? {}),\n meta: mapSharesMeta(response.meta),\n };\n },\n };\n}\n\n// ============================================================================\n// Shares — ShareablesApi-compatible adapter (private)\n// ============================================================================\n\nconst SHAREABLE_TYPE_MAP: Record<string, shares.ShareableType> = {\n Medium: \"media\",\n media: \"media\",\n Product: \"product\",\n product: \"product\",\n Library: \"library\",\n library: \"library\",\n Page: \"page\",\n page: \"page\",\n};\n\nfunction createShareAdapter(client: FetchClient): ShareApi {\n const portAdapter = createRawSharesAdapter(client);\n\n return {\n createShareLink: async (input) => {\n if (!input.relateableId) {\n throw new Error(\"Cannot create share link without a relateableId\");\n }\n const shareableType = SHAREABLE_TYPE_MAP[input.relateableType];\n if (!shareableType) {\n throw new Error(`Unknown shareable type: \"${input.relateableType}\"`);\n }\n\n const response = await portAdapter.createShare({\n shareable_type: shareableType,\n shareable_id: input.relateableId,\n });\n\n return response.share.url;\n },\n };\n}\n\n// ============================================================================\n// Pages — Raw BFF adapter (private)\n// ============================================================================\n\nfunction mapPage(\n raw: NonNullable<\n Awaited<ReturnType<typeof portalTenantContent.pages_list>>[\"pages\"]\n >[number],\n): pages.Page {\n return {\n id: raw.id ?? 0,\n title: raw.title ?? null,\n slug: raw.slug ?? null,\n source: raw.source ?? null,\n status: raw.status ?? \"unpublished\",\n countries: (raw.countries ?? []).map((c) => ({\n code: c.code ?? \"\",\n name: c.name ?? \"\",\n currency_code: c.currency_code ?? \"\",\n states: (c.states ?? []).map((s) => ({\n code: s.code ?? \"\",\n name: s.name ?? \"\",\n })),\n })),\n description: raw.description ?? null,\n image_url: raw.image_url ?? null,\n };\n}\n\nfunction mapPagesMeta(\n raw: Awaited<ReturnType<typeof portalTenantContent.pages_list>>[\"meta\"],\n): pages.PagesListResponse[\"meta\"] {\n return {\n request_id: raw?.request_id ?? null,\n timestamp: raw?.timestamp ?? \"\",\n pagination: raw?.pagination\n ? {\n cursor: raw.pagination.cursor ?? null,\n limit: raw.pagination.limit,\n next_cursor: raw.pagination.next_cursor ?? null,\n prev_cursor: raw.pagination.prev_cursor ?? null,\n }\n : undefined,\n };\n}\n\nfunction createRawPagesAdapter(client: FetchClient): ContentPagesApi {\n return {\n listPages: async (params) => {\n const response = await portalTenantContent.pages_list(client, {\n \"page[cursor]\": params?.cursor,\n \"page[limit]\": params?.limit,\n \"filter[title]\": params?.[\"filter[title]\"],\n sort: params?.sort,\n language_iso: params?.language_iso,\n });\n return {\n pages: (response.pages ?? []).map(mapPage),\n meta: mapPagesMeta(response.meta),\n };\n },\n\n getPage: async (id, language_iso) => {\n const response = await portalTenantContent.pages_show(\n client,\n id,\n language_iso ? { language_iso } : undefined,\n );\n if (!response.page) {\n throw new Error(`Page ${id} not found`);\n }\n return {\n page: mapPage(response.page),\n share_link: response.share_link ?? null,\n meta: mapPagesMeta(response.meta),\n };\n },\n };\n}\n\n// ============================================================================\n// Enrollment Packs — Raw BFF adapter (private)\n//\n// The list endpoint lives on portal-tenant (not portal-tenant-content).\n// The port (`ContentEnrollmentPacksApi`) is namespace-agnostic — this is\n// the only adapter file that has to know.\n// ============================================================================\n\nfunction mapEnrollmentPack(raw: {\n id?: number;\n title?: string;\n slug?: string | null;\n description?: string | null;\n url?: string;\n canonical_url?: string;\n images?: { url?: string; alt?: string | null }[];\n}): enrollmentPacks.EnrollmentPack {\n return {\n id: raw.id ?? 0,\n title: raw.title ?? \"\",\n slug: raw.slug ?? null,\n description: raw.description ?? null,\n url: raw.url ?? null,\n canonical_url: raw.canonical_url ?? null,\n images: (raw.images ?? []).map((img) => ({\n url: img.url ?? null,\n alt: img.alt ?? null,\n })),\n };\n}\n\nfunction mapEnrollmentPacksMeta(\n raw:\n | Awaited<ReturnType<typeof portalTenant.enrollment_packs_list>>[\"meta\"]\n | undefined,\n): enrollmentPacks.EnrollmentPacksListResponse[\"meta\"] {\n return {\n request_id: raw?.request_id ?? null,\n timestamp: raw?.timestamp ?? \"\",\n pagination: raw?.pagination\n ? {\n cursor: raw.pagination.cursor ?? null,\n limit: raw.pagination.limit,\n next_cursor: raw.pagination.next_cursor ?? null,\n prev_cursor: raw.pagination.prev_cursor ?? null,\n }\n : undefined,\n };\n}\n\nfunction createRawEnrollmentPacksAdapter(\n client: FetchClient,\n): ContentEnrollmentPacksApi {\n return {\n listEnrollmentPacks: async (params) => {\n const response = await portalTenant.enrollment_packs_list(client, {\n \"page[cursor]\": params?.cursor,\n \"page[limit]\": params?.limit,\n });\n // BFF marks `id` as optional in its generated type; drop entries\n // without one rather than mapping them to id=0 (which would silently\n // misroute downstream playlist-item operations).\n const packs = (response.enrollment_packs ?? [])\n .filter((p): p is typeof p & { id: number } => typeof p.id === \"number\")\n .map(mapEnrollmentPack);\n return {\n enrollment_packs: packs,\n meta: mapEnrollmentPacksMeta(response.meta),\n };\n },\n\n getEnrollmentPack: async (id) => {\n const response = await portalTenant.enrollment_packs_show(client, id);\n if (!response.enrollment_pack) {\n throw new Error(`EnrollmentPack ${id} not found`);\n }\n return {\n enrollment_pack: mapEnrollmentPack(response.enrollment_pack),\n meta: mapEnrollmentPacksMeta(response.meta),\n };\n },\n };\n}\n\n// ============================================================================\n// DAM Assets / Files — Raw BFF adapter (private)\n// ============================================================================\n\nfunction mapDamAsset(\n raw: NonNullable<\n Awaited<ReturnType<typeof portalTenantContent.dam_assets_list>>[\"assets\"]\n >[number],\n): damAssets.DamAsset {\n return {\n id: raw.id ?? 0,\n code: raw.code ?? \"\",\n name: raw.name ?? \"\",\n description: raw.description ?? null,\n category: raw.category ?? null,\n company: raw.company ?? null,\n default_variant_id: raw.default_variant_id ?? null,\n default_variant_url: raw.default_variant_url ?? null,\n canonical_path: raw.canonical_path ?? null,\n created_at: raw.created_at ?? \"\",\n updated_at: raw.updated_at ?? \"\",\n };\n}\n\nfunction mapDamAssetPath(\n raw: NonNullable<\n Awaited<\n ReturnType<typeof portalTenantContent.dam_asset_paths_list>\n >[\"asset_paths\"]\n >[number],\n): damAssets.DamAssetPath {\n return {\n id: raw.id ?? 0,\n asset_code: raw.asset_code ?? \"\",\n path: raw.path ?? \"\",\n created_at: raw.created_at ?? \"\",\n };\n}\n\nfunction mapDamAssetsMeta(\n raw: Awaited<ReturnType<typeof portalTenantContent.dam_assets_list>>[\"meta\"],\n): damAssets.DamAssetsListResponse[\"meta\"] {\n return {\n request_id: raw?.request_id ?? null,\n timestamp: raw?.timestamp ?? \"\",\n pagination: raw?.pagination\n ? {\n cursor: raw.pagination.cursor ?? null,\n limit: raw.pagination.limit,\n next_cursor: raw.pagination.next_cursor ?? null,\n prev_cursor: raw.pagination.prev_cursor ?? null,\n }\n : undefined,\n };\n}\n\nfunction createRawDamAssetsAdapter(client: FetchClient): ContentDamAssetsApi {\n return {\n listAssets: async (params) => {\n const response = await portalTenantContent.dam_assets_list(client, {\n \"page[cursor]\": params?.cursor,\n \"page[limit]\": params?.limit,\n });\n return {\n assets: (response.assets ?? []).map(mapDamAsset),\n meta: mapDamAssetsMeta(response.meta),\n };\n },\n\n createAsset: async (body) => {\n const response = await portalTenantContent.dam_assets_create(client, {\n asset: body,\n });\n return {\n asset: mapDamAsset(response.asset ?? {}),\n meta: mapDamAssetsMeta(response.meta),\n };\n },\n\n listAssetPaths: async (assetCode, params) => {\n const response = await portalTenantContent.dam_asset_paths_list(\n client,\n assetCode,\n {\n \"page[cursor]\": params?.cursor,\n \"page[limit]\": params?.limit,\n },\n );\n return {\n asset_paths: (response.asset_paths ?? []).map(mapDamAssetPath),\n meta: mapDamAssetsMeta(response.meta),\n };\n },\n\n createAssetPath: async (assetCode, body) => {\n const response = await portalTenantContent.dam_asset_paths_create(\n client,\n assetCode,\n { asset_path: body },\n );\n return {\n asset_path: mapDamAssetPath(response.asset_path ?? {}),\n meta: mapDamAssetsMeta(response.meta),\n };\n },\n };\n}\n\n// ============================================================================\n// Files — ShareablesApi-compatible adapter (private)\n// ============================================================================\n\nfunction createFileResourcesAdapter(client: FetchClient): FileResourcesApi {\n const portAdapter = createRawDamAssetsAdapter(client);\n const cursorByPage = new Map<number, string>();\n\n return {\n getFileResources: async (params) => {\n const pageNumber = params?.pageParam ? Number(params.pageParam) : 1;\n const pageSize = params?.pageSize ? Number(params.pageSize) : 25;\n const cursor = pageNumber > 1 ? cursorByPage.get(pageNumber) : undefined;\n\n const response = await portAdapter.listAssets({\n cursor,\n limit: pageSize,\n });\n\n const nextCursor = response.meta.pagination?.next_cursor;\n if (nextCursor) {\n cursorByPage.set(pageNumber + 1, nextCursor);\n }\n\n const fileResources: shareables.FileResource[] = response.assets.map(\n (asset) => ({\n id: asset.id,\n alt_text: asset.name,\n url: asset.default_variant_url ?? \"\",\n filename: asset.name,\n content_type: \"application/octet-stream\",\n content_size: 0,\n handle: asset.code,\n dam_asset_code: asset.code,\n preview_image_url: asset.default_variant_url ?? \"\",\n created_at: asset.created_at,\n updated_at: asset.updated_at ?? \"\",\n relateable_type: null,\n relateable_id: null,\n content: null,\n }),\n );\n\n const hasNextPage = !!nextCursor;\n\n return {\n file_resources: fileResources,\n meta: {\n total_count: fileResources.length,\n per_page: pageSize,\n current_page: pageNumber,\n total_pages: hasNextPage ? pageNumber + 1 : pageNumber,\n },\n };\n },\n };\n}\n\n// ============================================================================\n// Metrics — Raw BFF adapter (private)\n// ============================================================================\n\nfunction mapMetricsMeta(\n raw:\n | Awaited<\n ReturnType<typeof portalTenantContent.content_media_by_visits>\n >[\"meta\"]\n | undefined,\n): metrics.VisitedResponse[\"meta\"] {\n if (!raw) return undefined;\n return {\n request_id: raw.request_id ?? null,\n timestamp: raw.timestamp ?? \"\",\n pagination: raw.pagination\n ? {\n cursor: raw.pagination.cursor ?? null,\n limit: raw.pagination.limit,\n next_cursor: raw.pagination.next_cursor ?? null,\n prev_cursor: raw.pagination.prev_cursor ?? null,\n }\n : undefined,\n };\n}\n\nfunction createMetricsAdapter(client: FetchClient): ContentMetricsApi {\n return {\n listMediaVisited: async (params) => {\n const response = await portalTenantContent.content_media_by_visits(\n client,\n {\n period: params?.period,\n limit: params?.limit,\n language_iso: params?.language_iso,\n },\n );\n return {\n resources: response.resources ?? [],\n meta: mapMetricsMeta(response.meta),\n };\n },\n\n listMediaShareVisited: async (params) => {\n const response = await portalTenantContent.content_media_by_shares(\n client,\n {\n period: params?.period,\n limit: params?.limit,\n language_iso: params?.language_iso,\n },\n );\n return {\n resources: response.resources ?? [],\n meta: mapMetricsMeta(response.meta),\n };\n },\n\n listPlaylistsVisited: async (params) => {\n const response = await portalTenantContent.content_playlists_by_visits(\n client,\n {\n period: params?.period,\n limit: params?.limit,\n },\n );\n return {\n resources: response.resources ?? [],\n meta: mapMetricsMeta(response.meta),\n };\n },\n\n listPlaylistsShareVisited: async (params) => {\n const response = await portalTenantContent.content_playlists_by_shares(\n client,\n { period: params?.period, limit: params?.limit },\n );\n return {\n resources: response.resources ?? [],\n meta: mapMetricsMeta(response.meta),\n };\n },\n\n listPagesVisited: async (params) => {\n const response = await portalTenantContent.content_pages_by_visits(\n client,\n {\n period: params?.period,\n limit: params?.limit,\n language_iso: params?.language_iso,\n },\n );\n return {\n resources: response.resources ?? [],\n meta: mapMetricsMeta(response.meta),\n };\n },\n\n listPagesShareVisited: async (params) => {\n const response = await portalTenantContent.content_pages_by_shares(\n client,\n {\n period: params?.period,\n limit: params?.limit,\n language_iso: params?.language_iso,\n },\n );\n return {\n resources: response.resources ?? [],\n meta: mapMetricsMeta(response.meta),\n };\n },\n };\n}\n\n// ============================================================================\n// Product Media (private)\n// ============================================================================\n\n/**\n * Narrow interface for the product media endpoint. Matches\n * PortalProductsApi.getProductMedia without importing the full products-core\n * dependency graph, keeping the dependency graph clean.\n */\nexport interface ProductMediaSource {\n getProductMedia(productId: string | number): Promise<{\n media: ReadonlyArray<{\n id?: number;\n title?: string;\n media_type?: string;\n url?: string;\n }>;\n }>;\n}\n\nfunction mapProductMedia(raw: {\n id?: number;\n title?: string;\n media_type?: string;\n url?: string;\n}): shareables.ProductMedia {\n const isVideo = raw.media_type === \"video\";\n const isPdf = raw.media_type === \"pdf\" || raw.media_type === \"document\";\n return {\n id: raw.id ?? 0,\n slug: null,\n title: raw.title ?? \"\",\n kind: isVideo ? \"video\" : isPdf ? \"pdf\" : \"image\",\n media_type: raw.media_type ?? \"image\",\n media_format: raw.media_type ?? \"image\",\n image_url: !isVideo && !isPdf ? (raw.url ?? null) : null,\n video_url: isVideo ? (raw.url ?? null) : null,\n pdf_url: isPdf ? (raw.url ?? null) : null,\n powerpoint_url: null,\n duration: 0,\n description: null,\n subtitles: {},\n comments_count: 0,\n };\n}\n\nfunction createProductMediaAdapter(\n source: ProductMediaSource,\n): ProductMediaApi {\n return {\n getProductMedia: async (productId: number) => {\n const response = await source.getProductMedia(productId);\n return {\n media: (response.media ?? []).map(mapProductMedia),\n };\n },\n };\n}\n\n// ============================================================================\n// Internal test helpers (consumed by tests only — not re-exported from index.ts)\n// ============================================================================\n\n/** @internal — For tests only. */\nexport const _createRawMediaAdapter: typeof createRawMediaAdapter =\n createRawMediaAdapter;\n/** @internal — For tests only. */\nexport const _createRawDamAssetsAdapter: typeof createRawDamAssetsAdapter =\n createRawDamAssetsAdapter;\n/** @internal — For tests only. */\nexport const _createRawSharesAdapter: typeof createRawSharesAdapter =\n createRawSharesAdapter;\n/** @internal — For tests only. */\nexport const _createMetricsAdapter: typeof createMetricsAdapter =\n createMetricsAdapter;\n/** @internal — For tests only. */\nexport const _createRawPagesAdapter: typeof createRawPagesAdapter =\n createRawPagesAdapter;\n\n// ============================================================================\n// Public exports\n// ============================================================================\n\n/**\n * Creates a composite ContentDomainApi backed by the portal-tenant Content\n * BFF endpoints. Follows the same pattern as\n * `createPortalContactsDomainApiAdapter`.\n */\nexport function createPortalContentDomainApiAdapter(\n client: FetchClient,\n productsApi: ProductMediaSource,\n): ContentDomainApi {\n return {\n media: createMediaAdapter(client),\n playlists: createPlaylistsAdapter(client),\n fileResources: createFileResourcesAdapter(client),\n share: createShareAdapter(client),\n productMedia: createProductMediaAdapter(productsApi),\n metrics: createMetricsAdapter(client),\n pages: createRawPagesAdapter(client),\n };\n}\n\n/**\n * Creates a ContentPlaylistsApi (the port-level playlists adapter) for\n * operations that aren't part of the shareables PlaylistsApi — e.g.\n * `deletePlaylist`. Exposed separately because ContentDomainApi.playlists\n * is the higher-level shareables PlaylistsApi.\n */\nexport function createPortalContentPlaylistsAdapter(\n client: FetchClient,\n): ContentPlaylistsApi {\n return createRawPlaylistsAdapter(client);\n}\n\n/**\n * Creates a ContentPagesApi (the port-level pages adapter) for screens that\n * need to list/show pages outside of ShareablesApiProvider — e.g. the\n * playlist editor's content picker. Mirrors createPortalContentPlaylistsAdapter.\n */\nexport function createPortalContentPagesAdapter(\n client: FetchClient,\n): ContentPagesApi {\n return createRawPagesAdapter(client);\n}\n\n/**\n * Creates a ContentEnrollmentPacksApi adapter for screens that need to\n * list/show enrollment packs outside of ShareablesApiProvider — e.g. the\n * playlist editor's content picker. Backed by the portal-tenant\n * `/api/enrollment_packs` endpoint.\n */\nexport function createPortalContentEnrollmentPacksAdapter(\n client: FetchClient,\n): ContentEnrollmentPacksApi {\n return createRawEnrollmentPacksAdapter(client);\n}\n\n/**\n * Toggles a favorite entry on a given shareable (Medium / Playlist /\n * Product / etc.) via the portal-tenant BFF's /favorites/toggle endpoint.\n * Returns the new is_favorited state reported by the backend.\n */\nexport async function toggleFavorite(\n client: FetchClient,\n favoriteableId: number,\n favoriteableType: string,\n): Promise<{ is_favorited: boolean }> {\n const res = await client.post<{\n favorite: { is_favorited: boolean };\n }>(\"/api/content/favorites/toggle\", {\n favoriteable_id: favoriteableId,\n favoriteable_type: favoriteableType,\n });\n return { is_favorited: res.favorite?.is_favorited ?? false };\n}\n","import {\n createContext,\n type ReactElement,\n type ReactNode,\n use,\n useMemo,\n} from \"react\";\nimport { ShareablesApiProvider } from \"@fluid-app/shareables-core\";\nimport type { ContentMediaProductsApi } from \"@fluid-app/shareables-core/media-api\";\nimport type { ContentPagesApi } from \"@fluid-app/shareables-core/pages-api\";\nimport type { ContentEnrollmentPacksApi } from \"@fluid-app/shareables-core/enrollment-packs-api\";\nimport type { ContentPlaylistsApi } from \"@fluid-app/shareables-core/playlists-api\";\nimport type { PortalProductsApi } from \"@fluid-app/products-core\";\nimport { FilePickerApiProvider } from \"@fluid-app/file-picker-core\";\nimport { usePortalProductsApi } from \"@fluid-app/products-core\";\nimport { createFilePickerApiAdapter } from \"../adapters/file-picker-api-adapter\";\nimport { usePortalTenantClient } from \"../providers/PortalTenantClientProvider\";\nimport {\n createPortalContentDomainApiAdapter,\n createPortalContentEnrollmentPacksAdapter,\n createPortalContentPagesAdapter,\n createPortalContentPlaylistsAdapter,\n createPortalTenantMediaProductsAdapter,\n} from \"../adapters/content-api-adapter\";\n\n/**\n * Extra context values that screens need beyond ContentDomainApi.\n * ContentDomainApi flows through ShareablesApiProvider; these extras\n * are available via usePortalContentContext().\n */\nexport interface PortalContentContext {\n /** The products adapter — exposed so screens can call listProducts / getProduct\n * without a separate usePortalProductsApi() import. */\n productsApi: PortalProductsApi;\n /** Port-level playlists adapter for operations outside ShareablesApiProvider\n * (e.g. deletePlaylist). */\n playlistsAdapter: ContentPlaylistsApi;\n /** Port-level pages adapter for operations outside ShareablesApiProvider\n * (e.g. picker source for the playlist editor). */\n pagesAdapter: ContentPagesApi;\n /** Port-level enrollment-packs adapter — backed by the portal-tenant\n * /api/enrollment_packs endpoint. Used by the playlist editor's content\n * picker. */\n enrollmentPacksAdapter: ContentEnrollmentPacksApi;\n /** Media products adapter for tagging products on media. */\n mediaProductsAdapter: ContentMediaProductsApi;\n}\n\nconst ContentContext = createContext<PortalContentContext | null>(null);\n\nexport function usePortalContentContext(): PortalContentContext {\n const ctx = use(ContentContext);\n if (!ctx) {\n throw new Error(\n \"usePortalContentContext must be used within a <PortalContentApiProvider>\",\n );\n }\n return ctx;\n}\n\n/**\n * Provides all content-domain adapters (media, playlists, shares,\n * fileResources, productMedia) via ShareablesApiProvider, plus extra\n * context values available through usePortalContentContext().\n *\n * **Required ancestor:** `<PortalProductsApiProvider>` must appear above\n * this in the tree — it supplies the `PortalProductsApi` consumed via\n * `usePortalProductsApi()` for product-media bridging.\n */\nexport function PortalContentApiProvider({\n children,\n}: {\n children: ReactNode;\n}): ReactElement {\n const client = usePortalTenantClient();\n const productsApi = usePortalProductsApi();\n\n const contentApi = useMemo(\n () => createPortalContentDomainApiAdapter(client, productsApi),\n [client, productsApi],\n );\n\n const playlistsAdapter = useMemo(\n () => createPortalContentPlaylistsAdapter(client),\n [client],\n );\n\n const pagesAdapter = useMemo(\n () => createPortalContentPagesAdapter(client),\n [client],\n );\n\n const enrollmentPacksAdapter = useMemo(\n () => createPortalContentEnrollmentPacksAdapter(client),\n [client],\n );\n\n const mediaProductsAdapter = useMemo(\n () => createPortalTenantMediaProductsAdapter(client),\n [client],\n );\n\n const filePickerApi = useMemo(\n () => createFilePickerApiAdapter(client),\n [client],\n );\n\n const ctx = useMemo(\n () => ({\n productsApi,\n playlistsAdapter,\n pagesAdapter,\n enrollmentPacksAdapter,\n mediaProductsAdapter,\n }),\n [\n productsApi,\n playlistsAdapter,\n pagesAdapter,\n enrollmentPacksAdapter,\n mediaProductsAdapter,\n ],\n );\n\n return (\n <ContentContext.Provider value={ctx}>\n <ShareablesApiProvider value={contentApi}>\n <FilePickerApiProvider value={filePickerApi}>\n {children}\n </FilePickerApiProvider>\n </ShareablesApiProvider>\n </ContentContext.Provider>\n );\n}\n","export const shareablesEn = {\n // Common\n common_save: \"Save\",\n common_cancel: \"Cancel\",\n common_delete: \"Delete\",\n common_deleting: \"Deleting...\",\n common_edit: \"Edit\",\n common_done: \"Done\",\n common_on: \"On\",\n common_off: \"Off\",\n common_replace: \"Replace\",\n common_remove: \"Remove\",\n common_removing: \"Removing...\",\n common_add: \"Add\",\n common_adding: \"Adding...\",\n common_added: \"Added\",\n common_untitled: \"Untitled\",\n common_loading: \"Loading...\",\n common_na: \"N/A\",\n common_all: \"All\",\n common_mine: \"Mine\",\n common_company: \"Company\",\n common_product: \"Product\",\n common_enrollment: \"Enrollment\",\n common_enrollment_pack: \"Enrollment Pack\",\n enrollment_pack_fallback_name: \"Enrollment Pack #{{id}}\",\n common_page: \"Page\",\n common_unknown: \"Unknown\",\n common_title_label: \"Title\",\n common_description_label: \"Description\",\n common_start_writing_placeholder: \"Start writing...\",\n common_read_more: \"Read more\",\n common_read_less: \"Read less\",\n common_not_found_default: \"Not found or failed to load.\",\n common_load_error_default: \"Failed to load. Please try again.\",\n common_error_prefix: \"Error: \",\n common_fill_required_fields: \"Please fill out all required fields\",\n common_select_all: \"Select All\",\n common_deselect_all: \"Deselect All\",\n common_selected_count: \"{{count}} selected\",\n common_favorite: \"Favorite\",\n common_unfavorite: \"Unfavorite\",\n common_cancel_selection_aria: \"Cancel selection\",\n common_more_options_aria: \"More options\",\n common_list_view: \"List view\",\n common_grid_view: \"Grid view\",\n common_site_hostname_fallback: \"your-site.com\",\n\n // Sort options\n sort_newest: \"Newest\",\n sort_oldest: \"Oldest\",\n sort_newest_first: \"Newest first\",\n sort_name_asc: \"Name (A-Z)\",\n sort_name_desc: \"Name (Z-A)\",\n sort_title_asc: \"Title (A-Z)\",\n sort_title_desc: \"Title (Z-A)\",\n sort_date_newest: \"Date Created (Newest)\",\n sort_date_oldest: \"Date Created (Oldest)\",\n sort_price_asc: \"Price: Low to High\",\n sort_price_desc: \"Price: High to Low\",\n\n // Media\n media_breadcrumb: \"Media\",\n media_heading: \"Media\",\n media_new_title: \"New Media\",\n media_create_breadcrumb: \"New Media\",\n media_type_image: \"Image\",\n media_type_video: \"Video\",\n media_type_pdf: \"PDF\",\n media_type_default: \"Media\",\n media_create_success: \"Media created successfully\",\n media_create_error: \"Failed to create media: {{message}}\",\n media_save_success: \"Media saved successfully\",\n media_save_error: \"Failed to save: {{message}}\",\n media_delete_success: \"Media deleted\",\n media_delete_error: \"Failed to delete: {{message}}\",\n media_title_required: \"Title is required\",\n media_file_required: \"Please select a file\",\n media_not_found: \"Media not found or failed to load.\",\n media_select_button: \"Select Media\",\n media_replace_button: \"Replace Media\",\n media_add_button: \"Add Media\",\n media_upload_placeholder:\n \"No media uploaded. Click to upload an image, video, or PDF.\",\n media_details_heading: \"Media Details\",\n media_title_placeholder: \"Enter media title\",\n media_cta_button_label: \"CTA Button: \",\n media_thumbnail_label: \"Thumbnail\",\n media_thumbnail_alt: \"Thumbnail\",\n media_video_thumbnail_alt: \"Video thumbnail\",\n media_no_thumbnail: \"No thumbnail set\",\n media_pending_save: \"Pending — save to apply\",\n media_select_new_image: \"Select New Image\",\n media_thumbnail_capture_unavailable:\n \"Thumbnail capture is not available in this context\",\n media_thumbnail_upload_error: \"Failed to upload thumbnail\",\n media_no_media_available: \"No media available\",\n media_actions_aria: \"Media actions\",\n media_my_media_tab: \"My Media\",\n media_my_media_badge: \"My Media\",\n media_search_placeholder: \"Search media...\",\n media_filter_all_types: \"All types\",\n media_filter_images: \"Images\",\n media_filter_videos: \"Videos\",\n media_filter_pdfs: \"PDFs\",\n media_product_carousel_count: \"{{count}} ready-to-share assets\",\n media_product_carousel_description:\n \"Jump into product-led kits when someone asks what to buy.\",\n media_product_carousel_kit_title: \"{{title}} kit\",\n media_product_carousel_next: \"Next product kit\",\n media_product_carousel_previous: \"Previous product kit\",\n media_product_carousel_title: \"Sharables by product\",\n media_empty_default: \"No media available.\",\n media_delete_dialog_title: \"Delete Media\",\n media_delete_dialog_description:\n \"Are you sure you want to delete {{title}}? This action cannot be undone.\",\n media_delete_confirm_title: \"Delete this media?\",\n media_delete_confirm_description:\n \"This removes the item from your media library. Shared links that point to it will stop working.\",\n media_frame_capture_error:\n \"Couldn't capture the video frame. Please try again.\",\n media_select_from_video_frame: \"Select from video frame\",\n media_select_video_frame: \"Select Video Frame\",\n media_select_video_frame_title: \"Select Video Frame\",\n media_capture_frame: \"Capture Frame\",\n media_tagged_products_heading: \"Tagged Products\",\n media_no_products_tagged: \"No products tagged yet.\",\n media_add_product_button: \"Add Product\",\n media_add_products_button: \"Add Products\",\n media_products_selected_count: \"{{current}} of {{max}} products selected\",\n media_products_country_note:\n \"Products will only display in available countries.\",\n media_product_fallback_name: \"Product #{{id}}\",\n media_max_products_reached: \"Maximum {{max}} products reached\",\n media_select_products_title: \"Select Products to Tag\",\n media_products_selected_ratio: \"({{current}}/{{max}} selected)\",\n media_max_products_warning:\n \"You have reached the maximum limit of {{max}} products.\",\n media_limit_reached: \"Limit reached\",\n\n // CTA\n cta_dialog_title: \"CTA Button\",\n cta_dialog_description:\n \"Configure the call-to-action button that appears with your media.\",\n cta_enable_toggle_label: \"Enable call-to-action button\",\n cta_action_type_label: \"Action Type\",\n cta_type_placeholder: \"Select type\",\n cta_type_page: \"Page\",\n cta_type_cart: \"Cart\",\n cta_type_email: \"Email\",\n cta_type_phone: \"Phone\",\n cta_button_label: \"Button Label\",\n cta_default_button_text: \"Learn More\",\n cta_url_label: \"URL\",\n cta_url_placeholder: \"https://example.com\",\n\n // SEO\n seo_heading: \"SEO And Link Sharing\",\n seo_title_label: \"SEO Title\",\n seo_title_placeholder: \"Page title for search engines\",\n seo_description_label: \"SEO Description\",\n seo_description_placeholder: \"Description for search engines\",\n seo_block_crawlers_label: \"Block Crawlers\",\n seo_block_crawlers_description: \"Prevent search engines from indexing\",\n seo_block_crawlers_aria: \"Block search engine crawlers\",\n seo_preview_title_fallback: \"Your page title\",\n seo_preview_url_fallback: \"yoursite.com/media/...\",\n\n // Playlists\n playlist_breadcrumb: \"Playlists\",\n playlist_breadcrumb_fallback: \"Playlist\",\n playlist_create_breadcrumb: \"New Playlist\",\n playlist_edit_breadcrumb: \"Edit Playlist\",\n playlist_badge_label: \"Playlist\",\n playlist_create_success: \"Playlist created successfully\",\n playlist_create_error: \"Failed to create playlist\",\n playlist_update_success: \"Playlist updated successfully\",\n playlist_update_error: \"Failed to update playlist\",\n playlist_delete_success: \"Playlist deleted\",\n playlist_delete_success_full: \"Playlist deleted successfully\",\n playlist_delete_error: \"Failed to delete playlist\",\n playlist_not_found: \"Playlist not found or failed to load.\",\n playlist_create_items_partial_error:\n \"Playlist created but some items failed to add\",\n playlist_favorite_error: \"Failed to update favorite\",\n playlist_favorite_added: \"Added to favorites\",\n playlist_favorite_removed: \"Removed from favorites\",\n playlist_my_playlists_tab: \"My Playlists\",\n playlist_search_placeholder: \"Search playlists...\",\n playlist_create_button: \"Create Playlist\",\n playlist_empty_default: \"There are no playlists available at the moment.\",\n playlist_untitled: \"Untitled Playlist\",\n playlist_item_count_one: \"{{count}} item\",\n playlist_item_count_other: \"{{count}} items\",\n playlist_select_aria: \"Select {{title}}\",\n playlist_actions_aria: \"Playlist actions\",\n playlist_delete_confirm_title: \"Delete this playlist?\",\n playlist_delete_confirm_description:\n \"This removes the playlist from your library. Shared links that point to it will stop working.\",\n playlist_form_heading: \"Playlist\",\n playlist_form_description: \"Name your playlist and add a short description.\",\n playlist_name_label: \"Name *\",\n playlist_name_placeholder: \"Playlist name\",\n playlist_description_placeholder: \"Describe this playlist...\",\n playlist_items_heading: \"Playlist Items\",\n playlist_items_description:\n \"Manage the media and pages in your playlist. At least one is required.\",\n playlist_tagged_products_heading: \"Tagged Products\",\n playlist_tagged_products_description:\n \"Manage the products and enrollments in your playlist. These items will show as recommended items in the cart.\",\n playlist_add_item_button: \"Add Item\",\n playlist_add_item_success: \"Item added to playlist successfully\",\n playlist_add_item_error: \"Failed to add item to playlist\",\n playlist_remove_item_success: \"Item removed from playlist successfully\",\n playlist_remove_item_error: \"Failed to remove item from playlist\",\n playlist_reorder_error: \"Failed to save new item order\",\n playlist_no_items_selected: \"No items selected\",\n playlist_item_already_exists: \"This item is already in the playlist\",\n playlist_delete_item: \"Delete Item\",\n playlist_table_order: \"Order\",\n playlist_table_item: \"Item\",\n playlist_table_type: \"Type\",\n playlist_table_actions: \"Actions\",\n playlist_preview_heading: \"Preview\",\n playlist_og_title_fallback: \"Playlist title\",\n playlist_og_description_fallback:\n \"Description shown when this playlist is shared on social platforms.\",\n playlist_no_other_playlists: \"No Other Playlists\",\n playlist_no_other_playlists_description:\n \"There are no other playlists available\",\n playlist_view_link: \"View playlist ->\",\n playlist_other_playlists_tab: \"Other Playlists\",\n playlist_no_items: \"No Items\",\n playlist_no_items_description: \"This playlist doesn't have any items yet\",\n playlist_items_in_playlist_count: \"Items in playlist ({{count}})\",\n\n // Pages\n pages_breadcrumb: \"Pages\",\n pages_breadcrumb_fallback: \"Page\",\n pages_badge_label: \"Page\",\n pages_load_error: \"Failed to load pages. Please try again.\",\n pages_search_no_results:\n 'No pages match \"{{search}}\". Try a different search term.',\n pages_empty_default: \"No pages available.\",\n pages_search_placeholder: \"Search pages...\",\n pages_fallback_name: \"Page #{{id}}\",\n pages_untitled: \"Untitled Page\",\n pdf_previous_page_aria: \"Previous page\",\n pdf_next_page_aria: \"Next page\",\n pages_status_published: \"Published\",\n pages_status_unpublished: \"Unpublished\",\n pages_not_found: \"Page not found or failed to load.\",\n\n // Products\n products_breadcrumb: \"Products\",\n products_breadcrumb_fallback: \"Product\",\n products_load_error: \"Failed to load products. Please try again.\",\n products_load_more_error: \"Failed to load more products.\",\n products_add_error: \"Failed to add product. Please try again.\",\n products_remove_error: \"Failed to remove product. Please try again.\",\n products_search_placeholder: \"Search products...\",\n products_search_no_results: \"No products found matching your search.\",\n products_search_start_typing: \"Start typing to search for products.\",\n products_empty_default: \"No products available.\",\n products_not_found: \"Product not found or failed to load.\",\n products_no_image: \"No Product Image\",\n products_no_media: \"This product does not have any associated media\",\n products_price_label: \"Price\",\n products_related_sharables: \"Related Sharables\",\n products_asset_count: \"{{count}} assets\",\n\n // Files\n files_breadcrumb: \"Files\",\n files_load_error: \"Failed to load files. Please try again.\",\n files_search_no_results:\n 'No files match \"{{search}}\". Try a different search term.',\n files_empty_default: \"No files available.\",\n files_search_placeholder: \"Search files...\",\n files_untitled: \"Untitled File\",\n files_type_default: \"File\",\n files_size_b: \"B\",\n files_size_kb: \"KB\",\n files_size_mb: \"MB\",\n files_size_gb: \"GB\",\n\n // Share\n share_download_asset: \"Download Asset\",\n share_download_no_asset: \"No downloadable asset available\",\n share_link_copied: \"Share link copied to clipboard!\",\n share_link_copy_error: \"Failed to copy link to clipboard\",\n share_link_not_available: \"Share link not available yet. Please wait...\",\n share_social_description: \"Check out this {{type}}: {{title}}\",\n share_mysite_success: \"Shared to MySite\",\n share_mysite_error: \"Failed to share to MySite\",\n share_unique_link_heading: \"Share Your Unique Link\",\n open_image_viewer: \"Open image viewer\",\n open_image_viewer_for: \"Open image viewer: {{title}}\",\n close_image_viewer: \"Close image viewer\",\n image_viewer_description: \"Share image viewer\",\n image_unavailable: \"Image unavailable\",\n open_media_preview: \"Open media preview\",\n close_media_preview: \"Close media preview\",\n pdf_page_number_aria: \"PDF page number\",\n share_qr_code_alt: \"QR Code for share link\",\n share_qr_code_default_alt: \"QR Code\",\n share_qr_code_load_error: \"QR code failed to load\",\n share_mysite_button: \"MySite\",\n share_mysite_preview_title: \"MySite Preview\",\n share_button: \"Share\",\n share_generating_link: \"Generating link...\",\n share_loading_media: \"Loading media...\",\n share_media_load_error: \"Failed to load media\",\n share_analytics_coming_soon: \"Analytics Coming Soon\",\n share_analytics_description: \"View engagement metrics and performance data\",\n share_type_product: \"product\",\n share_type_media: \"media\",\n share_type_enrollment_pack: \"enrollment pack\",\n share_type_site: \"site\",\n share_type_library: \"library\",\n share_no_marketing_assets: \"No Marketing Assets\",\n share_no_associated_media:\n \"This {{label}} does not have any associated media\",\n share_related_sharables_count: \"Related Sharables ({{count}})\",\n share_no_tab_items_found: \"No {{tab}} found\",\n share_no_items_to_display: \"No items to display\",\n share_click_to_find_assets: \"Click to find shareable assets\",\n share_click_to_share_video: \"Click to share this video\",\n share_click_to_share_asset: \"Click to share this asset\",\n share_no_tagged_products: \"No Tagged Products\",\n share_no_tagged_products_description:\n \"No products are tagged in this playlist\",\n share_tagged_products_count: \"Tagged Products ({{count}})\",\n\n // Owner filter\n common_filter_search_no_results:\n 'No {{entityName}} match \"{{searchTerm}}\" with the current filters. Try a different search term or switch to \"All\".',\n common_search_no_results:\n 'No {{entityName}} match \"{{searchTerm}}\". Try a different search term.',\n common_filter_no_results:\n \"No matching {{entityName}} for the current filters.\",\n\n // Owner filter\n common_empty_default: \"Nothing available at the moment.\",\n playlist_title_required: \"Title is required\",\n media_alt_fallback: \"Media\",\n\n // Social sharing\n share_opening_facebook: \"Opening Facebook share dialog...\",\n share_opening_x: \"Opening X share dialog...\",\n share_opening_linkedin: \"Opening LinkedIn share dialog...\",\n share_copied_instagram:\n \"Link copied! Opening Instagram and paste link in bio or post!.\",\n share_copied_tiktok: \"Link copied! Opening TikTok and paste in your link!\",\n share_failed: \"Failed to share on {{platform}}. Please try again.\",\n\n // PDF / media fallbacks\n pdf_document_title: \"PDF document\",\n media_edit_add_product_failed: \"Failed to add product: {{message}}\",\n media_edit_remove_product_failed: \"Failed to remove product: {{message}}\",\n error_unknown: \"Unknown error\",\n media_edit_seo_preview_alt: \"SEO preview\",\n file_type_image_fallback: \"image\",\n\n // Modal\n modal_asset_details: \"Asset details\",\n\n // Owner filter fallback messages\n filter_empty_search_filtered:\n 'No {{entityName}} match \"{{searchTerm}}\" with the current filters. Try a different search term or switch to \"All\".',\n filter_empty_search:\n 'No {{entityName}} match \"{{searchTerm}}\". Try a different search term.',\n filter_empty_filtered: \"No matching {{entityName}} for the current filters.\",\n filter_empty_default: \"Nothing available at the moment.\",\n\n // Rich text editor\n editor_bold: \"Bold\",\n editor_italic: \"Italic\",\n editor_underline: \"Underline\",\n editor_align_left: \"Align left\",\n editor_align_center: \"Align center\",\n editor_align_right: \"Align right\",\n editor_justify: \"Justify\",\n editor_bullet_list: \"Bullet list\",\n editor_ordered_list: \"Ordered list\",\n} as const satisfies Record<string, string>;\n\nexport type ShareablesDict = typeof shareablesEn;\n","import {\n createDomainTranslations,\n type DomainTranslations,\n} from \"@fluid-app/i18n/translations\";\nimport { createStaticDictAdapter } from \"@fluid-app/i18n/static-dict-adapter\";\nimport type { TranslationApi } from \"@fluid-app/i18n/translation-api\";\nimport { shareablesEn, type ShareablesDict } from \"./translation-dictionary\";\n\nexport const shareablesDomain: DomainTranslations<ShareablesDict> =\n createDomainTranslations<ShareablesDict>({\n fallback: shareablesEn,\n loaders: {\n ar: () =>\n import(\"./locale/ar.json\").then(\n (m): ShareablesDict => m.default as ShareablesDict,\n ),\n bg: () =>\n import(\"./locale/bg.json\").then(\n (m): ShareablesDict => m.default as ShareablesDict,\n ),\n bn: () =>\n import(\"./locale/bn.json\").then(\n (m): ShareablesDict => m.default as ShareablesDict,\n ),\n cs: () =>\n import(\"./locale/cs.json\").then(\n (m): ShareablesDict => m.default as ShareablesDict,\n ),\n da: () =>\n import(\"./locale/da.json\").then(\n (m): ShareablesDict => m.default as ShareablesDict,\n ),\n de: () =>\n import(\"./locale/de.json\").then(\n (m): ShareablesDict => m.default as ShareablesDict,\n ),\n el: () =>\n import(\"./locale/el.json\").then(\n (m): ShareablesDict => m.default as ShareablesDict,\n ),\n es: () =>\n import(\"./locale/es.json\").then(\n (m): ShareablesDict => m.default as ShareablesDict,\n ),\n fi: () =>\n import(\"./locale/fi.json\").then(\n (m): ShareablesDict => m.default as ShareablesDict,\n ),\n fr: () =>\n import(\"./locale/fr.json\").then(\n (m): ShareablesDict => m.default as ShareablesDict,\n ),\n he: () =>\n import(\"./locale/he.json\").then(\n (m): ShareablesDict => m.default as ShareablesDict,\n ),\n hi: () =>\n import(\"./locale/hi.json\").then(\n (m): ShareablesDict => m.default as ShareablesDict,\n ),\n hr: () =>\n import(\"./locale/hr.json\").then(\n (m): ShareablesDict => m.default as ShareablesDict,\n ),\n hu: () =>\n import(\"./locale/hu.json\").then(\n (m): ShareablesDict => m.default as ShareablesDict,\n ),\n id: () =>\n import(\"./locale/id.json\").then(\n (m): ShareablesDict => m.default as ShareablesDict,\n ),\n it: () =>\n import(\"./locale/it.json\").then(\n (m): ShareablesDict => m.default as ShareablesDict,\n ),\n ja: () =>\n import(\"./locale/ja.json\").then(\n (m): ShareablesDict => m.default as ShareablesDict,\n ),\n ko: () =>\n import(\"./locale/ko.json\").then(\n (m): ShareablesDict => m.default as ShareablesDict,\n ),\n ms: () =>\n import(\"./locale/ms.json\").then(\n (m): ShareablesDict => m.default as ShareablesDict,\n ),\n nl: () =>\n import(\"./locale/nl.json\").then(\n (m): ShareablesDict => m.default as ShareablesDict,\n ),\n no: () =>\n import(\"./locale/no.json\").then(\n (m): ShareablesDict => m.default as ShareablesDict,\n ),\n pl: () =>\n import(\"./locale/pl.json\").then(\n (m): ShareablesDict => m.default as ShareablesDict,\n ),\n pt: () =>\n import(\"./locale/pt.json\").then(\n (m): ShareablesDict => m.default as ShareablesDict,\n ),\n ro: () =>\n import(\"./locale/ro.json\").then(\n (m): ShareablesDict => m.default as ShareablesDict,\n ),\n ru: () =>\n import(\"./locale/ru.json\").then(\n (m): ShareablesDict => m.default as ShareablesDict,\n ),\n sk: () =>\n import(\"./locale/sk.json\").then(\n (m): ShareablesDict => m.default as ShareablesDict,\n ),\n sv: () =>\n import(\"./locale/sv.json\").then(\n (m): ShareablesDict => m.default as ShareablesDict,\n ),\n th: () =>\n import(\"./locale/th.json\").then(\n (m): ShareablesDict => m.default as ShareablesDict,\n ),\n tl: () =>\n import(\"./locale/tl.json\").then(\n (m): ShareablesDict => m.default as ShareablesDict,\n ),\n tr: () =>\n import(\"./locale/tr.json\").then(\n (m): ShareablesDict => m.default as ShareablesDict,\n ),\n uk: () =>\n import(\"./locale/uk.json\").then(\n (m): ShareablesDict => m.default as ShareablesDict,\n ),\n vi: () =>\n import(\"./locale/vi.json\").then(\n (m): ShareablesDict => m.default as ShareablesDict,\n ),\n zh_CN: () =>\n import(\"./locale/zh_CN.json\").then(\n (m): ShareablesDict => m.default as ShareablesDict,\n ),\n zh_TW: () =>\n import(\"./locale/zh_TW.json\").then(\n (m): ShareablesDict => m.default as ShareablesDict,\n ),\n },\n });\n\nexport function createShareablesTranslationAdapter(\n locale: string,\n dict: ShareablesDict,\n): TranslationApi<ShareablesDict> {\n return createStaticDictAdapter(locale, dict);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"translation-adapter-DObP7Ra9.mjs","names":["portalTenantContent.dam_query","portalTenantContent.dam_assets_destroy","portalTenantContent.dam_assets_discard","portalTenantContent.dam_asset_paths_create","portalTenantContent.media_list","portalTenantContent.media_create","portalTenantContent.media_show","portalTenantContent.media_update","portalTenantContent.media_destroy","portalTenantContent.media_products_list","portalTenantContent.media_products_add","portalTenantContent.media_products_remove","portalTenantContent.playlists_list","portalTenantContent.playlists_create","portalTenantContent.playlists_show","portalTenantContent.playlists_update","portalTenantContent.playlists_destroy","portalTenantContent.playlists_items_list","portalTenantContent.playlists_items_add","portalTenantContent.playlists_items_remove","portalTenantContent.playlists_items_reorder","portalTenantContent.shares_list","portalTenantContent.shares_create","portalTenantContent.pages_list","portalTenantContent.pages_show","portalTenant.enrollment_packs_list","portalTenant.enrollment_packs_show","portalTenantContent.dam_assets_list","portalTenantContent.dam_assets_create","portalTenantContent.dam_asset_paths_list","portalTenantContent.dam_asset_paths_create","portalTenantContent.content_media_by_visits","portalTenantContent.content_media_by_shares","portalTenantContent.content_playlists_by_visits","portalTenantContent.content_playlists_by_shares","portalTenantContent.content_pages_by_visits","portalTenantContent.content_pages_by_shares"],"sources":["../../../api-clients/portal-tenant/src/namespaces/portal_tenant.ts","../../../api-clients/portal-tenant-content/src/namespaces/portal_tenant_content.ts","../../../shareables/core/src/context.tsx","../../../shareables/core/src/hooks/use-product-media-counts.ts","../../../shareables/core/src/hooks/use-media-mutations.ts","../../../shareables/core/src/utils.ts","../../../shareables/core/src/hooks/use-playlist-mutations.ts","../../../file-picker/core/src/file-picker-api-context.ts","../../../file-picker/core/src/schemas/dam.ts","../../../file-picker/api-client/src/api/url-proxy.ts","../src/adapters/file-picker-api-adapter.ts","../src/adapters/content-api-adapter.ts","../src/content/PortalContentApiProvider.tsx","../../../shareables/core/src/translation-dictionary.ts","../../../shareables/core/src/translation-adapter.ts"],"sourcesContent":["/**\n * Generated API client functions for portal_tenant\n *\n * DO NOT EDIT THIS FILE DIRECTLY\n * This file is auto-generated. To update:\n * 1. Update the OpenAPI spec file\n * 2. Run: pnpm generate\n */\n\nimport type { FetchClient } from \"../lib/fetch-client\";\nimport type { operations } from \"../generated/portal-tenant\";\n\n// ============================================================================\n// address_fields\n// ============================================================================\n\n/**\n * Get address fields for a country\n * Returns the address field configuration for a given country code, including field names, localized labels, and whether each field is required. Use the optional language_iso query parameter to receive labels in a specific locale; defaults to English.\n *\n * @param client - Fetch client instance\n * @param country_code - country_code\n * @param [params] - params\n */\nexport async function address_fields_show(\n client: FetchClient,\n country_code: string | number,\n params?: operations[\"address_fields_show\"][\"parameters\"][\"query\"],\n): Promise<\n operations[\"address_fields_show\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/countries/${country_code}/address_fields`, params);\n}\n\n// ============================================================================\n// account\n// ============================================================================\n\n/**\n * Get current account\n * Returns the authenticated member's account profile and company context. This is the primary endpoint the SPA calls to check auth status and display user information.\n *\n * @param client - Fetch client instance\n \n */\nexport async function account_show(\n client: FetchClient,\n): Promise<\n operations[\"account_show\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/account`);\n}\n\n/**\n * Update current account\n * Updates the authenticated member's profile fields such as name, phone, bio, avatar, and social links.\n *\n * @param client - Fetch client instance\n * @param body - body\n */\nexport async function account_update(\n client: FetchClient,\n body: operations[\"account_update\"][\"requestBody\"][\"content\"][\"application/json\"],\n): Promise<\n operations[\"account_update\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.patch(`/api/account`, body);\n}\n\n// ============================================================================\n// store\n// ============================================================================\n\n/**\n * Get store branding and feature flags\n * Returns the tenant company's store branding (logo, icon, app store URLs) and feature flags such as whether subscription bundling is enabled.\n *\n * @param client - Fetch client instance\n \n */\nexport async function store_show(\n client: FetchClient,\n): Promise<\n operations[\"store_show\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/store`);\n}\n\n// ============================================================================\n// app\n// ============================================================================\n\n/**\n * Get the app manifest\n * Returns the rendered manifest for the tenant company's active FluidOS definition, matched against the current user's country, rank, and roles.\n *\n * @param client - Fetch client instance\n \n */\nexport async function app_manifest_show(\n client: FetchClient,\n): Promise<\n operations[\"app_manifest_show\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/app/manifest`);\n}\n\n/**\n * List widget packages\n * Returns approved active portal widget packages for the tenant company. Company-owned packages are returned before approved packages from active installed droplets so the portal shell can load widgets in order.\n *\n * @param client - Fetch client instance\n \n */\nexport async function app_widget_packages_list(\n client: FetchClient,\n): Promise<\n operations[\"app_widget_packages_list\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/app/widget-packages`);\n}\n\n// ============================================================================\n// calendar_events\n// ============================================================================\n\n/**\n * List calendar events\n * Returns a paginated list of upcoming and ongoing calendar events for the tenant company, optionally filtered by the authenticated member's country when one is set.\n *\n * @param client - Fetch client instance\n * @param [params] - params\n */\nexport async function calendar_events_list(\n client: FetchClient,\n params?: operations[\"calendar_events_list\"][\"parameters\"][\"query\"],\n): Promise<\n operations[\"calendar_events_list\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/calendar/events`, params);\n}\n\n// ============================================================================\n// activities\n// ============================================================================\n\n/**\n * List recent activities\n * Returns a paginated list of recent activities for the authenticated member, ordered by most recent first. Each activity includes pre-computed user_name and target_name fields ready for direct rendering by the portal SPA. When `days_ago` is provided, the response is restricted to that rolling window and `meta.pagination.total_count` is populated.\n *\n * @param client - Fetch client instance\n * @param [params] - params\n */\nexport async function activities_list(\n client: FetchClient,\n params?: operations[\"activities_list\"][\"parameters\"][\"query\"],\n): Promise<\n operations[\"activities_list\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/activities`, params);\n}\n\n// ============================================================================\n// catch_ups\n// ============================================================================\n\n/**\n * List catch-up suggestions\n * Returns a paginated list of catch-up suggestions for the authenticated member. Limited to suggestions with at least one pending action that have not expired.\n *\n * @param client - Fetch client instance\n * @param [params] - params\n */\nexport async function catch_ups_list(\n client: FetchClient,\n params?: operations[\"catch_ups_list\"][\"parameters\"][\"query\"],\n): Promise<\n operations[\"catch_ups_list\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/catch_ups`, params);\n}\n\n/**\n * Get a catch-up suggestion\n * Returns a single catch-up suggestion by id, scoped to the authenticated member. Returns 404 when the catch-up belongs to a different member.\n *\n * @param client - Fetch client instance\n * @param id - id\n */\nexport async function catch_ups_show(\n client: FetchClient,\n id: string | number,\n): Promise<\n operations[\"catch_ups_show\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/catch_ups/${id}`);\n}\n\n// ============================================================================\n// orders\n// ============================================================================\n\n/**\n * List orders\n * Returns a paginated list of orders placed through the tenant company, optionally filtered by status.\n *\n * @param client - Fetch client instance\n * @param [params] - params\n */\nexport async function orders_list(\n client: FetchClient,\n params?: operations[\"orders_list\"][\"parameters\"][\"query\"],\n): Promise<\n operations[\"orders_list\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/orders`, params);\n}\n\n/**\n * Get an order\n * Returns a single order by token with its line items.\n *\n * @param client - Fetch client instance\n * @param token - token\n */\nexport async function orders_show(\n client: FetchClient,\n token: string | number,\n): Promise<\n operations[\"orders_show\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/orders/${token}`);\n}\n\n// ============================================================================\n// products\n// ============================================================================\n\n/**\n * List products\n * Returns a paginated list of products available in the tenant company's catalog. Supports sorting and filtering by title, product type, collection, and stock availability.\n *\n * @param client - Fetch client instance\n * @param [params] - params\n */\nexport async function products_list(\n client: FetchClient,\n params?: operations[\"products_list\"][\"parameters\"][\"query\"],\n): Promise<\n operations[\"products_list\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/products`, params);\n}\n\n/**\n * Get a product\n * Returns a single product by ID with its variants.\n *\n * @param client - Fetch client instance\n * @param id - id\n */\nexport async function products_show(\n client: FetchClient,\n id: string | number,\n): Promise<\n operations[\"products_show\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/products/${id}`);\n}\n\n/**\n * Search products\n * Searches the tenant company's product catalog by keyword, returning paginated results.\n *\n * @param client - Fetch client instance\n * @param [params] - params\n */\nexport async function products_search(\n client: FetchClient,\n params?: operations[\"products_search\"][\"parameters\"][\"query\"],\n): Promise<\n operations[\"products_search\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/products/search`, params);\n}\n\n/**\n * List product media\n * Returns all media (images, videos) attached to a product.\n *\n * @param client - Fetch client instance\n * @param id - id\n */\nexport async function products_media_list(\n client: FetchClient,\n id: string | number,\n): Promise<\n operations[\"products_media_list\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/products/${id}/media`);\n}\n\n// ============================================================================\n// enrollment_packs\n// ============================================================================\n\n/**\n * List enrollment packs\n * Returns a paginated list of active, non-discarded enrollment packs scoped to the current portal tenant's company. Each pack carries an empty `products` array — fetch a single pack via `/api/enrollment_packs/{id}` to load its visible products.\n *\n * @param client - Fetch client instance\n * @param [params] - params\n */\nexport async function enrollment_packs_list(\n client: FetchClient,\n params?: operations[\"enrollment_packs_list\"][\"parameters\"][\"query\"],\n): Promise<\n operations[\"enrollment_packs_list\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/enrollment_packs`, params);\n}\n\n/**\n * Get an enrollment pack\n * Returns a single active, non-discarded enrollment pack scoped to the current portal tenant's company.\n *\n * @param client - Fetch client instance\n * @param id - id\n */\nexport async function enrollment_packs_show(\n client: FetchClient,\n id: string | number,\n): Promise<\n operations[\"enrollment_packs_show\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/enrollment_packs/${id}`);\n}\n\n// ============================================================================\n// subscriptions\n// ============================================================================\n\n/**\n * List subscription bundles\n * Returns the runtime bundle groupings for the authenticated customer's active subscriptions. Bundles are computed at request time by grouping subscriptions that share customer, address (physical only), volume rep, next bill date, and digital flag — they have no persistent id. The response is unpaginated; customers typically have a small number of bundles.\n *\n * @param client - Fetch client instance\n \n */\nexport async function subscription_bundles_list(\n client: FetchClient,\n): Promise<\n operations[\"subscription_bundles_list\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/subscription_bundles`);\n}\n\n/**\n * List subscriptions\n * Returns a paginated list of the member's active and historical subscriptions. Supports filtering by lifecycle state and a free-text search across product and plan names.\n *\n * @param client - Fetch client instance\n * @param [params] - params\n */\nexport async function subscriptions_list(\n client: FetchClient,\n params?: operations[\"subscriptions_list\"][\"parameters\"][\"query\"],\n): Promise<\n operations[\"subscriptions_list\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/subscriptions`, params);\n}\n\n/**\n * Get a subscription\n * Returns a single subscription by its token.\n *\n * @param client - Fetch client instance\n * @param token - token\n */\nexport async function subscriptions_show(\n client: FetchClient,\n token: string | number,\n): Promise<\n operations[\"subscriptions_show\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/subscriptions/${token}`);\n}\n\n/**\n * Update a subscription\n * Updates a subscription's default payment method or quantity.\n *\n * @param client - Fetch client instance\n * @param token - token\n * @param body - body\n */\nexport async function subscriptions_update(\n client: FetchClient,\n token: string | number,\n body: operations[\"subscriptions_update\"][\"requestBody\"][\"content\"][\"application/json\"],\n): Promise<\n operations[\"subscriptions_update\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.put(`/api/subscriptions/${token}`, body);\n}\n\n/**\n * List subscription discounts\n * Returns active and historical discount attachments for a visible subscription, newest first.\n *\n * @param client - Fetch client instance\n * @param token - token\n */\nexport async function subscription_discounts_list(\n client: FetchClient,\n token: string | number,\n): Promise<\n operations[\"subscription_discounts_list\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/subscriptions/${token}/discounts`);\n}\n\n/**\n * Attach a subscription discount\n * Attaches an eligible discount to a visible subscription.\n *\n * @param client - Fetch client instance\n * @param token - token\n * @param body - body\n */\nexport async function subscription_discounts_attach(\n client: FetchClient,\n token: string | number,\n body: operations[\"subscription_discounts_attach\"][\"requestBody\"][\"content\"][\"application/json\"],\n): Promise<\n operations[\"subscription_discounts_attach\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.post(`/api/subscriptions/${token}/discounts`, body);\n}\n\n/**\n * Remove a subscription discount\n * Soft-removes a visible subscription discount attachment.\n *\n * @param client - Fetch client instance\n * @param token - token\n * @param id - id\n * @param [body] - body\n */\nexport async function subscription_discounts_remove(\n client: FetchClient,\n token: string | number,\n id: string | number,\n body?: NonNullable<\n operations[\"subscription_discounts_remove\"][\"requestBody\"]\n >[\"content\"][\"application/json\"],\n): Promise<\n operations[\"subscription_discounts_remove\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.delete(`/api/subscriptions/${token}/discounts/${id}`, { body });\n}\n\n/**\n * Pause a subscription\n * Pauses billing on an active subscription. When neither `next_bill_date` nor `number_of_orders` is provided, the subscription is paused indefinitely. Specifying both is rejected.\n *\n * @param client - Fetch client instance\n * @param token - token\n * @param [body] - body\n */\nexport async function subscriptions_pause(\n client: FetchClient,\n token: string | number,\n body?: NonNullable<\n operations[\"subscriptions_pause\"][\"requestBody\"]\n >[\"content\"][\"application/json\"],\n): Promise<\n operations[\"subscriptions_pause\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.post(`/api/subscriptions/${token}/pause`, body);\n}\n\n/**\n * Resume a subscription\n * Resumes billing on a paused subscription or restores normal scheduled billing for an exhausted past-due subscription without charging immediately. Paused subscriptions use the supplied next bill date, or the plan's next date when omitted. Exhausted subscriptions preserve a future bill date; a stale date is moved into the future using the subscription plan cadence.\n *\n * @param client - Fetch client instance\n * @param token - token\n * @param [body] - body\n */\nexport async function subscriptions_resume(\n client: FetchClient,\n token: string | number,\n body?: NonNullable<\n operations[\"subscriptions_resume\"][\"requestBody\"]\n >[\"content\"][\"application/json\"],\n): Promise<\n operations[\"subscriptions_resume\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.post(`/api/subscriptions/${token}/resume`, body);\n}\n\n/**\n * Preview a failed-cycle waiver\n * Returns the authoritative future billing and shipping timestamps that would be restored if the exhausted failed cycle were waived. An ineligible subscription returns 200 with eligible false and null dates.\n *\n * @param client - Fetch client instance\n * @param token - token\n */\nexport async function subscriptions_failed_cycle_waiver_preview(\n client: FetchClient,\n token: string | number,\n): Promise<\n operations[\"subscriptions_failed_cycle_waiver_preview\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/subscriptions/${token}/failed-cycle-waiver`);\n}\n\n/**\n * Skip the exhausted failed cycle\n * Waives the missed billing and shipping cycle without collecting payment and without creating an order or shipment. The missed shipment is skipped. The subscription's original billing and shipping cadence and anchors are preserved, and each stored next date is advanced independently only as needed to reach a future local date.\n *\n * @param client - Fetch client instance\n * @param token - token\n * @param [body] - body\n */\nexport async function subscriptions_failed_cycle_waiver_create(\n client: FetchClient,\n token: string | number,\n body?: NonNullable<\n operations[\"subscriptions_failed_cycle_waiver_create\"][\"requestBody\"]\n >[\"content\"][\"application/json\"],\n): Promise<\n operations[\"subscriptions_failed_cycle_waiver_create\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.post(`/api/subscriptions/${token}/failed-cycle-waiver`, body);\n}\n\n/**\n * Skip next billing cycle\n * Skips the next billing cycle for a subscription without pausing it.\n *\n * @param client - Fetch client instance\n * @param token - token\n */\nexport async function subscriptions_skip(\n client: FetchClient,\n token: string | number,\n): Promise<\n operations[\"subscriptions_skip\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.post(`/api/subscriptions/${token}/skip_next_billing`);\n}\n\n/**\n * Cancel a subscription\n * Cancels an active subscription.\n *\n * @param client - Fetch client instance\n * @param token - token\n */\nexport async function subscriptions_cancel(\n client: FetchClient,\n token: string | number,\n): Promise<\n operations[\"subscriptions_cancel\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.post(`/api/subscriptions/${token}/cancel`);\n}\n\n/**\n * Reactivate a subscription\n * Reactivates a previously cancelled subscription.\n *\n * @param client - Fetch client instance\n * @param token - token\n * @param [body] - body\n */\nexport async function subscriptions_reactivate(\n client: FetchClient,\n token: string | number,\n body?: NonNullable<\n operations[\"subscriptions_reactivate\"][\"requestBody\"]\n >[\"content\"][\"application/json\"],\n): Promise<\n operations[\"subscriptions_reactivate\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.post(`/api/subscriptions/${token}/reactivate`, body);\n}\n\n/**\n * Retry billing on a past-due subscription\n * Queues an immediate retry on a past-due subscription against whatever payment method is currently on file. The customer may retry the saved method directly or update the method before making this request.\n\n\nThe endpoint returns 200 for found subscriptions in normal operation, regardless of status — it is intentionally idempotent so the client can call it unconditionally without first checking status. A 422 can still be returned if the server cannot persist the retry state. Use the response's `queued` field to distinguish the two outcomes:\n\n - `queued: true` — the subscription was past_due and a retry is pending. A rapid duplicate preserves the first `next_retry_at` and does not enqueue another attempt.\n - `queued: false` — the subscription was not past_due and no state change occurred. Treat as a no-op.\n *\n * @param client - Fetch client instance\n * @param token - token\n */\nexport async function subscriptions_retry(\n client: FetchClient,\n token: string | number,\n): Promise<\n operations[\"subscriptions_retry\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.post(`/api/subscriptions/${token}/retry`);\n}\n\n// ============================================================================\n// subscription_bundles\n// ============================================================================\n\n/**\n * Create a subscription bundle\n * Bundles two or more existing subscriptions onto a shared bill date, address, and volume rep. All subscriptions must belong to the authenticated customer. Bundles are not persisted entities — the endpoint aligns each subscription's billing attributes so that they share a runtime grouping key.\n *\n * @param client - Fetch client instance\n * @param body - body\n */\nexport async function subscription_bundles_create(\n client: FetchClient,\n body: operations[\"subscription_bundles_create\"][\"requestBody\"][\"content\"][\"application/json\"],\n): Promise<\n operations[\"subscription_bundles_create\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.post(`/api/subscription_bundles/bundle`, body);\n}\n\n// ============================================================================\n// todos\n// ============================================================================\n\n/**\n * List todos\n * Returns a paginated list of tasks scoped to the authenticated member. Filter by completion state via the `state` query parameter; defaults to `incomplete` for backwards compatibility. Incomplete tasks are ordered by due date ascending (nulls last); completed tasks by completion time descending.\n *\n * @param client - Fetch client instance\n * @param [params] - params\n */\nexport async function todos_list(\n client: FetchClient,\n params?: operations[\"todos_list\"][\"parameters\"][\"query\"],\n): Promise<\n operations[\"todos_list\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/todos`, params);\n}\n\n/**\n * Create a todo\n * Creates a todo owned by the authenticated member. `contact_id` is optional — omit it (or send null) to create a standalone todo not attached to a contact, matching mobile widget parity. When `contact_id` is supplied the caller must own the contact.\n *\n * @param client - Fetch client instance\n * @param body - body\n */\nexport async function todos_create(\n client: FetchClient,\n body: operations[\"todos_create\"][\"requestBody\"][\"content\"][\"application/json\"],\n): Promise<\n operations[\"todos_create\"][\"responses\"][201][\"content\"][\"application/json\"]\n> {\n return client.post(`/api/todos`, body);\n}\n\n/**\n * Update a todo\n * Updates the given todo. Any non-empty subset of `body`, `due_at`, `completed`, and `contact_id` is accepted. Sending `completed: true` stamps `completed_at` with the current time; `false` clears it. A non-null `contact_id` must identify a contact owned by the authenticated user in the portal tenant company; `null` clears it. The existing widget call sending only `{ completed }` continues to work unchanged.\n *\n * @param client - Fetch client instance\n * @param id - id\n * @param body - body\n */\nexport async function todos_update(\n client: FetchClient,\n id: string | number,\n body: operations[\"todos_update\"][\"requestBody\"][\"content\"][\"application/json\"],\n): Promise<\n operations[\"todos_update\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.patch(`/api/todos/${id}`, body);\n}\n\n/**\n * Delete a todo\n * Deletes the given todo. Only the owning member can delete. Deleting a todo not visible to the acting member returns 404 (do not leak existence). Soft vs hard delete follows the Task model's existing destroy semantics.\n *\n * @param client - Fetch client instance\n * @param id - id\n */\nexport async function todos_destroy(\n client: FetchClient,\n id: string | number,\n): Promise<\n operations[\"todos_destroy\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.delete(`/api/todos/${id}`);\n}\n\n// ============================================================================\n// carts\n// ============================================================================\n\n/**\n * Claim a cart\n * Assigns the logged-in member as buyer_rep on an unclaimed FairShare cart. Any portal member (rep or customer) can claim. Returns an error if the cart has already been claimed.\n *\n * @param client - Fetch client instance\n * @param token - token\n */\nexport async function carts_claim(\n client: FetchClient,\n token: string | number,\n): Promise<\n operations[\"carts_claim\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.post(`/api/carts/${token}/claim`);\n}\n\n// ============================================================================\n// product_metrics\n// ============================================================================\n\n/**\n * Top products by direct visits\n * Ranked list of the company's products by total visits to the product page (aggregates metrics_product_visits across all visit sources).\n *\n * @param client - Fetch client instance\n * @param [params] - params\n */\nexport async function product_by_visits(\n client: FetchClient,\n params?: operations[\"product_by_visits\"][\"parameters\"][\"query\"],\n): Promise<\n operations[\"product_by_visits\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/products/by-visits`, params);\n}\n\n/**\n * Top products by share-link visits\n * Ranked list of the company's products by click-throughs on rep share links (aggregates metrics_share_shareable_visits where shareable_type='Product').\n *\n * @param client - Fetch client instance\n * @param [params] - params\n */\nexport async function product_by_shares(\n client: FetchClient,\n params?: operations[\"product_by_shares\"][\"parameters\"][\"query\"],\n): Promise<\n operations[\"product_by_shares\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/products/by-shares`, params);\n}\n\n// ============================================================================\n// enrollment_pack_metrics\n// ============================================================================\n\n/**\n * Top enrollment packs by direct visits\n * Ranked list of the company's enrollment packs by total visits to the pack page (aggregates metrics_enrollment_pack_visits across all visit sources).\n *\n * @param client - Fetch client instance\n * @param [params] - params\n */\nexport async function enrollment_pack_by_visits(\n client: FetchClient,\n params?: operations[\"enrollment_pack_by_visits\"][\"parameters\"][\"query\"],\n): Promise<\n operations[\"enrollment_pack_by_visits\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/enrollment_packs/by-visits`, params);\n}\n\n/**\n * Top enrollment packs by share-link visits\n * Ranked list of the company's enrollment packs by click-throughs on rep share links (aggregates metrics_share_shareable_visits where shareable_type='EnrollmentPack').\n *\n * @param client - Fetch client instance\n * @param [params] - params\n */\nexport async function enrollment_pack_by_shares(\n client: FetchClient,\n params?: operations[\"enrollment_pack_by_shares\"][\"parameters\"][\"query\"],\n): Promise<\n operations[\"enrollment_pack_by_shares\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/enrollment_packs/by-shares`, params);\n}\n","/**\n * Generated API client functions for portal_tenant_content\n *\n * DO NOT EDIT THIS FILE DIRECTLY\n * This file is auto-generated. To update:\n * 1. Update the OpenAPI spec file\n * 2. Run: pnpm generate\n */\n\nimport type { FetchClient } from \"../lib/fetch-client\";\nimport type { operations } from \"../generated/portal-tenant-content\";\n\n// ============================================================================\n// content\n// ============================================================================\n\n/**\n * List active languages for the tenant company\n * Returns active languages enabled for the tenant company, sorted by name. Used by the content/translation editor to populate the language switcher.\n *\n * @param client - Fetch client instance\n * @param [params] - params\n */\nexport async function content_languages_list(\n client: FetchClient,\n params?: operations[\"content_languages_list\"][\"parameters\"][\"query\"],\n): Promise<\n operations[\"content_languages_list\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/content/languages`, params);\n}\n\n/**\n * List media (own uploads and company share media)\n * Returns a paginated list of the member's own uploads and company share media. Training and update media are excluded.\n *\n * @param client - Fetch client instance\n * @param [params] - params\n */\nexport async function media_list(\n client: FetchClient,\n params?: operations[\"media_list\"][\"parameters\"][\"query\"],\n): Promise<\n operations[\"media_list\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/content/media`, params);\n}\n\n/**\n * Create a new media item\n * Creates a new media item record.\n *\n * @param client - Fetch client instance\n * @param body - body\n */\nexport async function media_create(\n client: FetchClient,\n body: operations[\"media_create\"][\"requestBody\"][\"content\"][\"application/json\"],\n): Promise<\n operations[\"media_create\"][\"responses\"][201][\"content\"][\"application/json\"]\n> {\n return client.post(`/api/content/media`, body);\n}\n\n/**\n * Get a specific media item\n * Returns a single media item by ID. When language_iso is provided, translatable fields (title, description, url) are returned for that language with no fallback — empty values indicate an untranslated field.\n *\n * @param client - Fetch client instance\n * @param id - id\n * @param [params] - params\n */\nexport async function media_show(\n client: FetchClient,\n id: string | number,\n params?: operations[\"media_show\"][\"parameters\"][\"query\"],\n): Promise<\n operations[\"media_show\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/content/media/${id}`, params);\n}\n\n/**\n * Update a media item (own uploads only)\n * Updates a media item's title, description, status, url, content_format, thumbnail, CTA, and SEO. When language_iso is provided, translatable fields are written against that language's translation row instead of the default locale.\n *\n * @param client - Fetch client instance\n * @param id - id\n * @param body - body\n * @param [params] - params\n */\nexport async function media_update(\n client: FetchClient,\n id: string | number,\n body: operations[\"media_update\"][\"requestBody\"][\"content\"][\"application/json\"],\n params?: operations[\"media_update\"][\"parameters\"][\"query\"],\n): Promise<\n operations[\"media_update\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.patch(`/api/content/media/${id}`, body, { params });\n}\n\n/**\n * Delete a media item (own uploads only)\n * Removes a media item.\n *\n * @param client - Fetch client instance\n * @param id - id\n */\nexport async function media_destroy(\n client: FetchClient,\n id: string | number,\n): Promise<\n operations[\"media_destroy\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.delete(`/api/content/media/${id}`);\n}\n\n/**\n * List products associated with a media item\n * Returns a paginated list of products associated with a media item.\n *\n * @param client - Fetch client instance\n * @param medium_id - medium_id\n * @param [params] - params\n */\nexport async function media_products_list(\n client: FetchClient,\n medium_id: string | number,\n params?: operations[\"media_products_list\"][\"parameters\"][\"query\"],\n): Promise<\n operations[\"media_products_list\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/content/media/${medium_id}/products`, params);\n}\n\n/**\n * Associate a product with a media item\n * Creates a product association for a media item.\n *\n * @param client - Fetch client instance\n * @param medium_id - medium_id\n * @param body - body\n */\nexport async function media_products_add(\n client: FetchClient,\n medium_id: string | number,\n body: operations[\"media_products_add\"][\"requestBody\"][\"content\"][\"application/json\"],\n): Promise<\n operations[\"media_products_add\"][\"responses\"][201][\"content\"][\"application/json\"]\n> {\n return client.post(`/api/content/media/${medium_id}/products`, body);\n}\n\n/**\n * Remove a product association from a media item\n * Removes a single product association from a media item.\n *\n * @param client - Fetch client instance\n * @param medium_id - medium_id\n * @param id - id\n */\nexport async function media_products_remove(\n client: FetchClient,\n medium_id: string | number,\n id: string | number,\n): Promise<\n operations[\"media_products_remove\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.delete(`/api/content/media/${medium_id}/products/${id}`);\n}\n\n/**\n * List playlists with cursor pagination\n * Returns a paginated list of playlists.\n *\n * @param client - Fetch client instance\n * @param [params] - params\n */\nexport async function playlists_list(\n client: FetchClient,\n params?: operations[\"playlists_list\"][\"parameters\"][\"query\"],\n): Promise<\n operations[\"playlists_list\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/content/playlists`, params);\n}\n\n/**\n * Create a new playlist\n * Creates a new playlist.\n *\n * @param client - Fetch client instance\n * @param body - body\n */\nexport async function playlists_create(\n client: FetchClient,\n body: operations[\"playlists_create\"][\"requestBody\"][\"content\"][\"application/json\"],\n): Promise<\n operations[\"playlists_create\"][\"responses\"][201][\"content\"][\"application/json\"]\n> {\n return client.post(`/api/content/playlists`, body);\n}\n\n/**\n * Get a specific playlist\n * Returns a single playlist by ID.\n *\n * @param client - Fetch client instance\n * @param id - id\n */\nexport async function playlists_show(\n client: FetchClient,\n id: string | number,\n): Promise<\n operations[\"playlists_show\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/content/playlists/${id}`);\n}\n\n/**\n * Update a playlist\n * Updates a playlist's title or metadata.\n *\n * @param client - Fetch client instance\n * @param id - id\n * @param body - body\n */\nexport async function playlists_update(\n client: FetchClient,\n id: string | number,\n body: operations[\"playlists_update\"][\"requestBody\"][\"content\"][\"application/json\"],\n): Promise<\n operations[\"playlists_update\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.patch(`/api/content/playlists/${id}`, body);\n}\n\n/**\n * Delete a playlist\n * Removes a playlist.\n *\n * @param client - Fetch client instance\n * @param id - id\n */\nexport async function playlists_destroy(\n client: FetchClient,\n id: string | number,\n): Promise<\n operations[\"playlists_destroy\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.delete(`/api/content/playlists/${id}`);\n}\n\n/**\n * List items in a playlist\n * Returns a paginated list of items in a playlist.\n *\n * @param client - Fetch client instance\n * @param playlist_id - playlist_id\n * @param [params] - params\n */\nexport async function playlists_items_list(\n client: FetchClient,\n playlist_id: string | number,\n params?: operations[\"playlists_items_list\"][\"parameters\"][\"query\"],\n): Promise<\n operations[\"playlists_items_list\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/content/playlists/${playlist_id}/items`, params);\n}\n\n/**\n * Add an item to a playlist\n * Adds a content item (media, page, product, or enrollment_pack) to a playlist.\n *\n * @param client - Fetch client instance\n * @param playlist_id - playlist_id\n * @param body - body\n */\nexport async function playlists_items_add(\n client: FetchClient,\n playlist_id: string | number,\n body: operations[\"playlists_items_add\"][\"requestBody\"][\"content\"][\"application/json\"],\n): Promise<\n operations[\"playlists_items_add\"][\"responses\"][201][\"content\"][\"application/json\"]\n> {\n return client.post(`/api/content/playlists/${playlist_id}/items`, body);\n}\n\n/**\n * Reorder items in a playlist\n * Sets the order of items in a playlist. Items not included in the payload are not moved. Flips the playlist to manual ordering.\n *\n * @param client - Fetch client instance\n * @param playlist_id - playlist_id\n * @param body - body\n */\nexport async function playlists_items_reorder(\n client: FetchClient,\n playlist_id: string | number,\n body: operations[\"playlists_items_reorder\"][\"requestBody\"][\"content\"][\"application/json\"],\n): Promise<\n operations[\"playlists_items_reorder\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.patch(\n `/api/content/playlists/${playlist_id}/items/reorder`,\n body,\n );\n}\n\n/**\n * Remove an item from a playlist\n * Removes a single item from a playlist.\n *\n * @param client - Fetch client instance\n * @param playlist_id - playlist_id\n * @param id - id\n */\nexport async function playlists_items_remove(\n client: FetchClient,\n playlist_id: string | number,\n id: string | number,\n): Promise<\n operations[\"playlists_items_remove\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.delete(`/api/content/playlists/${playlist_id}/items/${id}`);\n}\n\n/**\n * List pages for the company\n * Returns a paginated list of published pages for the authenticated rep's company. Members have read-only access — there is no create, update, or destroy action for pages in the portal BFF. Response shape matches pages_show (PortalTenant::Api::PageBlueprinter).\n *\n * @param client - Fetch client instance\n * @param [params] - params\n */\nexport async function pages_list(\n client: FetchClient,\n params?: operations[\"pages_list\"][\"parameters\"][\"query\"],\n): Promise<\n operations[\"pages_list\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/content/pages`, params);\n}\n\n/**\n * Get a specific page\n * Returns a single page by ID, scoped to the authenticated rep's company. Response is a lean portal-BFF shape rendered by PortalTenant::Api::PageBlueprinter — not the legacy admin shape. Admin-only fields (html_code, application_theme_template, search_engine_optimizer, open_graph, prompts, etc.) are intentionally omitted.\n *\n * @param client - Fetch client instance\n * @param id - id\n * @param [params] - params\n */\nexport async function pages_show(\n client: FetchClient,\n id: string | number,\n params?: operations[\"pages_show\"][\"parameters\"][\"query\"],\n): Promise<\n operations[\"pages_show\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/content/pages/${id}`, params);\n}\n\n/**\n * List share links for the current user\n * Returns a paginated list of share links.\n *\n * @param client - Fetch client instance\n * @param [params] - params\n */\nexport async function shares_list(\n client: FetchClient,\n params?: operations[\"shares_list\"][\"parameters\"][\"query\"],\n): Promise<\n operations[\"shares_list\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/shares`, params);\n}\n\n/**\n * Create a share link\n * Creates a new share link for content.\n *\n * @param client - Fetch client instance\n * @param body - body\n */\nexport async function shares_create(\n client: FetchClient,\n body: operations[\"shares_create\"][\"requestBody\"][\"content\"][\"application/json\"],\n): Promise<\n operations[\"shares_create\"][\"responses\"][201][\"content\"][\"application/json\"]\n> {\n return client.post(`/api/shares`, body);\n}\n\n/**\n * List DAM assets\n * Returns a paginated list of DAM assets for the company.\n *\n * @param client - Fetch client instance\n * @param [params] - params\n */\nexport async function dam_assets_list(\n client: FetchClient,\n params?: operations[\"dam_assets_list\"][\"parameters\"][\"query\"],\n): Promise<\n operations[\"dam_assets_list\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/content/dam/assets`, params);\n}\n\n/**\n * Create a DAM asset\n * Creates a new DAM asset. Supports two modes:\n1. **JSON placeholder** — send `application/json` with `asset[name]` to\n create a placeholder record for later file upload.\n\n2. **File upload** — send `multipart/form-data` with `asset[file]`,\n `asset[name]`, and optionally `asset[description]` and `asset[tags]`\n to upload a file and create the full asset with variants.\n *\n * @param client - Fetch client instance\n * @param body - body\n */\nexport async function dam_assets_create(\n client: FetchClient,\n body: operations[\"dam_assets_create\"][\"requestBody\"][\"content\"][\"application/json\"],\n): Promise<\n operations[\"dam_assets_create\"][\"responses\"][201][\"content\"][\"application/json\"]\n> {\n return client.post(`/api/content/dam/assets`, body);\n}\n\n/**\n * List paths for a DAM asset\n * Returns a paginated list of path aliases for a DAM asset.\n *\n * @param client - Fetch client instance\n * @param asset_code - asset_code\n * @param [params] - params\n */\nexport async function dam_asset_paths_list(\n client: FetchClient,\n asset_code: string | number,\n params?: operations[\"dam_asset_paths_list\"][\"parameters\"][\"query\"],\n): Promise<\n operations[\"dam_asset_paths_list\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/content/dam/assets/${asset_code}/paths`, params);\n}\n\n/**\n * Create a path alias for a DAM asset\n * Creates a new path alias for an existing DAM asset.\n *\n * @param client - Fetch client instance\n * @param asset_code - asset_code\n * @param body - body\n */\nexport async function dam_asset_paths_create(\n client: FetchClient,\n asset_code: string | number,\n body: operations[\"dam_asset_paths_create\"][\"requestBody\"][\"content\"][\"application/json\"],\n): Promise<\n operations[\"dam_asset_paths_create\"][\"responses\"][201][\"content\"][\"application/json\"]\n> {\n return client.post(`/api/content/dam/assets/${asset_code}/paths`, body);\n}\n\n/**\n * Query DAM assets using tree paths and tags\n * Searches and retrieves DAM assets using tree path pattern matching, tag-based variant filtering, wildcard name matching, and partial search. Supports cursor pagination for large result sets.\n *\n * @param client - Fetch client instance\n * @param body - body\n */\nexport async function dam_query(\n client: FetchClient,\n body: operations[\"dam_query\"][\"requestBody\"][\"content\"][\"application/json\"],\n): Promise<\n operations[\"dam_query\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.post(`/api/content/dam/query`, body);\n}\n\n/**\n * Delete a DAM asset\n * Permanently destroys a DAM asset, including its ImageKit storage, variants, and database records.\n *\n * @param client - Fetch client instance\n * @param code - code\n */\nexport async function dam_assets_destroy(\n client: FetchClient,\n code: string | number,\n): Promise<\n operations[\"dam_assets_destroy\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.delete(`/api/content/dam/assets/${code}`);\n}\n\n/**\n * Discard (soft-delete) a DAM asset\n * Soft-deletes a DAM asset. Used to discard an in-progress upload without permanently removing the record.\n *\n * @param client - Fetch client instance\n * @param code - code\n */\nexport async function dam_assets_discard(\n client: FetchClient,\n code: string | number,\n): Promise<\n operations[\"dam_assets_discard\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.patch(`/api/content/dam/assets/${code}/discard`);\n}\n\n/**\n * Toggle favorite status on a content item\n * Toggles the favorite status of a content item for the authenticated member. If the item is not currently favorited, it becomes favorited. If it is already favorited, the favorite is removed.\n *\n * @param client - Fetch client instance\n * @param body - body\n */\nexport async function favorites_toggle(\n client: FetchClient,\n body: operations[\"favorites_toggle\"][\"requestBody\"][\"content\"][\"application/json\"],\n): Promise<\n operations[\"favorites_toggle\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.post(`/api/content/favorites/toggle`, body);\n}\n\n// ============================================================================\n// media_metrics\n// ============================================================================\n\n/**\n * Top media by direct visits\n * Ranked list of the company's media by total visits (aggregates metrics_media_visits across all visit sources).\n *\n * @param client - Fetch client instance\n * @param [params] - params\n */\nexport async function content_media_by_visits(\n client: FetchClient,\n params?: operations[\"content_media_by_visits\"][\"parameters\"][\"query\"],\n): Promise<\n operations[\"content_media_by_visits\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/content/media/by-visits`, params);\n}\n\n/**\n * Top media by share-link visits\n * Ranked list of the company's media by click-throughs on rep share links (aggregates metrics_share_shareable_visits where shareable_type='Medium').\n *\n * @param client - Fetch client instance\n * @param [params] - params\n */\nexport async function content_media_by_shares(\n client: FetchClient,\n params?: operations[\"content_media_by_shares\"][\"parameters\"][\"query\"],\n): Promise<\n operations[\"content_media_by_shares\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/content/media/by-shares`, params);\n}\n\n// ============================================================================\n// playlist_metrics\n// ============================================================================\n\n/**\n * Top playlists by direct visits\n * Ranked list of the company's playlists by total visits (aggregates metrics_library_visits since playlists are stored in the libraries table).\n *\n * @param client - Fetch client instance\n * @param [params] - params\n */\nexport async function content_playlists_by_visits(\n client: FetchClient,\n params?: operations[\"content_playlists_by_visits\"][\"parameters\"][\"query\"],\n): Promise<\n operations[\"content_playlists_by_visits\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/content/playlists/by-visits`, params);\n}\n\n/**\n * Top playlists by share-link visits\n * Ranked list of the company's playlists by click-throughs on rep share links (aggregates metrics_share_shareable_visits where shareable_type='Library').\n *\n * @param client - Fetch client instance\n * @param [params] - params\n */\nexport async function content_playlists_by_shares(\n client: FetchClient,\n params?: operations[\"content_playlists_by_shares\"][\"parameters\"][\"query\"],\n): Promise<\n operations[\"content_playlists_by_shares\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/content/playlists/by-shares`, params);\n}\n\n// ============================================================================\n// page_metrics\n// ============================================================================\n\n/**\n * Top pages by direct visits\n * Ranked list of the company's pages by total visits (aggregates metrics_page_visits across all visit sources).\n *\n * @param client - Fetch client instance\n * @param [params] - params\n */\nexport async function content_pages_by_visits(\n client: FetchClient,\n params?: operations[\"content_pages_by_visits\"][\"parameters\"][\"query\"],\n): Promise<\n operations[\"content_pages_by_visits\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/content/pages/by-visits`, params);\n}\n\n/**\n * Top pages by share-link visits\n * Ranked list of the company's pages by click-throughs on rep share links (aggregates metrics_share_shareable_visits where shareable_type='Page').\n *\n * @param client - Fetch client instance\n * @param [params] - params\n */\nexport async function content_pages_by_shares(\n client: FetchClient,\n params?: operations[\"content_pages_by_shares\"][\"parameters\"][\"query\"],\n): Promise<\n operations[\"content_pages_by_shares\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/content/pages/by-shares`, params);\n}\n","import { createContext, use } from \"react\";\nimport type { FetchClient } from \"@fluid-app/api-client-core\";\n\ninterface ShareablesCoreConfig {\n /**\n * Legacy FetchClient for direct API calls (e.g. products-api-client).\n * Optional — portal-tenant contexts use BFF adapters instead.\n */\n client?: FetchClient;\n user: { id: number } | null;\n /** When true, use rep-scoped API endpoints (e.g. /users/v2025-06/media) */\n repContext?: boolean;\n}\n\nconst ShareablesCoreContext = createContext<ShareablesCoreConfig | null>(null);\n\nexport function ShareablesCoreProvider({\n config,\n children,\n}: {\n config: ShareablesCoreConfig;\n children: React.ReactNode;\n}): React.JSX.Element {\n return (\n <ShareablesCoreContext.Provider value={config}>\n {children}\n </ShareablesCoreContext.Provider>\n );\n}\n\nexport function useShareablesClient(): FetchClient | null {\n const ctx = use(ShareablesCoreContext);\n if (!ctx) {\n throw new Error(\n \"useShareablesClient must be used within a ShareablesCoreProvider\",\n );\n }\n return ctx.client ?? null;\n}\n\nexport function useShareablesUser(): { id: number } | null {\n const ctx = use(ShareablesCoreContext);\n if (!ctx) {\n throw new Error(\n \"useShareablesUser must be used within a ShareablesCoreProvider\",\n );\n }\n return ctx.user;\n}\n\nexport function useRepContext(): boolean {\n const ctx = use(ShareablesCoreContext);\n return ctx?.repContext ?? false;\n}\n","import { useQuery } from \"@tanstack/react-query\";\nimport { useShareablesApi } from \"../shareables-api-context\";\nimport { shareablesKeys } from \"../query-keys\";\nimport type { ContentDomainApi } from \"../content-domain-api\";\nimport type { shareables } from \"../types\";\n\ninterface ProductMediaCountsResult {\n [productId: number]: number;\n}\n\nexport type ProductMediaByProductId = Record<number, shareables.ProductMedia[]>;\n\nfunction getUniqueSortedProductIds(productIds: number[]) {\n return [...new Set(productIds)].toSorted((a, b) => a - b);\n}\n\nasync function fetchProductMediaByProductIds(\n api: ContentDomainApi,\n productIds: number[],\n): Promise<ProductMediaByProductId> {\n const productMediaByProductId: ProductMediaByProductId = {};\n\n const promises = productIds.map(async (productId) => {\n try {\n const response = await api.productMedia.getProductMedia(productId);\n productMediaByProductId[productId] = response.media || [];\n } catch (error) {\n console.warn(`Failed to fetch media for product ${productId}:`, error);\n productMediaByProductId[productId] = [];\n }\n });\n\n await Promise.allSettled(promises);\n return productMediaByProductId;\n}\n\nexport function useProductMediaByProductIds(productIds: number[]) {\n const api = useShareablesApi();\n const normalizedProductIds = getUniqueSortedProductIds(productIds);\n\n return useQuery({\n queryKey: shareablesKeys.productMedia.byProductIds(normalizedProductIds),\n queryFn: () => fetchProductMediaByProductIds(api, normalizedProductIds),\n enabled: normalizedProductIds.length > 0,\n staleTime: 5 * 60 * 1000,\n gcTime: 10 * 60 * 1000,\n });\n}\n\nexport function useProductMediaCounts(productIds: number[]) {\n const api = useShareablesApi();\n const normalizedProductIds = getUniqueSortedProductIds(productIds);\n\n return useQuery({\n queryKey: shareablesKeys.productMedia.byProductIds(normalizedProductIds),\n queryFn: () => fetchProductMediaByProductIds(api, normalizedProductIds),\n select: selectProductMediaCounts,\n enabled: normalizedProductIds.length > 0,\n staleTime: 5 * 60 * 1000,\n gcTime: 10 * 60 * 1000,\n });\n}\n\nfunction selectProductMediaCounts(\n productMediaByProductId: ProductMediaByProductId,\n): ProductMediaCountsResult {\n return Object.fromEntries(\n Object.entries(productMediaByProductId).map(([productId, media]) => [\n Number(productId),\n media.length,\n ]),\n );\n}\n\nexport function useProductMediaCount(productId: number) {\n const api = useShareablesApi();\n\n return useQuery({\n queryKey: shareablesKeys.productMedia.count(productId),\n queryFn: async (): Promise<number> => {\n try {\n const response = await api.productMedia.getProductMedia(productId);\n const mediaArray = response.media || [];\n return mediaArray.length;\n } catch (error) {\n console.warn(\n `Failed to fetch media count for product ${productId}:`,\n error,\n );\n return 0;\n }\n },\n enabled: !!productId,\n staleTime: 5 * 60 * 1000,\n gcTime: 10 * 60 * 1000,\n });\n}\n","import { useMutation, useQueryClient } from \"@tanstack/react-query\";\nimport type { shareables } from \"../types\";\nimport { useShareablesApi } from \"../shareables-api-context\";\nimport { useRepContext } from \"../context\";\nimport { shareablesKeys } from \"../query-keys\";\n\nexport interface UseMediaMutationsOptions {\n onDeleteSuccess?: (id: number) => void;\n onDeleteError?: (error: Error, id: number) => void;\n onDuplicateSuccess?: (newMedia: shareables.MediumResponse) => void;\n onDuplicateError?: (error: Error) => void;\n}\n\nexport const useMediaMutations = (options?: UseMediaMutationsOptions) => {\n const api = useShareablesApi();\n const queryClient = useQueryClient();\n const repContext = useRepContext();\n\n // Delete media mutation with optimistic updates\n const deleteMutation = useMutation({\n mutationFn: (id: number) => {\n return api.media.deleteMedia(id);\n },\n onMutate: async (id: number) => {\n await queryClient.cancelQueries({\n queryKey: shareablesKeys.media.all,\n });\n\n // Optimistically remove from media lists\n const previousData = queryClient.getQueriesData({\n queryKey: shareablesKeys.media.all,\n });\n\n queryClient.setQueriesData<unknown>(\n { queryKey: shareablesKeys.media.all },\n (oldData: unknown) => {\n if (!oldData) return oldData;\n\n // Handle different response formats\n if (Array.isArray(oldData)) {\n return oldData.filter((item: { id: number }) => item.id !== id);\n }\n\n const dataObj = oldData as Record<string, unknown>;\n if (dataObj.data && Array.isArray(dataObj.data)) {\n return {\n ...dataObj,\n data: dataObj.data.filter(\n (item: { id: number }) => item.id !== id,\n ),\n };\n }\n\n if (dataObj.media && Array.isArray(dataObj.media)) {\n return {\n ...dataObj,\n media: dataObj.media.filter(\n (item: { id: number }) => item.id !== id,\n ),\n };\n }\n\n return oldData;\n },\n );\n\n // Remove individual media query — use the id-only prefix so every\n // (repContext, locale) variant of this media's detail cache is\n // cleared, not just the default-locale slot.\n queryClient.removeQueries({\n queryKey: shareablesKeys.media.detailById(id),\n });\n\n return { previousData, id };\n },\n onSuccess: async (_, id) => {\n // Invalidate all media queries to refetch fresh data\n queryClient.invalidateQueries({\n queryKey: shareablesKeys.media.all,\n });\n options?.onDeleteSuccess?.(id);\n },\n onError: (error: Error, _id: number, context) => {\n // Rollback optimistic updates\n if (context?.previousData) {\n context.previousData.forEach(([queryKey, data]) => {\n queryClient.setQueryData(queryKey, data);\n });\n }\n\n console.error(\"Error deleting media:\", error);\n options?.onDeleteError?.(error, _id);\n },\n });\n\n // Duplicate media mutation with optimistic update\n const duplicateMutation = useMutation({\n mutationFn: (mediaData: shareables.MediumUpdate) => {\n return api.media.createMedia(mediaData);\n },\n onMutate: async (mediaData) => {\n await queryClient.cancelQueries({\n queryKey: shareablesKeys.media.all,\n });\n\n // Generate temporary ID for optimistic update\n const tempId = Date.now();\n\n // Create optimistic media object\n const optimisticMedia = {\n id: tempId,\n title: mediaData.title || \"Untitled Media\",\n description: mediaData.description || null,\n media_type: \"share\",\n media_format: null,\n image_url: mediaData.image_url || null,\n video_url: mediaData.video_url || null,\n pdf_url: mediaData.pdf_url || null,\n stripped: mediaData.description || null,\n active: mediaData.active ?? true,\n visibility: mediaData.visibility || null,\n share_link: null,\n views: 0,\n leads: 0,\n watch: null,\n video_status: null,\n duration: null,\n cta_url: mediaData.cta_url || null,\n cta_button_text: mediaData.cta_button_text || null,\n cta_enabled: mediaData.cta_enabled ?? false,\n cta_action_type: mediaData.cta_action_type || null,\n video_shopping_enabled: mediaData.video_shopping_enabled ?? false,\n prompts_enabled: mediaData.prompts_enabled ?? false,\n ranks: [],\n preview_link: null,\n attached_shareables: [],\n subtitles: {},\n user_id: null,\n created_at: new Date().toISOString(),\n };\n\n // Snapshot previous data for rollback\n const previousMediaLists = queryClient.getQueriesData({\n queryKey: shareablesKeys.media.all,\n });\n\n // Optimistically add media to list queries\n queryClient.setQueriesData<unknown>(\n { queryKey: shareablesKeys.media.all },\n (oldData: unknown) => {\n if (!oldData) return [optimisticMedia];\n\n // Handle different response formats\n if (Array.isArray(oldData)) {\n return [optimisticMedia, ...oldData];\n }\n\n const dataObj = oldData as Record<string, unknown>;\n if (dataObj.data && Array.isArray(dataObj.data)) {\n return { ...dataObj, data: [optimisticMedia, ...dataObj.data] };\n }\n\n if (dataObj.media && Array.isArray(dataObj.media)) {\n return { ...dataObj, media: [optimisticMedia, ...dataObj.media] };\n }\n\n return oldData;\n },\n );\n\n // Set optimistic individual media query\n queryClient.setQueryData(\n shareablesKeys.media.detail(tempId, repContext),\n {\n media: optimisticMedia,\n },\n );\n\n return { previousMediaLists, tempId };\n },\n onError: (_error, _mediaData, context) => {\n // Rollback optimistic updates\n if (context) {\n context.previousMediaLists.forEach(([queryKey, data]) => {\n queryClient.setQueryData(queryKey, data);\n });\n\n queryClient.removeQueries({\n queryKey: shareablesKeys.media.detailById(context.tempId),\n });\n }\n\n console.error(\"Error duplicating media:\", _error);\n options?.onDuplicateError?.(_error);\n },\n onSuccess: async (data, _mediaData, context) => {\n const realMediaId = data.id;\n\n if (context) {\n // Remove optimistic data\n queryClient.removeQueries({\n queryKey: shareablesKeys.media.detailById(context.tempId),\n });\n }\n\n // Set real media data\n queryClient.setQueryData(\n shareablesKeys.media.detail(realMediaId, repContext),\n {\n media: data,\n },\n );\n\n options?.onDuplicateSuccess?.(data);\n\n // Invalidate lists to get fresh data\n queryClient.invalidateQueries({\n queryKey: shareablesKeys.media.all,\n predicate: (query) => {\n return query.queryKey.length === 1 && query.queryKey[0] === \"media\";\n },\n });\n },\n });\n\n // Handler functions\n const handleDelete = async (id: number) => {\n try {\n await deleteMutation.mutateAsync(id);\n } catch (error) {\n console.error(\"Delete failed:\", error);\n }\n };\n\n const handleDuplicate = async (mediaData: shareables.MediumUpdate) => {\n try {\n await duplicateMutation.mutateAsync(mediaData);\n } catch (error) {\n console.error(\"Duplicate failed:\", error);\n }\n };\n\n return {\n deleteMutation,\n duplicateMutation,\n handleDelete,\n handleDuplicate,\n };\n};\n\n// ---------------------------------------------------------------------------\n// useCreateMediaMutation — dedicated create (no optimistic duplication logic)\n// ---------------------------------------------------------------------------\n\nexport interface UseCreateMediaOptions {\n onSuccess?: (newMedia: shareables.MediumResponse) => void;\n onError?: (error: Error) => void;\n}\n\nexport const useCreateMediaMutation = (options?: UseCreateMediaOptions) => {\n const api = useShareablesApi();\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: (payload: shareables.MediumUpdate) => {\n return api.media.createMedia(payload);\n },\n onSuccess: (data) => {\n queryClient.invalidateQueries({\n queryKey: shareablesKeys.media.all,\n });\n options?.onSuccess?.(data);\n },\n onError: (error) => {\n console.error(\"Error creating media:\", error);\n options?.onError?.(error as Error);\n },\n });\n};\n","/**\n * Check if an error is a cancellation/abort error from TanStack Query or AbortController.\n */\nexport function isCancellationError(error: unknown): boolean {\n return (\n !!error &&\n typeof error === \"object\" &&\n \"name\" in error &&\n (error.name === \"CancelledError\" || error.name === \"AbortError\")\n );\n}\n","import { useMutation, useQueryClient } from \"@tanstack/react-query\";\nimport type { shareables } from \"../types\";\nimport { useShareablesApi } from \"../shareables-api-context\";\nimport { shareablesKeys } from \"../query-keys\";\nimport { isCancellationError } from \"../utils\";\n\n// ---------------------------------------------------------------------------\n// Types for optimistic updates (internal)\n// ---------------------------------------------------------------------------\n\ninterface PlaylistItemLike {\n id?: number | null;\n order?: number;\n relateable_type?: string | null;\n relateable?: unknown;\n}\n\ntype PlaylistDetailCacheEntry = readonly [readonly unknown[], unknown];\n\nfunction updatePlaylistDetailItems(\n old: unknown,\n updateItems: (items: PlaylistItemLike[]) => PlaylistItemLike[],\n): unknown {\n if (!old || typeof old !== \"object\" || !(\"playlist\" in old)) return old;\n\n const playlistData = old as {\n playlist: { items?: PlaylistItemLike[] };\n };\n return {\n ...playlistData,\n playlist: {\n ...playlistData.playlist,\n items: updateItems(playlistData.playlist.items ?? []),\n },\n };\n}\n\nfunction rollbackPlaylistDetailEntries(\n queryClient: ReturnType<typeof useQueryClient>,\n previousData: PlaylistDetailCacheEntry[] | undefined,\n): void {\n for (const [queryKey, data] of previousData ?? []) {\n queryClient.setQueryData(queryKey, data);\n }\n}\n\n// ---------------------------------------------------------------------------\n// useAddItemToPlaylistMutation\n// ---------------------------------------------------------------------------\n\nexport interface UseAddItemOptions {\n onSuccess?: (playlistId: number) => void;\n onError?: (error: Error, playlistId: number) => void;\n}\n\ninterface AddItemToPlaylistParams {\n playlistId: number;\n newItem: PlaylistItemLike;\n data: { relateable_type: string; relateable_id: number; order: number };\n}\n\nexport const useAddItemToPlaylistMutation = (options?: UseAddItemOptions) => {\n const api = useShareablesApi();\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: ({ playlistId, data }: AddItemToPlaylistParams) => {\n return api.playlists.addItemToPlaylist(playlistId, {\n items: [data],\n });\n },\n onMutate: async ({ playlistId, newItem }: AddItemToPlaylistParams) => {\n const detailPrefix = shareablesKeys.playlists.detailById(playlistId);\n await queryClient.cancelQueries({ queryKey: detailPrefix });\n\n const previousData = queryClient.getQueriesData({\n queryKey: detailPrefix,\n });\n\n queryClient.setQueriesData({ queryKey: detailPrefix }, (old: unknown) =>\n updatePlaylistDetailItems(old, (items) => [...items, newItem]),\n );\n\n return { previousData };\n },\n onSuccess: (_, { playlistId }) => {\n queryClient.invalidateQueries({\n queryKey: shareablesKeys.playlists.detailById(playlistId),\n });\n queryClient.invalidateQueries({\n queryKey: shareablesKeys.playlists.all,\n });\n options?.onSuccess?.(playlistId);\n },\n onError: (error, { playlistId }, context) => {\n // Always rollback optimistic updates first\n rollbackPlaylistDetailEntries(queryClient, context?.previousData);\n\n if (isCancellationError(error)) return;\n\n console.error(\"Error adding item to playlist:\", error);\n options?.onError?.(error as Error, playlistId);\n },\n });\n};\n\n// ---------------------------------------------------------------------------\n// useRemoveItemsFromPlaylistMutation\n// ---------------------------------------------------------------------------\n\nexport interface UseRemoveItemsOptions {\n onSuccess?: (playlistId: number) => void;\n onError?: (error: Error, playlistId: number) => void;\n}\n\ninterface RemoveItemsFromPlaylistParams {\n playlistId: number;\n itemIds: number[];\n}\n\nexport const useRemoveItemsFromPlaylistMutation = (\n options?: UseRemoveItemsOptions,\n) => {\n const api = useShareablesApi();\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: ({ playlistId, itemIds }: RemoveItemsFromPlaylistParams) => {\n return api.playlists.removeItemsFromPlaylist(playlistId, {\n item_ids: itemIds,\n });\n },\n onMutate: async ({\n playlistId,\n itemIds,\n }: RemoveItemsFromPlaylistParams) => {\n const detailPrefix = shareablesKeys.playlists.detailById(playlistId);\n await queryClient.cancelQueries({ queryKey: detailPrefix });\n\n const previousData = queryClient.getQueriesData({\n queryKey: detailPrefix,\n });\n\n queryClient.setQueriesData({ queryKey: detailPrefix }, (old: unknown) =>\n updatePlaylistDetailItems(old, (items) =>\n items.filter((item) => item.id != null && !itemIds.includes(item.id)),\n ),\n );\n\n return { previousData };\n },\n onSuccess: (_, { playlistId }) => {\n queryClient.invalidateQueries({\n queryKey: shareablesKeys.playlists.detailById(playlistId),\n });\n queryClient.invalidateQueries({\n queryKey: shareablesKeys.playlists.all,\n });\n options?.onSuccess?.(playlistId);\n },\n onError: (error, { playlistId }, context) => {\n // Always rollback optimistic updates first\n rollbackPlaylistDetailEntries(queryClient, context?.previousData);\n\n if (isCancellationError(error)) return;\n\n // \"No valid playlist items found\" means the last item was removed — treat as success\n const errorMessage =\n error && typeof error === \"object\" && \"message\" in error\n ? String(error.message)\n : \"\";\n\n if (errorMessage.includes(\"No valid playlist items found\")) {\n queryClient.invalidateQueries({\n queryKey: shareablesKeys.playlists.detailById(playlistId),\n });\n options?.onSuccess?.(playlistId);\n return;\n }\n\n console.error(\"Error removing item from playlist:\", error);\n options?.onError?.(error as Error, playlistId);\n },\n });\n};\n\n// ---------------------------------------------------------------------------\n// useCreatePlaylistMutation\n// ---------------------------------------------------------------------------\n\nexport interface UseCreatePlaylistOptions {\n onSuccess?: (response: shareables.GetPlaylistResponse) => void;\n onError?: (error: Error) => void;\n}\n\nexport const useCreatePlaylistMutation = (\n options?: UseCreatePlaylistOptions,\n) => {\n const api = useShareablesApi();\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: (input: shareables.CreatePlaylistInput) => {\n return api.playlists.createPlaylist(input);\n },\n onSuccess: (createdPlaylist) => {\n queryClient.invalidateQueries({\n queryKey: shareablesKeys.playlists.all,\n });\n options?.onSuccess?.(createdPlaylist);\n },\n onError: (error) => {\n if (isCancellationError(error)) return;\n\n console.error(\"Error creating playlist:\", error);\n options?.onError?.(error as Error);\n },\n });\n};\n\n// ---------------------------------------------------------------------------\n// useUpdatePlaylistMutation\n// ---------------------------------------------------------------------------\n\nexport interface UseUpdatePlaylistOptions {\n onSuccess?: (playlistId: number) => void;\n onError?: (error: Error) => void;\n}\n\ninterface UpdatePlaylistParams {\n playlistId: number;\n data: shareables.UpdatePlaylistInput;\n}\n\nexport const useUpdatePlaylistMutation = (\n options?: UseUpdatePlaylistOptions,\n) => {\n const api = useShareablesApi();\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: ({ playlistId, data }: UpdatePlaylistParams) => {\n return api.playlists.updatePlaylist(playlistId, data);\n },\n onSuccess: (_, { playlistId }) => {\n queryClient.invalidateQueries({\n queryKey: shareablesKeys.playlists.all,\n });\n queryClient.invalidateQueries({\n queryKey: shareablesKeys.playlists.detail(playlistId),\n });\n options?.onSuccess?.(playlistId);\n },\n onError: (error) => {\n if (isCancellationError(error)) return;\n\n console.error(\"Error updating playlist:\", error);\n options?.onError?.(error as Error);\n },\n });\n};\n\n// ---------------------------------------------------------------------------\n// useReorderPlaylistItemsMutation\n// ---------------------------------------------------------------------------\n\nexport interface UseReorderPlaylistItemsOptions {\n onSuccess?: (playlistId: number) => void;\n onError?: (error: Error, playlistId: number) => void;\n}\n\ninterface ReorderPlaylistItemsParams {\n playlistId: number;\n data: shareables.ReorderPlaylistItemsInput;\n}\n\nexport const useReorderPlaylistItemsMutation = (\n options?: UseReorderPlaylistItemsOptions,\n) => {\n const api = useShareablesApi();\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: ({ playlistId, data }: ReorderPlaylistItemsParams) => {\n if (!api.playlists.reorderPlaylistItems) {\n return Promise.resolve();\n }\n return api.playlists.reorderPlaylistItems(playlistId, data);\n },\n onSuccess: (_, { playlistId }) => {\n if (api.playlists.reorderPlaylistItems) {\n queryClient.invalidateQueries({\n queryKey: shareablesKeys.playlists.detail(playlistId),\n });\n }\n options?.onSuccess?.(playlistId);\n },\n onError: (error, { playlistId }) => {\n if (isCancellationError(error)) return;\n\n console.error(\"Error reordering playlist items:\", error);\n options?.onError?.(error as Error, playlistId);\n },\n });\n};\n","import { createContext, useContext, type Provider } from \"react\";\nimport type { FilePickerApi } from \"./schemas/file-picker-api\";\n\nconst FilePickerApiContext = createContext<FilePickerApi | null>(null);\n\nexport const FilePickerApiProvider: Provider<FilePickerApi | null> =\n FilePickerApiContext.Provider;\n\nexport function useFilePickerApi(): FilePickerApi {\n const api = useContext(FilePickerApiContext);\n if (!api) {\n throw new Error(\n \"useFilePickerApi must be used within a FilePickerApiProvider\",\n );\n }\n return api;\n}\n","import { z } from \"zod\";\n\ntype DamVariantApi = {\n id: string;\n url: string | null;\n file_name: string;\n mime_type: string;\n content: any;\n created_at: string;\n updated_at: string;\n default: boolean;\n is_original: boolean;\n is_text: boolean;\n media_type: string;\n processing_status: string;\n tags: string[];\n};\n\nexport const damVariantSchema: z.ZodType<DamVariantApi> = z.object({\n id: z.string(),\n url: z.string().nullable(),\n file_name: z.string(),\n mime_type: z.string(),\n content: z.any().nullable(),\n created_at: z.string(),\n updated_at: z.string(),\n default: z.boolean(),\n is_original: z.boolean(),\n is_text: z.boolean(),\n media_type: z.string(),\n processing_status: z.string(),\n tags: z.array(z.string()),\n});\n\ntype DamAssetApi = {\n id: number;\n canonical_path: string;\n category: string;\n code: string;\n company: string;\n created_at: string;\n default_variant_id: string;\n default_variant_url?: string;\n description: string;\n name: string;\n updated_at: string;\n variants?: DamVariantApi[];\n};\n\nexport const damAssetSchema: z.ZodType<DamAssetApi> = z.object({\n id: z.number(),\n canonical_path: z.string(),\n category: z.string(),\n code: z.string(),\n company: z.string(),\n created_at: z.string(),\n default_variant_id: z.string(),\n default_variant_url: z.string().optional(),\n description: z.string(),\n name: z.string(),\n updated_at: z.string(),\n variants: z.array(damVariantSchema).optional(),\n});\n\ntype DamTreeFolderNode = {\n asset_code?: string | Record<string, unknown>;\n name?: string | Record<string, unknown>;\n category?: string | Record<string, unknown>;\n variants?: unknown[] | Record<string, unknown>;\n [key: string]: unknown;\n};\n\nexport const damTreeFolderNodeSchema: z.ZodType<DamTreeFolderNode> = z\n .object({\n asset_code: z\n .union([z.string(), z.record(z.string(), z.unknown())])\n .optional(),\n name: z.union([z.string(), z.record(z.string(), z.unknown())]).optional(),\n category: z\n .union([z.string(), z.record(z.string(), z.unknown())])\n .optional(),\n variants: z\n .union([z.array(z.unknown()), z.record(z.string(), z.unknown())])\n .optional(),\n })\n .passthrough();\n\nexport const damTreeSchema: z.ZodType<Record<string, any>> = z.record(\n z.string(),\n z.union([\n z.lazy(() => damTreeSchema),\n damAssetSchema,\n damTreeFolderNodeSchema,\n ]),\n);\n\ntype DamQueryResponse = {\n path: string;\n tree: Record<string, any>;\n meta?: { next_cursor?: string; total_count?: number };\n};\n\nexport const damQueryResponseSchema: z.ZodType<DamQueryResponse> = z.object({\n path: z.string(),\n tree: damTreeSchema,\n meta: z\n .object({\n next_cursor: z.string().optional(),\n total_count: z.number().optional(),\n })\n .optional(),\n});\n\ntype DamAssetCreateRequest = {\n asset: {\n file: any;\n name: string;\n description?: string;\n tags?: string;\n };\n};\n\nexport const damAssetCreateRequestSchema: z.ZodType<DamAssetCreateRequest> =\n z.object({\n asset: z.object({\n file: z.any(),\n name: z.string(),\n description: z.string().optional(),\n tags: z.string().optional(),\n }),\n });\n\ntype DamAssetCreateResponse = {\n asset: DamAssetApi;\n meta: { request_id: string; timestamp: string };\n};\n\nexport const damAssetCreateResponseSchema: z.ZodType<DamAssetCreateResponse> =\n z.object({\n asset: damAssetSchema,\n meta: z.object({\n request_id: z.string(),\n timestamp: z.string(),\n }),\n });\n\n// Schema for creating asset with placeholder (for ImageKit direct upload)\ntype DamAssetCreateWithPlaceholderRequest = {\n placeholder_asset: {\n mime_type: string;\n name?: string;\n description?: string;\n };\n skip_autotagging?: boolean;\n};\n\nexport const damAssetCreateWithPlaceholderRequestSchema: z.ZodType<DamAssetCreateWithPlaceholderRequest> =\n z.object({\n placeholder_asset: z.object({\n mime_type: z.string(),\n name: z.string().optional(),\n description: z.string().optional(),\n }),\n skip_autotagging: z.boolean().optional(),\n });\n\n// Schema for creating asset path without file upload (legacy)\ntype DamAssetPathCreateRequest = {\n asset?: {\n file: any;\n name: string;\n description?: string;\n tags?: string;\n };\n text_asset?: {\n file_name: string;\n mime_type: string;\n text: string;\n name?: string;\n description?: string;\n tags?: string;\n };\n placeholder_asset?: {\n mime_type: string;\n name?: string;\n description?: string;\n };\n skip_autotagging?: boolean;\n};\n\nexport const damAssetPathCreateRequestSchema: z.ZodType<DamAssetPathCreateRequest> =\n z.object({\n asset: z\n .object({\n file: z.any(),\n name: z.string(),\n description: z.string().optional(),\n tags: z.string().optional(),\n })\n .optional(),\n text_asset: z\n .object({\n file_name: z.string(),\n mime_type: z.string(),\n text: z.string(),\n name: z.string().optional(),\n description: z.string().optional(),\n tags: z.string().optional(),\n })\n .optional(),\n placeholder_asset: z\n .object({\n mime_type: z.string(),\n name: z.string().optional(),\n description: z.string().optional(),\n })\n .optional(),\n skip_autotagging: z.boolean().optional(),\n });\n\ntype DamAssetPathCreateResponse = {\n asset: { id: number; canonical_path: string; name: string };\n meta: { request_id: string; timestamp: string };\n};\n\nexport const damAssetPathCreateResponseSchema: z.ZodType<DamAssetPathCreateResponse> =\n z.object({\n asset: z.object({\n id: z.number(),\n canonical_path: z.string(),\n name: z.string(),\n }),\n meta: z.object({\n request_id: z.string(),\n timestamp: z.string(),\n }),\n });\n\nexport type { DamVariantApi, DamAssetApi };\nexport type DamTreeApi = z.infer<typeof damTreeSchema>;\nexport type { DamQueryResponse };\nexport type { DamAssetCreateRequest };\nexport type { DamAssetCreateResponse };\nexport type { DamAssetCreateWithPlaceholderRequest };\nexport type { DamAssetPathCreateRequest };\nexport type { DamAssetPathCreateResponse };\n","import { z } from \"zod\";\nimport type { UrlProxyResponse } from \"@fluid-app/file-picker-core\";\n\nexport type { UrlProxyResponse };\n\nconst urlProxyResponseSchema: z.ZodType<UrlProxyResponse> = z.object({\n data: z.string(),\n contentType: z.string(),\n size: z.number(),\n});\n\n/**\n * Proxy a URL fetch through the backend to bypass CORS restrictions.\n * The backend fetches the file and returns it as base64-encoded data.\n *\n * @param url - The URL to fetch\n * @param proxyEndpoint - The proxy endpoint (defaults to \"/api/proxy-url\")\n */\nexport async function proxyUrlFetch(\n url: string,\n proxyEndpoint: string = \"/api/proxy-url\",\n): Promise<UrlProxyResponse> {\n const response = await fetch(proxyEndpoint, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({ url }),\n });\n\n if (!response.ok) {\n const errorData = await response.json().catch(() => ({\n error: \"Failed to proxy URL fetch\",\n }));\n throw new Error(\n (errorData as { error?: string }).error || `HTTP ${response.status}`,\n );\n }\n\n const data: unknown = await response.json();\n return urlProxyResponseSchema.parse(data);\n}\n","import {\n damAssetSchema,\n damQueryResponseSchema,\n type CreateDamAssetParams,\n type CreateDamAssetPathForAssetsParams,\n type DamAssetCreateResponse,\n type DamAssetPathCreateResponse,\n type DamQueryParams,\n type DamQueryResponse,\n type FilePickerApi,\n type UnsplashSearchResponse,\n} from \"@fluid-app/file-picker-core\";\nimport { proxyUrlFetch } from \"@fluid-app/file-picker-api-client\";\nimport type { FetchClient } from \"@fluid-app/portal-tenant-api-client\";\nimport {\n portalTenantContent,\n type operations,\n} from \"@fluid-app/portal-tenant-content-api-client\";\n\n/** BFF create response — derived from the generated OpenAPI types. */\ntype DamAssetCreateBffResponse = Awaited<\n ReturnType<typeof portalTenantContent.dam_assets_create>\n>;\n\n/** BFF asset path create response — derived from the generated OpenAPI types. */\ntype DamAssetPathCreateBffResponse = Awaited<\n ReturnType<typeof portalTenantContent.dam_asset_paths_create>\n>;\n\n/**\n * Maps a BFF DAM asset to the file-picker port's DamAssetCreateResponse shape.\n *\n * The BFF response includes nullable meta.request_id (from Api::Response),\n * while the port schema requires a string. We coalesce to empty string.\n */\nfunction mapCreateResponse(\n response: DamAssetCreateBffResponse,\n): DamAssetCreateResponse {\n const raw = response.asset ?? {};\n return {\n asset: damAssetSchema.parse({\n ...raw,\n canonical_path: raw.canonical_path ?? \"\",\n category: raw.category ?? \"\",\n company: raw.company ?? \"\",\n description: raw.description ?? \"\",\n default_variant_id: raw.default_variant_id ?? \"\",\n }),\n meta: {\n request_id: response.meta?.request_id ?? \"\",\n timestamp: response.meta?.timestamp ?? new Date().toISOString(),\n },\n };\n}\n\n/**\n * Maps a BFF asset path response to the file-picker port's shape.\n */\nfunction mapAssetPathCreateResponse(\n response: DamAssetPathCreateBffResponse,\n): DamAssetPathCreateResponse {\n const assetPath = response.asset_path ?? {};\n return {\n asset: {\n id: assetPath.id ?? 0,\n canonical_path: assetPath.path ?? \"\",\n name: assetPath.asset_code ?? \"\",\n },\n meta: {\n request_id: response.meta?.request_id ?? \"\",\n timestamp: response.meta?.timestamp ?? new Date().toISOString(),\n },\n };\n}\n\n/**\n * Creates a FilePickerApi adapter backed by the portal-tenant BFF's\n * `/api/content/dam/*` endpoints, using cookie-based auth via the\n * provided FetchClient.\n *\n * Unsplash search is not available through the BFF — callers that need\n * Unsplash should use the legacy adapter or provide their own\n * implementation.\n *\n * The `onProgress` callback in `createDamAsset` is not supported — the\n * underlying `fetch` API does not expose upload progress events.\n *\n * URL proxy delegates to the same-origin `/api/proxy-url` endpoint\n * (served by the hosting app, not the BFF) for CORS bypass, identical\n * to the legacy adapter behaviour.\n */\nexport function createFilePickerApiAdapter(client: FetchClient): FilePickerApi {\n return {\n createDamAsset: async (\n params: CreateDamAssetParams,\n ): Promise<DamAssetCreateResponse> => {\n // The generated dam_assets_create uses client.post (JSON body), but\n // file uploads require multipart/form-data. Use requestWithFormData\n // directly, typing the response from the generated operation type.\n const formData = new FormData();\n formData.append(\"asset[file]\", params.file);\n formData.append(\"asset[name]\", params.name);\n\n if (params.description) {\n formData.append(\"asset[description]\", params.description);\n }\n\n if (params.tags && params.tags.length > 0) {\n formData.append(\"asset[tags]\", params.tags.join(\",\"));\n }\n\n const response =\n await client.requestWithFormData<DamAssetCreateBffResponse>(\n \"/api/content/dam/assets\",\n formData,\n { method: \"POST\" },\n );\n\n return mapCreateResponse(response);\n },\n\n queryDamAssets: async (\n params: DamQueryParams,\n ): Promise<DamQueryResponse> => {\n const response = await portalTenantContent.dam_query(\n client,\n params satisfies operations[\"dam_query\"][\"requestBody\"][\"content\"][\"application/json\"],\n );\n return damQueryResponseSchema.parse({\n ...response,\n meta: response.meta\n ? { next_cursor: response.meta.pagination?.next_cursor ?? undefined }\n : undefined,\n });\n },\n\n deleteDamAsset: async (code: string): Promise<unknown> => {\n return portalTenantContent.dam_assets_destroy(client, code);\n },\n\n discardDamAsset: async (code: string): Promise<unknown> => {\n return portalTenantContent.dam_assets_discard(client, code);\n },\n\n createDamAssetPathForAssets: async (\n params: CreateDamAssetPathForAssetsParams,\n ): Promise<DamAssetPathCreateResponse> => {\n const response = await portalTenantContent.dam_asset_paths_create(\n client,\n params.code,\n { asset_path: { path: params.asset_paths.join(\",\") } },\n );\n return mapAssetPathCreateResponse(response);\n },\n\n searchUnsplash: async (\n _query: string,\n _page?: number,\n _perPage?: number,\n ): Promise<UnsplashSearchResponse> => {\n throw new Error(\n \"Unsplash search is not available through the portal-tenant BFF. \" +\n \"Configure an Unsplash access key and use the standard FilePickerApi adapter instead.\",\n );\n },\n\n proxyUrlFetch: (url: string) => proxyUrlFetch(url),\n };\n}\n","/**\n * Portal Content Domain Adapter — Implements ContentDomainApi using the\n * portal-tenant Content BFF endpoints.\n *\n * Follows the composite adapter pattern (see contacts-api-adapter.ts):\n * all sub-factory functions are private; the only public export is the\n * composite `createPortalContentDomainApiAdapter`.\n */\n\nimport type { FetchClient } from \"@fluid-app/api-client-core\";\nimport type {\n ContentMediaApi,\n ContentMediaProductsApi,\n media,\n} from \"@fluid-app/shareables-core/media-api\";\nimport type {\n ContentPlaylistsApi,\n playlists,\n} from \"@fluid-app/shareables-core/playlists-api\";\nimport type {\n ContentSharesApi,\n shares,\n} from \"@fluid-app/shareables-core/shares-api\";\nimport type {\n ContentDamAssetsApi,\n damAssets,\n} from \"@fluid-app/shareables-core/dam-assets-api\";\nimport type {\n ContentMetricsApi,\n metrics,\n} from \"@fluid-app/shareables-core/metrics-api\";\nimport type {\n ContentPagesApi,\n pages,\n} from \"@fluid-app/shareables-core/pages-api\";\nimport type {\n ContentEnrollmentPacksApi,\n enrollmentPacks,\n} from \"@fluid-app/shareables-core/enrollment-packs-api\";\nimport type {\n MediaApi,\n PlaylistsApi,\n FileResourcesApi,\n ProductMediaApi,\n ShareApi,\n} from \"@fluid-app/shareables-core/shareables-api\";\nimport type { ContentDomainApi } from \"@fluid-app/shareables-core/content-domain-api\";\nimport type {\n shareables,\n PlaylistsQuery,\n} from \"@fluid-app/shareables-core/types\";\nimport { portalTenantContent } from \"@fluid-app/portal-tenant-content-api-client\";\nimport { portalTenant } from \"@fluid-app/portal-tenant-api-client\";\n\n// ============================================================================\n// Media — Raw BFF adapter (private)\n// ============================================================================\n\nfunction mapMedia(\n raw: NonNullable<\n Awaited<ReturnType<typeof portalTenantContent.media_show>>[\"media\"]\n >,\n): media.Media {\n return {\n id: raw.id ?? 0,\n title: raw.title ?? \"\",\n description: raw.description ?? null,\n content_format: raw.content_format ?? null,\n status: raw.status ?? \"active\",\n url: raw.url ?? null,\n thumbnail_url: raw.thumbnail_url ?? null,\n owner_type: raw.owner_type ?? \"\",\n cta: raw.cta\n ? {\n enabled: raw.cta.enabled ?? null,\n type: raw.cta.type ?? null,\n button_text: raw.cta.button_text ?? null,\n button_color: raw.cta.button_color ?? null,\n button_description: raw.cta.button_description ?? null,\n action_url: raw.cta.action_url ?? null,\n }\n : null,\n seo: raw.seo\n ? {\n title: raw.seo.title ?? null,\n description: raw.seo.description ?? null,\n image_url: raw.seo.image_url ?? null,\n block_crawler: raw.seo.block_crawler ?? null,\n }\n : null,\n created_at: raw.created_at ?? \"\",\n updated_at: raw.updated_at ?? \"\",\n };\n}\n\nfunction mapMediaMeta(\n raw: Awaited<ReturnType<typeof portalTenantContent.media_list>>[\"meta\"],\n): media.MediaListResponse[\"meta\"] {\n return {\n request_id: raw?.request_id ?? null,\n timestamp: raw?.timestamp ?? \"\",\n pagination: raw?.pagination\n ? {\n cursor: raw.pagination.cursor ?? null,\n limit: raw.pagination.limit,\n next_cursor: raw.pagination.next_cursor ?? null,\n prev_cursor: raw.pagination.prev_cursor ?? null,\n }\n : undefined,\n };\n}\n\nfunction createRawMediaAdapter(client: FetchClient): ContentMediaApi {\n return {\n listMedia: async (params) => {\n const response = await portalTenantContent.media_list(client, {\n \"page[cursor]\": params?.cursor,\n \"page[limit]\": params?.limit,\n \"filter[title]\": params?.[\"filter[title]\"],\n \"filter[ownership]\": params?.[\"filter[ownership]\"],\n \"filter[content_format]\": params?.[\"filter[content_format]\"],\n sort: params?.sort,\n language_iso: params?.language_iso,\n });\n return {\n media: (response.media ?? []).map(mapMedia),\n meta: mapMediaMeta(response.meta),\n };\n },\n\n createMedia: async (body) => {\n const response = await portalTenantContent.media_create(client, {\n media: body,\n });\n if (!response.media) {\n throw new Error(\"Media create response missing media\");\n }\n return {\n media: mapMedia(response.media),\n meta: mapMediaMeta(response.meta),\n };\n },\n\n getMedia: async (id, language_iso) => {\n const response = await portalTenantContent.media_show(\n client,\n id,\n language_iso ? { language_iso } : undefined,\n );\n if (!response.media) {\n throw new Error(\"Media show response missing media\");\n }\n return {\n media: mapMedia(response.media),\n meta: mapMediaMeta(response.meta),\n };\n },\n\n updateMedia: async (id, body, language_iso) => {\n const response = await portalTenantContent.media_update(\n client,\n id,\n { media: body },\n language_iso ? { language_iso } : undefined,\n );\n if (!response.media) {\n throw new Error(\"Media update response missing media\");\n }\n return {\n media: mapMedia(response.media),\n meta: mapMediaMeta(response.meta),\n };\n },\n\n deleteMedia: async (id) => {\n const response = await portalTenantContent.media_destroy(client, id);\n return {\n media: { id: response.media?.id ?? 0 },\n meta: mapMediaMeta(response.meta),\n };\n },\n };\n}\n\n/**\n * Creates a ContentMediaProductsApi adapter backed by the portal-tenant content BFF.\n */\nexport function createPortalTenantMediaProductsAdapter(\n client: FetchClient,\n): ContentMediaProductsApi {\n return {\n listMediaProducts: async (mediumId, params) => {\n const response = await portalTenantContent.media_products_list(\n client,\n mediumId,\n {\n \"page[cursor]\": params?.cursor,\n \"page[limit]\": params?.limit,\n language_iso: params?.language_iso,\n },\n );\n return {\n media_products: (response.media_products ?? []).map((p) => ({\n id: p.id ?? 0,\n name: p.name ?? undefined,\n slug: p.slug ?? null,\n image_url: p.image_url ?? null,\n price: p.price ?? null,\n currency: p.currency ?? null,\n added_at: p.added_at ?? null,\n })),\n meta: mapMediaMeta(response.meta),\n };\n },\n\n addMediaProduct: async (mediumId, body) => {\n const response = await portalTenantContent.media_products_add(\n client,\n mediumId,\n { product: { id: body.id } },\n );\n const p = response.media_product ?? {};\n return {\n media_product: {\n id: p.id ?? 0,\n name: p.name ?? undefined,\n slug: p.slug ?? null,\n image_url: p.image_url ?? null,\n price: p.price ?? null,\n currency: p.currency ?? null,\n added_at: p.added_at ?? null,\n },\n meta: {\n request_id: response.meta?.request_id ?? null,\n timestamp: response.meta?.timestamp ?? \"\",\n },\n };\n },\n\n removeMediaProduct: async (mediumId, productId) => {\n const response = await portalTenantContent.media_products_remove(\n client,\n mediumId,\n productId,\n );\n return {\n media_product: {\n product_id: response.media_product?.product_id ?? 0,\n },\n meta: {\n request_id: response.meta?.request_id ?? null,\n timestamp: response.meta?.timestamp ?? \"\",\n },\n };\n },\n };\n}\n\n// ============================================================================\n// Media — ShareablesApi-compatible adapter (private)\n// ============================================================================\n\nfunction mediaKindFromType(mediaType: string): string | null {\n if (mediaType === \"video\") return \"video\";\n if (mediaType === \"image\") return \"image\";\n if (mediaType === \"document\" || mediaType === \"pdf\") return \"pdf\";\n return null;\n}\n\nfunction toBffMediumResponse(bff: media.Media): shareables.MediumResponse {\n const kind = bff.content_format ?? null;\n const isVideo = kind === \"video\";\n const isPdf = kind === \"pdf\";\n const ctaData = bff.cta;\n const seoData = bff.seo;\n\n return {\n id: bff.id,\n user_id: null,\n owner_type: bff.owner_type ?? null,\n media_type: bff.content_format ?? \"image\",\n media_format: bff.content_format ?? \"image\",\n image_url:\n !isVideo && !isPdf\n ? (bff.url ?? bff.thumbnail_url ?? null)\n : (bff.thumbnail_url ?? null),\n video_url: isVideo ? (bff.url ?? null) : null,\n pdf_url: isPdf ? (bff.url ?? null) : null,\n title: bff.title,\n description: {\n id: null,\n name: null,\n body: bff.description ?? null,\n record_type: null,\n record_id: null,\n created_at: bff.created_at ?? null,\n updated_at: bff.updated_at ?? null,\n locale: null,\n },\n stripped: bff.description ?? null,\n kind,\n active: bff.status === \"active\",\n visibility: null,\n share_link: null,\n views: 0,\n leads: 0,\n watch: null,\n video_status: null,\n duration: null,\n cta_url: ctaData?.action_url ?? null,\n cta_button_text: ctaData?.button_text ?? null,\n cta_enabled: ctaData?.enabled ?? false,\n cta_action_type: ctaData?.type ?? null,\n video_shopping_enabled: false,\n prompts_enabled: false,\n ranks: [],\n preview_link: null,\n attached_shareables: [],\n created_at: bff.created_at,\n settings: {\n cta: ctaData\n ? {\n enabled: ctaData.enabled ?? undefined,\n type: ctaData.type ?? undefined,\n url: ctaData.action_url ?? undefined,\n button_text: ctaData.button_text ?? undefined,\n button_color: ctaData.button_color ?? undefined,\n button_description: ctaData.button_description ?? undefined,\n }\n : null,\n seo: seoData\n ? {\n title: seoData.title ?? undefined,\n description: seoData.description ?? undefined,\n image_url: seoData.image_url ?? undefined,\n block_crawler: seoData.block_crawler ?? undefined,\n }\n : null,\n },\n };\n}\n\nfunction createMediaAdapter(client: FetchClient): MediaApi {\n const portAdapter = createRawMediaAdapter(client);\n const cursorByPage = new Map<number, string>();\n let lastFilterKey = \"\";\n\n return {\n list: async (options) => {\n const response = await portAdapter.listMedia({\n cursor: options?.[\"page[cursor]\"],\n limit: options?.[\"page[limit]\"],\n \"filter[title]\": options?.[\"filter[title]\"],\n \"filter[ownership]\": options?.[\"filter[ownership]\"],\n \"filter[content_format]\": options?.[\"filter[content_format]\"],\n sort: options?.sort,\n language_iso: options?.language_iso,\n });\n return {\n media: response.media.map(toBffMediumResponse),\n nextCursor: response.meta.pagination?.next_cursor ?? null,\n };\n },\n\n getMedia: async (options) => {\n const pageNumber = options?.page ?? 1;\n\n // Clear cursor cache when search/sort/ownership/locale filters change\n const filterKey = `${options?.search_query ?? \"\"}|${options?.sorted_by ?? \"\"}|${options?.ownership ?? \"\"}|${options?.language_iso ?? \"\"}`;\n if (filterKey !== lastFilterKey) {\n cursorByPage.clear();\n lastFilterKey = filterKey;\n }\n\n const cursor = pageNumber > 1 ? cursorByPage.get(pageNumber) : undefined;\n\n // Map UI sort values (\"title_asc\", \"title_desc\") to BFF sort.\n const rawSort = options?.sorted_by;\n let bffSort: \"title_asc\" | \"title_desc\" | undefined;\n if (rawSort === \"title_asc\") {\n bffSort = \"title_asc\";\n } else if (rawSort === \"title_desc\") {\n bffSort = \"title_desc\";\n }\n\n const ownership = options?.ownership;\n const bffOwnership: \"all\" | \"mine\" | \"company\" | undefined =\n ownership === \"all\" || ownership === \"mine\" || ownership === \"company\"\n ? ownership\n : undefined;\n\n const response = await portAdapter.listMedia({\n cursor,\n limit: options?.per_page,\n \"filter[title]\": options?.search_query,\n \"filter[ownership]\": bffOwnership,\n sort: bffSort,\n language_iso: options?.language_iso,\n });\n\n const nextCursor = response.meta.pagination?.next_cursor;\n if (nextCursor) {\n cursorByPage.set(pageNumber + 1, nextCursor);\n }\n\n const transformedItems = response.media.map(toBffMediumResponse);\n\n // Cursor-based pagination doesn't expose a real total. Synthesize\n // a value so `page * PAGE_SIZE < total_count` yields the correct\n // hasNextPage boolean: if there's a next cursor, total exceeds the\n // current offset; otherwise it's exactly the items seen so far.\n const perPage = options?.per_page ?? 24;\n const syntheticTotal = nextCursor\n ? pageNumber * perPage + 1\n : (pageNumber - 1) * perPage + transformedItems.length;\n\n return {\n data: transformedItems,\n status: \"success\",\n media: transformedItems,\n meta: {\n total_count: syntheticTotal,\n current: pageNumber,\n per_page: perPage,\n pages: nextCursor ? pageNumber + 1 : pageNumber,\n next: nextCursor ? pageNumber + 1 : null,\n previous: pageNumber > 1 ? pageNumber - 1 : null,\n },\n };\n },\n\n getMediaById: async (id, language_iso) => {\n const response = await portAdapter.getMedia(id, language_iso);\n const medium = toBffMediumResponse(response.media);\n return {\n data: medium,\n status: \"success\",\n media: medium,\n };\n },\n\n createMedia: async (mediaData) => {\n // Per backend contract: send `content_format` on every POST that\n // includes a `url`, otherwise backend defaults to image_url/kind=\"image\"\n // regardless of the actual asset. The UI derives kind from MIME type\n // (see deriveMediaType in MediaCreateScreen).\n const contentFormat: \"image\" | \"video\" | \"pdf\" | \"ppt\" | undefined =\n mediaData.kind === \"image\" ||\n mediaData.kind === \"video\" ||\n mediaData.kind === \"pdf\" ||\n mediaData.kind === \"ppt\"\n ? mediaData.kind\n : undefined;\n const response = await portAdapter.createMedia({\n title: mediaData.title ?? \"\",\n description: mediaData.description,\n media_type: mediaData.media_type ?? \"image\",\n url:\n mediaData.image_url ??\n mediaData.video_url ??\n mediaData.pdf_url ??\n undefined,\n content_format: contentFormat,\n });\n return toBffMediumResponse(response.media);\n },\n\n updateMedia: async (id, mediaData, language_iso) => {\n const updateBody: media.MediaUpdateBody = {\n title: mediaData.title,\n description: mediaData.description,\n };\n // Map active boolean to status enum\n if (mediaData.active !== undefined) {\n updateBody.status = mediaData.active ? \"active\" : \"draft\";\n }\n // Map replacement media asset URL (image/video/pdf) → BFF single `url`\n const newUrl =\n mediaData.image_url ??\n mediaData.video_url ??\n mediaData.pdf_url ??\n undefined;\n if (newUrl !== undefined) {\n updateBody.url = newUrl;\n }\n // Map UI `kind` (from FilePickerResult) → BFF `content_format`.\n // Per backend contract: must be sent alongside `url` when asset type\n // changes, otherwise backend falls back to medium's stored `kind` and\n // the new URL lands in the wrong column. Runtime-narrow since the\n // source `MediumUpdate.kind` is typed as a broader string.\n if (\n mediaData.kind === \"image\" ||\n mediaData.kind === \"video\" ||\n mediaData.kind === \"pdf\" ||\n mediaData.kind === \"ppt\"\n ) {\n updateBody.content_format = mediaData.kind;\n }\n // Thumbnail override (for video thumbnail captures)\n if (mediaData.thumbnail_url !== undefined) {\n updateBody.thumbnail_url = mediaData.thumbnail_url;\n }\n // Map CTA from settings to top-level.\n // Note: to disable an existing CTA, callers set { enabled: false };\n // sending settings.cta = null is not currently supported by the BFF\n // (MediaUpdate.cta has no null variant), so we only forward when cta\n // is a defined object.\n if (mediaData.settings?.cta) {\n const rawType = mediaData.settings.cta.type;\n // Runtime-narrow CTA type rather than casting — the source type is\n // `string | null | undefined` so an unknown string would otherwise\n // be forwarded unvalidated to the BFF.\n const ctaType =\n rawType === \"link\" ||\n rawType === \"cart\" ||\n rawType === \"email\" ||\n rawType === \"phone\"\n ? rawType\n : undefined;\n updateBody.cta = {\n enabled: mediaData.settings.cta.enabled,\n type: ctaType,\n button_text: mediaData.settings.cta.button_text,\n button_color: mediaData.settings.cta.button_color,\n button_description: mediaData.settings.cta.button_description,\n action_url: mediaData.settings.cta.url,\n };\n }\n // Map SEO from settings to top-level\n if (mediaData.settings?.seo) {\n updateBody.seo = {\n title: mediaData.settings.seo.title,\n description: mediaData.settings.seo.description,\n image_url: mediaData.settings.seo.image_url,\n block_crawler: mediaData.settings.seo.block_crawler ?? undefined,\n };\n }\n const response = await portAdapter.updateMedia(\n id,\n updateBody,\n language_iso,\n );\n return toBffMediumResponse(response.media);\n },\n\n deleteMedia: async (id) => {\n await portAdapter.deleteMedia(id);\n return { success: true };\n },\n };\n}\n\n// ============================================================================\n// Playlists — Raw BFF adapter (private)\n// ============================================================================\n\nfunction mapPlaylist(\n raw: NonNullable<\n Awaited<ReturnType<typeof portalTenantContent.playlists_show>>[\"playlist\"]\n >,\n): playlists.Playlist {\n return {\n id: raw.id ?? 0,\n title: raw.title ?? \"\",\n description: raw.description ?? null,\n items_count: raw.items_count ?? 0,\n user_id: raw.member_id ?? undefined,\n is_favorited: raw.is_favorited,\n image_url: raw.image_url ?? null,\n created_at: raw.created_at ?? \"\",\n updated_at: raw.updated_at ?? \"\",\n };\n}\n\nfunction mapPlaylistItem(\n raw: NonNullable<\n Awaited<\n ReturnType<typeof portalTenantContent.playlists_items_list>\n >[\"playlist_items\"]\n >[number],\n): playlists.PlaylistItem {\n return {\n id: raw.id,\n content_type: raw.content_type,\n content_id: raw.content_id,\n position: raw.position,\n created_at: raw.created_at,\n content: raw.content as playlists.PlaylistItemContent,\n };\n}\n\nfunction mapPlaylistsMeta(\n raw: Awaited<ReturnType<typeof portalTenantContent.playlists_list>>[\"meta\"],\n): playlists.PlaylistsListResponse[\"meta\"] {\n return {\n request_id: raw?.request_id ?? null,\n timestamp: raw?.timestamp ?? \"\",\n pagination: raw?.pagination\n ? {\n cursor: raw.pagination.cursor ?? null,\n limit: raw.pagination.limit,\n next_cursor: raw.pagination.next_cursor ?? null,\n prev_cursor: raw.pagination.prev_cursor ?? null,\n }\n : undefined,\n };\n}\n\nfunction createRawPlaylistsAdapter(client: FetchClient): ContentPlaylistsApi {\n return {\n listPlaylists: async (params) => {\n const response = await portalTenantContent.playlists_list(client, {\n \"page[cursor]\": params?.cursor,\n \"page[limit]\": params?.limit,\n \"filter[title]\": params?.[\"filter[title]\"],\n \"filter[ownership]\": params?.[\"filter[ownership]\"],\n sort: params?.sort,\n });\n return {\n playlists: (response.playlists ?? []).map(mapPlaylist),\n meta: mapPlaylistsMeta(response.meta),\n };\n },\n\n createPlaylist: async (body) => {\n const response = await portalTenantContent.playlists_create(client, {\n playlist: body,\n });\n return {\n playlist: mapPlaylist(response.playlist ?? {}),\n meta: mapPlaylistsMeta(response.meta),\n };\n },\n\n getPlaylist: async (id) => {\n const response = await portalTenantContent.playlists_show(client, id);\n return {\n playlist: mapPlaylist(response.playlist ?? {}),\n meta: mapPlaylistsMeta(response.meta),\n };\n },\n\n updatePlaylist: async (id, body) => {\n const response = await portalTenantContent.playlists_update(client, id, {\n playlist: body,\n });\n return {\n playlist: mapPlaylist(response.playlist ?? {}),\n meta: mapPlaylistsMeta(response.meta),\n };\n },\n\n deletePlaylist: async (id) => {\n const response = await portalTenantContent.playlists_destroy(client, id);\n return {\n playlist: { id: response.playlist?.id ?? 0 },\n meta: mapPlaylistsMeta(response.meta),\n };\n },\n\n listPlaylistItems: async (playlistId, params) => {\n const response = await portalTenantContent.playlists_items_list(\n client,\n playlistId,\n {\n \"page[cursor]\": params?.cursor,\n \"page[limit]\": params?.limit,\n language_iso: params?.language_iso,\n },\n );\n return {\n playlist_items: (response.playlist_items ?? []).map(mapPlaylistItem),\n meta: mapPlaylistsMeta(response.meta),\n };\n },\n\n addPlaylistItem: async (playlistId, body) => {\n const response = await portalTenantContent.playlists_items_add(\n client,\n playlistId,\n { item: body },\n );\n const rawItem = response.playlist_item;\n if (!rawItem) {\n throw new Error(\"Playlist item add response missing playlist_item\");\n }\n return {\n playlist_item: mapPlaylistItem(rawItem),\n meta: mapPlaylistsMeta(response.meta),\n };\n },\n\n removePlaylistItem: async (playlistId, itemId) => {\n const response = await portalTenantContent.playlists_items_remove(\n client,\n playlistId,\n itemId,\n );\n return {\n playlist_item: { id: response.playlist_item?.id ?? 0 },\n meta: mapPlaylistsMeta(response.meta),\n };\n },\n\n reorderPlaylistItems: async (playlistId, body) => {\n const response = await portalTenantContent.playlists_items_reorder(\n client,\n playlistId,\n body,\n );\n return {\n playlist_id: response.playlist_id ?? playlistId,\n meta: mapPlaylistsMeta(response.meta),\n };\n },\n };\n}\n\n// ============================================================================\n// Playlists — ShareablesApi-compatible adapter (private)\n// ============================================================================\n\n// Map BFF content_type ↔ legacy admin polymorphic relateable_type used by the\n// Playlists UI, plus reverse for outgoing add-item payloads.\nconst CONTENT_TYPE_TO_RELATEABLE: Record<\n playlists.ContentType,\n \"Medium\" | \"Page\" | \"Product\" | \"EnrollmentPack\"\n> = {\n media: \"Medium\",\n page: \"Page\",\n product: \"Product\",\n enrollment_pack: \"EnrollmentPack\",\n};\n\nconst RELATEABLE_TO_CONTENT_TYPE: Record<string, playlists.ContentType> = {\n Medium: \"media\",\n Media: \"media\",\n media: \"media\",\n Page: \"page\",\n page: \"page\",\n Product: \"product\",\n product: \"product\",\n EnrollmentPack: \"enrollment_pack\",\n enrollment_pack: \"enrollment_pack\",\n};\n\nfunction firstImageUrl(\n images: Array<{ url?: string | null }> | undefined,\n): string | null {\n return images?.[0]?.url ?? null;\n}\n\nfunction toShareablePlaylistItem(\n item: playlists.PlaylistItem,\n): shareables.PlaylistItem {\n const relateableType = CONTENT_TYPE_TO_RELATEABLE[item.content_type];\n const base: shareables.PlaylistItem = {\n id: item.id,\n order: item.position ?? undefined,\n relateable_type: relateableType,\n relateable: { id: item.content_id },\n };\n\n switch (item.content_type) {\n case \"media\": {\n const c = item.content as playlists.MediaContent;\n const isVideo = c.content_format === \"video\";\n const isPdf = c.content_format === \"pdf\";\n base.title = c.title ?? \"Untitled\";\n base.image_url =\n isVideo || isPdf\n ? (c.thumbnail_url ?? null)\n : (c.url ?? c.thumbnail_url ?? null);\n base.kind = mediaKindFromType(c.content_format ?? \"\");\n base.video_url = isVideo ? (c.url ?? null) : null;\n base.duration = null;\n base.media_format = c.content_format ?? null;\n base.relateable = {\n id: c.id,\n title: c.title,\n image_url: base.image_url,\n media_format: c.content_format ?? null,\n video_url: base.video_url,\n kind: base.kind,\n description: {\n id: null,\n name: null,\n body: c.description ?? null,\n record_type: null,\n record_id: null,\n created_at: c.created_at ?? null,\n updated_at: c.updated_at ?? null,\n locale: null,\n },\n };\n break;\n }\n case \"page\": {\n const c = item.content as playlists.PageContent;\n base.title = c.title ?? \"Untitled\";\n base.image_url = c.image_url ?? null;\n base.relateable = {\n id: c.id,\n title: c.title,\n slug: c.slug ?? null,\n image_url: c.image_url ?? null,\n status: c.status,\n description: {\n id: null,\n name: null,\n body: c.description ?? null,\n record_type: null,\n record_id: null,\n created_at: null,\n updated_at: null,\n locale: null,\n },\n };\n break;\n }\n case \"product\": {\n const c = item.content as playlists.ProductContent;\n const image = firstImageUrl(c.images);\n base.title = c.name;\n base.image_url = image;\n base.relateable = {\n id: c.id,\n title: c.name,\n slug: c.slug ?? null,\n price: c.price ?? null,\n display_price: c.price ?? null,\n image_url: image,\n status: c.status ?? null,\n description: {\n id: null,\n name: null,\n body: c.description ?? null,\n record_type: null,\n record_id: null,\n created_at: c.created_at ?? null,\n updated_at: null,\n locale: null,\n },\n images: (c.images ?? []).map((img) => ({\n image_url: img.url ?? null,\n })),\n };\n break;\n }\n case \"enrollment_pack\": {\n const c = item.content as playlists.EnrollmentPackContent;\n const image = firstImageUrl(c.images);\n base.title = c.title;\n base.image_url = image;\n base.relateable = {\n id: c.id,\n title: c.title,\n slug: c.slug ?? null,\n canonical_url: c.url ?? null,\n image_url: image,\n description: {\n id: null,\n name: null,\n body: c.description ?? null,\n record_type: null,\n record_id: null,\n created_at: null,\n updated_at: null,\n locale: null,\n },\n images: (c.images ?? []).map((img) => ({\n image_url: img.url ?? null,\n })),\n };\n break;\n }\n default: {\n // If a new ContentType literal is added without updating this switch,\n // TypeScript will reject this assignment at compile time. At runtime,\n // unknown discriminators surface as a typed error rather than silently\n // producing a row with no title/image.\n const _exhaustive: never = item.content_type;\n throw new Error(\n `Unhandled playlist item content_type: ${String(_exhaustive)}`,\n );\n }\n }\n\n return base;\n}\n\nfunction toBffPlaylist(\n bff: playlists.Playlist,\n items?: shareables.PlaylistItem[],\n): shareables.Playlist {\n return {\n id: bff.id,\n title: bff.title,\n description: bff.description ?? null,\n image_url: bff.image_url ?? null,\n slug: null,\n active: true,\n user_id: bff.user_id ?? null,\n is_favorited: bff.is_favorited ?? false,\n items: items ?? [],\n items_count: bff.items_count,\n };\n}\n\nfunction createPlaylistsAdapter(client: FetchClient): PlaylistsApi {\n const portAdapter = createRawPlaylistsAdapter(client);\n\n return {\n getPlaylists: async (options?: PlaylistsQuery) => {\n // The UI sends Rails-style sort (\"-title\", \"title\", \"-created_at\")\n // but the BFF expects \"title_asc\", \"title_desc\", etc.\n const rawSort = options?.sort;\n let bffSort:\n | \"title_asc\"\n | \"title_desc\"\n | \"created_at_asc\"\n | \"created_at_desc\"\n | undefined;\n if (rawSort === \"title_asc\" || rawSort === \"title\") {\n bffSort = \"title_asc\";\n } else if (rawSort === \"title_desc\" || rawSort === \"-title\") {\n bffSort = \"title_desc\";\n } else if (rawSort === \"created_at_asc\" || rawSort === \"created_at\") {\n bffSort = \"created_at_asc\";\n } else if (rawSort === \"created_at_desc\" || rawSort === \"-created_at\") {\n bffSort = \"created_at_desc\";\n }\n\n const response = await portAdapter.listPlaylists({\n cursor: options?.[\"page[cursor]\"],\n limit: options?.[\"page[limit]\"],\n \"filter[title]\": options?.[\"filter[title]\"],\n \"filter[ownership]\": options?.[\"filter[ownership]\"],\n sort: bffSort,\n });\n\n return {\n playlists: response.playlists.map((p) => toBffPlaylist(p)),\n meta: {\n request_id: response.meta.request_id ?? \"\",\n timestamp: response.meta.timestamp ?? \"\",\n pagination: {\n cursor: response.meta.pagination?.cursor ?? null,\n limit: response.meta.pagination?.limit ?? 12,\n prev_cursor: response.meta.pagination?.prev_cursor ?? null,\n next_cursor: response.meta.pagination?.next_cursor ?? null,\n total_count: 0,\n total_pages: 0,\n },\n },\n };\n },\n\n getPlaylistById: async (id, language_iso) => {\n // Fetch playlist metadata and all items in parallel.\n // Items are cursor-paginated so we follow next_cursor until exhausted.\n const response = await portAdapter.getPlaylist(id);\n\n const allItems: playlists.PlaylistItem[] = [];\n let cursor: string | undefined;\n const MAX_PAGES = 50; // Safety limit: 50 pages × 100 items = 5,000 items max\n for (let i = 0; i < MAX_PAGES; i++) {\n const page = await portAdapter.listPlaylistItems(id, {\n cursor,\n limit: 100,\n language_iso,\n });\n allItems.push(...page.playlist_items);\n cursor = page.meta.pagination?.next_cursor ?? undefined;\n if (!cursor) break;\n }\n\n const items: shareables.PlaylistItem[] = allItems.map(\n toShareablePlaylistItem,\n );\n\n return {\n playlist: toBffPlaylist(response.playlist, items),\n meta: {\n request_id: response.meta.request_id ?? \"\",\n timestamp: response.meta.timestamp ?? \"\",\n },\n };\n },\n\n createPlaylist: async (data) => {\n const response = await portAdapter.createPlaylist({\n title: data.playlist.title,\n description: data.playlist.description,\n });\n return {\n playlist: toBffPlaylist(response.playlist),\n meta: {\n request_id: response.meta.request_id ?? \"\",\n timestamp: response.meta.timestamp ?? \"\",\n },\n };\n },\n\n updatePlaylist: async (id, data) => {\n const response = await portAdapter.updatePlaylist(id, {\n title: data.playlist.title,\n description: data.playlist.description,\n });\n return {\n playlist: toBffPlaylist(response.playlist),\n meta: {\n request_id: response.meta.request_id ?? \"\",\n timestamp: response.meta.timestamp ?? \"\",\n },\n };\n },\n\n addItemToPlaylist: async (id, data) => {\n // Sequential dispatch — the BFF assigns playlist position by insert\n // order when the request omits an explicit position, and shared\n // explicit positions across concurrent requests would race. for-of\n // ordering keeps the playlist deterministic regardless of caller.\n for (const item of data.items) {\n const contentType = RELATEABLE_TO_CONTENT_TYPE[item.relateable_type];\n if (!contentType) {\n throw new Error(\n `Unsupported relateable_type for playlist item: \"${item.relateable_type}\"`,\n );\n }\n await portAdapter.addPlaylistItem(id, {\n content_type: contentType,\n content_id: item.relateable_id,\n position:\n typeof item.order === \"number\" ? item.order : Number(item.order),\n });\n }\n return {\n id,\n title: \"\",\n description: null,\n image_url: null,\n slug: null,\n active: true,\n user_id: null,\n is_favorited: false,\n items: [],\n items_count: 0,\n } satisfies shareables.Playlist;\n },\n\n removeItemsFromPlaylist: async (playlistId, data) => {\n await Promise.all(\n data.item_ids.map((itemId) =>\n portAdapter.removePlaylistItem(playlistId, itemId),\n ),\n );\n return {\n id: playlistId,\n title: \"\",\n description: null,\n image_url: null,\n slug: null,\n active: true,\n user_id: null,\n is_favorited: false,\n items: [],\n items_count: 0,\n } satisfies shareables.Playlist;\n },\n\n reorderPlaylistItems: async (playlistId, data) => {\n await portAdapter.reorderPlaylistItems(playlistId, {\n items: data.items,\n });\n },\n };\n}\n\n// ============================================================================\n// Shares — Raw BFF adapter (private)\n// ============================================================================\n\nfunction isShareableType(\n value: string | undefined,\n): value is shares.ShareableType {\n return (\n value === \"media\" ||\n value === \"product\" ||\n value === \"library\" ||\n value === \"page\"\n );\n}\n\nfunction mapShare(\n raw: NonNullable<\n Awaited<ReturnType<typeof portalTenantContent.shares_list>>[\"shares\"]\n >[number],\n): shares.Share {\n return {\n id: raw.id ?? 0,\n url: raw.url ?? \"\",\n shareable_type: isShareableType(raw.shareable_type)\n ? raw.shareable_type\n : \"media\",\n shareable_id: raw.shareable_id ?? 0,\n created_at: raw.created_at ?? \"\",\n };\n}\n\nfunction mapSharesMeta(\n raw: Awaited<ReturnType<typeof portalTenantContent.shares_list>>[\"meta\"],\n): shares.SharesListResponse[\"meta\"] {\n return {\n request_id: raw?.request_id ?? null,\n timestamp: raw?.timestamp ?? \"\",\n pagination: raw?.pagination\n ? {\n cursor: raw.pagination.cursor ?? null,\n limit: raw.pagination.limit,\n next_cursor: raw.pagination.next_cursor ?? null,\n prev_cursor: raw.pagination.prev_cursor ?? null,\n }\n : undefined,\n };\n}\n\nfunction createRawSharesAdapter(client: FetchClient): ContentSharesApi {\n return {\n listShares: async (params) => {\n const response = await portalTenantContent.shares_list(client, {\n \"page[cursor]\": params?.cursor,\n \"page[limit]\": params?.limit,\n });\n return {\n shares: (response.shares ?? []).map(mapShare),\n meta: mapSharesMeta(response.meta),\n };\n },\n\n createShare: async (body) => {\n const response = await portalTenantContent.shares_create(client, {\n share: body,\n });\n return {\n share: mapShare(response.share ?? {}),\n meta: mapSharesMeta(response.meta),\n };\n },\n };\n}\n\n// ============================================================================\n// Shares — ShareablesApi-compatible adapter (private)\n// ============================================================================\n\nconst SHAREABLE_TYPE_MAP: Record<string, shares.ShareableType> = {\n Medium: \"media\",\n media: \"media\",\n Product: \"product\",\n product: \"product\",\n Library: \"library\",\n library: \"library\",\n Page: \"page\",\n page: \"page\",\n};\n\nfunction createShareAdapter(client: FetchClient): ShareApi {\n const portAdapter = createRawSharesAdapter(client);\n\n return {\n createShareLink: async (input) => {\n if (!input.relateableId) {\n throw new Error(\"Cannot create share link without a relateableId\");\n }\n const shareableType = SHAREABLE_TYPE_MAP[input.relateableType];\n if (!shareableType) {\n throw new Error(`Unknown shareable type: \"${input.relateableType}\"`);\n }\n\n const response = await portAdapter.createShare({\n shareable_type: shareableType,\n shareable_id: input.relateableId,\n });\n\n return response.share.url;\n },\n };\n}\n\n// ============================================================================\n// Pages — Raw BFF adapter (private)\n// ============================================================================\n\nfunction mapPage(\n raw: NonNullable<\n Awaited<ReturnType<typeof portalTenantContent.pages_list>>[\"pages\"]\n >[number],\n): pages.Page {\n return {\n id: raw.id ?? 0,\n title: raw.title ?? null,\n slug: raw.slug ?? null,\n source: raw.source ?? null,\n status: raw.status ?? \"unpublished\",\n countries: (raw.countries ?? []).map((c) => ({\n code: c.code ?? \"\",\n name: c.name ?? \"\",\n currency_code: c.currency_code ?? \"\",\n states: (c.states ?? []).map((s) => ({\n code: s.code ?? \"\",\n name: s.name ?? \"\",\n })),\n })),\n description: raw.description ?? null,\n image_url: raw.image_url ?? null,\n };\n}\n\nfunction mapPagesMeta(\n raw: Awaited<ReturnType<typeof portalTenantContent.pages_list>>[\"meta\"],\n): pages.PagesListResponse[\"meta\"] {\n return {\n request_id: raw?.request_id ?? null,\n timestamp: raw?.timestamp ?? \"\",\n pagination: raw?.pagination\n ? {\n cursor: raw.pagination.cursor ?? null,\n limit: raw.pagination.limit,\n next_cursor: raw.pagination.next_cursor ?? null,\n prev_cursor: raw.pagination.prev_cursor ?? null,\n }\n : undefined,\n };\n}\n\nfunction createRawPagesAdapter(client: FetchClient): ContentPagesApi {\n return {\n listPages: async (params) => {\n const response = await portalTenantContent.pages_list(client, {\n \"page[cursor]\": params?.cursor,\n \"page[limit]\": params?.limit,\n \"filter[title]\": params?.[\"filter[title]\"],\n sort: params?.sort,\n language_iso: params?.language_iso,\n });\n return {\n pages: (response.pages ?? []).map(mapPage),\n meta: mapPagesMeta(response.meta),\n };\n },\n\n getPage: async (id, language_iso) => {\n const response = await portalTenantContent.pages_show(\n client,\n id,\n language_iso ? { language_iso } : undefined,\n );\n if (!response.page) {\n throw new Error(`Page ${id} not found`);\n }\n return {\n page: mapPage(response.page),\n share_link: response.share_link ?? null,\n meta: mapPagesMeta(response.meta),\n };\n },\n };\n}\n\n// ============================================================================\n// Enrollment Packs — Raw BFF adapter (private)\n//\n// The list endpoint lives on portal-tenant (not portal-tenant-content).\n// The port (`ContentEnrollmentPacksApi`) is namespace-agnostic — this is\n// the only adapter file that has to know.\n// ============================================================================\n\nfunction mapEnrollmentPack(raw: {\n id?: number;\n title?: string;\n slug?: string | null;\n description?: string | null;\n url?: string;\n canonical_url?: string;\n images?: { url?: string; alt?: string | null }[];\n}): enrollmentPacks.EnrollmentPack {\n return {\n id: raw.id ?? 0,\n title: raw.title ?? \"\",\n slug: raw.slug ?? null,\n description: raw.description ?? null,\n url: raw.url ?? null,\n canonical_url: raw.canonical_url ?? null,\n images: (raw.images ?? []).map((img) => ({\n url: img.url ?? null,\n alt: img.alt ?? null,\n })),\n };\n}\n\nfunction mapEnrollmentPacksMeta(\n raw:\n | Awaited<ReturnType<typeof portalTenant.enrollment_packs_list>>[\"meta\"]\n | undefined,\n): enrollmentPacks.EnrollmentPacksListResponse[\"meta\"] {\n return {\n request_id: raw?.request_id ?? null,\n timestamp: raw?.timestamp ?? \"\",\n pagination: raw?.pagination\n ? {\n cursor: raw.pagination.cursor ?? null,\n limit: raw.pagination.limit,\n next_cursor: raw.pagination.next_cursor ?? null,\n prev_cursor: raw.pagination.prev_cursor ?? null,\n }\n : undefined,\n };\n}\n\nfunction createRawEnrollmentPacksAdapter(\n client: FetchClient,\n): ContentEnrollmentPacksApi {\n return {\n listEnrollmentPacks: async (params) => {\n const response = await portalTenant.enrollment_packs_list(client, {\n \"page[cursor]\": params?.cursor,\n \"page[limit]\": params?.limit,\n });\n // BFF marks `id` as optional in its generated type; drop entries\n // without one rather than mapping them to id=0 (which would silently\n // misroute downstream playlist-item operations).\n const packs = (response.enrollment_packs ?? [])\n .filter((p): p is typeof p & { id: number } => typeof p.id === \"number\")\n .map(mapEnrollmentPack);\n return {\n enrollment_packs: packs,\n meta: mapEnrollmentPacksMeta(response.meta),\n };\n },\n\n getEnrollmentPack: async (id) => {\n const response = await portalTenant.enrollment_packs_show(client, id);\n if (!response.enrollment_pack) {\n throw new Error(`EnrollmentPack ${id} not found`);\n }\n return {\n enrollment_pack: mapEnrollmentPack(response.enrollment_pack),\n meta: mapEnrollmentPacksMeta(response.meta),\n };\n },\n };\n}\n\n// ============================================================================\n// DAM Assets / Files — Raw BFF adapter (private)\n// ============================================================================\n\nfunction mapDamAsset(\n raw: NonNullable<\n Awaited<ReturnType<typeof portalTenantContent.dam_assets_list>>[\"assets\"]\n >[number],\n): damAssets.DamAsset {\n return {\n id: raw.id ?? 0,\n code: raw.code ?? \"\",\n name: raw.name ?? \"\",\n description: raw.description ?? null,\n category: raw.category ?? null,\n company: raw.company ?? null,\n default_variant_id: raw.default_variant_id ?? null,\n default_variant_url: raw.default_variant_url ?? null,\n canonical_path: raw.canonical_path ?? null,\n created_at: raw.created_at ?? \"\",\n updated_at: raw.updated_at ?? \"\",\n };\n}\n\nfunction mapDamAssetPath(\n raw: NonNullable<\n Awaited<\n ReturnType<typeof portalTenantContent.dam_asset_paths_list>\n >[\"asset_paths\"]\n >[number],\n): damAssets.DamAssetPath {\n return {\n id: raw.id ?? 0,\n asset_code: raw.asset_code ?? \"\",\n path: raw.path ?? \"\",\n created_at: raw.created_at ?? \"\",\n };\n}\n\nfunction mapDamAssetsMeta(\n raw: Awaited<ReturnType<typeof portalTenantContent.dam_assets_list>>[\"meta\"],\n): damAssets.DamAssetsListResponse[\"meta\"] {\n return {\n request_id: raw?.request_id ?? null,\n timestamp: raw?.timestamp ?? \"\",\n pagination: raw?.pagination\n ? {\n cursor: raw.pagination.cursor ?? null,\n limit: raw.pagination.limit,\n next_cursor: raw.pagination.next_cursor ?? null,\n prev_cursor: raw.pagination.prev_cursor ?? null,\n }\n : undefined,\n };\n}\n\nfunction createRawDamAssetsAdapter(client: FetchClient): ContentDamAssetsApi {\n return {\n listAssets: async (params) => {\n const response = await portalTenantContent.dam_assets_list(client, {\n \"page[cursor]\": params?.cursor,\n \"page[limit]\": params?.limit,\n });\n return {\n assets: (response.assets ?? []).map(mapDamAsset),\n meta: mapDamAssetsMeta(response.meta),\n };\n },\n\n createAsset: async (body) => {\n const response = await portalTenantContent.dam_assets_create(client, {\n asset: body,\n });\n return {\n asset: mapDamAsset(response.asset ?? {}),\n meta: mapDamAssetsMeta(response.meta),\n };\n },\n\n listAssetPaths: async (assetCode, params) => {\n const response = await portalTenantContent.dam_asset_paths_list(\n client,\n assetCode,\n {\n \"page[cursor]\": params?.cursor,\n \"page[limit]\": params?.limit,\n },\n );\n return {\n asset_paths: (response.asset_paths ?? []).map(mapDamAssetPath),\n meta: mapDamAssetsMeta(response.meta),\n };\n },\n\n createAssetPath: async (assetCode, body) => {\n const response = await portalTenantContent.dam_asset_paths_create(\n client,\n assetCode,\n { asset_path: body },\n );\n return {\n asset_path: mapDamAssetPath(response.asset_path ?? {}),\n meta: mapDamAssetsMeta(response.meta),\n };\n },\n };\n}\n\n// ============================================================================\n// Files — ShareablesApi-compatible adapter (private)\n// ============================================================================\n\nfunction createFileResourcesAdapter(client: FetchClient): FileResourcesApi {\n const portAdapter = createRawDamAssetsAdapter(client);\n const cursorByPage = new Map<number, string>();\n\n return {\n getFileResources: async (params) => {\n const pageNumber = params?.pageParam ? Number(params.pageParam) : 1;\n const pageSize = params?.pageSize ? Number(params.pageSize) : 25;\n const cursor = pageNumber > 1 ? cursorByPage.get(pageNumber) : undefined;\n\n const response = await portAdapter.listAssets({\n cursor,\n limit: pageSize,\n });\n\n const nextCursor = response.meta.pagination?.next_cursor;\n if (nextCursor) {\n cursorByPage.set(pageNumber + 1, nextCursor);\n }\n\n const fileResources: shareables.FileResource[] = response.assets.map(\n (asset) => ({\n id: asset.id,\n alt_text: asset.name,\n url: asset.default_variant_url ?? \"\",\n filename: asset.name,\n content_type: \"application/octet-stream\",\n content_size: 0,\n handle: asset.code,\n dam_asset_code: asset.code,\n preview_image_url: asset.default_variant_url ?? \"\",\n created_at: asset.created_at,\n updated_at: asset.updated_at ?? \"\",\n relateable_type: null,\n relateable_id: null,\n content: null,\n }),\n );\n\n const hasNextPage = !!nextCursor;\n\n return {\n file_resources: fileResources,\n meta: {\n total_count: fileResources.length,\n per_page: pageSize,\n current_page: pageNumber,\n total_pages: hasNextPage ? pageNumber + 1 : pageNumber,\n },\n };\n },\n };\n}\n\n// ============================================================================\n// Metrics — Raw BFF adapter (private)\n// ============================================================================\n\nfunction mapMetricsMeta(\n raw:\n | Awaited<\n ReturnType<typeof portalTenantContent.content_media_by_visits>\n >[\"meta\"]\n | undefined,\n): metrics.VisitedResponse[\"meta\"] {\n if (!raw) return undefined;\n return {\n request_id: raw.request_id ?? null,\n timestamp: raw.timestamp ?? \"\",\n pagination: raw.pagination\n ? {\n cursor: raw.pagination.cursor ?? null,\n limit: raw.pagination.limit,\n next_cursor: raw.pagination.next_cursor ?? null,\n prev_cursor: raw.pagination.prev_cursor ?? null,\n }\n : undefined,\n };\n}\n\nfunction createMetricsAdapter(client: FetchClient): ContentMetricsApi {\n return {\n listMediaVisited: async (params) => {\n const response = await portalTenantContent.content_media_by_visits(\n client,\n {\n period: params?.period,\n limit: params?.limit,\n language_iso: params?.language_iso,\n },\n );\n return {\n resources: response.resources ?? [],\n meta: mapMetricsMeta(response.meta),\n };\n },\n\n listMediaShareVisited: async (params) => {\n const response = await portalTenantContent.content_media_by_shares(\n client,\n {\n period: params?.period,\n limit: params?.limit,\n language_iso: params?.language_iso,\n },\n );\n return {\n resources: response.resources ?? [],\n meta: mapMetricsMeta(response.meta),\n };\n },\n\n listPlaylistsVisited: async (params) => {\n const response = await portalTenantContent.content_playlists_by_visits(\n client,\n {\n period: params?.period,\n limit: params?.limit,\n },\n );\n return {\n resources: response.resources ?? [],\n meta: mapMetricsMeta(response.meta),\n };\n },\n\n listPlaylistsShareVisited: async (params) => {\n const response = await portalTenantContent.content_playlists_by_shares(\n client,\n { period: params?.period, limit: params?.limit },\n );\n return {\n resources: response.resources ?? [],\n meta: mapMetricsMeta(response.meta),\n };\n },\n\n listPagesVisited: async (params) => {\n const response = await portalTenantContent.content_pages_by_visits(\n client,\n {\n period: params?.period,\n limit: params?.limit,\n language_iso: params?.language_iso,\n },\n );\n return {\n resources: response.resources ?? [],\n meta: mapMetricsMeta(response.meta),\n };\n },\n\n listPagesShareVisited: async (params) => {\n const response = await portalTenantContent.content_pages_by_shares(\n client,\n {\n period: params?.period,\n limit: params?.limit,\n language_iso: params?.language_iso,\n },\n );\n return {\n resources: response.resources ?? [],\n meta: mapMetricsMeta(response.meta),\n };\n },\n };\n}\n\n// ============================================================================\n// Product Media (private)\n// ============================================================================\n\n/**\n * Narrow interface for the product media endpoint. Matches\n * PortalProductsApi.getProductMedia without importing the full products-core\n * dependency graph, keeping the dependency graph clean.\n */\nexport interface ProductMediaSource {\n getProductMedia(productId: string | number): Promise<{\n media: ReadonlyArray<{\n id?: number;\n title?: string;\n media_type?: string;\n url?: string;\n }>;\n }>;\n}\n\nfunction mapProductMedia(raw: {\n id?: number;\n title?: string;\n media_type?: string;\n url?: string;\n}): shareables.ProductMedia {\n const isVideo = raw.media_type === \"video\";\n const isPdf = raw.media_type === \"pdf\" || raw.media_type === \"document\";\n return {\n id: raw.id ?? 0,\n slug: null,\n title: raw.title ?? \"\",\n kind: isVideo ? \"video\" : isPdf ? \"pdf\" : \"image\",\n media_type: raw.media_type ?? \"image\",\n media_format: raw.media_type ?? \"image\",\n image_url: !isVideo && !isPdf ? (raw.url ?? null) : null,\n video_url: isVideo ? (raw.url ?? null) : null,\n pdf_url: isPdf ? (raw.url ?? null) : null,\n powerpoint_url: null,\n duration: 0,\n description: null,\n subtitles: {},\n comments_count: 0,\n };\n}\n\nfunction createProductMediaAdapter(\n source: ProductMediaSource,\n): ProductMediaApi {\n return {\n getProductMedia: async (productId: number) => {\n const response = await source.getProductMedia(productId);\n return {\n media: (response.media ?? []).map(mapProductMedia),\n };\n },\n };\n}\n\n// ============================================================================\n// Internal test helpers (consumed by tests only — not re-exported from index.ts)\n// ============================================================================\n\n/** @internal — For tests only. */\nexport const _createRawMediaAdapter: typeof createRawMediaAdapter =\n createRawMediaAdapter;\n/** @internal — For tests only. */\nexport const _createRawDamAssetsAdapter: typeof createRawDamAssetsAdapter =\n createRawDamAssetsAdapter;\n/** @internal — For tests only. */\nexport const _createRawSharesAdapter: typeof createRawSharesAdapter =\n createRawSharesAdapter;\n/** @internal — For tests only. */\nexport const _createMetricsAdapter: typeof createMetricsAdapter =\n createMetricsAdapter;\n/** @internal — For tests only. */\nexport const _createRawPagesAdapter: typeof createRawPagesAdapter =\n createRawPagesAdapter;\n\n// ============================================================================\n// Public exports\n// ============================================================================\n\n/**\n * Creates a composite ContentDomainApi backed by the portal-tenant Content\n * BFF endpoints. Follows the same pattern as\n * `createPortalContactsDomainApiAdapter`.\n */\nexport function createPortalContentDomainApiAdapter(\n client: FetchClient,\n productsApi: ProductMediaSource,\n): ContentDomainApi {\n return {\n media: createMediaAdapter(client),\n playlists: createPlaylistsAdapter(client),\n fileResources: createFileResourcesAdapter(client),\n share: createShareAdapter(client),\n productMedia: createProductMediaAdapter(productsApi),\n metrics: createMetricsAdapter(client),\n pages: createRawPagesAdapter(client),\n };\n}\n\n/**\n * Creates a ContentPlaylistsApi (the port-level playlists adapter) for\n * operations that aren't part of the shareables PlaylistsApi — e.g.\n * `deletePlaylist`. Exposed separately because ContentDomainApi.playlists\n * is the higher-level shareables PlaylistsApi.\n */\nexport function createPortalContentPlaylistsAdapter(\n client: FetchClient,\n): ContentPlaylistsApi {\n return createRawPlaylistsAdapter(client);\n}\n\n/**\n * Creates a ContentPagesApi (the port-level pages adapter) for screens that\n * need to list/show pages outside of ShareablesApiProvider — e.g. the\n * playlist editor's content picker. Mirrors createPortalContentPlaylistsAdapter.\n */\nexport function createPortalContentPagesAdapter(\n client: FetchClient,\n): ContentPagesApi {\n return createRawPagesAdapter(client);\n}\n\n/**\n * Creates a ContentEnrollmentPacksApi adapter for screens that need to\n * list/show enrollment packs outside of ShareablesApiProvider — e.g. the\n * playlist editor's content picker. Backed by the portal-tenant\n * `/api/enrollment_packs` endpoint.\n */\nexport function createPortalContentEnrollmentPacksAdapter(\n client: FetchClient,\n): ContentEnrollmentPacksApi {\n return createRawEnrollmentPacksAdapter(client);\n}\n\n/**\n * Toggles a favorite entry on a given shareable (Medium / Playlist /\n * Product / etc.) via the portal-tenant BFF's /favorites/toggle endpoint.\n * Returns the new is_favorited state reported by the backend.\n */\nexport async function toggleFavorite(\n client: FetchClient,\n favoriteableId: number,\n favoriteableType: string,\n): Promise<{ is_favorited: boolean }> {\n const res = await client.post<{\n favorite: { is_favorited: boolean };\n }>(\"/api/content/favorites/toggle\", {\n favoriteable_id: favoriteableId,\n favoriteable_type: favoriteableType,\n });\n return { is_favorited: res.favorite?.is_favorited ?? false };\n}\n","import {\n createContext,\n type ReactElement,\n type ReactNode,\n use,\n useMemo,\n} from \"react\";\nimport { ShareablesApiProvider } from \"@fluid-app/shareables-core\";\nimport type { ContentMediaProductsApi } from \"@fluid-app/shareables-core/media-api\";\nimport type { ContentPagesApi } from \"@fluid-app/shareables-core/pages-api\";\nimport type { ContentEnrollmentPacksApi } from \"@fluid-app/shareables-core/enrollment-packs-api\";\nimport type { ContentPlaylistsApi } from \"@fluid-app/shareables-core/playlists-api\";\nimport type { PortalProductsApi } from \"@fluid-app/products-core\";\nimport { FilePickerApiProvider } from \"@fluid-app/file-picker-core\";\nimport { usePortalProductsApi } from \"@fluid-app/products-core\";\nimport { createFilePickerApiAdapter } from \"../adapters/file-picker-api-adapter\";\nimport { usePortalTenantClient } from \"../providers/PortalTenantClientProvider\";\nimport {\n createPortalContentDomainApiAdapter,\n createPortalContentEnrollmentPacksAdapter,\n createPortalContentPagesAdapter,\n createPortalContentPlaylistsAdapter,\n createPortalTenantMediaProductsAdapter,\n} from \"../adapters/content-api-adapter\";\n\n/**\n * Extra context values that screens need beyond ContentDomainApi.\n * ContentDomainApi flows through ShareablesApiProvider; these extras\n * are available via usePortalContentContext().\n */\nexport interface PortalContentContext {\n /** The products adapter — exposed so screens can call listProducts / getProduct\n * without a separate usePortalProductsApi() import. */\n productsApi: PortalProductsApi;\n /** Port-level playlists adapter for operations outside ShareablesApiProvider\n * (e.g. deletePlaylist). */\n playlistsAdapter: ContentPlaylistsApi;\n /** Port-level pages adapter for operations outside ShareablesApiProvider\n * (e.g. picker source for the playlist editor). */\n pagesAdapter: ContentPagesApi;\n /** Port-level enrollment-packs adapter — backed by the portal-tenant\n * /api/enrollment_packs endpoint. Used by the playlist editor's content\n * picker. */\n enrollmentPacksAdapter: ContentEnrollmentPacksApi;\n /** Media products adapter for tagging products on media. */\n mediaProductsAdapter: ContentMediaProductsApi;\n}\n\nconst ContentContext = createContext<PortalContentContext | null>(null);\n\nexport function usePortalContentContext(): PortalContentContext {\n const ctx = use(ContentContext);\n if (!ctx) {\n throw new Error(\n \"usePortalContentContext must be used within a <PortalContentApiProvider>\",\n );\n }\n return ctx;\n}\n\n/**\n * Provides all content-domain adapters (media, playlists, shares,\n * fileResources, productMedia) via ShareablesApiProvider, plus extra\n * context values available through usePortalContentContext().\n *\n * **Required ancestor:** `<PortalProductsApiProvider>` must appear above\n * this in the tree — it supplies the `PortalProductsApi` consumed via\n * `usePortalProductsApi()` for product-media bridging.\n */\nexport function PortalContentApiProvider({\n children,\n}: {\n children: ReactNode;\n}): ReactElement {\n const client = usePortalTenantClient();\n const productsApi = usePortalProductsApi();\n\n const contentApi = useMemo(\n () => createPortalContentDomainApiAdapter(client, productsApi),\n [client, productsApi],\n );\n\n const playlistsAdapter = useMemo(\n () => createPortalContentPlaylistsAdapter(client),\n [client],\n );\n\n const pagesAdapter = useMemo(\n () => createPortalContentPagesAdapter(client),\n [client],\n );\n\n const enrollmentPacksAdapter = useMemo(\n () => createPortalContentEnrollmentPacksAdapter(client),\n [client],\n );\n\n const mediaProductsAdapter = useMemo(\n () => createPortalTenantMediaProductsAdapter(client),\n [client],\n );\n\n const filePickerApi = useMemo(\n () => createFilePickerApiAdapter(client),\n [client],\n );\n\n const ctx = useMemo(\n () => ({\n productsApi,\n playlistsAdapter,\n pagesAdapter,\n enrollmentPacksAdapter,\n mediaProductsAdapter,\n }),\n [\n productsApi,\n playlistsAdapter,\n pagesAdapter,\n enrollmentPacksAdapter,\n mediaProductsAdapter,\n ],\n );\n\n return (\n <ContentContext.Provider value={ctx}>\n <ShareablesApiProvider value={contentApi}>\n <FilePickerApiProvider value={filePickerApi}>\n {children}\n </FilePickerApiProvider>\n </ShareablesApiProvider>\n </ContentContext.Provider>\n );\n}\n","export const shareablesEn = {\n // Common\n common_save: \"Save\",\n common_cancel: \"Cancel\",\n common_delete: \"Delete\",\n common_deleting: \"Deleting...\",\n common_edit: \"Edit\",\n common_done: \"Done\",\n common_on: \"On\",\n common_off: \"Off\",\n common_replace: \"Replace\",\n common_remove: \"Remove\",\n common_removing: \"Removing...\",\n common_add: \"Add\",\n common_adding: \"Adding...\",\n common_added: \"Added\",\n common_untitled: \"Untitled\",\n common_loading: \"Loading...\",\n common_na: \"N/A\",\n common_all: \"All\",\n common_mine: \"Mine\",\n common_company: \"Company\",\n common_product: \"Product\",\n common_enrollment: \"Enrollment\",\n common_enrollment_pack: \"Enrollment Pack\",\n enrollment_pack_fallback_name: \"Enrollment Pack #{{id}}\",\n common_page: \"Page\",\n common_unknown: \"Unknown\",\n common_title_label: \"Title\",\n common_description_label: \"Description\",\n common_start_writing_placeholder: \"Start writing...\",\n common_read_more: \"Read more\",\n common_read_less: \"Read less\",\n common_not_found_default: \"Not found or failed to load.\",\n common_load_error_default: \"Failed to load. Please try again.\",\n common_error_prefix: \"Error: \",\n common_fill_required_fields: \"Please fill out all required fields\",\n common_select_all: \"Select All\",\n common_deselect_all: \"Deselect All\",\n common_selected_count: \"{{count}} selected\",\n common_favorite: \"Favorite\",\n common_unfavorite: \"Unfavorite\",\n common_cancel_selection_aria: \"Cancel selection\",\n common_more_options_aria: \"More options\",\n common_list_view: \"List view\",\n common_grid_view: \"Grid view\",\n common_site_hostname_fallback: \"your-site.com\",\n\n // Sort options\n sort_newest: \"Newest\",\n sort_oldest: \"Oldest\",\n sort_newest_first: \"Newest first\",\n sort_name_asc: \"Name (A-Z)\",\n sort_name_desc: \"Name (Z-A)\",\n sort_title_asc: \"Title (A-Z)\",\n sort_title_desc: \"Title (Z-A)\",\n sort_date_newest: \"Date Created (Newest)\",\n sort_date_oldest: \"Date Created (Oldest)\",\n sort_price_asc: \"Price: Low to High\",\n sort_price_desc: \"Price: High to Low\",\n\n // Media\n media_breadcrumb: \"Media\",\n media_heading: \"Media\",\n media_new_title: \"New Media\",\n media_create_breadcrumb: \"New Media\",\n media_type_image: \"Image\",\n media_type_video: \"Video\",\n media_type_pdf: \"PDF\",\n media_type_default: \"Media\",\n media_create_success: \"Media created successfully\",\n media_create_error: \"Failed to create media: {{message}}\",\n media_save_success: \"Media saved successfully\",\n media_save_error: \"Failed to save: {{message}}\",\n media_delete_success: \"Media deleted\",\n media_delete_error: \"Failed to delete: {{message}}\",\n media_title_required: \"Title is required\",\n media_file_required: \"Please select a file\",\n media_not_found: \"Media not found or failed to load.\",\n media_select_button: \"Select Media\",\n media_replace_button: \"Replace Media\",\n media_add_button: \"Add Media\",\n media_upload_placeholder:\n \"No media uploaded. Click to upload an image, video, or PDF.\",\n media_details_heading: \"Media Details\",\n media_title_placeholder: \"Enter media title\",\n media_cta_button_label: \"CTA Button: \",\n media_thumbnail_label: \"Thumbnail\",\n media_thumbnail_alt: \"Thumbnail\",\n media_video_thumbnail_alt: \"Video thumbnail\",\n media_no_thumbnail: \"No thumbnail set\",\n media_pending_save: \"Pending — save to apply\",\n media_select_new_image: \"Select New Image\",\n media_thumbnail_capture_unavailable:\n \"Thumbnail capture is not available in this context\",\n media_thumbnail_upload_error: \"Failed to upload thumbnail\",\n media_no_media_available: \"No media available\",\n media_actions_aria: \"Media actions\",\n media_my_media_tab: \"My Media\",\n media_my_media_badge: \"My Media\",\n media_search_placeholder: \"Search media...\",\n media_filter_all_types: \"All types\",\n media_filter_images: \"Images\",\n media_filter_videos: \"Videos\",\n media_filter_pdfs: \"PDFs\",\n media_product_carousel_count: \"{{count}} ready-to-share assets\",\n media_product_carousel_description:\n \"Jump into product-led kits when someone asks what to buy.\",\n media_product_carousel_kit_title: \"{{title}} kit\",\n media_product_carousel_next: \"Next product kit\",\n media_product_carousel_previous: \"Previous product kit\",\n media_product_carousel_title: \"Sharables by product\",\n media_empty_default: \"No media available.\",\n media_delete_dialog_title: \"Delete Media\",\n media_delete_dialog_description:\n \"Are you sure you want to delete {{title}}? This action cannot be undone.\",\n media_delete_confirm_title: \"Delete this media?\",\n media_delete_confirm_description:\n \"This removes the item from your media library. Shared links that point to it will stop working.\",\n media_frame_capture_error:\n \"Couldn't capture the video frame. Please try again.\",\n media_select_from_video_frame: \"Select from video frame\",\n media_select_video_frame: \"Select Video Frame\",\n media_select_video_frame_title: \"Select Video Frame\",\n media_capture_frame: \"Capture Frame\",\n media_tagged_products_heading: \"Tagged Products\",\n media_no_products_tagged: \"No products tagged yet.\",\n media_add_product_button: \"Add Product\",\n media_add_products_button: \"Add Products\",\n media_products_selected_count: \"{{current}} of {{max}} products selected\",\n media_products_country_note:\n \"Products will only display in available countries.\",\n media_product_fallback_name: \"Product #{{id}}\",\n media_max_products_reached: \"Maximum {{max}} products reached\",\n media_select_products_title: \"Select Products to Tag\",\n media_products_selected_ratio: \"({{current}}/{{max}} selected)\",\n media_max_products_warning:\n \"You have reached the maximum limit of {{max}} products.\",\n media_limit_reached: \"Limit reached\",\n\n // CTA\n cta_dialog_title: \"CTA Button\",\n cta_dialog_description:\n \"Configure the call-to-action button that appears with your media.\",\n cta_enable_toggle_label: \"Enable call-to-action button\",\n cta_action_type_label: \"Action Type\",\n cta_type_placeholder: \"Select type\",\n cta_type_page: \"Page\",\n cta_type_cart: \"Cart\",\n cta_type_email: \"Email\",\n cta_type_phone: \"Phone\",\n cta_button_label: \"Button Label\",\n cta_default_button_text: \"Learn More\",\n cta_url_label: \"URL\",\n cta_url_placeholder: \"https://example.com\",\n\n // SEO\n seo_heading: \"SEO And Link Sharing\",\n seo_title_label: \"SEO Title\",\n seo_title_placeholder: \"Page title for search engines\",\n seo_description_label: \"SEO Description\",\n seo_description_placeholder: \"Description for search engines\",\n seo_block_crawlers_label: \"Block Crawlers\",\n seo_block_crawlers_description: \"Prevent search engines from indexing\",\n seo_block_crawlers_aria: \"Block search engine crawlers\",\n seo_preview_title_fallback: \"Your page title\",\n seo_preview_url_fallback: \"yoursite.com/media/...\",\n\n // Playlists\n playlist_breadcrumb: \"Playlists\",\n playlist_breadcrumb_fallback: \"Playlist\",\n playlist_create_breadcrumb: \"New Playlist\",\n playlist_edit_breadcrumb: \"Edit Playlist\",\n playlist_badge_label: \"Playlist\",\n playlist_create_success: \"Playlist created successfully\",\n playlist_create_error: \"Failed to create playlist\",\n playlist_update_success: \"Playlist updated successfully\",\n playlist_update_error: \"Failed to update playlist\",\n playlist_delete_success: \"Playlist deleted\",\n playlist_delete_success_full: \"Playlist deleted successfully\",\n playlist_delete_error: \"Failed to delete playlist\",\n playlist_not_found: \"Playlist not found or failed to load.\",\n playlist_create_items_partial_error:\n \"Playlist created but some items failed to add\",\n playlist_favorite_error: \"Failed to update favorite\",\n playlist_favorite_added: \"Added to favorites\",\n playlist_favorite_removed: \"Removed from favorites\",\n playlist_my_playlists_tab: \"My Playlists\",\n playlist_search_placeholder: \"Search playlists...\",\n playlist_create_button: \"Create Playlist\",\n playlist_empty_default: \"There are no playlists available at the moment.\",\n playlist_untitled: \"Untitled Playlist\",\n playlist_item_count_one: \"{{count}} item\",\n playlist_item_count_other: \"{{count}} items\",\n playlist_select_aria: \"Select {{title}}\",\n playlist_actions_aria: \"Playlist actions\",\n playlist_delete_confirm_title: \"Delete this playlist?\",\n playlist_delete_confirm_description:\n \"This removes the playlist from your library. Shared links that point to it will stop working.\",\n playlist_form_heading: \"Playlist\",\n playlist_form_description: \"Name your playlist and add a short description.\",\n playlist_name_label: \"Name *\",\n playlist_name_placeholder: \"Playlist name\",\n playlist_description_placeholder: \"Describe this playlist...\",\n playlist_items_heading: \"Playlist Items\",\n playlist_items_description:\n \"Manage the media and pages in your playlist. At least one is required.\",\n playlist_tagged_products_heading: \"Tagged Products\",\n playlist_tagged_products_description:\n \"Manage the products and enrollments in your playlist. These items will show as recommended items in the cart.\",\n playlist_add_item_button: \"Add Item\",\n playlist_add_item_success: \"Item added to playlist successfully\",\n playlist_add_item_error: \"Failed to add item to playlist\",\n playlist_remove_item_success: \"Item removed from playlist successfully\",\n playlist_remove_item_error: \"Failed to remove item from playlist\",\n playlist_reorder_error: \"Failed to save new item order\",\n playlist_no_items_selected: \"No items selected\",\n playlist_item_already_exists: \"This item is already in the playlist\",\n playlist_delete_item: \"Delete Item\",\n playlist_table_order: \"Order\",\n playlist_table_item: \"Item\",\n playlist_table_type: \"Type\",\n playlist_table_actions: \"Actions\",\n playlist_preview_heading: \"Preview\",\n playlist_og_title_fallback: \"Playlist title\",\n playlist_og_description_fallback:\n \"Description shown when this playlist is shared on social platforms.\",\n playlist_no_other_playlists: \"No Other Playlists\",\n playlist_no_other_playlists_description:\n \"There are no other playlists available\",\n playlist_view_link: \"View playlist ->\",\n playlist_other_playlists_tab: \"Other Playlists\",\n playlist_no_items: \"No Items\",\n playlist_no_items_description: \"This playlist doesn't have any items yet\",\n playlist_items_in_playlist_count: \"Items in playlist ({{count}})\",\n\n // Pages\n pages_breadcrumb: \"Pages\",\n pages_breadcrumb_fallback: \"Page\",\n pages_badge_label: \"Page\",\n pages_load_error: \"Failed to load pages. Please try again.\",\n pages_search_no_results:\n 'No pages match \"{{search}}\". Try a different search term.',\n pages_empty_default: \"No pages available.\",\n pages_search_placeholder: \"Search pages...\",\n pages_fallback_name: \"Page #{{id}}\",\n pages_untitled: \"Untitled Page\",\n pdf_previous_page_aria: \"Previous page\",\n pdf_next_page_aria: \"Next page\",\n pages_status_published: \"Published\",\n pages_status_unpublished: \"Unpublished\",\n pages_not_found: \"Page not found or failed to load.\",\n\n // Products\n products_breadcrumb: \"Products\",\n products_breadcrumb_fallback: \"Product\",\n products_load_error: \"Failed to load products. Please try again.\",\n products_load_more_error: \"Failed to load more products.\",\n products_add_error: \"Failed to add product. Please try again.\",\n products_remove_error: \"Failed to remove product. Please try again.\",\n products_search_placeholder: \"Search products...\",\n products_search_no_results: \"No products found matching your search.\",\n products_search_start_typing: \"Start typing to search for products.\",\n products_empty_default: \"No products available.\",\n products_not_found: \"Product not found or failed to load.\",\n products_no_image: \"No Product Image\",\n products_no_media: \"This product does not have any associated media\",\n products_price_label: \"Price\",\n products_related_sharables: \"Related Sharables\",\n products_asset_count: \"{{count}} assets\",\n\n // Files\n files_breadcrumb: \"Files\",\n files_load_error: \"Failed to load files. Please try again.\",\n files_search_no_results:\n 'No files match \"{{search}}\". Try a different search term.',\n files_empty_default: \"No files available.\",\n files_search_placeholder: \"Search files...\",\n files_untitled: \"Untitled File\",\n files_type_default: \"File\",\n files_size_b: \"B\",\n files_size_kb: \"KB\",\n files_size_mb: \"MB\",\n files_size_gb: \"GB\",\n\n // Share\n share_download_asset: \"Download Asset\",\n share_download_no_asset: \"No downloadable asset available\",\n share_link_copied: \"Share link copied to clipboard!\",\n share_link_copy_error: \"Failed to copy link to clipboard\",\n share_link_not_available: \"Share link not available yet. Please wait...\",\n share_social_description: \"Check out this {{type}}: {{title}}\",\n share_mysite_success: \"Shared to MySite\",\n share_mysite_error: \"Failed to share to MySite\",\n share_unique_link_heading: \"Share Your Unique Link\",\n open_image_viewer: \"Open image viewer\",\n open_image_viewer_for: \"Open image viewer: {{title}}\",\n close_image_viewer: \"Close image viewer\",\n image_viewer_description: \"Share image viewer\",\n image_unavailable: \"Image unavailable\",\n open_media_preview: \"Open media preview\",\n close_media_preview: \"Close media preview\",\n pdf_page_number_aria: \"PDF page number\",\n share_qr_code_alt: \"QR Code for share link\",\n share_qr_code_default_alt: \"QR Code\",\n share_qr_code_load_error: \"QR code failed to load\",\n share_mysite_button: \"MySite\",\n share_mysite_preview_title: \"MySite Preview\",\n share_button: \"Share\",\n share_generating_link: \"Generating link...\",\n share_loading_media: \"Loading media...\",\n share_media_load_error: \"Failed to load media\",\n share_analytics_coming_soon: \"Analytics Coming Soon\",\n share_analytics_description: \"View engagement metrics and performance data\",\n share_type_product: \"product\",\n share_type_media: \"media\",\n share_type_enrollment_pack: \"enrollment pack\",\n share_type_site: \"site\",\n share_type_library: \"library\",\n share_no_marketing_assets: \"No Marketing Assets\",\n share_no_associated_media:\n \"This {{label}} does not have any associated media\",\n share_related_sharables_count: \"Related Sharables ({{count}})\",\n share_no_tab_items_found: \"No {{tab}} found\",\n share_no_items_to_display: \"No items to display\",\n share_click_to_find_assets: \"Click to find shareable assets\",\n share_click_to_share_video: \"Click to share this video\",\n share_click_to_share_asset: \"Click to share this asset\",\n share_no_tagged_products: \"No Tagged Products\",\n share_no_tagged_products_description:\n \"No products are tagged in this playlist\",\n share_tagged_products_count: \"Tagged Products ({{count}})\",\n\n // Owner filter\n common_filter_search_no_results:\n 'No {{entityName}} match \"{{searchTerm}}\" with the current filters. Try a different search term or switch to \"All\".',\n common_search_no_results:\n 'No {{entityName}} match \"{{searchTerm}}\". Try a different search term.',\n common_filter_no_results:\n \"No matching {{entityName}} for the current filters.\",\n\n // Owner filter\n common_empty_default: \"Nothing available at the moment.\",\n playlist_title_required: \"Title is required\",\n media_alt_fallback: \"Media\",\n\n // Social sharing\n share_opening_facebook: \"Opening Facebook share dialog...\",\n share_opening_x: \"Opening X share dialog...\",\n share_opening_linkedin: \"Opening LinkedIn share dialog...\",\n share_copied_instagram:\n \"Link copied! Opening Instagram and paste link in bio or post!.\",\n share_copied_tiktok: \"Link copied! Opening TikTok and paste in your link!\",\n share_failed: \"Failed to share on {{platform}}. Please try again.\",\n\n // PDF / media fallbacks\n pdf_document_title: \"PDF document\",\n media_edit_add_product_failed: \"Failed to add product: {{message}}\",\n media_edit_remove_product_failed: \"Failed to remove product: {{message}}\",\n error_unknown: \"Unknown error\",\n media_edit_seo_preview_alt: \"SEO preview\",\n file_type_image_fallback: \"image\",\n\n // Modal\n modal_asset_details: \"Asset details\",\n\n // Owner filter fallback messages\n filter_empty_search_filtered:\n 'No {{entityName}} match \"{{searchTerm}}\" with the current filters. Try a different search term or switch to \"All\".',\n filter_empty_search:\n 'No {{entityName}} match \"{{searchTerm}}\". Try a different search term.',\n filter_empty_filtered: \"No matching {{entityName}} for the current filters.\",\n filter_empty_default: \"Nothing available at the moment.\",\n\n // Rich text editor\n editor_bold: \"Bold\",\n editor_italic: \"Italic\",\n editor_underline: \"Underline\",\n editor_align_left: \"Align left\",\n editor_align_center: \"Align center\",\n editor_align_right: \"Align right\",\n editor_justify: \"Justify\",\n editor_bullet_list: \"Bullet list\",\n editor_ordered_list: \"Ordered list\",\n} as const satisfies Record<string, string>;\n\nexport type ShareablesDict = typeof shareablesEn;\n","import {\n createDomainTranslations,\n type DomainTranslations,\n} from \"@fluid-app/i18n/translations\";\nimport { createStaticDictAdapter } from \"@fluid-app/i18n/static-dict-adapter\";\nimport type { TranslationApi } from \"@fluid-app/i18n/translation-api\";\nimport { shareablesEn, type ShareablesDict } from \"./translation-dictionary\";\n\nexport const shareablesDomain: DomainTranslations<ShareablesDict> =\n createDomainTranslations<ShareablesDict>({\n fallback: shareablesEn,\n loaders: {\n ar: () =>\n import(\"./locale/ar.json\").then(\n (m): ShareablesDict => m.default as ShareablesDict,\n ),\n bg: () =>\n import(\"./locale/bg.json\").then(\n (m): ShareablesDict => m.default as ShareablesDict,\n ),\n bn: () =>\n import(\"./locale/bn.json\").then(\n (m): ShareablesDict => m.default as ShareablesDict,\n ),\n cs: () =>\n import(\"./locale/cs.json\").then(\n (m): ShareablesDict => m.default as ShareablesDict,\n ),\n da: () =>\n import(\"./locale/da.json\").then(\n (m): ShareablesDict => m.default as ShareablesDict,\n ),\n de: () =>\n import(\"./locale/de.json\").then(\n (m): ShareablesDict => m.default as ShareablesDict,\n ),\n el: () =>\n import(\"./locale/el.json\").then(\n (m): ShareablesDict => m.default as ShareablesDict,\n ),\n es: () =>\n import(\"./locale/es.json\").then(\n (m): ShareablesDict => m.default as ShareablesDict,\n ),\n fi: () =>\n import(\"./locale/fi.json\").then(\n (m): ShareablesDict => m.default as ShareablesDict,\n ),\n fr: () =>\n import(\"./locale/fr.json\").then(\n (m): ShareablesDict => m.default as ShareablesDict,\n ),\n he: () =>\n import(\"./locale/he.json\").then(\n (m): ShareablesDict => m.default as ShareablesDict,\n ),\n hi: () =>\n import(\"./locale/hi.json\").then(\n (m): ShareablesDict => m.default as ShareablesDict,\n ),\n hr: () =>\n import(\"./locale/hr.json\").then(\n (m): ShareablesDict => m.default as ShareablesDict,\n ),\n hu: () =>\n import(\"./locale/hu.json\").then(\n (m): ShareablesDict => m.default as ShareablesDict,\n ),\n id: () =>\n import(\"./locale/id.json\").then(\n (m): ShareablesDict => m.default as ShareablesDict,\n ),\n it: () =>\n import(\"./locale/it.json\").then(\n (m): ShareablesDict => m.default as ShareablesDict,\n ),\n ja: () =>\n import(\"./locale/ja.json\").then(\n (m): ShareablesDict => m.default as ShareablesDict,\n ),\n ko: () =>\n import(\"./locale/ko.json\").then(\n (m): ShareablesDict => m.default as ShareablesDict,\n ),\n ms: () =>\n import(\"./locale/ms.json\").then(\n (m): ShareablesDict => m.default as ShareablesDict,\n ),\n nl: () =>\n import(\"./locale/nl.json\").then(\n (m): ShareablesDict => m.default as ShareablesDict,\n ),\n no: () =>\n import(\"./locale/no.json\").then(\n (m): ShareablesDict => m.default as ShareablesDict,\n ),\n pl: () =>\n import(\"./locale/pl.json\").then(\n (m): ShareablesDict => m.default as ShareablesDict,\n ),\n pt: () =>\n import(\"./locale/pt.json\").then(\n (m): ShareablesDict => m.default as ShareablesDict,\n ),\n ro: () =>\n import(\"./locale/ro.json\").then(\n (m): ShareablesDict => m.default as ShareablesDict,\n ),\n ru: () =>\n import(\"./locale/ru.json\").then(\n (m): ShareablesDict => m.default as ShareablesDict,\n ),\n sk: () =>\n import(\"./locale/sk.json\").then(\n (m): ShareablesDict => m.default as ShareablesDict,\n ),\n sv: () =>\n import(\"./locale/sv.json\").then(\n (m): ShareablesDict => m.default as ShareablesDict,\n ),\n th: () =>\n import(\"./locale/th.json\").then(\n (m): ShareablesDict => m.default as ShareablesDict,\n ),\n tl: () =>\n import(\"./locale/tl.json\").then(\n (m): ShareablesDict => m.default as ShareablesDict,\n ),\n tr: () =>\n import(\"./locale/tr.json\").then(\n (m): ShareablesDict => m.default as ShareablesDict,\n ),\n uk: () =>\n import(\"./locale/uk.json\").then(\n (m): ShareablesDict => m.default as ShareablesDict,\n ),\n vi: () =>\n import(\"./locale/vi.json\").then(\n (m): ShareablesDict => m.default as ShareablesDict,\n ),\n zh_CN: () =>\n import(\"./locale/zh_CN.json\").then(\n (m): ShareablesDict => m.default as ShareablesDict,\n ),\n zh_TW: () =>\n import(\"./locale/zh_TW.json\").then(\n (m): ShareablesDict => m.default as ShareablesDict,\n ),\n },\n });\n\nexport function createShareablesTranslationAdapter(\n locale: string,\n dict: ShareablesDict,\n): TranslationApi<ShareablesDict> {\n return createStaticDictAdapter(locale, dict);\n}\n"],"mappings":"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"}
|