@agent-native/core 0.76.8 → 0.76.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/corpus/README.md +1 -1
- package/corpus/core/CHANGELOG.md +48 -0
- package/corpus/core/package.json +1 -1
- package/corpus/core/scripts/generate-og-font-data.mjs +9 -5
- package/corpus/core/src/agent/run-store.ts +21 -0
- package/corpus/core/src/client/AgentPanel.tsx +70 -1
- package/corpus/core/src/client/AssistantChat.tsx +1 -3
- package/corpus/core/src/client/MultiTabAssistantChat.tsx +0 -62
- package/corpus/core/src/client/composer/TiptapComposer.tsx +6 -13
- package/corpus/core/src/server/agent-chat-plugin.ts +26 -0
- package/corpus/core/src/server/og-fonts-data.ts +7 -4
- package/corpus/core/src/server/og-fonts.ts +10 -3
- package/corpus/core/src/server/social-og-image.ts +45 -6
- package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +199 -19
- package/corpus/templates/analytics/app/pages/adhoc/AdhocRouter.tsx +1 -21
- package/corpus/templates/analytics/app/pages/adhoc/DashboardSkeleton.tsx +35 -0
- package/corpus/templates/analytics/app/pages/adhoc/explorer-dashboard/index.tsx +3 -23
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +3 -26
- package/corpus/templates/analytics/changelog/2026-06-24-daily-dashboard-charts-now-use-local-day-buckets-and-show-th.md +6 -0
- package/corpus/templates/analytics/changelog/2026-06-24-dashboard-loading-placeholders-now-span-the-available-page-w.md +6 -0
- package/corpus/templates/analytics/changelog/2026-06-24-first-party-dashboard-dates-now-align-to-pacific-time-for-da.md +6 -0
- package/corpus/templates/analytics/server/lib/first-party-metric-catalog.ts +19 -7
- package/dist/agent/run-store.d.ts +11 -0
- package/dist/agent/run-store.d.ts.map +1 -1
- package/dist/agent/run-store.js +20 -0
- package/dist/agent/run-store.js.map +1 -1
- package/dist/client/AgentPanel.d.ts +5 -1
- package/dist/client/AgentPanel.d.ts.map +1 -1
- package/dist/client/AgentPanel.js +23 -4
- package/dist/client/AgentPanel.js.map +1 -1
- package/dist/client/AssistantChat.d.ts +1 -3
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/MultiTabAssistantChat.d.ts.map +1 -1
- package/dist/client/MultiTabAssistantChat.js +1 -17
- package/dist/client/MultiTabAssistantChat.js.map +1 -1
- package/dist/client/composer/TiptapComposer.d.ts +4 -0
- package/dist/client/composer/TiptapComposer.d.ts.map +1 -1
- package/dist/client/composer/TiptapComposer.js +5 -9
- package/dist/client/composer/TiptapComposer.js.map +1 -1
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +26 -0
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/dist/server/og-fonts-data.d.ts +1 -0
- package/dist/server/og-fonts-data.d.ts.map +1 -1
- package/dist/server/og-fonts-data.js +5 -4
- package/dist/server/og-fonts-data.js.map +1 -1
- package/dist/server/og-fonts.d.ts +1 -0
- package/dist/server/og-fonts.d.ts.map +1 -1
- package/dist/server/og-fonts.js +10 -4
- package/dist/server/og-fonts.js.map +1 -1
- package/dist/server/social-og-image.d.ts.map +1 -1
- package/dist/server/social-og-image.js +33 -6
- package/dist/server/social-og-image.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export declare const OG_FONT_FAMILY = "Liberation Sans";
|
|
2
|
+
export declare const OG_ARABIC_FONT_FAMILY = "Noto Naskh Arabic";
|
|
2
3
|
/**
|
|
3
4
|
* Materialize the embedded OG fonts to disk and return their paths for resvg's
|
|
4
5
|
* `fontFiles` option. resvg 2.x only accepts file paths (no in-memory buffers),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"og-fonts.d.ts","sourceRoot":"","sources":["../../src/server/og-fonts.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"og-fonts.d.ts","sourceRoot":"","sources":["../../src/server/og-fonts.ts"],"names":[],"mappings":"AA8BA,eAAO,MAAM,cAAc,oBAAoB,CAAC;AAChD,eAAO,MAAM,qBAAqB,sBAAsB,CAAC;AAIzD;;;;;;GAMG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,EAAE,GAAG,SAAS,CA+BzD"}
|
package/dist/server/og-fonts.js
CHANGED
|
@@ -2,13 +2,14 @@ import { createHash } from "node:crypto";
|
|
|
2
2
|
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
3
3
|
import { tmpdir } from "node:os";
|
|
4
4
|
import path from "node:path";
|
|
5
|
-
import { LIBERATION_SANS_BOLD_BASE64, LIBERATION_SANS_REGULAR_BASE64, } from "./og-fonts-data.js";
|
|
5
|
+
import { LIBERATION_SANS_BOLD_BASE64, LIBERATION_SANS_REGULAR_BASE64, NOTO_NASKH_ARABIC_BASE64, } from "./og-fonts-data.js";
|
|
6
6
|
/**
|
|
7
7
|
* Liberation Sans is the metric-compatible libre replacement for
|
|
8
|
-
* Arial/Helvetica that the OG image SVG asks for.
|
|
8
|
+
* Arial/Helvetica that the OG image SVG asks for. Noto Naskh Arabic fills the
|
|
9
|
+
* Arabic script gap for localized docs titles. They ship embedded as base64
|
|
9
10
|
* (see {@link ./og-fonts-data.ts}) so the renderer never depends on the host's
|
|
10
|
-
* system fonts — Linux serverless runtimes (Netlify/Lambda) have neither Arial
|
|
11
|
-
*
|
|
11
|
+
* system fonts — Linux serverless runtimes (Netlify/Lambda) have neither Arial,
|
|
12
|
+
* Inter, nor Arabic fallback fonts.
|
|
12
13
|
*/
|
|
13
14
|
const OG_FONT_FILES = [
|
|
14
15
|
{
|
|
@@ -16,8 +17,13 @@ const OG_FONT_FILES = [
|
|
|
16
17
|
base64: LIBERATION_SANS_REGULAR_BASE64,
|
|
17
18
|
},
|
|
18
19
|
{ filename: "LiberationSans-Bold.ttf", base64: LIBERATION_SANS_BOLD_BASE64 },
|
|
20
|
+
{
|
|
21
|
+
filename: "NotoNaskhArabic-Variable.ttf",
|
|
22
|
+
base64: NOTO_NASKH_ARABIC_BASE64,
|
|
23
|
+
},
|
|
19
24
|
];
|
|
20
25
|
export const OG_FONT_FAMILY = "Liberation Sans";
|
|
26
|
+
export const OG_ARABIC_FONT_FAMILY = "Noto Naskh Arabic";
|
|
21
27
|
let cachedFontFiles;
|
|
22
28
|
/**
|
|
23
29
|
* Materialize the embedded OG fonts to disk and return their paths for resvg's
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"og-fonts.js","sourceRoot":"","sources":["../../src/server/og-fonts.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC/D,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EACL,2BAA2B,EAC3B,8BAA8B,
|
|
1
|
+
{"version":3,"file":"og-fonts.js","sourceRoot":"","sources":["../../src/server/og-fonts.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC/D,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EACL,2BAA2B,EAC3B,8BAA8B,EAC9B,wBAAwB,GACzB,MAAM,oBAAoB,CAAC;AAE5B;;;;;;;GAOG;AACH,MAAM,aAAa,GAAG;IACpB;QACE,QAAQ,EAAE,4BAA4B;QACtC,MAAM,EAAE,8BAA8B;KACvC;IACD,EAAE,QAAQ,EAAE,yBAAyB,EAAE,MAAM,EAAE,2BAA2B,EAAE;IAC5E;QACE,QAAQ,EAAE,8BAA8B;QACxC,MAAM,EAAE,wBAAwB;KACjC;CACO,CAAC;AAEX,MAAM,CAAC,MAAM,cAAc,GAAG,iBAAiB,CAAC;AAChD,MAAM,CAAC,MAAM,qBAAqB,GAAG,mBAAmB,CAAC;AAEzD,IAAI,eAA4C,CAAC;AAEjD;;;;;;GAMG;AACH,MAAM,UAAU,kBAAkB;IAChC,IAAI,eAAe,KAAK,SAAS;QAAE,OAAO,eAAe,IAAI,SAAS,CAAC;IAEvE,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC;QAClC,MAAM,OAAO,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;YACzC,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;YACjD,IAAI,CAAC,KAAK,CAAC,UAAU;gBAAE,MAAM,IAAI,KAAK,CAAC,eAAe,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;YACvE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YAC3B,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACnB,OAAO,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,KAAK,EAAE,CAAC;QAC5C,CAAC,CAAC,CAAC;QAEH,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CACvB,MAAM,EAAE,EACR,yBAAyB,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAC3D,CAAC;QACF,SAAS,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAExC,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,EAAE;YACpD,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;YAC5C,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC;gBAAE,aAAa,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;YACtD,OAAO,MAAM,CAAC;QAChB,CAAC,CAAC,CAAC;QAEH,eAAe,GAAG,SAAS,CAAC;QAC5B,OAAO,SAAS,CAAC;IACnB,CAAC;IAAC,MAAM,CAAC;QACP,eAAe,GAAG,IAAI,CAAC;QACvB,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC","sourcesContent":["import { createHash } from \"node:crypto\";\nimport { existsSync, mkdirSync, writeFileSync } from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport path from \"node:path\";\nimport {\n LIBERATION_SANS_BOLD_BASE64,\n LIBERATION_SANS_REGULAR_BASE64,\n NOTO_NASKH_ARABIC_BASE64,\n} from \"./og-fonts-data.js\";\n\n/**\n * Liberation Sans is the metric-compatible libre replacement for\n * Arial/Helvetica that the OG image SVG asks for. Noto Naskh Arabic fills the\n * Arabic script gap for localized docs titles. They ship embedded as base64\n * (see {@link ./og-fonts-data.ts}) so the renderer never depends on the host's\n * system fonts — Linux serverless runtimes (Netlify/Lambda) have neither Arial,\n * Inter, nor Arabic fallback fonts.\n */\nconst OG_FONT_FILES = [\n {\n filename: \"LiberationSans-Regular.ttf\",\n base64: LIBERATION_SANS_REGULAR_BASE64,\n },\n { filename: \"LiberationSans-Bold.ttf\", base64: LIBERATION_SANS_BOLD_BASE64 },\n {\n filename: \"NotoNaskhArabic-Variable.ttf\",\n base64: NOTO_NASKH_ARABIC_BASE64,\n },\n] as const;\n\nexport const OG_FONT_FAMILY = \"Liberation Sans\";\nexport const OG_ARABIC_FONT_FAMILY = \"Noto Naskh Arabic\";\n\nlet cachedFontFiles: string[] | null | undefined;\n\n/**\n * Materialize the embedded OG fonts to disk and return their paths for resvg's\n * `fontFiles` option. resvg 2.x only accepts file paths (no in-memory buffers),\n * so the bytes are written once to a content-hashed tmp directory and cached\n * for the lifetime of the process. Returns `undefined` if the fonts can't be\n * written, letting the caller fall back to system fonts.\n */\nexport function resolveOgFontFiles(): string[] | undefined {\n if (cachedFontFiles !== undefined) return cachedFontFiles ?? undefined;\n\n try {\n const hash = createHash(\"sha256\");\n const decoded = OG_FONT_FILES.map((font) => {\n const bytes = Buffer.from(font.base64, \"base64\");\n if (!bytes.byteLength) throw new Error(`empty font: ${font.filename}`);\n hash.update(font.filename);\n hash.update(bytes);\n return { filename: font.filename, bytes };\n });\n\n const fontDir = path.join(\n tmpdir(),\n `agent-native-og-fonts-${hash.digest(\"hex\").slice(0, 16)}`,\n );\n mkdirSync(fontDir, { recursive: true });\n\n const fontFiles = decoded.map(({ filename, bytes }) => {\n const target = path.join(fontDir, filename);\n if (!existsSync(target)) writeFileSync(target, bytes);\n return target;\n });\n\n cachedFontFiles = fontFiles;\n return fontFiles;\n } catch {\n cachedFontFiles = null;\n return undefined;\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"social-og-image.d.ts","sourceRoot":"","sources":["../../src/server/social-og-image.ts"],"names":[],"mappings":"AAAA,OAAO,EAML,KAAK,OAAO,EACb,MAAM,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"social-og-image.d.ts","sourceRoot":"","sources":["../../src/server/social-og-image.ts"],"names":[],"mappings":"AAAA,OAAO,EAML,KAAK,OAAO,EACb,MAAM,IAAI,CAAC;AAYZ,MAAM,WAAW,uBAAuB;IACtC,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED,eAAO,MAAM,2BAA2B,OAAO,CAAC;AAChD,eAAO,MAAM,4BAA4B,MAAM,CAAC;AAChD,eAAO,MAAM,mCAAmC,2EAC0B,CAAC;AAC3E,eAAO,MAAM,2CAA2C,oFAC2B,CAAC;AAyNpF,wBAAgB,gCAAgC,CAAC,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,CAyBxE;AAqBD,wBAAgB,8BAA8B,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAUtE;AAED,wBAAgB,2BAA2B,CACzC,KAAK,GAAE,uBAA4B,GAClC,MAAM,CA2DR;AAED,wBAAsB,2BAA2B,CAC/C,KAAK,GAAE,uBAA4B,GAClC,OAAO,CAAC,UAAU,CAAC,CAuBrB;AAED,wBAAgB,iCAAiC,CAC/C,UAAU,CAAC,EAAE,MAAM,EACnB,WAAW,SAAc,GACxB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAYxB;AAED,wBAAgB,+BAA+B,CAC7C,OAAO,GAAE,uBAA4B,2FAsCtC"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { defineEventHandler, getHeader, getMethod, getQuery, getRequestURL, } from "h3";
|
|
2
2
|
import { resolveBuiltInAuthMarketing, resolveBuiltInAuthMarketingByName, } from "./auth-marketing.js";
|
|
3
3
|
import { getAppName } from "./app-name.js";
|
|
4
|
-
import { OG_FONT_FAMILY, resolveOgFontFiles } from "./og-fonts.js";
|
|
4
|
+
import { OG_ARABIC_FONT_FAMILY, OG_FONT_FAMILY, resolveOgFontFiles, } from "./og-fonts.js";
|
|
5
5
|
export const AGENT_NATIVE_OG_IMAGE_WIDTH = 1200;
|
|
6
6
|
export const AGENT_NATIVE_OG_IMAGE_HEIGHT = 630;
|
|
7
7
|
export const AGENT_NATIVE_OG_IMAGE_CACHE_CONTROL = "public, max-age=60, stale-while-revalidate=604800, stale-if-error=3600";
|
|
@@ -12,7 +12,8 @@ const BRAND_BLUE = "#00B5FF";
|
|
|
12
12
|
const BRAND_MINT = "#48FFE4";
|
|
13
13
|
const BG = "#000000";
|
|
14
14
|
const FG = "#f5f5f5";
|
|
15
|
-
const
|
|
15
|
+
const DEFAULT_FONT_FAMILY = `${OG_FONT_FAMILY}, Arial, Helvetica, system-ui, sans-serif`;
|
|
16
|
+
const ARABIC_FONT_FAMILY = `${OG_ARABIC_FONT_FAMILY}, ${OG_FONT_FAMILY}, Arial, Helvetica, system-ui, sans-serif`;
|
|
16
17
|
const DEFAULT_ACCENT_TEXT = "100% free and open source";
|
|
17
18
|
const LOGO_MARK = `
|
|
18
19
|
<path d="M24.5537 65.7695H0L15.0859 39.4619L37.708 0L60.4912 39.4619H39.6396L24.5537 65.7695Z" fill="white"/>
|
|
@@ -68,6 +69,12 @@ function estimateTextWidth(value, fontSize) {
|
|
|
68
69
|
}
|
|
69
70
|
return units * fontSize;
|
|
70
71
|
}
|
|
72
|
+
function containsArabicText(value) {
|
|
73
|
+
return /[\u0600-\u06ff\u0750-\u077f\u0870-\u089f\ufb50-\ufdff\ufe70-\ufeff]/u.test(value);
|
|
74
|
+
}
|
|
75
|
+
function fontFamilyForText(value) {
|
|
76
|
+
return containsArabicText(value) ? ARABIC_FONT_FAMILY : DEFAULT_FONT_FAMILY;
|
|
77
|
+
}
|
|
71
78
|
function trimTextToWidth(value, fontSize, maxWidth) {
|
|
72
79
|
const ellipsis = "...";
|
|
73
80
|
let trimmed = value.trim();
|
|
@@ -142,8 +149,11 @@ function getTitleLayout(title) {
|
|
|
142
149
|
lineHeight: 60,
|
|
143
150
|
};
|
|
144
151
|
}
|
|
145
|
-
function textBlock({ lines, x, y, fontSize, lineHeight, weight, fill, anchor = "start", }) {
|
|
146
|
-
|
|
152
|
+
function textBlock({ lines, x, y, fontSize, lineHeight, weight, fill, anchor = "start", direction, fontFamily = DEFAULT_FONT_FAMILY, }) {
|
|
153
|
+
const directionAttrs = direction
|
|
154
|
+
? ` direction="${direction}" unicode-bidi="plaintext"`
|
|
155
|
+
: "";
|
|
156
|
+
return `<text x="${x}" y="${y}" text-anchor="${anchor}"${directionAttrs} font-family="${fontFamily}" font-size="${fontSize}" font-weight="${weight}" fill="${fill}">${lines
|
|
147
157
|
.map((line, index) => `<tspan x="${x}" dy="${index === 0 ? 0 : lineHeight}">${escapeSvg(line)}</tspan>`)
|
|
148
158
|
.join("")}</text>`;
|
|
149
159
|
}
|
|
@@ -195,6 +205,10 @@ export function renderAgentNativeOgImageSvg(input = {}) {
|
|
|
195
205
|
const title = cleanText(input.title) || titleFromAppName(appName);
|
|
196
206
|
const accentText = cleanText(input.accentText) || DEFAULT_ACCENT_TEXT;
|
|
197
207
|
const titleLayout = getTitleLayout(title);
|
|
208
|
+
const titleIsRtl = containsArabicText(title);
|
|
209
|
+
const textX = titleIsRtl ? WIDTH - 80 : 80;
|
|
210
|
+
const accentX = titleIsRtl ? WIDTH - 84 : 84;
|
|
211
|
+
const textAnchor = titleIsRtl ? "end" : "start";
|
|
198
212
|
const titleY = titleLayout.lines.length > 1 ? 288 : 330;
|
|
199
213
|
const accentY = titleY + titleLayout.lineHeight * (titleLayout.lines.length - 1) + 70;
|
|
200
214
|
return `<svg xmlns="http://www.w3.org/2000/svg" width="${WIDTH}" height="${HEIGHT}" viewBox="0 0 ${WIDTH} ${HEIGHT}">
|
|
@@ -216,7 +230,7 @@ export function renderAgentNativeOgImageSvg(input = {}) {
|
|
|
216
230
|
<g>
|
|
217
231
|
${textBlock({
|
|
218
232
|
lines: titleLayout.lines,
|
|
219
|
-
x:
|
|
233
|
+
x: textX,
|
|
220
234
|
y: titleY,
|
|
221
235
|
fontSize: titleLayout.fontSize,
|
|
222
236
|
lineHeight: titleLayout.lineHeight,
|
|
@@ -225,8 +239,21 @@ export function renderAgentNativeOgImageSvg(input = {}) {
|
|
|
225
239
|
// bundle, which is the intended look for the display title.
|
|
226
240
|
weight: 800,
|
|
227
241
|
fill: FG,
|
|
242
|
+
anchor: textAnchor,
|
|
243
|
+
direction: titleIsRtl ? "rtl" : undefined,
|
|
244
|
+
fontFamily: fontFamilyForText(title),
|
|
245
|
+
})}
|
|
246
|
+
${textBlock({
|
|
247
|
+
lines: [accentText],
|
|
248
|
+
x: accentX,
|
|
249
|
+
y: accentY,
|
|
250
|
+
fontSize: 34,
|
|
251
|
+
lineHeight: 40,
|
|
252
|
+
weight: 800,
|
|
253
|
+
fill: BRAND_BLUE,
|
|
254
|
+
anchor: textAnchor,
|
|
255
|
+
fontFamily: fontFamilyForText(accentText),
|
|
228
256
|
})}
|
|
229
|
-
<text x="84" y="${accentY}" font-family="${FONT_FAMILY}" font-size="34" font-weight="800" fill="${BRAND_BLUE}">${escapeSvg(accentText)}</text>
|
|
230
257
|
</g>
|
|
231
258
|
</svg>`;
|
|
232
259
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"social-og-image.js","sourceRoot":"","sources":["../../src/server/social-og-image.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n defineEventHandler,\n getHeader,\n getMethod,\n getQuery,\n getRequestURL,\n type H3Event,\n} from \"h3\";\nimport {\n resolveBuiltInAuthMarketing,\n resolveBuiltInAuthMarketingByName,\n} from \"./auth-marketing.js\";\nimport { getAppName } from \"./app-name.js\";\nimport { OG_FONT_FAMILY, resolveOgFontFiles } from \"./og-fonts.js\";\n\nexport interface AgentNativeOgImageInput {\n appName?: string | null;\n title?: string | null;\n accentText?: string | null;\n}\n\nexport const AGENT_NATIVE_OG_IMAGE_WIDTH = 1200;\nexport const AGENT_NATIVE_OG_IMAGE_HEIGHT = 630;\nexport const AGENT_NATIVE_OG_IMAGE_CACHE_CONTROL =\n \"public, max-age=60, stale-while-revalidate=604800, stale-if-error=3600\";\nexport const AGENT_NATIVE_OG_IMAGE_NETLIFY_CACHE_CONTROL =\n \"public, durable, max-age=60, stale-while-revalidate=604800, stale-if-error=3600\";\n\nconst WIDTH = AGENT_NATIVE_OG_IMAGE_WIDTH;\nconst HEIGHT = AGENT_NATIVE_OG_IMAGE_HEIGHT;\nconst BRAND_BLUE = \"#00B5FF\";\nconst BRAND_MINT = \"#48FFE4\";\nconst BG = \"#000000\";\nconst FG = \"#f5f5f5\";\nconst FONT_FAMILY = `${OG_FONT_FAMILY}, Arial, Helvetica, system-ui, sans-serif`;\nconst DEFAULT_ACCENT_TEXT = \"100% free and open source\";\n\nconst LOGO_MARK = `\n <path d=\"M24.5537 65.7695H0L15.0859 39.4619L37.708 0L60.4912 39.4619H39.6396L24.5537 65.7695Z\" fill=\"white\"/>\n <path d=\"M89.446 0H114L76.2921 65.7704H51.7383L89.446 0Z\" fill=\"url(#brand)\"/>\n`;\n\nfunction escapeSvg(value: string): string {\n return value\n .replace(/&/g, \"&\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/\"/g, \""\");\n}\n\nfunction cleanText(value: string | null | undefined): string {\n return String(value ?? \"\")\n .replace(/\\s+/g, \" \")\n .trim();\n}\n\nfunction titleCase(value: string): string {\n return value\n .split(/[\\s._-]+/)\n .filter(Boolean)\n .map((part) => part.charAt(0).toUpperCase() + part.slice(1).toLowerCase())\n .join(\" \");\n}\n\nfunction titleFromAppName(appName: string): string {\n if (appName) return appName;\n const basePath =\n process.env.VITE_APP_BASE_PATH || process.env.APP_BASE_PATH || \"\";\n const slug = basePath.split(\"/\").filter(Boolean)[0] || \"\";\n return titleCase(slug) || \"Agent-Native\";\n}\n\ninterface WrappedText {\n lines: string[];\n truncated: boolean;\n}\n\ninterface TitleLayout {\n lines: string[];\n fontSize: number;\n lineHeight: number;\n}\n\nfunction estimateTextWidth(value: string, fontSize: number): number {\n let units = 0;\n for (const char of value) {\n if (char === \" \") {\n units += 0.28;\n } else if (/[MW@#%&]/.test(char)) {\n units += 0.86;\n } else if (/[A-Z]/.test(char)) {\n units += 0.64;\n } else if (/[ilI.,:;|!']/u.test(char)) {\n units += 0.26;\n } else if (/[0-9]/.test(char)) {\n units += 0.56;\n } else {\n units += 0.54;\n }\n }\n return units * fontSize;\n}\n\nfunction trimTextToWidth(\n value: string,\n fontSize: number,\n maxWidth: number,\n): string {\n const ellipsis = \"...\";\n let trimmed = value.trim();\n while (\n trimmed.length > 0 &&\n estimateTextWidth(`${trimmed}${ellipsis}`, fontSize) > maxWidth\n ) {\n trimmed = trimmed.slice(0, -1).trimEnd();\n }\n return trimmed ? `${trimmed}${ellipsis}` : ellipsis;\n}\n\nfunction wrapTextToWidth(\n value: string,\n fontSize: number,\n maxWidth: number,\n maxLines: number,\n): WrappedText {\n const words = value.split(/\\s+/).filter(Boolean);\n const lines: string[] = [];\n let current = \"\";\n let truncated = false;\n\n for (const word of words) {\n const next = current ? `${current} ${word}` : word;\n if (estimateTextWidth(next, fontSize) <= maxWidth) {\n current = next;\n continue;\n }\n if (!current) {\n lines.push(trimTextToWidth(word, fontSize, maxWidth));\n truncated = true;\n current = \"\";\n } else {\n lines.push(current);\n current = word;\n }\n if (lines.length === maxLines) {\n truncated = true;\n break;\n }\n }\n if (current && lines.length < maxLines) lines.push(current);\n\n const usedWordCount = lines.join(\" \").split(/\\s+/).filter(Boolean).length;\n if (usedWordCount < words.length && lines.length > 0) {\n lines[lines.length - 1] = trimTextToWidth(\n lines[lines.length - 1],\n fontSize,\n maxWidth,\n );\n truncated = true;\n }\n\n return {\n lines: lines.length ? lines : [trimTextToWidth(value, fontSize, maxWidth)],\n truncated,\n };\n}\n\nfunction getTitleLayout(title: string): TitleLayout {\n const maxTitleWidth = 900;\n if (estimateTextWidth(title, 88) <= maxTitleWidth) {\n return {\n lines: [title],\n fontSize: 88,\n lineHeight: 96,\n };\n }\n\n for (const fontSize of [76, 70, 64, 58, 52]) {\n const wrapped = wrapTextToWidth(title, fontSize, maxTitleWidth, 2);\n if (!wrapped.truncated) {\n const lineHeight = Math.round(fontSize * 1.1);\n return {\n lines: wrapped.lines,\n fontSize,\n lineHeight,\n };\n }\n }\n\n const fallbackFontSize = 52;\n const wrapped = wrapTextToWidth(title, fallbackFontSize, maxTitleWidth, 2);\n return {\n lines: wrapped.lines,\n fontSize: fallbackFontSize,\n lineHeight: 60,\n };\n}\n\nfunction textBlock({\n lines,\n x,\n y,\n fontSize,\n lineHeight,\n weight,\n fill,\n anchor = \"start\",\n}: {\n lines: string[];\n x: number;\n y: number;\n fontSize: number;\n lineHeight: number;\n weight: number;\n fill: string;\n anchor?: \"start\" | \"middle\";\n}): string {\n return `<text x=\"${x}\" y=\"${y}\" text-anchor=\"${anchor}\" font-family=\"${FONT_FAMILY}\" font-size=\"${fontSize}\" font-weight=\"${weight}\" fill=\"${fill}\">${lines\n .map(\n (line, index) =>\n `<tspan x=\"${x}\" dy=\"${index === 0 ? 0 : lineHeight}\">${escapeSvg(line)}</tspan>`,\n )\n .join(\"\")}</text>`;\n}\n\nexport function resolveAgentNativeOgImageAppName(event?: H3Event): string {\n const explicitAppName = cleanText(process.env.APP_NAME);\n if (explicitAppName) {\n return (\n resolveBuiltInAuthMarketingByName(explicitAppName)?.appName ??\n explicitAppName\n );\n }\n\n const requestHost = event\n ? (getHeader(event, \"x-forwarded-host\") ?? getHeader(event, \"host\"))\n : undefined;\n const requestPath = event ? getRequestURL(event).pathname : undefined;\n const builtInAppName = resolveBuiltInAuthMarketing({\n requestHost,\n requestPath,\n })?.appName;\n if (builtInAppName) return builtInAppName;\n\n const appName = getAppName();\n if (appName) {\n return resolveBuiltInAuthMarketingByName(appName)?.appName ?? appName;\n }\n\n return \"Agent-Native\";\n}\n\nfunction queryStringValue(\n value: unknown,\n maxLength: number,\n): string | undefined {\n if (typeof value !== \"string\") return undefined;\n const clean = cleanText(value).slice(0, maxLength);\n return clean || undefined;\n}\n\nfunction pngBody(bytes: Uint8Array): ArrayBuffer {\n const body = new ArrayBuffer(bytes.byteLength);\n new Uint8Array(body).set(bytes);\n return body;\n}\n\nfunction textByteLength(value: string): number {\n return new TextEncoder().encode(value).byteLength;\n}\n\nexport function isResvgRuntimeUnavailableError(error: unknown): boolean {\n const message = error instanceof Error ? error.message : String(error ?? \"\");\n return (\n /@resvg\\/resvg-js|resvgjs\\.[\\w-]+\\.node|native binding/i.test(message) &&\n // \"no such module\" is workerd's wording when the package is externalized\n // out of the Cloudflare worker bundle.\n /cannot find|no such module|err_module_not_found|dlopen|invalid elf|wrong architecture|not a valid win32|native binding/i.test(\n message,\n )\n );\n}\n\nexport function renderAgentNativeOgImageSvg(\n input: AgentNativeOgImageInput = {},\n): string {\n const appName =\n cleanText(input.appName) || resolveAgentNativeOgImageAppName();\n const title = cleanText(input.title) || titleFromAppName(appName);\n const accentText = cleanText(input.accentText) || DEFAULT_ACCENT_TEXT;\n const titleLayout = getTitleLayout(title);\n const titleY = titleLayout.lines.length > 1 ? 288 : 330;\n const accentY =\n titleY + titleLayout.lineHeight * (titleLayout.lines.length - 1) + 70;\n\n return `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"${WIDTH}\" height=\"${HEIGHT}\" viewBox=\"0 0 ${WIDTH} ${HEIGHT}\">\n <title>${escapeSvg(title)} - Agent-Native preview</title>\n <defs>\n <linearGradient id=\"brand\" x1=\"101.702\" y1=\"67.4791\" x2=\"113.672\" y2=\"-37.4275\" gradientUnits=\"userSpaceOnUse\">\n <stop stop-color=\"${BRAND_BLUE}\"/>\n <stop offset=\"1\" stop-color=\"${BRAND_MINT}\"/>\n </linearGradient>\n <pattern id=\"grid\" width=\"48\" height=\"48\" patternUnits=\"userSpaceOnUse\">\n <path d=\"M 48 0 L 0 0 0 48\" fill=\"none\" stroke=\"#ffffff\" stroke-opacity=\"0.07\" stroke-width=\"1\"/>\n </pattern>\n </defs>\n <rect width=\"${WIDTH}\" height=\"${HEIGHT}\" fill=\"${BG}\"/>\n <rect width=\"${WIDTH}\" height=\"${HEIGHT}\" fill=\"url(#grid)\"/>\n <g transform=\"translate(80 116) scale(0.94)\">\n ${LOGO_MARK}\n </g>\n <g>\n ${textBlock({\n lines: titleLayout.lines,\n x: 80,\n y: titleY,\n fontSize: titleLayout.fontSize,\n lineHeight: titleLayout.lineHeight,\n // resvg's fontdb maps font-weight 850 to the Regular face (only 400/700\n // exist for Liberation Sans); 800 resolves to Bold, the heaviest face we\n // bundle, which is the intended look for the display title.\n weight: 800,\n fill: FG,\n })}\n <text x=\"84\" y=\"${accentY}\" font-family=\"${FONT_FAMILY}\" font-size=\"34\" font-weight=\"800\" fill=\"${BRAND_BLUE}\">${escapeSvg(accentText)}</text>\n </g>\n</svg>`;\n}\n\nexport async function renderAgentNativeOgImagePng(\n input: AgentNativeOgImageInput = {},\n): Promise<Uint8Array> {\n const overridePackage =\n typeof process !== \"undefined\"\n ? process.env.AGENT_NATIVE_RESVG_PACKAGE\n : undefined;\n const resvgPackage = overridePackage || \"@resvg/resvg-js\";\n const { Resvg } = await import(/* @vite-ignore */ resvgPackage);\n // Feed resvg the embedded Liberation Sans font explicitly. System fonts can't\n // be relied on: Linux serverless runtimes (Netlify/Lambda) ship neither Arial\n // nor Inter, so without a bundled font every `<text>` rendered blank.\n const fontFiles = resolveOgFontFiles();\n const hasBundledFonts = Boolean(fontFiles?.length);\n const image = new Resvg(renderAgentNativeOgImageSvg(input), {\n fitTo: { mode: \"width\", value: WIDTH },\n font: {\n loadSystemFonts: !hasBundledFonts,\n ...(hasBundledFonts ? { fontFiles } : {}),\n defaultFontFamily: OG_FONT_FAMILY,\n serifFamily: OG_FONT_FAMILY,\n sansSerifFamily: OG_FONT_FAMILY,\n },\n }).render();\n return image.asPng();\n}\n\nexport function agentNativeOgImageResponseHeaders(\n byteLength?: number,\n contentType = \"image/png\",\n): Record<string, string> {\n const headers: Record<string, string> = {\n \"Content-Type\": contentType,\n \"Cache-Control\": AGENT_NATIVE_OG_IMAGE_CACHE_CONTROL,\n \"CDN-Cache-Control\": AGENT_NATIVE_OG_IMAGE_CACHE_CONTROL,\n \"Netlify-CDN-Cache-Control\": AGENT_NATIVE_OG_IMAGE_NETLIFY_CACHE_CONTROL,\n \"Cross-Origin-Resource-Policy\": \"cross-origin\",\n };\n if (typeof byteLength === \"number\") {\n headers[\"Content-Length\"] = String(byteLength);\n }\n return headers;\n}\n\nexport function createAgentNativeOgImageHandler(\n options: AgentNativeOgImageInput = {},\n) {\n return defineEventHandler(async (event) => {\n if (getMethod(event) === \"HEAD\") {\n return new Response(null, {\n headers: agentNativeOgImageResponseHeaders(),\n });\n }\n\n const query = getQuery(event);\n const appName =\n cleanText(options.appName) || resolveAgentNativeOgImageAppName(event);\n const input = {\n ...options,\n appName,\n title: cleanText(options.title) || queryStringValue(query.title, 140),\n accentText:\n cleanText(options.accentText) || queryStringValue(query.accentText, 80),\n };\n\n let png: Uint8Array;\n try {\n png = await renderAgentNativeOgImagePng(input);\n } catch (error) {\n if (!isResvgRuntimeUnavailableError(error)) throw error;\n const svg = renderAgentNativeOgImageSvg(input);\n return new Response(svg, {\n headers: agentNativeOgImageResponseHeaders(\n textByteLength(svg),\n \"image/svg+xml; charset=utf-8\",\n ),\n });\n }\n\n return new Response(pngBody(png), {\n headers: agentNativeOgImageResponseHeaders(png.byteLength),\n });\n });\n}\n"]}
|
|
1
|
+
{"version":3,"file":"social-og-image.js","sourceRoot":"","sources":["../../src/server/social-og-image.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n defineEventHandler,\n getHeader,\n getMethod,\n getQuery,\n getRequestURL,\n type H3Event,\n} from \"h3\";\nimport {\n resolveBuiltInAuthMarketing,\n resolveBuiltInAuthMarketingByName,\n} from \"./auth-marketing.js\";\nimport { getAppName } from \"./app-name.js\";\nimport {\n OG_ARABIC_FONT_FAMILY,\n OG_FONT_FAMILY,\n resolveOgFontFiles,\n} from \"./og-fonts.js\";\n\nexport interface AgentNativeOgImageInput {\n appName?: string | null;\n title?: string | null;\n accentText?: string | null;\n}\n\nexport const AGENT_NATIVE_OG_IMAGE_WIDTH = 1200;\nexport const AGENT_NATIVE_OG_IMAGE_HEIGHT = 630;\nexport const AGENT_NATIVE_OG_IMAGE_CACHE_CONTROL =\n \"public, max-age=60, stale-while-revalidate=604800, stale-if-error=3600\";\nexport const AGENT_NATIVE_OG_IMAGE_NETLIFY_CACHE_CONTROL =\n \"public, durable, max-age=60, stale-while-revalidate=604800, stale-if-error=3600\";\n\nconst WIDTH = AGENT_NATIVE_OG_IMAGE_WIDTH;\nconst HEIGHT = AGENT_NATIVE_OG_IMAGE_HEIGHT;\nconst BRAND_BLUE = \"#00B5FF\";\nconst BRAND_MINT = \"#48FFE4\";\nconst BG = \"#000000\";\nconst FG = \"#f5f5f5\";\nconst DEFAULT_FONT_FAMILY = `${OG_FONT_FAMILY}, Arial, Helvetica, system-ui, sans-serif`;\nconst ARABIC_FONT_FAMILY = `${OG_ARABIC_FONT_FAMILY}, ${OG_FONT_FAMILY}, Arial, Helvetica, system-ui, sans-serif`;\nconst DEFAULT_ACCENT_TEXT = \"100% free and open source\";\n\nconst LOGO_MARK = `\n <path d=\"M24.5537 65.7695H0L15.0859 39.4619L37.708 0L60.4912 39.4619H39.6396L24.5537 65.7695Z\" fill=\"white\"/>\n <path d=\"M89.446 0H114L76.2921 65.7704H51.7383L89.446 0Z\" fill=\"url(#brand)\"/>\n`;\n\nfunction escapeSvg(value: string): string {\n return value\n .replace(/&/g, \"&\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/\"/g, \""\");\n}\n\nfunction cleanText(value: string | null | undefined): string {\n return String(value ?? \"\")\n .replace(/\\s+/g, \" \")\n .trim();\n}\n\nfunction titleCase(value: string): string {\n return value\n .split(/[\\s._-]+/)\n .filter(Boolean)\n .map((part) => part.charAt(0).toUpperCase() + part.slice(1).toLowerCase())\n .join(\" \");\n}\n\nfunction titleFromAppName(appName: string): string {\n if (appName) return appName;\n const basePath =\n process.env.VITE_APP_BASE_PATH || process.env.APP_BASE_PATH || \"\";\n const slug = basePath.split(\"/\").filter(Boolean)[0] || \"\";\n return titleCase(slug) || \"Agent-Native\";\n}\n\ninterface WrappedText {\n lines: string[];\n truncated: boolean;\n}\n\ninterface TitleLayout {\n lines: string[];\n fontSize: number;\n lineHeight: number;\n}\n\nfunction estimateTextWidth(value: string, fontSize: number): number {\n let units = 0;\n for (const char of value) {\n if (char === \" \") {\n units += 0.28;\n } else if (/[MW@#%&]/.test(char)) {\n units += 0.86;\n } else if (/[A-Z]/.test(char)) {\n units += 0.64;\n } else if (/[ilI.,:;|!']/u.test(char)) {\n units += 0.26;\n } else if (/[0-9]/.test(char)) {\n units += 0.56;\n } else {\n units += 0.54;\n }\n }\n return units * fontSize;\n}\n\nfunction containsArabicText(value: string): boolean {\n return /[\\u0600-\\u06ff\\u0750-\\u077f\\u0870-\\u089f\\ufb50-\\ufdff\\ufe70-\\ufeff]/u.test(\n value,\n );\n}\n\nfunction fontFamilyForText(value: string): string {\n return containsArabicText(value) ? ARABIC_FONT_FAMILY : DEFAULT_FONT_FAMILY;\n}\n\nfunction trimTextToWidth(\n value: string,\n fontSize: number,\n maxWidth: number,\n): string {\n const ellipsis = \"...\";\n let trimmed = value.trim();\n while (\n trimmed.length > 0 &&\n estimateTextWidth(`${trimmed}${ellipsis}`, fontSize) > maxWidth\n ) {\n trimmed = trimmed.slice(0, -1).trimEnd();\n }\n return trimmed ? `${trimmed}${ellipsis}` : ellipsis;\n}\n\nfunction wrapTextToWidth(\n value: string,\n fontSize: number,\n maxWidth: number,\n maxLines: number,\n): WrappedText {\n const words = value.split(/\\s+/).filter(Boolean);\n const lines: string[] = [];\n let current = \"\";\n let truncated = false;\n\n for (const word of words) {\n const next = current ? `${current} ${word}` : word;\n if (estimateTextWidth(next, fontSize) <= maxWidth) {\n current = next;\n continue;\n }\n if (!current) {\n lines.push(trimTextToWidth(word, fontSize, maxWidth));\n truncated = true;\n current = \"\";\n } else {\n lines.push(current);\n current = word;\n }\n if (lines.length === maxLines) {\n truncated = true;\n break;\n }\n }\n if (current && lines.length < maxLines) lines.push(current);\n\n const usedWordCount = lines.join(\" \").split(/\\s+/).filter(Boolean).length;\n if (usedWordCount < words.length && lines.length > 0) {\n lines[lines.length - 1] = trimTextToWidth(\n lines[lines.length - 1],\n fontSize,\n maxWidth,\n );\n truncated = true;\n }\n\n return {\n lines: lines.length ? lines : [trimTextToWidth(value, fontSize, maxWidth)],\n truncated,\n };\n}\n\nfunction getTitleLayout(title: string): TitleLayout {\n const maxTitleWidth = 900;\n if (estimateTextWidth(title, 88) <= maxTitleWidth) {\n return {\n lines: [title],\n fontSize: 88,\n lineHeight: 96,\n };\n }\n\n for (const fontSize of [76, 70, 64, 58, 52]) {\n const wrapped = wrapTextToWidth(title, fontSize, maxTitleWidth, 2);\n if (!wrapped.truncated) {\n const lineHeight = Math.round(fontSize * 1.1);\n return {\n lines: wrapped.lines,\n fontSize,\n lineHeight,\n };\n }\n }\n\n const fallbackFontSize = 52;\n const wrapped = wrapTextToWidth(title, fallbackFontSize, maxTitleWidth, 2);\n return {\n lines: wrapped.lines,\n fontSize: fallbackFontSize,\n lineHeight: 60,\n };\n}\n\nfunction textBlock({\n lines,\n x,\n y,\n fontSize,\n lineHeight,\n weight,\n fill,\n anchor = \"start\",\n direction,\n fontFamily = DEFAULT_FONT_FAMILY,\n}: {\n lines: string[];\n x: number;\n y: number;\n fontSize: number;\n lineHeight: number;\n weight: number;\n fill: string;\n anchor?: \"start\" | \"middle\" | \"end\";\n direction?: \"ltr\" | \"rtl\";\n fontFamily?: string;\n}): string {\n const directionAttrs = direction\n ? ` direction=\"${direction}\" unicode-bidi=\"plaintext\"`\n : \"\";\n return `<text x=\"${x}\" y=\"${y}\" text-anchor=\"${anchor}\"${directionAttrs} font-family=\"${fontFamily}\" font-size=\"${fontSize}\" font-weight=\"${weight}\" fill=\"${fill}\">${lines\n .map(\n (line, index) =>\n `<tspan x=\"${x}\" dy=\"${index === 0 ? 0 : lineHeight}\">${escapeSvg(line)}</tspan>`,\n )\n .join(\"\")}</text>`;\n}\n\nexport function resolveAgentNativeOgImageAppName(event?: H3Event): string {\n const explicitAppName = cleanText(process.env.APP_NAME);\n if (explicitAppName) {\n return (\n resolveBuiltInAuthMarketingByName(explicitAppName)?.appName ??\n explicitAppName\n );\n }\n\n const requestHost = event\n ? (getHeader(event, \"x-forwarded-host\") ?? getHeader(event, \"host\"))\n : undefined;\n const requestPath = event ? getRequestURL(event).pathname : undefined;\n const builtInAppName = resolveBuiltInAuthMarketing({\n requestHost,\n requestPath,\n })?.appName;\n if (builtInAppName) return builtInAppName;\n\n const appName = getAppName();\n if (appName) {\n return resolveBuiltInAuthMarketingByName(appName)?.appName ?? appName;\n }\n\n return \"Agent-Native\";\n}\n\nfunction queryStringValue(\n value: unknown,\n maxLength: number,\n): string | undefined {\n if (typeof value !== \"string\") return undefined;\n const clean = cleanText(value).slice(0, maxLength);\n return clean || undefined;\n}\n\nfunction pngBody(bytes: Uint8Array): ArrayBuffer {\n const body = new ArrayBuffer(bytes.byteLength);\n new Uint8Array(body).set(bytes);\n return body;\n}\n\nfunction textByteLength(value: string): number {\n return new TextEncoder().encode(value).byteLength;\n}\n\nexport function isResvgRuntimeUnavailableError(error: unknown): boolean {\n const message = error instanceof Error ? error.message : String(error ?? \"\");\n return (\n /@resvg\\/resvg-js|resvgjs\\.[\\w-]+\\.node|native binding/i.test(message) &&\n // \"no such module\" is workerd's wording when the package is externalized\n // out of the Cloudflare worker bundle.\n /cannot find|no such module|err_module_not_found|dlopen|invalid elf|wrong architecture|not a valid win32|native binding/i.test(\n message,\n )\n );\n}\n\nexport function renderAgentNativeOgImageSvg(\n input: AgentNativeOgImageInput = {},\n): string {\n const appName =\n cleanText(input.appName) || resolveAgentNativeOgImageAppName();\n const title = cleanText(input.title) || titleFromAppName(appName);\n const accentText = cleanText(input.accentText) || DEFAULT_ACCENT_TEXT;\n const titleLayout = getTitleLayout(title);\n const titleIsRtl = containsArabicText(title);\n const textX = titleIsRtl ? WIDTH - 80 : 80;\n const accentX = titleIsRtl ? WIDTH - 84 : 84;\n const textAnchor = titleIsRtl ? \"end\" : \"start\";\n const titleY = titleLayout.lines.length > 1 ? 288 : 330;\n const accentY =\n titleY + titleLayout.lineHeight * (titleLayout.lines.length - 1) + 70;\n\n return `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"${WIDTH}\" height=\"${HEIGHT}\" viewBox=\"0 0 ${WIDTH} ${HEIGHT}\">\n <title>${escapeSvg(title)} - Agent-Native preview</title>\n <defs>\n <linearGradient id=\"brand\" x1=\"101.702\" y1=\"67.4791\" x2=\"113.672\" y2=\"-37.4275\" gradientUnits=\"userSpaceOnUse\">\n <stop stop-color=\"${BRAND_BLUE}\"/>\n <stop offset=\"1\" stop-color=\"${BRAND_MINT}\"/>\n </linearGradient>\n <pattern id=\"grid\" width=\"48\" height=\"48\" patternUnits=\"userSpaceOnUse\">\n <path d=\"M 48 0 L 0 0 0 48\" fill=\"none\" stroke=\"#ffffff\" stroke-opacity=\"0.07\" stroke-width=\"1\"/>\n </pattern>\n </defs>\n <rect width=\"${WIDTH}\" height=\"${HEIGHT}\" fill=\"${BG}\"/>\n <rect width=\"${WIDTH}\" height=\"${HEIGHT}\" fill=\"url(#grid)\"/>\n <g transform=\"translate(80 116) scale(0.94)\">\n ${LOGO_MARK}\n </g>\n <g>\n ${textBlock({\n lines: titleLayout.lines,\n x: textX,\n y: titleY,\n fontSize: titleLayout.fontSize,\n lineHeight: titleLayout.lineHeight,\n // resvg's fontdb maps font-weight 850 to the Regular face (only 400/700\n // exist for Liberation Sans); 800 resolves to Bold, the heaviest face we\n // bundle, which is the intended look for the display title.\n weight: 800,\n fill: FG,\n anchor: textAnchor,\n direction: titleIsRtl ? \"rtl\" : undefined,\n fontFamily: fontFamilyForText(title),\n })}\n ${textBlock({\n lines: [accentText],\n x: accentX,\n y: accentY,\n fontSize: 34,\n lineHeight: 40,\n weight: 800,\n fill: BRAND_BLUE,\n anchor: textAnchor,\n fontFamily: fontFamilyForText(accentText),\n })}\n </g>\n</svg>`;\n}\n\nexport async function renderAgentNativeOgImagePng(\n input: AgentNativeOgImageInput = {},\n): Promise<Uint8Array> {\n const overridePackage =\n typeof process !== \"undefined\"\n ? process.env.AGENT_NATIVE_RESVG_PACKAGE\n : undefined;\n const resvgPackage = overridePackage || \"@resvg/resvg-js\";\n const { Resvg } = await import(/* @vite-ignore */ resvgPackage);\n // Feed resvg the embedded Liberation Sans font explicitly. System fonts can't\n // be relied on: Linux serverless runtimes (Netlify/Lambda) ship neither Arial\n // nor Inter, so without a bundled font every `<text>` rendered blank.\n const fontFiles = resolveOgFontFiles();\n const hasBundledFonts = Boolean(fontFiles?.length);\n const image = new Resvg(renderAgentNativeOgImageSvg(input), {\n fitTo: { mode: \"width\", value: WIDTH },\n font: {\n loadSystemFonts: !hasBundledFonts,\n ...(hasBundledFonts ? { fontFiles } : {}),\n defaultFontFamily: OG_FONT_FAMILY,\n serifFamily: OG_FONT_FAMILY,\n sansSerifFamily: OG_FONT_FAMILY,\n },\n }).render();\n return image.asPng();\n}\n\nexport function agentNativeOgImageResponseHeaders(\n byteLength?: number,\n contentType = \"image/png\",\n): Record<string, string> {\n const headers: Record<string, string> = {\n \"Content-Type\": contentType,\n \"Cache-Control\": AGENT_NATIVE_OG_IMAGE_CACHE_CONTROL,\n \"CDN-Cache-Control\": AGENT_NATIVE_OG_IMAGE_CACHE_CONTROL,\n \"Netlify-CDN-Cache-Control\": AGENT_NATIVE_OG_IMAGE_NETLIFY_CACHE_CONTROL,\n \"Cross-Origin-Resource-Policy\": \"cross-origin\",\n };\n if (typeof byteLength === \"number\") {\n headers[\"Content-Length\"] = String(byteLength);\n }\n return headers;\n}\n\nexport function createAgentNativeOgImageHandler(\n options: AgentNativeOgImageInput = {},\n) {\n return defineEventHandler(async (event) => {\n if (getMethod(event) === \"HEAD\") {\n return new Response(null, {\n headers: agentNativeOgImageResponseHeaders(),\n });\n }\n\n const query = getQuery(event);\n const appName =\n cleanText(options.appName) || resolveAgentNativeOgImageAppName(event);\n const input = {\n ...options,\n appName,\n title: cleanText(options.title) || queryStringValue(query.title, 140),\n accentText:\n cleanText(options.accentText) || queryStringValue(query.accentText, 80),\n };\n\n let png: Uint8Array;\n try {\n png = await renderAgentNativeOgImagePng(input);\n } catch (error) {\n if (!isResvgRuntimeUnavailableError(error)) throw error;\n const svg = renderAgentNativeOgImageSvg(input);\n return new Response(svg, {\n headers: agentNativeOgImageResponseHeaders(\n textByteLength(svg),\n \"image/svg+xml; charset=utf-8\",\n ),\n });\n }\n\n return new Response(pngBody(png), {\n headers: agentNativeOgImageResponseHeaders(png.byteLength),\n });\n });\n}\n"]}
|