@fluid-app/portal-sdk 0.1.133 → 0.1.134

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.
Files changed (23) hide show
  1. package/dist/{ProductsScreen-DMldTDPg.mjs → ProductsScreen-BsuY5uQt.mjs} +2 -2
  2. package/dist/{ProductsScreen-BPNdpsYm.cjs → ProductsScreen-CC4bgiMI.cjs} +2 -2
  3. package/dist/{ProductsScreen-jdy2j9_J.mjs → ProductsScreen-Ccxux_2H.mjs} +2 -2
  4. package/dist/{ProductsScreen-jdy2j9_J.mjs.map → ProductsScreen-Ccxux_2H.mjs.map} +1 -1
  5. package/dist/{ProductsScreen-BY285fh-.cjs → ProductsScreen-yBjW5cWx.cjs} +2 -2
  6. package/dist/{ProductsScreen-BY285fh-.cjs.map → ProductsScreen-yBjW5cWx.cjs.map} +1 -1
  7. package/dist/{ShareablesScreen-DMBXIMMj.cjs → ShareablesScreen-BGHIqliw.cjs} +2 -2
  8. package/dist/{ShareablesScreen-znVUD_OK.cjs → ShareablesScreen-C3Xue2W7.cjs} +156 -110
  9. package/dist/ShareablesScreen-C3Xue2W7.cjs.map +1 -0
  10. package/dist/{ShareablesScreen-B6tMQzuX.mjs → ShareablesScreen-D8o7wTGM.mjs} +157 -111
  11. package/dist/ShareablesScreen-D8o7wTGM.mjs.map +1 -0
  12. package/dist/{ShareablesScreen-d_ThfnNQ.mjs → ShareablesScreen-DdaBX6Su.mjs} +2 -2
  13. package/dist/index.cjs +7 -7
  14. package/dist/index.d.cts.map +1 -1
  15. package/dist/index.d.mts.map +1 -1
  16. package/dist/index.mjs +7 -7
  17. package/dist/{src-C5GUPE_i.cjs → src-BAcQ6URl.cjs} +9 -8
  18. package/dist/{src-C5GUPE_i.cjs.map → src-BAcQ6URl.cjs.map} +1 -1
  19. package/dist/{src-DcIV4Mpe.mjs → src-j_uOaPI8.mjs} +10 -3
  20. package/dist/{src-DcIV4Mpe.mjs.map → src-j_uOaPI8.mjs.map} +1 -1
  21. package/package.json +19 -19
  22. package/dist/ShareablesScreen-B6tMQzuX.mjs.map +0 -1
  23. package/dist/ShareablesScreen-znVUD_OK.cjs.map +0 -1
@@ -1,9 +1,9 @@
1
- import { et as USER_TYPES, u as usePortalTenantClient } from "./FluidProvider-BUdNsR8f.mjs";
1
+ import { et as USER_TYPES, n as useFluidContext, u as usePortalTenantClient, yt as createFetchClient } from "./FluidProvider-BUdNsR8f.mjs";
2
2
  import { t as useFluidAuth } from "./use-fluid-auth-DrPeCmW-.mjs";
3
3
  import { n as useCurrentUser } from "./use-current-user-BP_GJuQe.mjs";
4
4
  import { n as useAppNavigation } from "./AppNavigationContext-Du3Qq0yc.mjs";
5
5
  import { i as useSdkClient } from "./use-account-clients-BjK5QVYl.mjs";
6
- import { a as ShareablesApiProvider, i as ShareablesUIProvider, n as ShareablesApp, o as ShareablesCoreProvider, r as getFileMimeType } from "./src-DcIV4Mpe.mjs";
6
+ import { a as ShareablesCoreProvider, i as ShareablesApiProvider, n as ShareablesApp, r as ShareablesUIProvider } from "./src-j_uOaPI8.mjs";
7
7
  import { t as usePortalProductsClient } from "./use-portal-products-client-dV5jIXpp.mjs";
8
8
  import { useCallback, useMemo } from "react";
9
9
  import { jsx } from "react/jsx-runtime";
@@ -77,7 +77,7 @@ z.object({ asset: z.object({
77
77
  description: z.string().optional(),
78
78
  tags: z.string().optional()
79
79
  }) });
80
- const damAssetCreateResponseSchema = z.object({
80
+ z.object({
81
81
  asset: damAssetSchema,
82
82
  meta: z.object({
83
83
  request_id: z.string(),
@@ -114,7 +114,7 @@ z.object({
114
114
  }).optional(),
115
115
  skip_autotagging: z.boolean().optional()
116
116
  });
117
- const damAssetPathCreateResponseSchema = z.object({
117
+ z.object({
118
118
  asset: z.object({
119
119
  id: z.number(),
120
120
  canonical_path: z.string(),
@@ -293,8 +293,14 @@ async function dam_assets_list(client, params) {
293
293
  return client.get(`/api/content/dam/assets`, params);
294
294
  }
295
295
  /**
296
- * Create a DAM asset placeholder
297
- * Creates a new DAM asset placeholder record with a canonical path.
296
+ * Create a DAM asset
297
+ * Creates a new DAM asset. Supports two modes:
298
+ 1. **JSON placeholder** — send `application/json` with `asset[name]` to
299
+ create a placeholder record for later file upload.
300
+
301
+ 2. **File upload** — send `multipart/form-data` with `asset[file]`,
302
+ `asset[name]`, and optionally `asset[description]` and `asset[tags]`
303
+ to upload a file and create the full asset with variants.
298
304
  *
299
305
  * @param client - Fetch client instance
300
306
  * @param body - body
@@ -324,6 +330,36 @@ async function dam_asset_paths_list(client, asset_code, params) {
324
330
  async function dam_asset_paths_create(client, asset_code, body) {
325
331
  return client.post(`/api/content/dam/assets/${asset_code}/paths`, body);
326
332
  }
333
+ /**
334
+ * Query DAM assets using tree paths and tags
335
+ * 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.
336
+ *
337
+ * @param client - Fetch client instance
338
+ * @param body - body
339
+ */
340
+ async function dam_query(client, body) {
341
+ return client.post(`/api/content/dam/query`, body);
342
+ }
343
+ /**
344
+ * Delete a DAM asset
345
+ * Permanently destroys a DAM asset, including its ImageKit storage, variants, and database records.
346
+ *
347
+ * @param client - Fetch client instance
348
+ * @param code - code
349
+ */
350
+ async function dam_assets_destroy(client, code) {
351
+ return client.delete(`/api/content/dam/assets/${code}`);
352
+ }
353
+ /**
354
+ * Discard (soft-delete) a DAM asset
355
+ * Soft-deletes a DAM asset. Used to discard an in-progress upload without permanently removing the record.
356
+ *
357
+ * @param client - Fetch client instance
358
+ * @param code - code
359
+ */
360
+ async function dam_assets_discard(client, code) {
361
+ return client.patch(`/api/content/dam/assets/${code}/discard`);
362
+ }
327
363
  //#endregion
328
364
  //#region ../../shareables/api-client/src/portal-tenant-media-adapter.ts
329
365
  /**
@@ -799,9 +835,12 @@ function mapDamAsset(raw) {
799
835
  id: raw.id ?? 0,
800
836
  code: raw.code ?? "",
801
837
  name: raw.name ?? "",
802
- content_type: raw.content_type ?? null,
803
- byte_size: raw.byte_size ?? null,
804
- url: raw.url ?? null,
838
+ description: raw.description ?? null,
839
+ category: raw.category ?? null,
840
+ company: raw.company ?? null,
841
+ default_variant_id: raw.default_variant_id ?? null,
842
+ default_variant_url: raw.default_variant_url ?? null,
843
+ canonical_path: raw.canonical_path ?? null,
805
844
  created_at: raw.created_at ?? "",
806
845
  updated_at: raw.updated_at ?? ""
807
846
  };
@@ -898,15 +937,15 @@ function createPortalTenantFilesShareablesAdapter(client) {
898
937
  const fileResources = response.assets.map((asset) => ({
899
938
  id: asset.id,
900
939
  alt_text: asset.name,
901
- url: asset.url ?? "",
940
+ url: asset.default_variant_url ?? "",
902
941
  filename: asset.name,
903
- content_type: asset.content_type ?? "application/octet-stream",
904
- content_size: asset.byte_size ?? 0,
942
+ content_type: "application/octet-stream",
943
+ content_size: 0,
905
944
  handle: asset.code,
906
945
  dam_asset_code: asset.code,
907
- preview_image_url: asset.url ?? "",
946
+ preview_image_url: asset.default_variant_url ?? "",
908
947
  created_at: asset.created_at,
909
- updated_at: asset.updated_at,
948
+ updated_at: asset.updated_at ?? "",
910
949
  relateable_type: null,
911
950
  relateable_id: null,
912
951
  content: null
@@ -1016,87 +1055,6 @@ function createPortalTenantSharesShareablesAdapter(client) {
1016
1055
  } };
1017
1056
  }
1018
1057
  //#endregion
1019
- //#region ../../file-picker/api-client/src/client.ts
1020
- function createFilePickerClient(config) {
1021
- return {
1022
- fetchClient: config.fetchClient,
1023
- uploadStrategy: config.uploadStrategy,
1024
- unsplashAccessKey: config.unsplashAccessKey,
1025
- proxyEndpoint: config.proxyEndpoint ?? "/api/proxy-url"
1026
- };
1027
- }
1028
- //#endregion
1029
- //#region ../../file-picker/api-client/src/api/dam-assets.ts
1030
- /**
1031
- * Create a DAM asset. Text files use FormData upload; non-text files
1032
- * delegate to the provided uploadStrategy (e.g. ImageKit).
1033
- * If no uploadStrategy is provided, all files use FormData upload.
1034
- */
1035
- async function createDamAsset(fetchClient, params, uploadStrategy) {
1036
- const mimeType = getFileMimeType(params.file);
1037
- if (mimeType.startsWith("text/") || mimeType === "application/json" || mimeType === "application/xml" || params.file.name.endsWith(".txt") || params.file.name.endsWith(".json") || params.file.name.endsWith(".xml") || params.file.name.endsWith(".csv")) return createDamAssetViaFormData(fetchClient, params);
1038
- if (uploadStrategy) return uploadStrategy.uploadFile(params);
1039
- return createDamAssetViaFormData(fetchClient, params);
1040
- }
1041
- async function createDamAssetViaFormData(fetchClient, params) {
1042
- const formData = new FormData();
1043
- formData.append("asset[file]", params.file);
1044
- formData.append("asset[name]", params.name);
1045
- if (params.description) formData.append("asset[description]", params.description);
1046
- if (params.tags && params.tags.length > 0) formData.append("asset[tags]", params.tags.join(","));
1047
- const response = await fetchClient.requestWithFormData("/dam/assets", formData, { method: "POST" });
1048
- return damAssetCreateResponseSchema.parse(response);
1049
- }
1050
- async function createDamAssetPathForAssets(fetchClient, { asset_paths, code }) {
1051
- const response = await fetchClient.post(`/dam/assets/${code}/asset_paths`, { asset_paths });
1052
- return damAssetPathCreateResponseSchema.parse(response);
1053
- }
1054
- //#endregion
1055
- //#region ../../file-picker/api-client/src/api/dam-query.ts
1056
- async function queryDamAssets(fetchClient, params) {
1057
- const response = await fetchClient.post("/dam/query", params);
1058
- return damQueryResponseSchema.parse(response);
1059
- }
1060
- async function deleteDamAsset(fetchClient, code) {
1061
- return fetchClient.delete(`/dam/assets/${code}`);
1062
- }
1063
- async function discardDamAsset(fetchClient, code) {
1064
- return fetchClient.patch(`/dam/assets/${code}/discard`);
1065
- }
1066
- //#endregion
1067
- //#region ../../file-picker/api-client/src/api/unsplash.ts
1068
- const unsplashImageSchema = z.object({
1069
- id: z.string(),
1070
- urls: z.object({
1071
- raw: z.string(),
1072
- full: z.string(),
1073
- regular: z.string(),
1074
- small: z.string(),
1075
- thumb: z.string()
1076
- }),
1077
- alt_description: z.string().nullable(),
1078
- description: z.string().nullable(),
1079
- user: z.object({
1080
- name: z.string(),
1081
- username: z.string()
1082
- }),
1083
- width: z.number(),
1084
- height: z.number()
1085
- });
1086
- const unsplashSearchResponseSchema = z.object({
1087
- results: z.array(unsplashImageSchema),
1088
- total: z.number(),
1089
- total_pages: z.number()
1090
- });
1091
- /**
1092
- * Search Unsplash for photos matching a query.
1093
- */
1094
- async function searchUnsplash(query, accessKey, page = 1, perPage = 20) {
1095
- const response = await fetch(`https://api.unsplash.com/search/photos?query=${encodeURIComponent(query)}&page=${page}&per_page=${perPage}&client_id=${accessKey}`);
1096
- if (!response.ok) throw new Error("Failed to search Unsplash");
1097
- return unsplashSearchResponseSchema.parse(await response.json());
1098
- }
1099
- //#endregion
1100
1058
  //#region ../../file-picker/api-client/src/api/url-proxy.ts
1101
1059
  const urlProxyResponseSchema = z.object({
1102
1060
  data: z.string(),
@@ -1124,24 +1082,93 @@ async function proxyUrlFetch(url, proxyEndpoint = "/api/proxy-url") {
1124
1082
  return urlProxyResponseSchema.parse(data);
1125
1083
  }
1126
1084
  //#endregion
1127
- //#region ../../file-picker/api-client/src/create-file-picker-api.ts
1085
+ //#region ../../file-picker/api-client/src/portal-tenant-adapter.ts
1086
+ /**
1087
+ * Maps a BFF DAM asset to the file-picker port's DamAssetCreateResponse shape.
1088
+ *
1089
+ * The BFF response includes nullable meta.request_id (from Api::Response),
1090
+ * while the port schema requires a string. We coalesce to empty string.
1091
+ */
1092
+ function mapCreateResponse(response) {
1093
+ const raw = response.asset ?? {};
1094
+ return {
1095
+ asset: damAssetSchema.parse({
1096
+ ...raw,
1097
+ canonical_path: raw.canonical_path ?? "",
1098
+ category: raw.category ?? "",
1099
+ company: raw.company ?? "",
1100
+ description: raw.description ?? "",
1101
+ default_variant_id: raw.default_variant_id ?? ""
1102
+ }),
1103
+ meta: {
1104
+ request_id: response.meta?.request_id ?? "",
1105
+ timestamp: response.meta?.timestamp ?? (/* @__PURE__ */ new Date()).toISOString()
1106
+ }
1107
+ };
1108
+ }
1109
+ /**
1110
+ * Maps a BFF asset path response to the file-picker port's shape.
1111
+ */
1112
+ function mapAssetPathCreateResponse(response) {
1113
+ const assetPath = response.asset_path ?? {};
1114
+ return {
1115
+ asset: {
1116
+ id: assetPath.id ?? 0,
1117
+ canonical_path: assetPath.path ?? "",
1118
+ name: assetPath.asset_code ?? ""
1119
+ },
1120
+ meta: {
1121
+ request_id: response.meta?.request_id ?? "",
1122
+ timestamp: response.meta?.timestamp ?? (/* @__PURE__ */ new Date()).toISOString()
1123
+ }
1124
+ };
1125
+ }
1128
1126
  /**
1129
- * Creates a FilePickerApi-compatible adapter backed by the real API client
1130
- * functions. The returned object satisfies the FilePickerApi interface
1131
- * from @fluid-app/file-picker-core via structural typing.
1127
+ * Creates a FilePickerApi adapter backed by the portal-tenant BFF's
1128
+ * `/api/content/dam/*` endpoints, using cookie-based auth via the
1129
+ * provided FetchClient.
1130
+ *
1131
+ * Unsplash search is not available through the BFF — callers that need
1132
+ * Unsplash should use the legacy adapter or provide their own
1133
+ * implementation.
1134
+ *
1135
+ * The `onProgress` callback in `createDamAsset` is not supported — the
1136
+ * underlying `fetch` API does not expose upload progress events.
1137
+ *
1138
+ * URL proxy delegates to the same-origin `/api/proxy-url` endpoint
1139
+ * (served by the hosting app, not the BFF) for CORS bypass, identical
1140
+ * to the legacy adapter behaviour.
1132
1141
  */
1133
- function createFilePickerApi(client) {
1142
+ function createPortalTenantFilePickerApiAdapter(client) {
1134
1143
  return {
1135
- createDamAsset: (params) => createDamAsset(client.fetchClient, params, client.uploadStrategy),
1136
- queryDamAssets: (params) => queryDamAssets(client.fetchClient, params),
1137
- searchUnsplash: (query, page, perPage) => {
1138
- if (!client.unsplashAccessKey) throw new Error("Unsplash access key not configured");
1139
- return searchUnsplash(query, client.unsplashAccessKey, page, perPage);
1144
+ createDamAsset: async (params) => {
1145
+ const formData = new FormData();
1146
+ formData.append("asset[file]", params.file);
1147
+ formData.append("asset[name]", params.name);
1148
+ if (params.description) formData.append("asset[description]", params.description);
1149
+ if (params.tags && params.tags.length > 0) formData.append("asset[tags]", params.tags.join(","));
1150
+ return mapCreateResponse(await client.requestWithFormData("/api/content/dam/assets", formData, { method: "POST" }));
1151
+ },
1152
+ queryDamAssets: async (params) => {
1153
+ const response = await dam_query(client, params);
1154
+ return damQueryResponseSchema.parse({
1155
+ ...response,
1156
+ meta: response.meta ? { next_cursor: response.meta.pagination?.next_cursor ?? void 0 } : void 0
1157
+ });
1158
+ },
1159
+ deleteDamAsset: async (code) => {
1160
+ return dam_assets_destroy(client, code);
1161
+ },
1162
+ discardDamAsset: async (code) => {
1163
+ return dam_assets_discard(client, code);
1164
+ },
1165
+ createDamAssetPathForAssets: async (params) => {
1166
+ return mapAssetPathCreateResponse(await dam_asset_paths_create(client, params.code, { asset_path: { path: params.asset_paths.join(",") } }));
1167
+ },
1168
+ searchUnsplash: async (_query, _page, _perPage) => {
1169
+ throw new Error("Unsplash search is not available through the portal-tenant BFF. Configure an Unsplash access key and use the standard FilePickerApi adapter instead.");
1140
1170
  },
1141
- deleteDamAsset: (code) => deleteDamAsset(client.fetchClient, code),
1142
- discardDamAsset: (code) => discardDamAsset(client.fetchClient, code),
1143
- createDamAssetPathForAssets: (params) => createDamAssetPathForAssets(client.fetchClient, params),
1144
- proxyUrlFetch: (url) => proxyUrlFetch(url, client.proxyEndpoint)
1171
+ proxyUrlFetch: (url) => proxyUrlFetch(url)
1145
1172
  };
1146
1173
  }
1147
1174
  //#endregion
@@ -1178,6 +1205,7 @@ function ShareablesScreen({ background, textColor, accentColor, padding, borderR
1178
1205
  const domainClient = useSdkClient();
1179
1206
  const portalProductsApi = usePortalProductsClient();
1180
1207
  const portalTenantClient = usePortalTenantClient();
1208
+ const { config } = useFluidContext();
1181
1209
  const { data: userData } = useCurrentUser();
1182
1210
  const { currentSlug, navigate } = useAppNavigation();
1183
1211
  const { isCustomer } = useUserType();
@@ -1238,7 +1266,25 @@ function ShareablesScreen({ background, textColor, accentColor, padding, borderR
1238
1266
  }) };
1239
1267
  } }
1240
1268
  }), [portalTenantClient, portalProductsApi]);
1241
- const filePickerApi = useMemo(() => createFilePickerApi(createFilePickerClient({ fetchClient: domainClient })), [domainClient]);
1269
+ const filePickerApi = useMemo(() => {
1270
+ const baseUrl = config.baseUrl.replace(/\/+$/, "").replace(/\/api$/, "");
1271
+ const csrfToken = typeof document !== "undefined" ? document.querySelector("meta[name=\"csrf-token\"]")?.getAttribute("content") : null;
1272
+ return createPortalTenantFilePickerApiAdapter(createFetchClient({
1273
+ baseUrl,
1274
+ getAuthToken: config.getAuthToken,
1275
+ onAuthError: config.onAuthError,
1276
+ credentials: "include",
1277
+ defaultHeaders: {
1278
+ ...config.defaultHeaders,
1279
+ ...csrfToken ? { "X-CSRF-Token": csrfToken } : {}
1280
+ }
1281
+ }));
1282
+ }, [
1283
+ config.baseUrl,
1284
+ config.getAuthToken,
1285
+ config.onAuthError,
1286
+ config.defaultHeaders
1287
+ ]);
1242
1288
  const uiConfig = useMemo(() => ({
1243
1289
  user: userData ? {
1244
1290
  id: userData.id,
@@ -1311,4 +1357,4 @@ const shareablesScreenPropertySchema = {
1311
1357
  //#endregion
1312
1358
  export { shareablesScreenPropertySchema as n, useUserType as r, ShareablesScreen as t };
1313
1359
 
1314
- //# sourceMappingURL=ShareablesScreen-B6tMQzuX.mjs.map
1360
+ //# sourceMappingURL=ShareablesScreen-D8o7wTGM.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ShareablesScreen-D8o7wTGM.mjs","names":["mapMeta","portalTenantContent.media_list","portalTenantContent.media_create","portalTenantContent.media_show","portalTenantContent.media_update","portalTenantContent.media_destroy","mediaKindFromType","mapMeta","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","mapMeta","portalTenantContent.dam_assets_list","portalTenantContent.dam_assets_create","portalTenantContent.dam_asset_paths_list","portalTenantContent.dam_asset_paths_create","portalTenantContent.shares_list","portalTenantContent.shares_create","portalTenantContent.dam_query","portalTenantContent.dam_assets_destroy","portalTenantContent.dam_assets_discard","portalTenantContent.dam_asset_paths_create"],"sources":["../src/hooks/use-user-type.ts","../../../file-picker/core/src/schemas/dam.ts","../../../api-clients/portal-tenant-content/src/namespaces/portal_tenant_content.ts","../../../shareables/api-client/src/portal-tenant-media-adapter.ts","../../../shareables/api-client/src/portal-tenant-playlists-adapter.ts","../../../shareables/api-client/src/portal-tenant-dam-assets-adapter.ts","../../../shareables/api-client/src/portal-tenant-shares-adapter.ts","../../../file-picker/api-client/src/api/url-proxy.ts","../../../file-picker/api-client/src/portal-tenant-adapter.ts","../src/screens/ShareablesScreen.tsx"],"sourcesContent":["import { useMemo } from \"react\";\nimport { useFluidAuth } from \"./use-fluid-auth\";\nimport { USER_TYPES, type UserType } from \"../auth/types\";\n\nexport interface UseUserTypeResult {\n userType: UserType | null;\n isCustomer: boolean;\n isRep: boolean;\n isAdmin: boolean;\n}\n\n/**\n * Convenience hook for user-type checks in the portal SDK.\n */\nexport function useUserType(): UseUserTypeResult {\n const { user } = useFluidAuth();\n\n return useMemo(() => {\n const userType = user?.user_type ?? null;\n return {\n userType,\n isCustomer: userType === USER_TYPES.customer,\n isRep: userType === USER_TYPES.rep,\n isAdmin:\n userType === USER_TYPES.admin || userType === USER_TYPES.root_admin,\n };\n }, [user?.user_type]);\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 };\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 })\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","/**\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 media (own uploads and company media)\n * Returns a paginated list of the member's own uploads and company-owned media.\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.\n *\n * @param client - Fetch client instance\n * @param id - id\n */\nexport async function media_show(\n client: FetchClient,\n id: string | number,\n): Promise<\n operations[\"media_show\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.get(`/api/content/media/${id}`);\n}\n\n/**\n * Update a media item (own uploads only)\n * Updates a media item's title or description.\n *\n * @param client - Fetch client instance\n * @param id - id\n * @param body - body\n */\nexport async function media_update(\n client: FetchClient,\n id: string | number,\n body: operations[\"media_update\"][\"requestBody\"][\"content\"][\"application/json\"],\n): Promise<\n operations[\"media_update\"][\"responses\"][200][\"content\"][\"application/json\"]\n> {\n return client.patch(`/api/content/media/${id}`, body);\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 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 media item 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 * 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 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","import type {\n ContentMediaApi,\n media,\n} from \"@fluid-app/shareables-core/media-api\";\nimport type { MediaApi } from \"@fluid-app/shareables-core/shareables-api\";\nimport type { shareables } from \"@fluid-app/shareables-core/types\";\nimport type { FetchClient } from \"./lib/fetch-client\";\nimport { portalTenantContent } from \"@fluid-app/portal-tenant-content-api-client\";\n\n/**\n * Maps a BFF media object to the port's Media shape, providing defaults\n * for optional fields returned by the generated client.\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 media_type: raw.media_type ?? \"\",\n url: raw.url ?? null,\n thumbnail_url: raw.thumbnail_url ?? null,\n owner_type: raw.owner_type ?? \"\",\n created_at: raw.created_at ?? \"\",\n updated_at: raw.updated_at ?? \"\",\n };\n}\n\n/**\n * Maps the BFF meta envelope to the port's ApiMeta shape.\n */\nfunction mapMeta(\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\n/**\n * Creates a ContentMediaApi adapter backed by the portal-tenant content BFF.\n *\n * Maps the generated portal-tenant-content namespace functions to the abstract\n * ContentMediaApi port, closing over the FetchClient so consumers don't need\n * to pass it per-call.\n */\nexport function createPortalTenantMediaAdapter(\n client: FetchClient,\n): 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 media_type: params?.media_type,\n \"filter[title]\": params?.[\"filter[title]\"],\n sort: params?.sort,\n });\n return {\n media: (response.media ?? []).map(mapMedia),\n meta: mapMeta(response.meta),\n };\n },\n\n createMedia: async (body) => {\n const response = await portalTenantContent.media_create(client, {\n media: body,\n });\n return {\n media: mapMedia(response.media ?? {}),\n meta: mapMeta(response.meta),\n };\n },\n\n getMedia: async (id) => {\n const response = await portalTenantContent.media_show(client, id);\n return {\n media: mapMedia(response.media ?? {}),\n meta: mapMeta(response.meta),\n };\n },\n\n updateMedia: async (id, body) => {\n const response = await portalTenantContent.media_update(client, id, {\n media: body,\n });\n return {\n media: mapMedia(response.media ?? {}),\n meta: mapMeta(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: mapMeta(response.meta),\n };\n },\n };\n}\n\n// ---------------------------------------------------------------------------\n// ShareablesApi-compatible adapter\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 = mediaKindFromType(bff.media_type);\n const isVideo = bff.media_type === \"video\";\n const isPdf = bff.media_type === \"pdf\" || bff.media_type === \"document\";\n\n return {\n id: bff.id,\n user_id: null,\n media_type: bff.media_type,\n media_format: bff.media_type,\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: true,\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: null,\n cta_button_text: null,\n cta_enabled: false,\n cta_action_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 };\n}\n\n/**\n * Creates a ShareablesApi[\"media\"]-compatible adapter backed by the\n * portal-tenant content BFF. Includes cursor-to-page-number caching\n * for bridging the legacy UI's page-number pagination.\n */\nexport function createPortalTenantMediaShareablesAdapter(\n client: FetchClient,\n): MediaApi {\n const portAdapter = createPortalTenantMediaAdapter(client);\n const cursorByPage = new Map<number, string>();\n let lastFilterKey = \"\";\n\n return {\n getMedia: async (options) => {\n const pageNumber = options?.page ?? 1;\n\n // Clear cursor cache when search/sort/type filters change\n const filterKey = `${options?.search_query ?? \"\"}|${options?.sorted_by ?? \"\"}|${options?.media_type ?? options?.with_type ?? \"\"}`;\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 response = await portAdapter.listMedia({\n cursor,\n limit: options?.per_page,\n media_type: options?.media_type ?? options?.with_type,\n \"filter[title]\": options?.search_query,\n sort: bffSort,\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 return {\n data: transformedItems,\n status: \"success\",\n media: transformedItems,\n meta: {\n total_count: transformedItems.length,\n current: pageNumber,\n per_page: options?.per_page ?? 24,\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) => {\n const response = await portAdapter.getMedia(id);\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 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 });\n return toBffMediumResponse(response.media);\n },\n\n updateMedia: async (id, mediaData) => {\n const response = await portAdapter.updateMedia(id, {\n title: mediaData.title,\n description: mediaData.description,\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","import type {\n ContentPlaylistsApi,\n playlists,\n} from \"@fluid-app/shareables-core/playlists-api\";\nimport type { PlaylistsApi } from \"@fluid-app/shareables-core/shareables-api\";\nimport type {\n shareables,\n PlaylistsQuery,\n} from \"@fluid-app/shareables-core/types\";\nimport type { FetchClient } from \"./lib/fetch-client\";\nimport { portalTenantContent } from \"@fluid-app/portal-tenant-content-api-client\";\n\n/**\n * Maps a BFF playlist object to the port's Playlist shape.\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.user_id,\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\n/**\n * Maps a BFF playlist item to the port's PlaylistItem shape.\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 ?? 0,\n media_id: raw.media_id ?? 0,\n position: raw.position ?? null,\n title: raw.title,\n image_url: raw.image_url ?? null,\n media_type: raw.media_type,\n video_url: raw.video_url ?? null,\n duration: raw.duration ?? null,\n created_at: raw.created_at ?? \"\",\n };\n}\n\n/**\n * Maps the BFF meta envelope to the port's ApiMeta shape.\n */\nfunction mapMeta(\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\n/**\n * Creates a ContentPlaylistsApi adapter backed by the portal-tenant content BFF.\n *\n * Maps the generated portal-tenant-content namespace functions to the abstract\n * ContentPlaylistsApi port, closing over the FetchClient so consumers don't\n * need to pass it per-call.\n */\nexport function createPortalTenantPlaylistsAdapter(\n client: FetchClient,\n): 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 sort: params?.sort,\n });\n return {\n playlists: (response.playlists ?? []).map(mapPlaylist),\n meta: mapMeta(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: mapMeta(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: mapMeta(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: mapMeta(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: mapMeta(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 },\n );\n return {\n playlist_items: (response.playlist_items ?? []).map(mapPlaylistItem),\n meta: mapMeta(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 return {\n playlist_item: mapPlaylistItem(response.playlist_item ?? {}),\n meta: mapMeta(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: mapMeta(response.meta),\n };\n },\n };\n}\n\n// ---------------------------------------------------------------------------\n// ShareablesApi-compatible adapter\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 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\n/**\n * Creates a ShareablesApi[\"playlists\"]-compatible adapter backed by the\n * portal-tenant content BFF. Fetches playlist + items in parallel for\n * detail views and maps enriched flat fields onto playlist items.\n */\nexport function createPortalTenantPlaylistsShareablesAdapter(\n client: FetchClient,\n): PlaylistsApi {\n const portAdapter = createPortalTenantPlaylistsAdapter(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 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) => {\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 });\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((item) => ({\n id: item.id,\n order: item.position ?? undefined,\n relateable_type: \"Medium\",\n relateable: { id: item.media_id },\n // Flat fields from BFF — the UI reads these first\n title: item.title ?? \"Untitled\",\n image_url: item.image_url ?? null,\n kind: mediaKindFromType(item.media_type ?? \"\"),\n video_url: item.video_url ?? null,\n duration: item.duration ?? null,\n media_format: item.media_type ?? null,\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 await Promise.all(\n data.items.map((item) =>\n portAdapter.addPlaylistItem(id, {\n media_id: item.relateable_id,\n position:\n typeof item.order === \"number\" ? item.order : Number(item.order),\n }),\n ),\n );\n const updated = await portAdapter.getPlaylist(id);\n return toBffPlaylist(updated.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 const updated = await portAdapter.getPlaylist(playlistId);\n return toBffPlaylist(updated.playlist);\n },\n };\n}\n","import type {\n ContentDamAssetsApi,\n damAssets,\n} from \"@fluid-app/shareables-core/dam-assets-api\";\nimport type { FileResourcesApi } from \"@fluid-app/shareables-core/shareables-api\";\nimport type { shareables } from \"@fluid-app/shareables-core/types\";\nimport type { FetchClient } from \"./lib/fetch-client\";\nimport { portalTenantContent } from \"@fluid-app/portal-tenant-content-api-client\";\n\n/**\n * Maps a BFF DAM asset to the port's DamAsset shape.\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\n/**\n * Maps a BFF DAM asset path to the port's DamAssetPath shape.\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\n/**\n * Maps the BFF meta envelope to the port's ApiMeta shape.\n */\nfunction mapMeta(\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\n/**\n * Creates a ContentDamAssetsApi adapter backed by the portal-tenant content BFF.\n *\n * Maps the generated portal-tenant-content namespace functions to the abstract\n * ContentDamAssetsApi port, closing over the FetchClient so consumers don't\n * need to pass it per-call.\n */\nexport function createPortalTenantDamAssetsAdapter(\n client: FetchClient,\n): 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: mapMeta(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: mapMeta(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: mapMeta(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: mapMeta(response.meta),\n };\n },\n };\n}\n\n// ---------------------------------------------------------------------------\n// ShareablesApi-compatible adapter\n// ---------------------------------------------------------------------------\n\n/**\n * Creates a ShareablesApi[\"fileResources\"]-compatible adapter backed by the\n * portal-tenant content BFF. Maps DamAsset to FileResource shape and\n * includes cursor-to-page-number caching for legacy UI pagination.\n */\nexport function createPortalTenantFilesShareablesAdapter(\n client: FetchClient,\n): FileResourcesApi {\n const portAdapter = createPortalTenantDamAssetsAdapter(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","import type {\n ContentSharesApi,\n shares,\n} from \"@fluid-app/shareables-core/shares-api\";\nimport type { ShareApi } from \"@fluid-app/shareables-core/shareables-api\";\nimport type { FetchClient } from \"./lib/fetch-client\";\nimport { portalTenantContent } from \"@fluid-app/portal-tenant-content-api-client\";\n\n/**\n * Narrows an unknown string to a valid ShareableType at runtime.\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\n/**\n * Maps a BFF share to the port's Share shape.\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\n/**\n * Maps the BFF meta envelope to the port's ApiMeta shape.\n */\nfunction mapMeta(\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\n/**\n * Creates a ContentSharesApi adapter backed by the portal-tenant content BFF.\n *\n * Maps the generated portal-tenant-content namespace functions to the abstract\n * ContentSharesApi port, closing over the FetchClient so consumers don't need\n * to pass it per-call.\n */\nexport function createPortalTenantSharesAdapter(\n client: FetchClient,\n): 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: mapMeta(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: mapMeta(response.meta),\n };\n },\n };\n}\n\n// ---------------------------------------------------------------------------\n// ShareablesApi-compatible adapter\n// ---------------------------------------------------------------------------\n\n/**\n * Maps legacy Rails model names (used by the UI) to BFF shareable_type values.\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\n/**\n * Creates a ShareablesApi[\"share\"]-compatible adapter backed by the\n * portal-tenant content BFF. Maps legacy model names to BFF shareable types.\n */\nexport function createPortalTenantSharesShareablesAdapter(\n client: FetchClient,\n): ShareApi {\n const portAdapter = createPortalTenantSharesAdapter(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 const response = await portAdapter.createShare({\n shareable_type: shareableType,\n shareable_id: input.relateableId,\n });\n return response.share.url;\n },\n };\n}\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 type { FetchClientInstance } from \"@fluid-app/api-client-core\";\nimport {\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 {\n portalTenantContent,\n type operations,\n} from \"@fluid-app/portal-tenant-content-api-client\";\nimport { proxyUrlFetch } from \"./api/url-proxy\";\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 createPortalTenantFilePickerApiAdapter(\n client: FetchClientInstance,\n): 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","import { useCallback, useMemo, type ComponentProps } from \"react\";\nimport type {\n BackgroundValue,\n BorderRadiusOptions,\n ColorOptions,\n PaddingOptions,\n} from \"../types\";\nimport type { WidgetPropertySchema } from \"../registries/property-schema-types\";\nimport {\n ShareablesCoreProvider,\n ShareablesApiProvider,\n type ShareablesApi,\n} from \"@fluid-app/shareables-core\";\nimport { ShareablesUIProvider, ShareablesApp } from \"@fluid-app/shareables-ui\";\nimport {\n createPortalTenantPlaylistsAdapter,\n createPortalTenantMediaShareablesAdapter,\n createPortalTenantPlaylistsShareablesAdapter,\n createPortalTenantFilesShareablesAdapter,\n createPortalTenantSharesShareablesAdapter,\n} from \"@fluid-app/shareables-api-client\";\nimport { createPortalTenantFilePickerApiAdapter } from \"@fluid-app/file-picker-api-client\";\nimport { createFetchClient } from \"@fluid-app/api-client-core\";\nimport { useCurrentUser } from \"../hooks/use-current-user\";\nimport { useAppNavigation } from \"../shell/AppNavigationContext\";\nimport { useSdkClient } from \"../account/use-account-clients\";\nimport { usePortalTenantClient } from \"../providers/PortalTenantClientProvider\";\nimport { useFluidContext } from \"../providers/FluidProvider\";\nimport { useUserType } from \"../hooks/use-user-type\";\nimport { usePortalProductsClient } from \"../products/use-portal-products-client\";\n\ntype ShareablesScreenProps = ComponentProps<\"div\"> & {\n background?: BackgroundValue;\n textColor?: ColorOptions;\n accentColor?: ColorOptions;\n padding?: PaddingOptions;\n borderRadius?: BorderRadiusOptions;\n};\n\n/**\n * Parse the current shareables sub-route from the full slug.\n *\n * System nav slugs are \"share/products\", \"share/media\", \"share/playlists\".\n * Detail pages append an ID: \"share/products/123\", \"share/media/456\".\n *\n * \"share/products\" → screen=\"products\", detailId=null\n * \"share/products/123\" → screen=\"products\", detailId=\"123\"\n * \"share/media/456\" → screen=\"media\", detailId=\"456\"\n * \"share/playlists\" → screen=\"playlists\", detailId=null\n * \"share/playlists/789\" → screen=\"playlists\", detailId=\"789\"\n * \"share/files\" → screen=\"files\", detailId=null\n * \"share\" → screen=null (default to products)\n */\nfunction parseShareablesRoute(currentSlug: string): {\n screen: string | null;\n detailId: string | null;\n action: string | null;\n} {\n // Strip the \"share\" prefix\n const slugWithoutPrefix = currentSlug.replace(/^share\\/?/, \"\");\n if (!slugWithoutPrefix) {\n return { screen: null, detailId: null, action: null };\n }\n\n const parts = slugWithoutPrefix.split(\"/\");\n const screen = parts[0] || null;\n const detailId = parts[1] || null;\n const action = parts[2] || null;\n return { screen, detailId, action };\n}\n\nexport function ShareablesScreen({\n /* eslint-disable @typescript-eslint/no-unused-vars -- destructured to exclude from divProps spread */\n background,\n textColor,\n accentColor,\n padding,\n borderRadius,\n /* eslint-enable @typescript-eslint/no-unused-vars */\n ...divProps\n}: ShareablesScreenProps): React.JSX.Element {\n const domainClient = useSdkClient();\n const portalProductsApi = usePortalProductsClient();\n const portalTenantClient = usePortalTenantClient();\n const { config } = useFluidContext();\n const { data: userData } = useCurrentUser();\n const { currentSlug, navigate } = useAppNavigation();\n const { isCustomer } = useUserType();\n\n const fetchProducts = useCallback(\n async (search: string, cursor?: string, limit?: number) => {\n if (search) {\n return portalProductsApi.searchProducts(search, { cursor, limit });\n }\n return portalProductsApi.listProducts({ cursor, limit });\n },\n [portalProductsApi],\n );\n\n const fetchProduct = useCallback(\n async (id: string | number) => portalProductsApi.getProduct(id),\n [portalProductsApi],\n );\n\n const { screen, detailId, action } = parseShareablesRoute(currentSlug);\n\n const handleNavigate = useCallback(\n (subScreen: string, id?: string) => {\n const path = id ? `share/${subScreen}/${id}` : `share/${subScreen}`;\n navigate(path);\n },\n [navigate],\n );\n\n const handleBack = useCallback(() => {\n if (detailId && screen) {\n // Navigate back to the listing for the current screen\n navigate(`share/${screen}`);\n } else {\n // Navigate to the default shareables screen\n navigate(\"share/products\");\n }\n }, [navigate, detailId, screen]);\n\n const coreConfig = useMemo(\n () => ({\n client: domainClient,\n user: userData ? { id: userData.id } : null,\n repContext: true,\n }),\n [domainClient, userData],\n );\n\n // Create the port-level playlists adapter for the standalone deletePlaylist\n // callback (which uses the port interface directly, not ShareablesApi).\n const playlistsAdapter = useMemo(\n () => createPortalTenantPlaylistsAdapter(portalTenantClient),\n [portalTenantClient],\n );\n\n // Build ShareablesApi by composing portal-tenant BFF adapters directly.\n const shareablesApi = useMemo<ShareablesApi>(\n () => ({\n media: createPortalTenantMediaShareablesAdapter(portalTenantClient),\n playlists:\n createPortalTenantPlaylistsShareablesAdapter(portalTenantClient),\n fileResources:\n createPortalTenantFilesShareablesAdapter(portalTenantClient),\n share: createPortalTenantSharesShareablesAdapter(portalTenantClient),\n productMedia: {\n getProductMedia: async (productId: number) => {\n const response = await portalProductsApi.getProductMedia(productId);\n return {\n media: (response.media ?? []).map((item) => {\n const isVideo = item.media_type === \"video\";\n const isPdf =\n item.media_type === \"pdf\" || item.media_type === \"document\";\n return {\n id: item.id ?? 0,\n slug: null,\n title: item.title ?? \"\",\n kind: isVideo ? \"video\" : isPdf ? \"pdf\" : \"image\",\n media_type: item.media_type ?? \"image\",\n media_format: item.media_type ?? \"image\",\n image_url: !isVideo && !isPdf ? (item.url ?? null) : null,\n video_url: isVideo ? (item.url ?? null) : null,\n pdf_url: isPdf ? (item.url ?? null) : null,\n powerpoint_url: null,\n duration: 0,\n description: null,\n subtitles: {},\n comments_count: 0,\n };\n }),\n };\n },\n },\n }),\n [portalTenantClient, portalProductsApi],\n );\n\n const filePickerApi = useMemo(() => {\n const baseUrl = config.baseUrl.replace(/\\/+$/, \"\").replace(/\\/api$/, \"\");\n const csrfToken =\n typeof document !== \"undefined\"\n ? document\n .querySelector('meta[name=\"csrf-token\"]')\n ?.getAttribute(\"content\")\n : null;\n\n const bffClient = createFetchClient({\n baseUrl,\n getAuthToken: config.getAuthToken,\n onAuthError: config.onAuthError,\n credentials: \"include\",\n defaultHeaders: {\n ...config.defaultHeaders,\n ...(csrfToken ? { \"X-CSRF-Token\": csrfToken } : {}),\n },\n });\n\n return createPortalTenantFilePickerApiAdapter(bffClient);\n }, [\n config.baseUrl,\n config.getAuthToken,\n config.onAuthError,\n config.defaultHeaders,\n ]);\n\n const uiConfig = useMemo(\n () => ({\n user: userData\n ? {\n id: userData.id,\n company: userData.company\n ? { logo_url: userData.company.logo_url }\n : null,\n }\n : undefined,\n affiliateId:\n (userData as { affiliate_id?: number } | undefined)?.affiliate_id ??\n null,\n basePath: \"\",\n navigate: (path: string) => {\n // Strip leading slash — cards generate paths like \"/share/product/123\"\n const cleanPath = path.replace(/^\\//, \"\");\n // Ensure share/ prefix — screen components pass relative paths like \"media/new\"\n const prefixed = cleanPath.startsWith(\"share/\")\n ? cleanPath\n : `share/${cleanPath}`;\n navigate(prefixed);\n },\n showToast: (opts: {\n title: string;\n type: \"success\" | \"error\" | \"warning\";\n }) => {\n console.warn(`[Shareables] ${opts.type}: ${opts.title}`);\n },\n filePickerApi,\n onToggleFavorite: async (params: {\n favoriteableId: number;\n favoriteableType: string;\n }) => {\n const affiliateId = (userData as { affiliate_id?: number } | undefined)\n ?.affiliate_id;\n if (!affiliateId) throw new Error(\"No affiliate ID\");\n return domainClient.post<{ is_favorited: boolean }>(\n `/user_companies/${affiliateId}/favorites/toggle.json`,\n {\n favoriteable_id: params.favoriteableId,\n favoriteable_type: params.favoriteableType,\n },\n );\n },\n onDeletePlaylist: isCustomer\n ? undefined\n : async (playlistId: number) => {\n await playlistsAdapter.deletePlaylist(playlistId);\n },\n readOnly: isCustomer,\n }),\n [\n userData,\n navigate,\n filePickerApi,\n domainClient,\n isCustomer,\n playlistsAdapter,\n ],\n );\n\n return (\n <div {...divProps} className={`h-full ${divProps.className ?? \"\"}`}>\n <ShareablesCoreProvider config={coreConfig}>\n <ShareablesApiProvider api={shareablesApi}>\n <ShareablesUIProvider config={uiConfig}>\n <ShareablesApp\n screen={screen}\n detailId={detailId}\n action={action}\n companyLogoUrl={userData?.company?.logo_url}\n countryCode={userData?.country?.iso}\n fetchProducts={fetchProducts}\n fetchProduct={fetchProduct}\n onNavigate={handleNavigate}\n onBack={handleBack}\n />\n </ShareablesUIProvider>\n </ShareablesApiProvider>\n </ShareablesCoreProvider>\n </div>\n );\n}\n\nexport const shareablesScreenPropertySchema: WidgetPropertySchema = {\n widgetType: \"ShareablesScreen\",\n displayName: \"Shareables Screen\",\n tabsConfig: [{ id: \"styling\", label: \"Styling\" }],\n fields: [],\n} as const satisfies WidgetPropertySchema;\n"],"mappings":"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"}
@@ -34,9 +34,9 @@ import "./TableWidget-CfSqeNQj.mjs";
34
34
  import "./ToDoWidget-DaxkgCEl.mjs";
35
35
  import "./VideoWidget-CHktk3hs.mjs";
36
36
  import "./ScreenHeaderContext-CrdfLGKk.mjs";
37
- import { n as shareablesScreenPropertySchema, t as ShareablesScreen } from "./ShareablesScreen-B6tMQzuX.mjs";
37
+ import { n as shareablesScreenPropertySchema, t as ShareablesScreen } from "./ShareablesScreen-D8o7wTGM.mjs";
38
38
  import "./dist-CMGXkSgZ.mjs";
39
39
  import "./dist-CayuD99K.mjs";
40
- import "./src-DcIV4Mpe.mjs";
40
+ import "./src-j_uOaPI8.mjs";
41
41
  import "./sortable.esm-BzPsVjTI.mjs";
42
42
  export { ShareablesScreen, shareablesScreenPropertySchema };
package/dist/index.cjs CHANGED
@@ -38,7 +38,7 @@ const require_use_fluid_auth = require("./use-fluid-auth-B7lF_1HS.cjs");
38
38
  const require_ScreenHeaderContext = require("./ScreenHeaderContext-DpVOhFzT.cjs");
39
39
  const require_use_fluid_api = require("./use-fluid-api-B3R_ElCy.cjs");
40
40
  const require_use_current_user = require("./use-current-user-DISrPz9d.cjs");
41
- const require_ShareablesScreen = require("./ShareablesScreen-znVUD_OK.cjs");
41
+ const require_ShareablesScreen = require("./ShareablesScreen-C3Xue2W7.cjs");
42
42
  const require_CustomersScreen = require("./CustomersScreen-9f10-_AZ.cjs");
43
43
  const require_AppNavigationContext = require("./AppNavigationContext-Agp0UkCQ.cjs");
44
44
  const require_MessagingScreen = require("./MessagingScreen-XCotnB-I.cjs");
@@ -51,9 +51,9 @@ require("./src-ClULVolb.cjs");
51
51
  require("./dist-DkYXiQQ1.cjs");
52
52
  const require_OrdersScreen = require("./OrdersScreen-XdAMVGvp.cjs");
53
53
  const require_SubscriptionsScreen = require("./SubscriptionsScreen-fAMrA1cS.cjs");
54
- require("./src-C5GUPE_i.cjs");
54
+ require("./src-BAcQ6URl.cjs");
55
55
  require("./dist-BSbac3uh.cjs");
56
- const require_ProductsScreen = require("./ProductsScreen-BY285fh-.cjs");
56
+ const require_ProductsScreen = require("./ProductsScreen-yBjW5cWx.cjs");
57
57
  const require_MySiteScreen = require("./MySiteScreen-D56qESn0.cjs");
58
58
  const require_ShopScreen = require("./ShopScreen-BVIT_QS-.cjs");
59
59
  require("./UpgradeScreen-7on9GOgu.cjs");
@@ -3007,8 +3007,8 @@ const MessagingScreen$1 = (0, react.lazy)(() => Promise.resolve().then(() => req
3007
3007
  const ContactsScreen$1 = (0, react.lazy)(() => Promise.resolve().then(() => require("./ContactsScreen-DgBckwm3.cjs")).then((m) => ({ default: m.ContactsScreen })));
3008
3008
  const ShopScreen$1 = (0, react.lazy)(() => Promise.resolve().then(() => require("./ShopScreen-Bsjdn-E9.cjs")).then((m) => ({ default: m.ShopScreen })));
3009
3009
  const CustomersScreen$1 = (0, react.lazy)(() => Promise.resolve().then(() => require("./CustomersScreen-9f10-_AZ.cjs")).then((n) => n.CustomersScreen_exports).then((m) => ({ default: m.CustomersScreen })));
3010
- const ProductsScreen$1 = (0, react.lazy)(() => Promise.resolve().then(() => require("./ProductsScreen-BPNdpsYm.cjs")).then((m) => ({ default: m.ProductsScreen })));
3011
- const ShareablesScreen$1 = (0, react.lazy)(() => Promise.resolve().then(() => require("./ShareablesScreen-DMBXIMMj.cjs")).then((m) => ({ default: m.ShareablesScreen })));
3010
+ const ProductsScreen$1 = (0, react.lazy)(() => Promise.resolve().then(() => require("./ProductsScreen-CC4bgiMI.cjs")).then((m) => ({ default: m.ProductsScreen })));
3011
+ const ShareablesScreen$1 = (0, react.lazy)(() => Promise.resolve().then(() => require("./ShareablesScreen-BGHIqliw.cjs")).then((m) => ({ default: m.ShareablesScreen })));
3012
3012
  const MySiteScreen$1 = (0, react.lazy)(() => Promise.resolve().then(() => require("./MySiteScreen-C00HjZdl.cjs")).then((m) => ({ default: m.MySiteScreen })));
3013
3013
  const UpgradeScreen = (0, react.lazy)(() => Promise.resolve().then(() => require("./UpgradeScreen--eiiE1rX.cjs")).then((m) => ({ default: m.UpgradeScreen })));
3014
3014
  const AppDownloadScreen = (0, react.lazy)(() => Promise.resolve().then(() => require("./AppDownloadScreen-B-i6Rydi.cjs")).then((m) => ({ default: m.AppDownloadScreen })));
@@ -4482,9 +4482,9 @@ const screenPropertySchemas = {
4482
4482
  OrdersScreen: () => Promise.resolve().then(() => require("./OrdersScreen-DdRZm6L3.cjs")).then((m) => m.ordersScreenPropertySchema),
4483
4483
  SubscriptionsScreen: () => Promise.resolve().then(() => require("./SubscriptionsScreen-vsJ2o2c3.cjs")).then((m) => m.subscriptionsScreenPropertySchema),
4484
4484
  CustomersScreen: () => Promise.resolve().then(() => require("./CustomersScreen-9f10-_AZ.cjs")).then((n) => n.CustomersScreen_exports).then((m) => m.customersScreenPropertySchema),
4485
- ProductsScreen: () => Promise.resolve().then(() => require("./ProductsScreen-BPNdpsYm.cjs")).then((m) => m.productsScreenPropertySchema),
4485
+ ProductsScreen: () => Promise.resolve().then(() => require("./ProductsScreen-CC4bgiMI.cjs")).then((m) => m.productsScreenPropertySchema),
4486
4486
  MySiteScreen: () => Promise.resolve().then(() => require("./MySiteScreen-C00HjZdl.cjs")).then((m) => m.mySiteScreenPropertySchema),
4487
- ShareablesScreen: () => Promise.resolve().then(() => require("./ShareablesScreen-DMBXIMMj.cjs")).then((m) => m.shareablesScreenPropertySchema),
4487
+ ShareablesScreen: () => Promise.resolve().then(() => require("./ShareablesScreen-BGHIqliw.cjs")).then((m) => m.shareablesScreenPropertySchema),
4488
4488
  ShopScreen: () => Promise.resolve().then(() => require("./ShopScreen-Bsjdn-E9.cjs")).then((m) => m.shopScreenPropertySchema),
4489
4489
  UpgradeScreen: () => Promise.resolve().then(() => require("./UpgradeScreen--eiiE1rX.cjs")).then((m) => m.upgradeScreenPropertySchema),
4490
4490
  AppDownloadScreen: () => Promise.resolve().then(() => require("./AppDownloadScreen-B-i6Rydi.cjs")).then((m) => m.appDownloadScreenPropertySchema)