@vercel/og 0.5.19 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/figma/index.d.ts +7 -0
- package/dist/index.edge.d.ts +2 -1
- package/dist/index.edge.js +196 -2
- package/dist/index.edge.js.map +1 -1
- package/dist/index.edge.types.d.ts +2 -0
- package/dist/index.node.d.ts +2 -1
- package/dist/index.node.js +195 -1
- package/dist/index.node.js.map +1 -1
- package/dist/index.node.types.d.ts +2 -0
- package/dist/resvg.wasm +0 -0
- package/dist/types.d.ts +53 -0
- package/package.json +2 -2
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { EdgeImageResponse } from 'src/index.edge.types';
|
|
2
|
+
import { FigmaImageResponseProps } from 'src/types';
|
|
3
|
+
declare type InternalFigmaImageResponseProps = FigmaImageResponseProps & {
|
|
4
|
+
Response: EdgeImageResponse;
|
|
5
|
+
};
|
|
6
|
+
export declare const FigmaImageResponse: ({ url, template, fonts, imageResponseOptions, Response, }: InternalFigmaImageResponseProps) => Promise<import("../index.edge").ImageResponse>;
|
|
7
|
+
export {};
|
package/dist/index.edge.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { ReactElement } from 'react';
|
|
2
|
-
import type { ImageResponseOptions } from './types';
|
|
2
|
+
import type { ImageResponseOptions, FigmaImageResponseProps } from './types';
|
|
3
3
|
export declare class ImageResponse extends Response {
|
|
4
4
|
constructor(element: ReactElement, options?: ImageResponseOptions);
|
|
5
5
|
}
|
|
6
|
+
export declare const experimental_FigmaImageResponse: (props: FigmaImageResponseProps) => Promise<ImageResponse>;
|
package/dist/index.edge.js
CHANGED
|
@@ -18135,7 +18135,7 @@ async function initYoga(t) {
|
|
|
18135
18135
|
return wrapAsm(r);
|
|
18136
18136
|
}
|
|
18137
18137
|
|
|
18138
|
-
// node_modules/.pnpm/@resvg+resvg-wasm@2.
|
|
18138
|
+
// node_modules/.pnpm/@resvg+resvg-wasm@2.6.0/node_modules/@resvg/resvg-wasm/index.mjs
|
|
18139
18139
|
var resvg_wasm_exports = {};
|
|
18140
18140
|
__export(resvg_wasm_exports, {
|
|
18141
18141
|
Resvg: () => Resvg2,
|
|
@@ -18843,6 +18843,196 @@ async function render(satori, resvg, opts, defaultFonts, element) {
|
|
|
18843
18843
|
return resvgJS.render().asPng();
|
|
18844
18844
|
}
|
|
18845
18845
|
|
|
18846
|
+
// src/figma/index.tsx
|
|
18847
|
+
var FigmaImageResponse = async ({
|
|
18848
|
+
url,
|
|
18849
|
+
template,
|
|
18850
|
+
fonts,
|
|
18851
|
+
imageResponseOptions,
|
|
18852
|
+
Response: Response2
|
|
18853
|
+
}) => {
|
|
18854
|
+
const { fileId, nodeId } = parseFigmaUrl(url);
|
|
18855
|
+
const figmaAPIToken = assertValue(process.env.FIGMA_PERSONAL_ACCESS_TOKEN, "Missing environment variable: `FIGMA_PERSONAL_ACCESS_TOKEN`. You can get one at https://www.figma.com/developers/api#authentication");
|
|
18856
|
+
const figmaResponse = await fetch(`https://api.figma.com/v1/images/${fileId}?ids=${nodeId}&svg_outline_text=false&format=svg&svg_include_id=true`, {
|
|
18857
|
+
method: "GET",
|
|
18858
|
+
headers: {
|
|
18859
|
+
"X-FIGMA-TOKEN": figmaAPIToken
|
|
18860
|
+
},
|
|
18861
|
+
cache: "no-store"
|
|
18862
|
+
});
|
|
18863
|
+
const figmaResponseJson = await figmaResponse.json();
|
|
18864
|
+
const svgDownloadPath = figmaResponseJson.images[nodeId.replace("-", ":")];
|
|
18865
|
+
const svgResponse = await fetch(svgDownloadPath, { cache: "no-store" });
|
|
18866
|
+
const svg = await svgResponse.text();
|
|
18867
|
+
const { width, height } = getSvgDimensions(svg);
|
|
18868
|
+
const textNodes = getTextNodes(svg);
|
|
18869
|
+
const textNodeAttributes = textNodes.map(parseSvgText);
|
|
18870
|
+
return new Response2({
|
|
18871
|
+
key: "0",
|
|
18872
|
+
type: "div",
|
|
18873
|
+
props: {
|
|
18874
|
+
style: { display: "flex" },
|
|
18875
|
+
children: [
|
|
18876
|
+
{
|
|
18877
|
+
type: "img",
|
|
18878
|
+
props: {
|
|
18879
|
+
style: { position: "absolute" },
|
|
18880
|
+
alt: "",
|
|
18881
|
+
width,
|
|
18882
|
+
height,
|
|
18883
|
+
src: svgToBase64(svg)
|
|
18884
|
+
}
|
|
18885
|
+
},
|
|
18886
|
+
{
|
|
18887
|
+
type: "div",
|
|
18888
|
+
props: {
|
|
18889
|
+
style: { display: "flex", position: "relative", width: "100%" },
|
|
18890
|
+
children: textNodeAttributes.map((textNode) => {
|
|
18891
|
+
const t = template[textNode.id];
|
|
18892
|
+
let value = "";
|
|
18893
|
+
if (t === void 0) {
|
|
18894
|
+
value = textNode.content;
|
|
18895
|
+
} else if (isComplexTemplate(t)) {
|
|
18896
|
+
value = t.value;
|
|
18897
|
+
} else {
|
|
18898
|
+
value = t;
|
|
18899
|
+
}
|
|
18900
|
+
let cssProps = {};
|
|
18901
|
+
let centerHorizontally = false;
|
|
18902
|
+
if (isComplexTemplate(t) && t.props) {
|
|
18903
|
+
const {
|
|
18904
|
+
centerHorizontally: centerHorizontallyProp,
|
|
18905
|
+
...otherCSSProps
|
|
18906
|
+
} = t.props;
|
|
18907
|
+
cssProps = otherCSSProps;
|
|
18908
|
+
centerHorizontally = centerHorizontallyProp || false;
|
|
18909
|
+
}
|
|
18910
|
+
if (centerHorizontally) {
|
|
18911
|
+
const templateStyles = {
|
|
18912
|
+
color: textNode.fill,
|
|
18913
|
+
marginTop: `${parseInt(textNode.y) - parseInt(textNode.fontSize)}px`,
|
|
18914
|
+
fontWeight: textNode.fontWeight || "400",
|
|
18915
|
+
fontSize: textNode.fontSize,
|
|
18916
|
+
fontFamily: textNode.fontFamily,
|
|
18917
|
+
letterSpacing: textNode.letterSpacing,
|
|
18918
|
+
textAlign: "center",
|
|
18919
|
+
...cssProps
|
|
18920
|
+
};
|
|
18921
|
+
return {
|
|
18922
|
+
type: "div",
|
|
18923
|
+
props: {
|
|
18924
|
+
style: {
|
|
18925
|
+
display: "flex",
|
|
18926
|
+
justifyContent: "center",
|
|
18927
|
+
position: "absolute",
|
|
18928
|
+
width: "100%"
|
|
18929
|
+
},
|
|
18930
|
+
children: {
|
|
18931
|
+
type: "div",
|
|
18932
|
+
props: {
|
|
18933
|
+
style: templateStyles,
|
|
18934
|
+
children: value
|
|
18935
|
+
}
|
|
18936
|
+
}
|
|
18937
|
+
}
|
|
18938
|
+
};
|
|
18939
|
+
}
|
|
18940
|
+
return {
|
|
18941
|
+
type: "div",
|
|
18942
|
+
props: {
|
|
18943
|
+
style: {
|
|
18944
|
+
position: "absolute",
|
|
18945
|
+
color: textNode.fill,
|
|
18946
|
+
left: `${textNode.x}px`,
|
|
18947
|
+
top: `${parseInt(textNode.y) - parseInt(textNode.fontSize)}px`,
|
|
18948
|
+
fontWeight: textNode.fontWeight || "400",
|
|
18949
|
+
fontSize: textNode.fontSize,
|
|
18950
|
+
fontFamily: textNode.fontFamily,
|
|
18951
|
+
letterSpacing: textNode.letterSpacing,
|
|
18952
|
+
...cssProps
|
|
18953
|
+
},
|
|
18954
|
+
children: value
|
|
18955
|
+
}
|
|
18956
|
+
};
|
|
18957
|
+
})
|
|
18958
|
+
}
|
|
18959
|
+
}
|
|
18960
|
+
]
|
|
18961
|
+
}
|
|
18962
|
+
}, {
|
|
18963
|
+
width,
|
|
18964
|
+
height,
|
|
18965
|
+
fonts,
|
|
18966
|
+
...imageResponseOptions
|
|
18967
|
+
});
|
|
18968
|
+
};
|
|
18969
|
+
var isComplexTemplate = (template) => {
|
|
18970
|
+
return typeof template !== "string" && template !== void 0 && "value" in template;
|
|
18971
|
+
};
|
|
18972
|
+
function svgToBase64(svg) {
|
|
18973
|
+
const base64 = Buffer.from(svg).toString("base64");
|
|
18974
|
+
return "data:image/svg+xml;base64," + base64;
|
|
18975
|
+
}
|
|
18976
|
+
function getSvgDimensions(svg) {
|
|
18977
|
+
const widthMatch = svg.match(/width="(\d+)/);
|
|
18978
|
+
const heightMatch = svg.match(/height="(\d+)/);
|
|
18979
|
+
if (widthMatch && heightMatch) {
|
|
18980
|
+
const width = parseInt(widthMatch[1], 10);
|
|
18981
|
+
const height = parseInt(heightMatch[1], 10);
|
|
18982
|
+
return { width, height };
|
|
18983
|
+
}
|
|
18984
|
+
return { width: 0, height: 0 };
|
|
18985
|
+
}
|
|
18986
|
+
function getTextNodes(svg) {
|
|
18987
|
+
const regex = /<text[^>]*>(.*?)<\/text>/g;
|
|
18988
|
+
let match;
|
|
18989
|
+
const matches = [];
|
|
18990
|
+
while ((match = regex.exec(svg)) !== null) {
|
|
18991
|
+
matches.push(match[0]);
|
|
18992
|
+
}
|
|
18993
|
+
return matches;
|
|
18994
|
+
}
|
|
18995
|
+
function parseSvgText(svgText) {
|
|
18996
|
+
var _a2, _b2, _c, _d, _e, _f2, _g, _h, _i;
|
|
18997
|
+
const id = ((_a2 = svgText.match(/id="([^"]*)"/)) == null ? void 0 : _a2[1]) || "";
|
|
18998
|
+
const fill = ((_b2 = svgText.match(/fill="([^"]*)"/)) == null ? void 0 : _b2[1]) || "";
|
|
18999
|
+
const fontFamily = ((_c = svgText.match(/font-family="([^"]*)"/)) == null ? void 0 : _c[1]) || "";
|
|
19000
|
+
const fontSize = ((_d = svgText.match(/font-size="([^"]*)"/)) == null ? void 0 : _d[1]) || "";
|
|
19001
|
+
const fontWeight = ((_e = svgText.match(/font-weight="([^"]*)"/)) == null ? void 0 : _e[1]) || "";
|
|
19002
|
+
const letterSpacing = ((_f2 = svgText.match(/letter-spacing="([^"]*)"/)) == null ? void 0 : _f2[1]) || "";
|
|
19003
|
+
const x = ((_g = svgText.match(/<tspan[^>]*x="([^"]*)"/)) == null ? void 0 : _g[1]) || "";
|
|
19004
|
+
const y = ((_h = svgText.match(/<tspan[^>]*y="([^"]*)"/)) == null ? void 0 : _h[1]) || "";
|
|
19005
|
+
const content = ((_i = svgText.match(/<tspan[^>]*>([^<]*)<\/tspan>/)) == null ? void 0 : _i[1]) || "";
|
|
19006
|
+
return {
|
|
19007
|
+
id,
|
|
19008
|
+
fill,
|
|
19009
|
+
fontFamily,
|
|
19010
|
+
fontSize,
|
|
19011
|
+
fontWeight,
|
|
19012
|
+
letterSpacing,
|
|
19013
|
+
x,
|
|
19014
|
+
y,
|
|
19015
|
+
content
|
|
19016
|
+
};
|
|
19017
|
+
}
|
|
19018
|
+
function parseFigmaUrl(figmaUrl) {
|
|
19019
|
+
const regex = /\/file\/([^/]+)\/[^?]+\?[^#]*node-id=([^&#]+)/;
|
|
19020
|
+
const match = figmaUrl.match(regex);
|
|
19021
|
+
let fileId = "";
|
|
19022
|
+
let nodeId = "";
|
|
19023
|
+
if (match) {
|
|
19024
|
+
fileId = match[1] || "";
|
|
19025
|
+
nodeId = match[2] || "";
|
|
19026
|
+
}
|
|
19027
|
+
return { fileId, nodeId };
|
|
19028
|
+
}
|
|
19029
|
+
function assertValue(v, errorMessage) {
|
|
19030
|
+
if (v === void 0) {
|
|
19031
|
+
throw new Error(errorMessage);
|
|
19032
|
+
}
|
|
19033
|
+
return v;
|
|
19034
|
+
}
|
|
19035
|
+
|
|
18846
19036
|
// src/index.edge.ts
|
|
18847
19037
|
var initializedResvg = initWasm(resvg_wasm);
|
|
18848
19038
|
var initializedYoga = initYoga(yoga_wasm).then((yoga2) => Rl(yoga2));
|
|
@@ -18878,8 +19068,12 @@ var ImageResponse = class extends Response {
|
|
|
18878
19068
|
});
|
|
18879
19069
|
}
|
|
18880
19070
|
};
|
|
19071
|
+
var experimental_FigmaImageResponse = async (props) => {
|
|
19072
|
+
return FigmaImageResponse({ ...props, Response: ImageResponse });
|
|
19073
|
+
};
|
|
18881
19074
|
export {
|
|
18882
|
-
ImageResponse
|
|
19075
|
+
ImageResponse,
|
|
19076
|
+
experimental_FigmaImageResponse
|
|
18883
19077
|
};
|
|
18884
19078
|
/*!
|
|
18885
19079
|
* escape-html
|