@c-rex/services 0.3.0-build.52 → 0.3.0-build.56

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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/html-enrichment/descriptor.ts","../../src/html-enrichment/endpoint-path.ts","../../src/base-client-request.ts","../../src/html-enrichment/loader.ts"],"sourcesContent":["import type {\r\n HtmlEnrichmentDescriptor,\r\n HtmlEnrichmentLoadMode,\r\n HtmlEnrichmentState,\r\n} from \"./types\";\r\n\r\nconst VALID_LOAD_MODES = new Set<string>([\"onload\", \"onappear\", \"onclick\"]);\r\nconst VALID_STATES = new Set<string>([\r\n \"unloaded\",\r\n \"loading\",\r\n \"loaded\",\r\n \"denied\",\r\n \"error\",\r\n]);\r\n\r\nconst toQueryParamName = (rawName: string): string => {\r\n const normalized = rawName.toLowerCase();\r\n if (normalized === \"restriction\") return \"Restrict\";\r\n\r\n return rawName\r\n .split(\"-\")\r\n .filter(Boolean)\r\n .map((part) => part.charAt(0).toUpperCase() + part.slice(1))\r\n .join(\"\");\r\n};\r\n\r\nconst parseParamValue = (name: string, value: string): string | string[] => {\r\n // Restrict selectors use semicolons internally, so the complete selector is\r\n // one API value. Other marker params use semicolons as list separators.\r\n if (name === \"Restrict\") return value.trim();\r\n return value\r\n .split(\";\")\r\n .map((item) => item.trim())\r\n .filter(Boolean);\r\n};\r\n\r\nconst parseParams = (\r\n el: HTMLElement,\r\n): Record<string, string | string[]> | undefined => {\r\n const params: Record<string, string | string[]> = {};\r\n\r\n for (const attributeName of el.getAttributeNames()) {\r\n const prefix = \"data-crex-param-\";\r\n if (!attributeName.startsWith(prefix)) continue;\r\n\r\n const rawValue = el.getAttribute(attributeName);\r\n if (!rawValue) continue;\r\n const name = toQueryParamName(attributeName.slice(prefix.length));\r\n params[name] = parseParamValue(name, rawValue);\r\n }\r\n\r\n return Object.keys(params).length > 0 ? params : undefined;\r\n};\r\n\r\n/**\r\n * Convert a `data-crex-*` enriched DOM node into a typed descriptor.\r\n * Unknown `load`/`state` values are dropped (undefined) rather than trusted.\r\n */\r\nexport const parseEnrichmentDescriptor = (\r\n el: HTMLElement,\r\n): HtmlEnrichmentDescriptor => {\r\n const loadModeRaw = el.getAttribute(\"data-crex-load\") ?? undefined;\r\n const stateRaw = el.getAttribute(\"data-crex-state\") ?? undefined;\r\n\r\n return {\r\n elementId: el.id || undefined,\r\n loadMode:\r\n loadModeRaw && VALID_LOAD_MODES.has(loadModeRaw)\r\n ? (loadModeRaw as HtmlEnrichmentLoadMode)\r\n : undefined,\r\n endpoint: el.getAttribute(\"data-crex-endpoint\") ?? undefined,\r\n state:\r\n stateRaw && VALID_STATES.has(stateRaw)\r\n ? (stateRaw as HtmlEnrichmentState)\r\n : undefined,\r\n clientFilter: el.getAttribute(\"data-crex-client-filter\") ?? undefined,\r\n renderer: el.getAttribute(\"data-crex-renderer\") ?? undefined,\r\n resourceId: el.getAttribute(\"data-crex-id\") ?? undefined,\r\n params: parseParams(el),\r\n };\r\n};\r\n","/**\r\n * API version segment injected into resolved enrichment paths.\r\n * Kept as a code constant for now; promote to an env var when versioning\r\n * needs to vary per deployment (note: client-side use requires NEXT_PUBLIC_*).\r\n */\r\nexport const IDS_API_VERSION = \"v1\";\r\n\r\nconst capitalize = (s: string): string =>\r\n s ? s.charAt(0).toUpperCase() + s.slice(1) : s;\r\n\r\n/**\r\n * Convert a logical endpoint slug into a versioned API base path.\r\n *\r\n * Slug shape: `<area>-<resource>` (resource may be multi-word, dash-separated).\r\n * `ids-resources` -> `ids/v1/Resources`\r\n * `ids-info-units` -> `ids/v1/InfoUnits`\r\n *\r\n * Returns null when the slug does not match the expected shape.\r\n * The full path is later combined with the encoded resource id by the loader\r\n * and resolved against the API root by `CrexApi.buildUrl`.\r\n */\r\nexport const slugToPath = (\r\n slug: string,\r\n version: string = IDS_API_VERSION,\r\n): string | null => {\r\n const parts = slug.split(\"-\").filter(Boolean);\r\n if (parts.length < 2) return null;\r\n\r\n const [area, ...resourceParts] = parts;\r\n const resource = resourceParts.map(capitalize).join(\"\");\r\n if (!area || !resource) return null;\r\n\r\n return `${area}/${version}/${resource}`;\r\n};\r\n","export const baseClientRequest = async <T>(\r\n endpoint: string,\r\n queryParams?: Record<\r\n string,\r\n string | number | boolean | (string | number | boolean)[] | undefined\r\n >,\r\n options?: { signal?: AbortSignal },\r\n extra?: { responseType?: \"json\" | \"text\" },\r\n): Promise<T> => {\r\n const res = await fetch(`/api/rpc`, {\r\n method: \"POST\",\r\n headers: { \"Content-Type\": \"application/json\" },\r\n body: JSON.stringify({\r\n method: \"CrexApi.execute\",\r\n params: {\r\n url: endpoint,\r\n method: \"GET\",\r\n params: queryParams,\r\n responseType: extra?.responseType,\r\n },\r\n }),\r\n credentials: \"include\",\r\n signal: options?.signal,\r\n });\r\n\r\n const json = await res.json();\r\n\r\n if (!res.ok) throw new Error(json.error || \"Unknown error\");\r\n\r\n return json.data;\r\n};\r\n","import type { LiteralModel, RenditionModel } from \"@c-rex/interfaces\";\r\nimport { baseClientRequest } from \"../base-client-request\";\r\nimport { slugToPath } from \"./endpoint-path\";\r\nimport type {\r\n HtmlEnrichmentDescriptor,\r\n HtmlEnrichmentEndpointResult,\r\n} from \"./types\";\r\n\r\n/**\r\n * Access-denied heuristic. This is NOT an HTTP auth failure — metadata may\r\n * resolve while the content rendition is licence-restricted. HTTP 403 is the\r\n * current signal until the IDS API confirms a canonical denied contract\r\n * (see HTML_RUNTIME_ENRICHMENT_SPEC.md → Open Questions).\r\n */\r\nconst isDeniedError = (err: unknown): boolean =>\r\n err instanceof Error && err.message.includes(\"403\");\r\n\r\n/**\r\n * Generic enrichment loader: resolves `data-crex-endpoint` (slug) + the\r\n * `data-crex-id` resource IRI into a single request and returns the raw HTML.\r\n *\r\n * Request shape: `{<area>/<version>/<Resource>}/view/{encodeURIComponent(id)}`\r\n * fetched as text. The `/view/` segment returns the rendered HTML rendition.\r\n * Works for any `<area>-<resource>` slug — no per-endpoint registration needed.\r\n */\r\nexport const loadEnrichmentHtml = async (\r\n descriptor: HtmlEnrichmentDescriptor,\r\n): Promise<HtmlEnrichmentEndpointResult> => {\r\n if (!descriptor.endpoint || !descriptor.resourceId) {\r\n return { html: null, isDenied: false };\r\n }\r\n\r\n const basePath = slugToPath(descriptor.endpoint);\r\n if (!basePath) {\r\n return { html: null, isDenied: false };\r\n }\r\n\r\n const url = `${basePath}/view/${encodeURIComponent(descriptor.resourceId)}`;\r\n\r\n try {\r\n const html = await baseClientRequest<string>(\r\n url,\r\n descriptor.params,\r\n undefined,\r\n {\r\n responseType: \"text\",\r\n },\r\n );\r\n return { html, isDenied: false };\r\n } catch (err: unknown) {\r\n if (isDeniedError(err)) {\r\n return { html: null, isDenied: true };\r\n }\r\n throw err;\r\n }\r\n};\r\n\r\n/**\r\n * Loads a collection-style enrichment marker such as the GMP Startseite tile\r\n * container. Collection markers do not have a data-crex-id; their API query is\r\n * carried by data-crex-param-* attributes instead.\r\n */\r\nexport const loadEnrichmentCollection = async (\r\n descriptor: HtmlEnrichmentDescriptor,\r\n): Promise<HtmlEnrichmentEndpointResult> => {\r\n if (!descriptor.endpoint) return { html: null, isDenied: false };\r\n\r\n const basePath = slugToPath(descriptor.endpoint);\r\n if (!basePath) return { html: null, isDenied: false };\r\n\r\n const params = { ...(descriptor.params ?? {}) };\r\n const fields = params.Fields;\r\n const hasRenditions = Array.isArray(fields)\r\n ? fields.some((field) => String(field).toLowerCase() === \"renditions\")\r\n : String(fields ?? \"\")\r\n .toLowerCase()\r\n .includes(\"renditions\");\r\n\r\n // Tile renderers need the rendition objects and their view links in the\r\n // collection response. Keep the marker's explicit params authoritative,\r\n // while filling in the two optional API flags when renditions were asked for.\r\n if (hasRenditions) {\r\n if (params.Embed === undefined) params.Embed = [\"renditions\"];\r\n if (params.Links === undefined) params.Links = true;\r\n }\r\n\r\n try {\r\n const data = await baseClientRequest<unknown>(basePath, params);\r\n return { html: null, data, isDenied: false };\r\n } catch (err: unknown) {\r\n if (isDeniedError(err)) {\r\n return { html: null, isDenied: true };\r\n }\r\n throw err;\r\n }\r\n};\r\n\r\n/** Selects the individual-resource or collection loader from the marker. */\r\nexport const loadEnrichment = async (\r\n descriptor: HtmlEnrichmentDescriptor,\r\n): Promise<HtmlEnrichmentEndpointResult> =>\r\n descriptor.resourceId\r\n ? loadEnrichmentHtml(descriptor)\r\n : loadEnrichmentCollection(descriptor);\r\n\r\n/**\r\n * Minimal shape shared by the iiRDS model endpoints used for onclick enrichment\r\n * (Fragments, InformationUnits, …). Kept loose so any model-with-renditions\r\n * endpoint works without per-endpoint typing.\r\n */\r\nexport type EnrichmentResourceModel = {\r\n /**\r\n * Root short id of the resource. Used to build in-app navigation targets\r\n * (e.g. swapping the topic id segment) instead of rendering the payload.\r\n */\r\n shortId?: string | null;\r\n renditions?: RenditionModel[] | null;\r\n titles?: LiteralModel[] | null;\r\n labels?: LiteralModel[] | null;\r\n /**\r\n * Content access state. The request itself can succeed (HTTP 200, metadata\r\n * present) while the content is licence-restricted — IDS signals that here\r\n * rather than via an HTTP error.\r\n */\r\n authorization?: { state?: string | null } | null;\r\n};\r\n\r\nexport type EnrichmentResourceResult = {\r\n data: EnrichmentResourceModel | null;\r\n isDenied: boolean;\r\n};\r\n\r\n/**\r\n * Generic onclick enrichment loader: resolves `data-crex-endpoint` (slug) + the\r\n * `data-crex-id` resource IRI and fetches the JSON model (e.g. a Fragment or\r\n * InformationUnit) for rendering inside a popover/modal. Endpoint resolution is\r\n * fully dynamic via `slugToPath` — no per-endpoint hardcoding.\r\n */\r\nexport const loadEnrichmentResource = async (\r\n descriptor: HtmlEnrichmentDescriptor,\r\n queryParams?: Record<\r\n string,\r\n string | number | boolean | (string | number | boolean)[] | undefined\r\n >,\r\n): Promise<EnrichmentResourceResult> => {\r\n if (!descriptor.endpoint || !descriptor.resourceId) {\r\n return { data: null, isDenied: false };\r\n }\r\n\r\n const basePath = slugToPath(descriptor.endpoint);\r\n if (!basePath) {\r\n return { data: null, isDenied: false };\r\n }\r\n\r\n const url = `${basePath}/${encodeURIComponent(descriptor.resourceId)}`;\r\n\r\n try {\r\n const data = await baseClientRequest<EnrichmentResourceModel>(\r\n url,\r\n queryParams,\r\n );\r\n // Denied is carried in the (successful) payload, not as an HTTP error.\r\n const isDenied = data?.authorization?.state === \"denied\";\r\n return { data, isDenied };\r\n } catch (err: unknown) {\r\n if (isDeniedError(err)) {\r\n return { data: null, isDenied: true };\r\n }\r\n throw err;\r\n }\r\n};\r\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/html-enrichment/descriptor.ts","../../src/html-enrichment/endpoint-path.ts","../../src/base-client-request.ts","../../src/html-enrichment/loader.ts"],"sourcesContent":["import type {\r\n HtmlEnrichmentDescriptor,\r\n HtmlEnrichmentLoadMode,\r\n HtmlEnrichmentState,\r\n} from \"./types\";\r\n\r\nconst VALID_LOAD_MODES = new Set<string>([\"onload\", \"onappear\", \"onclick\"]);\r\nconst VALID_STATES = new Set<string>([\r\n \"unloaded\",\r\n \"loading\",\r\n \"loaded\",\r\n \"denied\",\r\n \"error\",\r\n]);\r\n\r\nconst toQueryParamName = (rawName: string): string => {\r\n const normalized = rawName.toLowerCase();\r\n if (normalized === \"restriction\") return \"Restrict\";\r\n\r\n return rawName\r\n .split(\"-\")\r\n .filter(Boolean)\r\n .map((part) => part.charAt(0).toUpperCase() + part.slice(1))\r\n .join(\"\");\r\n};\r\n\r\nconst parseParamValue = (name: string, value: string): string | string[] => {\r\n // Restrict selectors use semicolons internally, so the complete selector is\r\n // one API value. Other marker params use semicolons as list separators.\r\n if (name === \"Restrict\") return value.trim();\r\n return value\r\n .split(\";\")\r\n .map((item) => item.trim())\r\n .filter(Boolean);\r\n};\r\n\r\nconst parseParams = (\r\n el: HTMLElement,\r\n): Record<string, string | string[]> | undefined => {\r\n const params: Record<string, string | string[]> = {};\r\n\r\n for (const attributeName of el.getAttributeNames()) {\r\n const prefix = \"data-crex-param-\";\r\n if (!attributeName.startsWith(prefix)) continue;\r\n\r\n const rawValue = el.getAttribute(attributeName);\r\n if (!rawValue) continue;\r\n const name = toQueryParamName(attributeName.slice(prefix.length));\r\n params[name] = parseParamValue(name, rawValue);\r\n }\r\n\r\n return Object.keys(params).length > 0 ? params : undefined;\r\n};\r\n\r\n/**\r\n * Convert a `data-crex-*` enriched DOM node into a typed descriptor.\r\n * Unknown `load`/`state` values are dropped (undefined) rather than trusted.\r\n */\r\nexport const parseEnrichmentDescriptor = (\r\n el: HTMLElement,\r\n): HtmlEnrichmentDescriptor => {\r\n const loadModeRaw = el.getAttribute(\"data-crex-load\") ?? undefined;\r\n const stateRaw = el.getAttribute(\"data-crex-state\") ?? undefined;\r\n\r\n return {\r\n elementId: el.id || undefined,\r\n loadMode:\r\n loadModeRaw && VALID_LOAD_MODES.has(loadModeRaw)\r\n ? (loadModeRaw as HtmlEnrichmentLoadMode)\r\n : undefined,\r\n endpoint: el.getAttribute(\"data-crex-endpoint\") ?? undefined,\r\n state:\r\n stateRaw && VALID_STATES.has(stateRaw)\r\n ? (stateRaw as HtmlEnrichmentState)\r\n : undefined,\r\n clientFilter: el.getAttribute(\"data-crex-client-filter\") ?? undefined,\r\n renderer: el.getAttribute(\"data-crex-renderer\") ?? undefined,\r\n resourceId: el.getAttribute(\"data-crex-id\") ?? undefined,\r\n params: parseParams(el),\r\n };\r\n};\r\n","/**\r\n * API version segment injected into resolved enrichment paths.\r\n * Kept as a code constant for now; promote to an env var when versioning\r\n * needs to vary per deployment (note: client-side use requires NEXT_PUBLIC_*).\r\n */\r\nexport const IDS_API_VERSION = \"v1\";\r\n\r\nconst capitalize = (s: string): string =>\r\n s ? s.charAt(0).toUpperCase() + s.slice(1) : s;\r\n\r\n/**\r\n * Convert a logical endpoint slug into a versioned API base path.\r\n *\r\n * Slug shape: `<area>-<resource>` (resource may be multi-word, dash-separated).\r\n * `ids-resources` -> `ids/v1/Resources`\r\n * `ids-info-units` -> `ids/v1/InfoUnits`\r\n *\r\n * Returns null when the slug does not match the expected shape.\r\n * The full path is later combined with the encoded resource id by the loader\r\n * and resolved against the API root by `CrexApi.buildUrl`.\r\n */\r\nexport const slugToPath = (\r\n slug: string,\r\n version: string = IDS_API_VERSION,\r\n): string | null => {\r\n const parts = slug.split(\"-\").filter(Boolean);\r\n if (parts.length < 2) return null;\r\n\r\n const [area, ...resourceParts] = parts;\r\n const resource = resourceParts.map(capitalize).join(\"\");\r\n if (!area || !resource) return null;\r\n\r\n return `${area}/${version}/${resource}`;\r\n};\r\n","export const baseClientRequest = async <T>(\r\n endpoint: string,\r\n queryParams?: Record<\r\n string,\r\n string | number | boolean | (string | number | boolean)[] | undefined\r\n >,\r\n options?: { signal?: AbortSignal },\r\n extra?: {\r\n responseType?: \"json\" | \"text\";\r\n authMode?: \"configured\" | \"anonymous\";\r\n },\r\n): Promise<T> => {\r\n const res = await fetch(`/api/rpc`, {\r\n method: \"POST\",\r\n headers: { \"Content-Type\": \"application/json\" },\r\n body: JSON.stringify({\r\n method: \"CrexApi.execute\",\r\n params: {\r\n url: endpoint,\r\n method: \"GET\",\r\n params: queryParams,\r\n responseType: extra?.responseType,\r\n authMode: extra?.authMode,\r\n },\r\n }),\r\n credentials: \"include\",\r\n signal: options?.signal,\r\n });\r\n\r\n const json = await res.json();\r\n\r\n if (!res.ok) throw new Error(json.error || \"Unknown error\");\r\n\r\n return json.data;\r\n};\r\n","import type { LiteralModel, RenditionModel } from \"@c-rex/interfaces\";\r\nimport { baseClientRequest } from \"../base-client-request\";\r\nimport { slugToPath } from \"./endpoint-path\";\r\nimport type {\r\n HtmlEnrichmentDescriptor,\r\n HtmlEnrichmentEndpointResult,\r\n} from \"./types\";\r\n\r\n/**\r\n * Access-denied heuristic. This is NOT an HTTP auth failure — metadata may\r\n * resolve while the content rendition is licence-restricted. HTTP 403 is the\r\n * current signal until the IDS API confirms a canonical denied contract\r\n * (see HTML_RUNTIME_ENRICHMENT_SPEC.md → Open Questions).\r\n */\r\nconst isDeniedError = (err: unknown): boolean =>\r\n err instanceof Error && err.message.includes(\"403\");\r\n\r\n/**\r\n * Generic enrichment loader: resolves `data-crex-endpoint` (slug) + the\r\n * `data-crex-id` resource IRI into a single request and returns the raw HTML.\r\n *\r\n * Request shape: `{<area>/<version>/<Resource>}/view/{encodeURIComponent(id)}`\r\n * fetched as text. The `/view/` segment returns the rendered HTML rendition.\r\n * Works for any `<area>-<resource>` slug — no per-endpoint registration needed.\r\n */\r\nexport const loadEnrichmentHtml = async (\r\n descriptor: HtmlEnrichmentDescriptor,\r\n): Promise<HtmlEnrichmentEndpointResult> => {\r\n if (!descriptor.endpoint || !descriptor.resourceId) {\r\n return { html: null, isDenied: false };\r\n }\r\n\r\n const basePath = slugToPath(descriptor.endpoint);\r\n if (!basePath) {\r\n return { html: null, isDenied: false };\r\n }\r\n\r\n const url = `${basePath}/view/${encodeURIComponent(descriptor.resourceId)}`;\r\n\r\n try {\r\n const html = await baseClientRequest<string>(\r\n url,\r\n descriptor.params,\r\n undefined,\r\n {\r\n responseType: \"text\",\r\n },\r\n );\r\n return { html, isDenied: false };\r\n } catch (err: unknown) {\r\n if (isDeniedError(err)) {\r\n return { html: null, isDenied: true };\r\n }\r\n throw err;\r\n }\r\n};\r\n\r\n/**\r\n * Loads a collection-style enrichment marker such as the GMP Startseite tile\r\n * container. Collection markers do not have a data-crex-id; their API query is\r\n * carried by data-crex-param-* attributes instead.\r\n */\r\nexport const loadEnrichmentCollection = async (\r\n descriptor: HtmlEnrichmentDescriptor,\r\n): Promise<HtmlEnrichmentEndpointResult> => {\r\n if (!descriptor.endpoint) return { html: null, isDenied: false };\r\n\r\n const basePath = slugToPath(descriptor.endpoint);\r\n if (!basePath) return { html: null, isDenied: false };\r\n\r\n const params = { ...(descriptor.params ?? {}) };\r\n const fields = params.Fields;\r\n const hasRenditions = Array.isArray(fields)\r\n ? fields.some((field) => String(field).toLowerCase() === \"renditions\")\r\n : String(fields ?? \"\")\r\n .toLowerCase()\r\n .includes(\"renditions\");\r\n\r\n // Tile renderers need the rendition objects and their view links in the\r\n // collection response. Keep the marker's explicit params authoritative,\r\n // while filling in the two optional API flags when renditions were asked for.\r\n if (hasRenditions) {\r\n if (params.Embed === undefined) params.Embed = [\"renditions\"];\r\n if (params.Links === undefined) params.Links = true;\r\n }\r\n\r\n try {\r\n const isPublicGmpStartTiles =\r\n descriptor.renderer === \"GMPTilesRenderer\" &&\r\n basePath === \"iirds/v1/Fragments\";\r\n const data = isPublicGmpStartTiles\r\n ? await baseClientRequest<unknown>(basePath, params, undefined, {\r\n authMode: \"anonymous\",\r\n })\r\n : await baseClientRequest<unknown>(basePath, params);\r\n return { html: null, data, isDenied: false };\r\n } catch (err: unknown) {\r\n if (isDeniedError(err)) {\r\n return { html: null, isDenied: true };\r\n }\r\n throw err;\r\n }\r\n};\r\n\r\n/** Selects the individual-resource or collection loader from the marker. */\r\nexport const loadEnrichment = async (\r\n descriptor: HtmlEnrichmentDescriptor,\r\n): Promise<HtmlEnrichmentEndpointResult> =>\r\n descriptor.resourceId\r\n ? loadEnrichmentHtml(descriptor)\r\n : loadEnrichmentCollection(descriptor);\r\n\r\n/**\r\n * Minimal shape shared by the iiRDS model endpoints used for onclick enrichment\r\n * (Fragments, InformationUnits, …). Kept loose so any model-with-renditions\r\n * endpoint works without per-endpoint typing.\r\n */\r\nexport type EnrichmentResourceModel = {\r\n /**\r\n * Root short id of the resource. Used to build in-app navigation targets\r\n * (e.g. swapping the topic id segment) instead of rendering the payload.\r\n */\r\n shortId?: string | null;\r\n renditions?: RenditionModel[] | null;\r\n titles?: LiteralModel[] | null;\r\n labels?: LiteralModel[] | null;\r\n /**\r\n * Content access state. The request itself can succeed (HTTP 200, metadata\r\n * present) while the content is licence-restricted — IDS signals that here\r\n * rather than via an HTTP error.\r\n */\r\n authorization?: { state?: string | null } | null;\r\n};\r\n\r\nexport type EnrichmentResourceResult = {\r\n data: EnrichmentResourceModel | null;\r\n isDenied: boolean;\r\n};\r\n\r\n/**\r\n * Generic onclick enrichment loader: resolves `data-crex-endpoint` (slug) + the\r\n * `data-crex-id` resource IRI and fetches the JSON model (e.g. a Fragment or\r\n * InformationUnit) for rendering inside a popover/modal. Endpoint resolution is\r\n * fully dynamic via `slugToPath` — no per-endpoint hardcoding.\r\n */\r\nexport const loadEnrichmentResource = async (\r\n descriptor: HtmlEnrichmentDescriptor,\r\n queryParams?: Record<\r\n string,\r\n string | number | boolean | (string | number | boolean)[] | undefined\r\n >,\r\n): Promise<EnrichmentResourceResult> => {\r\n if (!descriptor.endpoint || !descriptor.resourceId) {\r\n return { data: null, isDenied: false };\r\n }\r\n\r\n const basePath = slugToPath(descriptor.endpoint);\r\n if (!basePath) {\r\n return { data: null, isDenied: false };\r\n }\r\n\r\n const url = `${basePath}/${encodeURIComponent(descriptor.resourceId)}`;\r\n\r\n try {\r\n const data = await baseClientRequest<EnrichmentResourceModel>(\r\n url,\r\n queryParams,\r\n );\r\n // Denied is carried in the (successful) payload, not as an HTTP error.\r\n const isDenied = data?.authorization?.state === \"denied\";\r\n return { data, isDenied };\r\n } catch (err: unknown) {\r\n if (isDeniedError(err)) {\r\n return { data: null, isDenied: true };\r\n }\r\n throw err;\r\n }\r\n};\r\n"],"mappings":"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","names":[]}
package/dist/index.js CHANGED
@@ -890,7 +890,8 @@ var baseClientRequest = async (endpoint, queryParams, options, extra) => {
890
890
  url: endpoint,
891
891
  method: "GET",
892
892
  params: queryParams,
893
- responseType: extra?.responseType
893
+ responseType: extra?.responseType,
894
+ authMode: extra?.authMode
894
895
  }
895
896
  }),
896
897
  credentials: "include",
@@ -1637,7 +1638,6 @@ var fetchOrganizationProfileById = async (id, query, context) => {
1637
1638
  { id },
1638
1639
  resolveOrganizationProfileQuery(query)
1639
1640
  );
1640
- console.log("[OrganizationProfile] Raw VCARD response:", organization);
1641
1641
  return toOrganizationProfile(organization, {
1642
1642
  uiLanguage: context.uiLanguage,
1643
1643
  displayNameFallback: context.fallbackName,