Update dependencies in package.json and yarn.lock for improved functionality and performance. Added new API endpoints for 'navgroup' in cms-api.generated.ts, enhanced image URL handling in rusty-image.ts, and refined logo URL processing in Layout.astro. This update includes version upgrades for several packages, ensuring compatibility with the latest features and fixes.
Deploy to Firebase Hosting / deploy (push) Failing after 14s
Deploy to Firebase Hosting / deploy (push) Failing after 14s
This commit is contained in:
+3
-3
@@ -17,14 +17,14 @@
|
|||||||
"firebase-deploy:nocache": "yarn build && firebase deploy --only hosting"
|
"firebase-deploy:nocache": "yarn build && firebase deploy --only hosting"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@astrojs/sitemap": "^3.7.0",
|
"@astrojs/sitemap": "^3.7.2",
|
||||||
"@astrojs/svelte": "^7.2.5",
|
"@astrojs/svelte": "^8.0.4",
|
||||||
"@fontsource-variable/lora": "^5.2.8",
|
"@fontsource-variable/lora": "^5.2.8",
|
||||||
"@fontsource-variable/rubik": "^5.2.8",
|
"@fontsource-variable/rubik": "^5.2.8",
|
||||||
"@fontsource/inter": "^5.2.8",
|
"@fontsource/inter": "^5.2.8",
|
||||||
"@iconify/svelte": "^5.2.1",
|
"@iconify/svelte": "^5.2.1",
|
||||||
"@tailwindcss/vite": "^4.1.18",
|
"@tailwindcss/vite": "^4.1.18",
|
||||||
"astro": "^5.17.1",
|
"astro": "^6.1.1",
|
||||||
"json5": "^2.2.3",
|
"json5": "^2.2.3",
|
||||||
"marked": "^17.0.2",
|
"marked": "^17.0.2",
|
||||||
"svelte": "^5.51.2",
|
"svelte": "^5.51.2",
|
||||||
|
|||||||
@@ -225,9 +225,12 @@ try {
|
|||||||
})) ??
|
})) ??
|
||||||
(await getPageConfigBySlug("default", { locale: "de", resolve: "logo" }));
|
(await getPageConfigBySlug("default", { locale: "de", resolve: "logo" }));
|
||||||
const rawLogo = pageConfig?.logo;
|
const rawLogo = pageConfig?.logo;
|
||||||
|
/** Logo-URL: String (z. B. `/api/assets/…`) oder aufgelöstes img-Objekt. */
|
||||||
const logoFileUrl =
|
const logoFileUrl =
|
||||||
typeof rawLogo === "string" && rawLogo.startsWith("http")
|
typeof rawLogo === "string" && rawLogo.trim()
|
||||||
? rawLogo
|
? rawLogo.trim().startsWith("//")
|
||||||
|
? `https:${rawLogo.trim()}`
|
||||||
|
: rawLogo.trim()
|
||||||
: ((
|
: ((
|
||||||
rawLogo as
|
rawLogo as
|
||||||
| { src?: string; _slug?: string; file?: { url?: string } }
|
| { src?: string; _slug?: string; file?: { url?: string } }
|
||||||
@@ -237,9 +240,10 @@ try {
|
|||||||
?._slug ??
|
?._slug ??
|
||||||
(rawLogo as { file?: { url?: string } } | undefined)?.file?.url);
|
(rawLogo as { file?: { url?: string } } | undefined)?.file?.url);
|
||||||
if (logoFileUrl) {
|
if (logoFileUrl) {
|
||||||
const u = logoFileUrl.startsWith("//")
|
const u =
|
||||||
? `https:${logoFileUrl}`
|
typeof logoFileUrl === "string" && logoFileUrl.startsWith("//")
|
||||||
: logoFileUrl;
|
? `https:${logoFileUrl}`
|
||||||
|
: logoFileUrl;
|
||||||
logoUrl = await ensureTransformedImage(u, {
|
logoUrl = await ensureTransformedImage(u, {
|
||||||
height: 56,
|
height: 56,
|
||||||
fit: "contain",
|
fit: "contain",
|
||||||
|
|||||||
@@ -375,6 +375,23 @@ export interface paths {
|
|||||||
patch?: never;
|
patch?: never;
|
||||||
trace?: never;
|
trace?: never;
|
||||||
};
|
};
|
||||||
|
"/api/collections/navgroup": {
|
||||||
|
parameters: {
|
||||||
|
query?: never;
|
||||||
|
header?: never;
|
||||||
|
path?: never;
|
||||||
|
cookie?: never;
|
||||||
|
};
|
||||||
|
/** Get schema definition for 'navgroup' */
|
||||||
|
get: operations["getNavgroupSchema"];
|
||||||
|
put?: never;
|
||||||
|
post?: never;
|
||||||
|
delete?: never;
|
||||||
|
options?: never;
|
||||||
|
head?: never;
|
||||||
|
patch?: never;
|
||||||
|
trace?: never;
|
||||||
|
};
|
||||||
"/api/collections/navigation": {
|
"/api/collections/navigation": {
|
||||||
parameters: {
|
parameters: {
|
||||||
query?: never;
|
query?: never;
|
||||||
@@ -1639,6 +1656,63 @@ export interface paths {
|
|||||||
patch?: never;
|
patch?: never;
|
||||||
trace?: never;
|
trace?: never;
|
||||||
};
|
};
|
||||||
|
"/api/content/navgroup": {
|
||||||
|
parameters: {
|
||||||
|
query?: never;
|
||||||
|
header?: never;
|
||||||
|
path?: never;
|
||||||
|
cookie?: never;
|
||||||
|
};
|
||||||
|
/** List 'navgroup' entries */
|
||||||
|
get: operations["listNavgroup"];
|
||||||
|
put?: never;
|
||||||
|
/** Create a new 'navgroup' entry */
|
||||||
|
post: operations["createNavgroup"];
|
||||||
|
delete?: never;
|
||||||
|
options?: never;
|
||||||
|
head?: never;
|
||||||
|
patch?: never;
|
||||||
|
trace?: never;
|
||||||
|
};
|
||||||
|
"/api/content/navgroup/{slug}": {
|
||||||
|
parameters: {
|
||||||
|
query?: never;
|
||||||
|
header?: never;
|
||||||
|
path?: never;
|
||||||
|
cookie?: never;
|
||||||
|
};
|
||||||
|
/** Get 'navgroup' entry by slug */
|
||||||
|
get: operations["getNavgroup"];
|
||||||
|
/** Update 'navgroup' entry */
|
||||||
|
put: operations["updateNavgroup"];
|
||||||
|
post?: never;
|
||||||
|
/** Delete 'navgroup' entry */
|
||||||
|
delete: operations["deleteNavgroup"];
|
||||||
|
options?: never;
|
||||||
|
head?: never;
|
||||||
|
patch?: never;
|
||||||
|
trace?: never;
|
||||||
|
};
|
||||||
|
"/api/content/navgroup/{slug}/referrers": {
|
||||||
|
parameters: {
|
||||||
|
query?: never;
|
||||||
|
header?: never;
|
||||||
|
path?: never;
|
||||||
|
cookie?: never;
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* List referrers of 'navgroup' entry
|
||||||
|
* @description Returns all entries that reference this entry (reverse index). Empty when not using referrer index (e.g. with RUSTYCMS_ENVIRONMENTS).
|
||||||
|
*/
|
||||||
|
get: operations["getNavgroupReferrers"];
|
||||||
|
put?: never;
|
||||||
|
post?: never;
|
||||||
|
delete?: never;
|
||||||
|
options?: never;
|
||||||
|
head?: never;
|
||||||
|
patch?: never;
|
||||||
|
trace?: never;
|
||||||
|
};
|
||||||
"/api/content/navigation": {
|
"/api/content/navigation": {
|
||||||
parameters: {
|
parameters: {
|
||||||
query?: never;
|
query?: never;
|
||||||
@@ -3025,7 +3099,7 @@ export interface components {
|
|||||||
/** @description Entry identifier (filename) */
|
/** @description Entry identifier (filename) */
|
||||||
readonly _slug?: string;
|
readonly _slug?: string;
|
||||||
/** @description Banner headline */
|
/** @description Banner headline */
|
||||||
headline: string;
|
headline?: string;
|
||||||
/** @description Banner image (optional) */
|
/** @description Banner image (optional) */
|
||||||
image?: string | {
|
image?: string | {
|
||||||
/** @description Alt text / description for accessibility */
|
/** @description Alt text / description for accessibility */
|
||||||
@@ -3050,7 +3124,7 @@ export interface components {
|
|||||||
/** @description URL slug (used as filename) */
|
/** @description URL slug (used as filename) */
|
||||||
_slug: string;
|
_slug: string;
|
||||||
/** @description Banner headline */
|
/** @description Banner headline */
|
||||||
headline: string;
|
headline?: string;
|
||||||
/** @description Banner image (optional) */
|
/** @description Banner image (optional) */
|
||||||
image?: string | {
|
image?: string | {
|
||||||
/** @description Alt text / description for accessibility */
|
/** @description Alt text / description for accessibility */
|
||||||
@@ -3745,6 +3819,26 @@ export interface components {
|
|||||||
/** @description Internal component name */
|
/** @description Internal component name */
|
||||||
name: string;
|
name: string;
|
||||||
};
|
};
|
||||||
|
navgroup: {
|
||||||
|
/** @description Entry identifier (filename) */
|
||||||
|
readonly _slug?: string;
|
||||||
|
/** @description Display label of the group */
|
||||||
|
label: string;
|
||||||
|
/** @description Sub-links shown in the dropdown */
|
||||||
|
links: string[];
|
||||||
|
/** @description Optional URL for the group label itself */
|
||||||
|
url?: string;
|
||||||
|
};
|
||||||
|
navgroup_input: {
|
||||||
|
/** @description URL slug (used as filename) */
|
||||||
|
_slug: string;
|
||||||
|
/** @description Display label of the group */
|
||||||
|
label: string;
|
||||||
|
/** @description Sub-links shown in the dropdown */
|
||||||
|
links: string[];
|
||||||
|
/** @description Optional URL for the group label itself */
|
||||||
|
url?: string;
|
||||||
|
};
|
||||||
navigation: {
|
navigation: {
|
||||||
/** @description Entry identifier (filename) */
|
/** @description Entry identifier (filename) */
|
||||||
readonly _slug?: string;
|
readonly _slug?: string;
|
||||||
@@ -3855,6 +3949,8 @@ export interface components {
|
|||||||
seoDescription: string;
|
seoDescription: string;
|
||||||
/** @description Default SEO title for website */
|
/** @description Default SEO title for website */
|
||||||
seoTitle: string;
|
seoTitle: string;
|
||||||
|
/** @description Site name */
|
||||||
|
siteName: string;
|
||||||
/** @description Website URL */
|
/** @description Website URL */
|
||||||
website: string;
|
website: string;
|
||||||
};
|
};
|
||||||
@@ -3880,6 +3976,8 @@ export interface components {
|
|||||||
seoDescription: string;
|
seoDescription: string;
|
||||||
/** @description Default SEO title for website */
|
/** @description Default SEO title for website */
|
||||||
seoTitle: string;
|
seoTitle: string;
|
||||||
|
/** @description Site name */
|
||||||
|
siteName: string;
|
||||||
/** @description Website URL */
|
/** @description Website URL */
|
||||||
website: string;
|
website: string;
|
||||||
};
|
};
|
||||||
@@ -5398,6 +5496,31 @@ export interface operations {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
getNavgroupSchema: {
|
||||||
|
parameters: {
|
||||||
|
query?: never;
|
||||||
|
header?: never;
|
||||||
|
path?: never;
|
||||||
|
cookie?: never;
|
||||||
|
};
|
||||||
|
requestBody?: never;
|
||||||
|
responses: {
|
||||||
|
/** @description Schema definition */
|
||||||
|
200: {
|
||||||
|
headers: {
|
||||||
|
[name: string]: unknown;
|
||||||
|
};
|
||||||
|
content?: never;
|
||||||
|
};
|
||||||
|
/** @description Collection not found */
|
||||||
|
404: {
|
||||||
|
headers: {
|
||||||
|
[name: string]: unknown;
|
||||||
|
};
|
||||||
|
content?: never;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
getNavigationSchema: {
|
getNavigationSchema: {
|
||||||
parameters: {
|
parameters: {
|
||||||
query?: never;
|
query?: never;
|
||||||
@@ -10068,6 +10191,240 @@ export interface operations {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
listNavgroup: {
|
||||||
|
parameters: {
|
||||||
|
query?: {
|
||||||
|
/** @description Field name to sort by */
|
||||||
|
_sort?: string;
|
||||||
|
/** @description Sort order (default: asc) */
|
||||||
|
_order?: "asc" | "desc";
|
||||||
|
/** @description Page number (1-indexed) */
|
||||||
|
_page?: number;
|
||||||
|
/** @description Items per page */
|
||||||
|
_per_page?: number;
|
||||||
|
/** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */
|
||||||
|
_resolve?: string;
|
||||||
|
/** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */
|
||||||
|
_locale?: string;
|
||||||
|
/** @description Filter by label */
|
||||||
|
label?: string;
|
||||||
|
/** @description Filter by url */
|
||||||
|
url?: string;
|
||||||
|
/** @description Filter by links */
|
||||||
|
links?: string;
|
||||||
|
};
|
||||||
|
header?: never;
|
||||||
|
path?: never;
|
||||||
|
cookie?: never;
|
||||||
|
};
|
||||||
|
requestBody?: never;
|
||||||
|
responses: {
|
||||||
|
/** @description Paginated list of entries */
|
||||||
|
200: {
|
||||||
|
headers: {
|
||||||
|
[name: string]: unknown;
|
||||||
|
};
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
items?: components["schemas"]["navgroup"][];
|
||||||
|
page?: number;
|
||||||
|
per_page?: number;
|
||||||
|
total?: number;
|
||||||
|
total_pages?: number;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
createNavgroup: {
|
||||||
|
parameters: {
|
||||||
|
query?: {
|
||||||
|
/** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */
|
||||||
|
_resolve?: string;
|
||||||
|
/** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */
|
||||||
|
_locale?: string;
|
||||||
|
};
|
||||||
|
header?: never;
|
||||||
|
path?: never;
|
||||||
|
cookie?: never;
|
||||||
|
};
|
||||||
|
requestBody: {
|
||||||
|
content: {
|
||||||
|
"application/json": components["schemas"]["navgroup_input"];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
responses: {
|
||||||
|
/** @description Entry created */
|
||||||
|
201: {
|
||||||
|
headers: {
|
||||||
|
[name: string]: unknown;
|
||||||
|
};
|
||||||
|
content: {
|
||||||
|
"application/json": components["schemas"]["navgroup"];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
/** @description Validation error */
|
||||||
|
400: {
|
||||||
|
headers: {
|
||||||
|
[name: string]: unknown;
|
||||||
|
};
|
||||||
|
content?: never;
|
||||||
|
};
|
||||||
|
/** @description Entry already exists */
|
||||||
|
409: {
|
||||||
|
headers: {
|
||||||
|
[name: string]: unknown;
|
||||||
|
};
|
||||||
|
content?: never;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
getNavgroup: {
|
||||||
|
parameters: {
|
||||||
|
query?: {
|
||||||
|
/** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */
|
||||||
|
_resolve?: string;
|
||||||
|
/** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */
|
||||||
|
_locale?: string;
|
||||||
|
};
|
||||||
|
header?: never;
|
||||||
|
path: {
|
||||||
|
/** @description Entry identifier (filename without extension) */
|
||||||
|
slug: string;
|
||||||
|
};
|
||||||
|
cookie?: never;
|
||||||
|
};
|
||||||
|
requestBody?: never;
|
||||||
|
responses: {
|
||||||
|
/** @description The entry */
|
||||||
|
200: {
|
||||||
|
headers: {
|
||||||
|
[name: string]: unknown;
|
||||||
|
};
|
||||||
|
content: {
|
||||||
|
"application/json": components["schemas"]["navgroup"];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
/** @description Entry not found */
|
||||||
|
404: {
|
||||||
|
headers: {
|
||||||
|
[name: string]: unknown;
|
||||||
|
};
|
||||||
|
content?: never;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
updateNavgroup: {
|
||||||
|
parameters: {
|
||||||
|
query?: {
|
||||||
|
/** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */
|
||||||
|
_resolve?: string;
|
||||||
|
/** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */
|
||||||
|
_locale?: string;
|
||||||
|
};
|
||||||
|
header?: never;
|
||||||
|
path: {
|
||||||
|
/** @description Entry identifier (filename without extension) */
|
||||||
|
slug: string;
|
||||||
|
};
|
||||||
|
cookie?: never;
|
||||||
|
};
|
||||||
|
requestBody: {
|
||||||
|
content: {
|
||||||
|
"application/json": components["schemas"]["navgroup"];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
responses: {
|
||||||
|
/** @description Entry updated */
|
||||||
|
200: {
|
||||||
|
headers: {
|
||||||
|
[name: string]: unknown;
|
||||||
|
};
|
||||||
|
content: {
|
||||||
|
"application/json": components["schemas"]["navgroup"];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
/** @description Validation error */
|
||||||
|
400: {
|
||||||
|
headers: {
|
||||||
|
[name: string]: unknown;
|
||||||
|
};
|
||||||
|
content?: never;
|
||||||
|
};
|
||||||
|
/** @description Entry not found */
|
||||||
|
404: {
|
||||||
|
headers: {
|
||||||
|
[name: string]: unknown;
|
||||||
|
};
|
||||||
|
content?: never;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
deleteNavgroup: {
|
||||||
|
parameters: {
|
||||||
|
query?: {
|
||||||
|
/** @description Resolve references: 'all' or comma-separated field names (e.g. row1Content,topFullwidthBanner). Resolved entries are embedded instead of { _type, _slug }. */
|
||||||
|
_resolve?: string;
|
||||||
|
/** @description Locale for content (e.g. de, en). Only used when RUSTYCMS_LOCALES is set. Default = first locale. References are resolved in the same locale. */
|
||||||
|
_locale?: string;
|
||||||
|
};
|
||||||
|
header?: never;
|
||||||
|
path: {
|
||||||
|
/** @description Entry identifier (filename without extension) */
|
||||||
|
slug: string;
|
||||||
|
};
|
||||||
|
cookie?: never;
|
||||||
|
};
|
||||||
|
requestBody?: never;
|
||||||
|
responses: {
|
||||||
|
/** @description Entry deleted */
|
||||||
|
204: {
|
||||||
|
headers: {
|
||||||
|
[name: string]: unknown;
|
||||||
|
};
|
||||||
|
content?: never;
|
||||||
|
};
|
||||||
|
/** @description Entry not found */
|
||||||
|
404: {
|
||||||
|
headers: {
|
||||||
|
[name: string]: unknown;
|
||||||
|
};
|
||||||
|
content?: never;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
getNavgroupReferrers: {
|
||||||
|
parameters: {
|
||||||
|
query?: never;
|
||||||
|
header?: never;
|
||||||
|
path: {
|
||||||
|
/** @description Entry slug */
|
||||||
|
slug: string;
|
||||||
|
};
|
||||||
|
cookie?: never;
|
||||||
|
};
|
||||||
|
requestBody?: never;
|
||||||
|
responses: {
|
||||||
|
/** @description List of referrers (collection, slug, field, locale) */
|
||||||
|
200: {
|
||||||
|
headers: {
|
||||||
|
[name: string]: unknown;
|
||||||
|
};
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
/** @description Collection of the referring entry */
|
||||||
|
collection?: string;
|
||||||
|
/** @description Field that holds the reference */
|
||||||
|
field?: string;
|
||||||
|
/** @description Locale of the referring entry if applicable */
|
||||||
|
locale?: string | null;
|
||||||
|
/** @description Slug of the referring entry */
|
||||||
|
slug?: string;
|
||||||
|
}[];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
listNavigation: {
|
listNavigation: {
|
||||||
parameters: {
|
parameters: {
|
||||||
query?: {
|
query?: {
|
||||||
@@ -10585,6 +10942,8 @@ export interface operations {
|
|||||||
_locale?: string;
|
_locale?: string;
|
||||||
/** @description Filter by logo */
|
/** @description Filter by logo */
|
||||||
logo?: string;
|
logo?: string;
|
||||||
|
/** @description Filter by siteName */
|
||||||
|
siteName?: string;
|
||||||
/** @description Filter by website */
|
/** @description Filter by website */
|
||||||
website?: string;
|
website?: string;
|
||||||
/** @description Filter by footerText1 */
|
/** @description Filter by footerText1 */
|
||||||
|
|||||||
+47
-15
@@ -35,6 +35,19 @@ function getCmsBaseUrl(): string {
|
|||||||
return base;
|
return base;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Relative CMS-Pfade (z. B. `/api/assets/…`) für Fetch/Transform absolut machen.
|
||||||
|
* RustyCMS liefert oft relative URLs; `/api/transform` braucht eine absolute URL.
|
||||||
|
*/
|
||||||
|
export function normalizeMediaUrl(url: string): string {
|
||||||
|
const u = url.trim();
|
||||||
|
if (!u) return u;
|
||||||
|
if (u.startsWith("//")) return `https:${u}`;
|
||||||
|
if (u.startsWith("http://") || u.startsWith("https://")) return u;
|
||||||
|
if (u.startsWith("/")) return `${getCmsBaseUrl()}${u}`;
|
||||||
|
return u;
|
||||||
|
}
|
||||||
|
|
||||||
/** Stabile Dateiendung aus format. */
|
/** Stabile Dateiendung aus format. */
|
||||||
function formatToExt(format: string): string {
|
function formatToExt(format: string): string {
|
||||||
switch (format.toLowerCase()) {
|
switch (format.toLowerCase()) {
|
||||||
@@ -79,9 +92,10 @@ export async function ensureTransformedImage(
|
|||||||
url: string,
|
url: string,
|
||||||
params: RustyImageTransformParams = {},
|
params: RustyImageTransformParams = {},
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
|
const absoluteUrl = normalizeMediaUrl(url);
|
||||||
const format = params.format ?? DEFAULT_FORMAT;
|
const format = params.format ?? DEFAULT_FORMAT;
|
||||||
const ext = formatToExt(format);
|
const ext = formatToExt(format);
|
||||||
const hash = hashForTransform(url, params);
|
const hash = hashForTransform(absoluteUrl, params);
|
||||||
const { width, height } = params;
|
const { width, height } = params;
|
||||||
const dimSuffix =
|
const dimSuffix =
|
||||||
width != null && height != null
|
width != null && height != null
|
||||||
@@ -130,7 +144,7 @@ export async function ensureTransformedImage(
|
|||||||
|
|
||||||
const baseUrl = getCmsBaseUrl();
|
const baseUrl = getCmsBaseUrl();
|
||||||
const searchParams = new URLSearchParams();
|
const searchParams = new URLSearchParams();
|
||||||
searchParams.set("url", url);
|
searchParams.set("url", absoluteUrl);
|
||||||
if (params.width != null) searchParams.set("w", String(params.width));
|
if (params.width != null) searchParams.set("w", String(params.width));
|
||||||
if (params.height != null) searchParams.set("h", String(params.height));
|
if (params.height != null) searchParams.set("h", String(params.height));
|
||||||
if (params.ar != null) searchParams.set("ar", params.ar);
|
if (params.ar != null) searchParams.set("ar", params.ar);
|
||||||
@@ -144,7 +158,7 @@ export async function ensureTransformedImage(
|
|||||||
const res = await fetch(transformUrl);
|
const res = await fetch(transformUrl);
|
||||||
if (!res.ok) {
|
if (!res.ok) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`rusty-image: transform failed ${res.status} for ${url}: ${await res.text()}`,
|
`rusty-image: transform failed ${res.status} for ${absoluteUrl}: ${await res.text()}`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -163,10 +177,16 @@ export async function ensureTransformedImage(
|
|||||||
type ImageArrayItem = string | { src?: string };
|
type ImageArrayItem = string | { src?: string };
|
||||||
|
|
||||||
function toImageUrl(item: ImageArrayItem): string | null {
|
function toImageUrl(item: ImageArrayItem): string | null {
|
||||||
if (typeof item === "string")
|
if (typeof item === "string") {
|
||||||
return item.startsWith("//") ? `https:${item}` : item;
|
const s = item.trim();
|
||||||
if (item && typeof item === "object" && typeof item.src === "string")
|
if (!s) return null;
|
||||||
return item.src.startsWith("//") ? `https:${item.src}` : item.src;
|
return normalizeMediaUrl(s.startsWith("//") ? `https:${s}` : s);
|
||||||
|
}
|
||||||
|
if (item && typeof item === "object" && typeof item.src === "string") {
|
||||||
|
const s = item.src.trim();
|
||||||
|
if (!s) return null;
|
||||||
|
return normalizeMediaUrl(s.startsWith("//") ? `https:${s}` : s);
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -182,7 +202,7 @@ export async function resolveImageUrls(
|
|||||||
const result: string[] = [];
|
const result: string[] = [];
|
||||||
for (const item of items) {
|
for (const item of items) {
|
||||||
const u = toImageUrl(item);
|
const u = toImageUrl(item);
|
||||||
if (!u || !u.startsWith("http")) continue;
|
if (!u) continue;
|
||||||
try {
|
try {
|
||||||
result.push(await ensureTransformedImage(u, params));
|
result.push(await ensureTransformedImage(u, params));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -198,11 +218,16 @@ function getImageBlockUrl(block: {
|
|||||||
img?: string | { src?: string; file?: { url?: string }; title?: string };
|
img?: string | { src?: string; file?: { url?: string }; title?: string };
|
||||||
}): string | null {
|
}): string | null {
|
||||||
const source = block.image ?? block.img;
|
const source = block.image ?? block.img;
|
||||||
if (typeof source === "string" && source.startsWith("http")) return source;
|
if (typeof source === "string") {
|
||||||
|
const s = source.trim();
|
||||||
|
if (!s) return null;
|
||||||
|
return normalizeMediaUrl(s.startsWith("//") ? `https:${s}` : s);
|
||||||
|
}
|
||||||
if (source && typeof source === "object") {
|
if (source && typeof source === "object") {
|
||||||
const u =
|
const u =
|
||||||
"src" in source && typeof source.src === "string" ? source.src : source.file?.url;
|
"src" in source && typeof source.src === "string" ? source.src : source.file?.url;
|
||||||
if (typeof u === "string") return u.startsWith("//") ? `https:${u}` : u;
|
if (typeof u !== "string" || !u.trim()) return null;
|
||||||
|
return normalizeMediaUrl(u.startsWith("//") ? `https:${u}` : u);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -211,8 +236,14 @@ function getImageBlockUrl(block: {
|
|||||||
function getGalleryImageUrl(
|
function getGalleryImageUrl(
|
||||||
img: { src?: string; file?: { url?: string } },
|
img: { src?: string; file?: { url?: string } },
|
||||||
): string | null {
|
): string | null {
|
||||||
if (typeof img.src === "string") return img.src.startsWith("//") ? `https:${img.src}` : img.src;
|
if (typeof img.src === "string" && img.src.trim()) {
|
||||||
if (img.file?.url) return img.file.url.startsWith("//") ? `https:${img.file.url}` : img.file.url;
|
const s = img.src;
|
||||||
|
return normalizeMediaUrl(s.startsWith("//") ? `https:${s}` : s);
|
||||||
|
}
|
||||||
|
if (img.file?.url) {
|
||||||
|
const s = img.file.url;
|
||||||
|
return normalizeMediaUrl(s.startsWith("//") ? `https:${s}` : s);
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -256,9 +287,10 @@ export async function processMarkdownHtmlImages(
|
|||||||
for (const m of matches) {
|
for (const m of matches) {
|
||||||
const rawSrc = m[2];
|
const rawSrc = m[2];
|
||||||
const url = rawSrc.startsWith("//") ? `https:${rawSrc}` : rawSrc;
|
const url = rawSrc.startsWith("//") ? `https:${rawSrc}` : rawSrc;
|
||||||
if (!url.startsWith("http")) continue;
|
const absolute = normalizeMediaUrl(url);
|
||||||
|
if (!absolute.startsWith("http")) continue;
|
||||||
try {
|
try {
|
||||||
const transformedPath = await ensureTransformedImage(url, transformParams);
|
const transformedPath = await ensureTransformedImage(absolute, transformParams);
|
||||||
const href = transformedPath.startsWith("/") ? transformedPath : `/${transformedPath}`;
|
const href = transformedPath.startsWith("/") ? transformedPath : `/${transformedPath}`;
|
||||||
const newImg = m[0].replace(rawSrc, transformedPath);
|
const newImg = m[0].replace(rawSrc, transformedPath);
|
||||||
const newBlock = `<a href="${href}" target="_blank" rel="noopener noreferrer" class="markdown-image-link">${newImg}</a>`;
|
const newBlock = `<a href="${href}" target="_blank" rel="noopener noreferrer" class="markdown-image-link">${newImg}</a>`;
|
||||||
@@ -352,7 +384,7 @@ export async function resolveContentImages(
|
|||||||
for (const img of block.images) {
|
for (const img of block.images) {
|
||||||
if (!img || typeof img !== "object") continue;
|
if (!img || typeof img !== "object") continue;
|
||||||
const url = getGalleryImageUrl(img);
|
const url = getGalleryImageUrl(img);
|
||||||
if (!url || !url.startsWith("http")) continue;
|
if (!url) continue;
|
||||||
try {
|
try {
|
||||||
(img as { resolvedSrc?: string }).resolvedSrc =
|
(img as { resolvedSrc?: string }).resolvedSrc =
|
||||||
await ensureTransformedImage(url, galleryParams);
|
await ensureTransformedImage(url, galleryParams);
|
||||||
|
|||||||
Reference in New Issue
Block a user