@ogxjs/core 0.1.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.
Files changed (82) hide show
  1. package/README.md +102 -0
  2. package/dist/builder.d.ts +75 -0
  3. package/dist/builder.d.ts.map +1 -0
  4. package/dist/builder.js +243 -0
  5. package/dist/cache.d.ts +32 -0
  6. package/dist/cache.d.ts.map +1 -0
  7. package/dist/cache.js +71 -0
  8. package/dist/css.d.ts +83 -0
  9. package/dist/css.d.ts.map +1 -0
  10. package/dist/css.js +1 -0
  11. package/dist/font-registry.d.ts +34 -0
  12. package/dist/font-registry.d.ts.map +1 -0
  13. package/dist/font-registry.js +59 -0
  14. package/dist/fonts/inter/inter-300.ttf +0 -0
  15. package/dist/fonts/inter/inter-400.ttf +0 -0
  16. package/dist/fonts/inter/inter-500.ttf +0 -0
  17. package/dist/fonts/inter/inter-600.ttf +0 -0
  18. package/dist/fonts/inter/inter-700.ttf +0 -0
  19. package/dist/fonts.d.ts +29 -0
  20. package/dist/fonts.d.ts.map +1 -0
  21. package/dist/fonts.js +90 -0
  22. package/dist/index.d.ts +18 -0
  23. package/dist/index.d.ts.map +1 -0
  24. package/dist/index.js +19 -0
  25. package/dist/ogx.d.ts +16 -0
  26. package/dist/ogx.d.ts.map +1 -0
  27. package/dist/ogx.js +104 -0
  28. package/dist/presets/blog.d.ts +31 -0
  29. package/dist/presets/blog.d.ts.map +1 -0
  30. package/dist/presets/blog.js +98 -0
  31. package/dist/presets/docs.d.ts +23 -0
  32. package/dist/presets/docs.d.ts.map +1 -0
  33. package/dist/presets/docs.js +87 -0
  34. package/dist/presets/index.d.ts +20 -0
  35. package/dist/presets/index.d.ts.map +1 -0
  36. package/dist/presets/index.js +11 -0
  37. package/dist/presets/minimal.d.ts +20 -0
  38. package/dist/presets/minimal.d.ts.map +1 -0
  39. package/dist/presets/minimal.js +53 -0
  40. package/dist/presets/social.d.ts +29 -0
  41. package/dist/presets/social.d.ts.map +1 -0
  42. package/dist/presets/social.js +66 -0
  43. package/dist/render-png.d.ts +7 -0
  44. package/dist/render-png.d.ts.map +1 -0
  45. package/dist/render-png.js +19 -0
  46. package/dist/render-svg.d.ts +7 -0
  47. package/dist/render-svg.d.ts.map +1 -0
  48. package/dist/render-svg.js +123 -0
  49. package/dist/render.d.ts +10 -0
  50. package/dist/render.d.ts.map +1 -0
  51. package/dist/render.js +180 -0
  52. package/dist/tailwind/colors.d.ts +6 -0
  53. package/dist/tailwind/colors.d.ts.map +1 -0
  54. package/dist/tailwind/colors.js +281 -0
  55. package/dist/tailwind/index.d.ts +2 -0
  56. package/dist/tailwind/index.d.ts.map +1 -0
  57. package/dist/tailwind/index.js +1 -0
  58. package/dist/tailwind/parser.d.ts +15 -0
  59. package/dist/tailwind/parser.d.ts.map +1 -0
  60. package/dist/tailwind/parser.js +1037 -0
  61. package/dist/tailwind/scales.d.ts +26 -0
  62. package/dist/tailwind/scales.d.ts.map +1 -0
  63. package/dist/tailwind/scales.js +126 -0
  64. package/dist/tailwind/test-parser.d.ts +2 -0
  65. package/dist/tailwind/test-parser.d.ts.map +1 -0
  66. package/dist/tailwind/test-parser.js +10 -0
  67. package/dist/targets.d.ts +67 -0
  68. package/dist/targets.d.ts.map +1 -0
  69. package/dist/targets.js +25 -0
  70. package/dist/types.d.ts +173 -0
  71. package/dist/types.d.ts.map +1 -0
  72. package/dist/types.js +10 -0
  73. package/dist/utils/assets.d.ts +11 -0
  74. package/dist/utils/assets.d.ts.map +1 -0
  75. package/dist/utils/assets.js +35 -0
  76. package/dist/utils/color.d.ts +14 -0
  77. package/dist/utils/color.d.ts.map +1 -0
  78. package/dist/utils/color.js +68 -0
  79. package/dist/utils/text.d.ts +14 -0
  80. package/dist/utils/text.d.ts.map +1 -0
  81. package/dist/utils/text.js +50 -0
  82. package/package.json +71 -0
package/README.md ADDED
@@ -0,0 +1,102 @@
1
+ # @ogxjs/core
2
+
3
+ > Tailwind-first OG image generator powered by Satori
4
+
5
+ Generate beautiful Open Graph images using Tailwind CSS classes and an ergonomic builder API. Built for Node.js, also compatible with Bun and Deno.
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ npm install @ogxjs/core
11
+ # or
12
+ bun add @ogxjs/core
13
+ ```
14
+
15
+ ## Quick Start
16
+
17
+ ```typescript
18
+ import { ogx } from "@ogxjs/core";
19
+ import { writeFile } from "node:fs/promises";
20
+
21
+ // Generate a PNG using a preset
22
+ const image = await ogx({
23
+ preset: "minimal",
24
+ title: "Hello, World!",
25
+ subtitle: "This is my OG image",
26
+ });
27
+
28
+ // Save to file
29
+ await writeFile("og.png", image);
30
+ ```
31
+
32
+ ## Builder API
33
+
34
+ Create custom layouts with an ergonomic builder:
35
+
36
+ ```typescript
37
+ import { stack, div, span, render } from "@ogxjs/core";
38
+
39
+ const element = stack("w-full h-full bg-gradient-to-br from-blue-500 to-purple-600 p-20", [
40
+ div("bg-white rounded-2xl p-12 shadow-2xl", [
41
+ span("text-6xl font-bold text-gray-900", "Custom Layout"),
42
+ span("text-2xl text-gray-600 mt-4", "Built with Tailwind classes"),
43
+ ]),
44
+ ]);
45
+
46
+ const image = await render(element);
47
+ ```
48
+
49
+ ## Presets
50
+
51
+ Built-in presets for common use cases:
52
+
53
+ - `minimal` - Clean and simple
54
+ - `blog` - Blog post headers
55
+ - `docs` - Documentation pages
56
+ - `social` - Social media cards
57
+
58
+ ```typescript
59
+ await ogx({
60
+ preset: "blog",
61
+ title: "Building with OGX",
62
+ description: "Learn how to create dynamic OG images",
63
+ author: "John Doe",
64
+ date: "Dec 28, 2024",
65
+ });
66
+ ```
67
+
68
+ ## Custom Fonts
69
+
70
+ ```typescript
71
+ import { loadInterFont, fontRegistry } from "@ogxjs/core";
72
+
73
+ // Load and register fonts
74
+ const inter = await loadInterFont(400);
75
+ fontRegistry.register(inter);
76
+
77
+ // Use in your images
78
+ await ogx({
79
+ preset: "minimal",
80
+ title: "Custom Font",
81
+ fonts: fontRegistry.getFonts(),
82
+ });
83
+ ```
84
+
85
+ ## Browser-safe SVG Rendering
86
+
87
+ ```typescript
88
+ import { renderToSVG } from "@ogxjs/core/svg";
89
+
90
+ // Render to SVG (no Node.js dependencies)
91
+ const svg = await renderToSVG(element);
92
+ ```
93
+
94
+ ## Exports
95
+
96
+ - `@ogxjs/core` - Main package (PNG rendering, presets, builder)
97
+ - `@ogxjs/core/svg` - Browser-safe SVG rendering
98
+ - `@ogxjs/core/png` - Node.js PNG rendering
99
+
100
+ ## License
101
+
102
+ MIT
@@ -0,0 +1,75 @@
1
+ import type { OGXChildren, OGXElement, OGXElementProps, TailwindSpacing, TailwindUtility } from "./types";
2
+ /**
3
+ * Universal element factory (h/createElement style)
4
+ */
5
+ export declare function h(type: string, props?: OGXElementProps | string | TailwindUtility[], children?: OGXChildren): OGXElement;
6
+ /** Create a div element */
7
+ export declare const div: (tw?: TailwindUtility | TailwindUtility[], children?: OGXChildren, props?: Omit<OGXElementProps, "tw" | "children">) => OGXElement;
8
+ /** Create a span element */
9
+ export declare const span: (tw?: TailwindUtility | TailwindUtility[], children?: OGXChildren, props?: Omit<OGXElementProps, "tw" | "children">) => OGXElement;
10
+ /** Create an img element */
11
+ export declare const img: (src: string, tw?: TailwindUtility | TailwindUtility[], props?: Omit<OGXElementProps, "tw" | "src">) => OGXElement;
12
+ /** Create a vertical stack (flex-col) */
13
+ export declare const stack: (tw?: TailwindUtility | TailwindUtility[], children?: OGXChildren, props?: Omit<OGXElementProps, "tw" | "children">) => OGXElement;
14
+ /** Create a horizontal row (flex-row) */
15
+ export declare const row: (tw?: TailwindUtility | TailwindUtility[], children?: OGXChildren, props?: Omit<OGXElementProps, "tw" | "children">) => OGXElement;
16
+ /** Create an absolute positioned overlay */
17
+ export declare const absolute: (tw?: TailwindUtility | TailwindUtility[], children?: OGXChildren, props?: Omit<OGXElementProps, "tw" | "children">) => OGXElement;
18
+ /** Create a grid-like layout (flex-row with wrap) */
19
+ export declare const grid: (tw?: TailwindUtility | TailwindUtility[], children?: OGXChildren, props?: Omit<OGXElementProps, "tw" | "children">) => OGXElement;
20
+ /** Create a semantic header */
21
+ export declare const header: (tw?: TailwindUtility | TailwindUtility[], children?: OGXChildren, props?: Omit<OGXElementProps, "tw" | "children">) => OGXElement;
22
+ /** Create a semantic footer */
23
+ export declare const footer: (tw?: TailwindUtility | TailwindUtility[], children?: OGXChildren, props?: Omit<OGXElementProps, "tw" | "children">) => OGXElement;
24
+ /** Create a semantic main content area */
25
+ export declare const main: (tw?: TailwindUtility | TailwindUtility[], children?: OGXChildren, props?: Omit<OGXElementProps, "tw" | "children">) => OGXElement;
26
+ /** Create a spacer (flex-1 or custom size) */
27
+ export declare const spacer: (size?: TailwindSpacing | number, tw?: TailwindUtility | TailwindUtility[]) => OGXElement;
28
+ /**
29
+ * Semantic Typography
30
+ */
31
+ export declare const h1: (tw?: TailwindUtility | TailwindUtility[], children?: OGXChildren) => OGXElement;
32
+ export declare const h2: (tw?: TailwindUtility | TailwindUtility[], children?: OGXChildren) => OGXElement;
33
+ export declare const p: (tw?: TailwindUtility | TailwindUtility[], children?: OGXChildren) => OGXElement;
34
+ /**
35
+ * Fluent Builder API (Chainable)
36
+ */
37
+ export declare class FluentBuilder {
38
+ private _element;
39
+ constructor(element: OGXElement);
40
+ get element(): OGXElement;
41
+ gap(val: TailwindSpacing): this;
42
+ padding(val: TailwindSpacing): this;
43
+ px(val: TailwindSpacing): this;
44
+ py(val: TailwindSpacing): this;
45
+ margin(val: TailwindSpacing): this;
46
+ mt(val: TailwindSpacing): this;
47
+ rounded(val?: "sm" | "md" | "lg" | "xl" | "2xl" | "3xl" | "full"): this;
48
+ center(): this;
49
+ itemsCenter(): this;
50
+ justifyCenter(): this;
51
+ justifyBetween(): this;
52
+ bg(color: string): this;
53
+ text(color: string): this;
54
+ border(color?: string): this;
55
+ shadow(val?: "sm" | "md" | "lg" | "xl" | "2xl"): this;
56
+ opacity(val: string): this;
57
+ private _add;
58
+ }
59
+ /** Wrap an element for fluent chaining */
60
+ export declare const fluent: (el: OGXElement) => FluentBuilder;
61
+ /**
62
+ * High-level Primitives
63
+ */
64
+ /** Create a card container */
65
+ export declare const card: (tw?: TailwindUtility | TailwindUtility[], children?: OGXChildren) => OGXElement;
66
+ /** Create a badge/pill */
67
+ export declare const badge: (text: string, color?: "blue" | "green" | "purple" | "slate") => OGXElement;
68
+ /**
69
+ * External Asset Helpers
70
+ */
71
+ /** Helper to use a raw SVG string directly in img */
72
+ export declare function svgFromContent(svg: string): string;
73
+ /** Proxy/Alias for URLs */
74
+ export declare function imgFromUrl(url: string): string;
75
+ //# sourceMappingURL=builder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"builder.d.ts","sourceRoot":"","sources":["../src/builder.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,243 @@
1
+ /**
2
+ * Universal element factory (h/createElement style)
3
+ */
4
+ export function h(type, props = {}, children) {
5
+ // Shorthand: h('div', 'bg-blue-500', 'Hello')
6
+ if (typeof props === "string" || Array.isArray(props)) {
7
+ return {
8
+ type,
9
+ props: {
10
+ tw: normalizeTW(props),
11
+ children,
12
+ },
13
+ };
14
+ }
15
+ return {
16
+ type,
17
+ props: {
18
+ ...props,
19
+ children: children ?? props.children,
20
+ },
21
+ };
22
+ }
23
+ /** Internal helper to normalize tailwind utilities into a flat array of single classes */
24
+ function normalizeTW(tw) {
25
+ if (!tw)
26
+ return [];
27
+ if (Array.isArray(tw)) {
28
+ // Even if it is an array, some elements might be strings with spaces
29
+ return tw.flatMap((item) => typeof item === "string" ? item.split(/\s+/).filter(Boolean) : [item]);
30
+ }
31
+ return tw.split(/\s+/).filter(Boolean);
32
+ }
33
+ /** Create a div element */
34
+ export const div = (tw, children, props) => h("div", {
35
+ tw: ["flex", ...normalizeTW(tw)],
36
+ children,
37
+ ...props,
38
+ });
39
+ /** Create a span element */
40
+ export const span = (tw, children, props) => h("span", { tw: normalizeTW(tw), children, ...props });
41
+ /** Create an img element */
42
+ export const img = (src, tw, props) => h("img", { src, tw: normalizeTW(tw), ...props });
43
+ /** Create a vertical stack (flex-col) */
44
+ export const stack = (tw, children, props) => h("div", {
45
+ tw: ["flex", "flex-col", ...normalizeTW(tw)],
46
+ children,
47
+ ...props,
48
+ });
49
+ /** Create a horizontal row (flex-row) */
50
+ export const row = (tw, children, props) => h("div", {
51
+ tw: ["flex", "flex-row", ...normalizeTW(tw)],
52
+ children,
53
+ ...props,
54
+ });
55
+ /** Create an absolute positioned overlay */
56
+ export const absolute = (tw, children, props) => h("div", {
57
+ tw: ["absolute", "inset-0", "flex", ...normalizeTW(tw)],
58
+ children,
59
+ ...props,
60
+ });
61
+ /** Create a grid-like layout (flex-row with wrap) */
62
+ export const grid = (tw, children, props) => h("div", {
63
+ tw: ["flex", "flex-row", "flex-wrap", ...normalizeTW(tw)],
64
+ children,
65
+ ...props,
66
+ });
67
+ /** Create a semantic header */
68
+ export const header = (tw, children, props) => h("div", {
69
+ tw: ["flex", ...normalizeTW(tw)],
70
+ children,
71
+ ...props,
72
+ });
73
+ /** Create a semantic footer */
74
+ export const footer = (tw, children, props) => h("div", {
75
+ tw: ["flex", ...normalizeTW(tw)],
76
+ children,
77
+ ...props,
78
+ });
79
+ /** Create a semantic main content area */
80
+ export const main = (tw, children, props) => h("div", {
81
+ tw: ["flex", ...normalizeTW(tw)],
82
+ children,
83
+ ...props,
84
+ });
85
+ /** Create a spacer (flex-1 or custom size) */
86
+ export const spacer = (size, tw) => {
87
+ const style = {};
88
+ if (typeof size === "number") {
89
+ style.flex = `0 0 ${size}px`;
90
+ }
91
+ else if (size) {
92
+ // If it's a tailwind spacing string, it will be handled by the parser in tw
93
+ }
94
+ else {
95
+ style.flex = 1;
96
+ }
97
+ return h("div", {
98
+ tw: [
99
+ size && typeof size === "string" ? `w-${size}` : "flex-1",
100
+ ...normalizeTW(tw),
101
+ ],
102
+ style,
103
+ });
104
+ };
105
+ /**
106
+ * Semantic Typography
107
+ */
108
+ export const h1 = (tw, children) => h("div", {
109
+ tw: ["flex", "text-6xl", "font-bold", ...normalizeTW(tw)],
110
+ children,
111
+ });
112
+ export const h2 = (tw, children) => h("div", {
113
+ tw: ["flex", "text-4xl", "font-semibold", ...normalizeTW(tw)],
114
+ children,
115
+ });
116
+ export const p = (tw, children) => h("div", {
117
+ tw: ["flex", "text-lg", "text-slate-400", ...normalizeTW(tw)],
118
+ children,
119
+ });
120
+ /**
121
+ * Fluent Builder API (Chainable)
122
+ */
123
+ export class FluentBuilder {
124
+ _element;
125
+ constructor(element) {
126
+ this._element = element;
127
+ }
128
+ get element() {
129
+ return this._element;
130
+ }
131
+ // Layout
132
+ gap(val) {
133
+ this._add(`gap-${val}`);
134
+ return this;
135
+ }
136
+ padding(val) {
137
+ this._add(`p-${val}`);
138
+ return this;
139
+ }
140
+ px(val) {
141
+ this._add(`px-${val}`);
142
+ return this;
143
+ }
144
+ py(val) {
145
+ this._add(`py-${val}`);
146
+ return this;
147
+ }
148
+ margin(val) {
149
+ this._add(`m-${val}`);
150
+ return this;
151
+ }
152
+ mt(val) {
153
+ this._add(`mt-${val}`);
154
+ return this;
155
+ }
156
+ rounded(val = "md") {
157
+ this._add(`rounded-${val}`);
158
+ return this;
159
+ }
160
+ // Flex
161
+ center() {
162
+ this._add("items-center justify-center");
163
+ return this;
164
+ }
165
+ itemsCenter() {
166
+ this._add("items-center");
167
+ return this;
168
+ }
169
+ justifyCenter() {
170
+ this._add("justify-center");
171
+ return this;
172
+ }
173
+ justifyBetween() {
174
+ this._add("justify-between");
175
+ return this;
176
+ }
177
+ // Style
178
+ bg(color) {
179
+ this._add(`bg-${color}`);
180
+ return this;
181
+ }
182
+ text(color) {
183
+ this._add(`text-${color}`);
184
+ return this;
185
+ }
186
+ border(color) {
187
+ this._add("border");
188
+ if (color)
189
+ this._add(`border-${color}`);
190
+ return this;
191
+ }
192
+ shadow(val = "md") {
193
+ this._add(`shadow-${val}`);
194
+ return this;
195
+ }
196
+ opacity(val) {
197
+ this._add(`opacity-${val}`);
198
+ return this;
199
+ }
200
+ _add(tw) {
201
+ const current = this._element.props.tw || [];
202
+ const next = Array.isArray(current) ? [...current] : [current];
203
+ next.push(...tw.split(/\s+/));
204
+ this._element.props.tw = next;
205
+ }
206
+ }
207
+ /** Wrap an element for fluent chaining */
208
+ export const fluent = (el) => new FluentBuilder(el);
209
+ /**
210
+ * High-level Primitives
211
+ */
212
+ /** Create a card container */
213
+ export const card = (tw, children) => stack([
214
+ "bg-white",
215
+ "shadow-lg",
216
+ "rounded-2xl",
217
+ "p-8",
218
+ "border",
219
+ "border-slate-100",
220
+ ...normalizeTW(tw),
221
+ ], children);
222
+ /** Create a badge/pill */
223
+ export const badge = (text, color = "blue") => {
224
+ const variants = {
225
+ blue: "bg-blue-500/10 text-blue-500 border-blue-500/20",
226
+ green: "bg-green-500/10 text-green-500 border-green-500/20",
227
+ purple: "bg-purple-500/10 text-purple-500 border-purple-500/20",
228
+ slate: "bg-slate-500/10 text-slate-500 border-slate-500/20",
229
+ };
230
+ const [bg, tx, border] = variants[color].split(" ");
231
+ return div([bg, border, "px-3", "py-1", "rounded-full", "border"], [span([tx, "text-sm", "font-bold"], text)]);
232
+ };
233
+ /**
234
+ * External Asset Helpers
235
+ */
236
+ /** Helper to use a raw SVG string directly in img */
237
+ export function svgFromContent(svg) {
238
+ return `data:image/svg+xml;base64,${Buffer.from(svg).toString("base64")}`;
239
+ }
240
+ /** Proxy/Alias for URLs */
241
+ export function imgFromUrl(url) {
242
+ return url;
243
+ }
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Simple in-memory cache for generated images
3
+ */
4
+ export declare class SnapshotCache {
5
+ private static instance;
6
+ private cache;
7
+ private ttl;
8
+ private constructor();
9
+ static getInstance(): SnapshotCache;
10
+ /**
11
+ * Set cache TTL
12
+ */
13
+ setTTL(milliseconds: number): void;
14
+ /**
15
+ * Calculate a hash for a configuration object
16
+ */
17
+ getHash(config: any): string;
18
+ /**
19
+ * Get an item from cache
20
+ */
21
+ get(hash: string): any | null;
22
+ /**
23
+ * Store an item in cache
24
+ */
25
+ set(hash: string, data: any): void;
26
+ /**
27
+ * Clear the cache
28
+ */
29
+ clear(): void;
30
+ }
31
+ export declare const snapshotCache: SnapshotCache;
32
+ //# sourceMappingURL=cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAgB;IACvC,OAAO,CAAC,KAAK,CAAuD;IACpE,OAAO,CAAC,GAAG,CAAa;IAExB,OAAO;IAEP,MAAM,CAAC,WAAW,IAAI,aAAa;IAOnC;;OAEG;IACH,MAAM,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI;IAIlC;;OAEG;IACH,OAAO,CAAC,MAAM,EAAE,GAAG,GAAG,MAAM;IAkB5B;;OAEG;IACH,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,GAAG,GAAG,IAAI;IAY7B;;OAEG;IACH,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,GAAG,IAAI;IAOlC;;OAEG;IACH,KAAK,IAAI,IAAI;CAGd;AAED,eAAO,MAAM,aAAa,eAA8B,CAAC"}
package/dist/cache.js ADDED
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Simple in-memory cache for generated images
3
+ */
4
+ export class SnapshotCache {
5
+ static instance;
6
+ cache = new Map();
7
+ ttl = 0; // Cache TTL in milliseconds, 0 means no expiration
8
+ constructor() { }
9
+ static getInstance() {
10
+ if (!SnapshotCache.instance) {
11
+ SnapshotCache.instance = new SnapshotCache();
12
+ }
13
+ return SnapshotCache.instance;
14
+ }
15
+ /**
16
+ * Set cache TTL
17
+ */
18
+ setTTL(milliseconds) {
19
+ this.ttl = milliseconds;
20
+ }
21
+ /**
22
+ * Calculate a hash for a configuration object
23
+ */
24
+ getHash(config) {
25
+ // Stringify config
26
+ const str = JSON.stringify(config, (key, value) => {
27
+ if (typeof value === "function")
28
+ return undefined;
29
+ if (key === "debug")
30
+ return undefined;
31
+ return value;
32
+ });
33
+ // Basic hash for browser/fallback
34
+ let hash = 0;
35
+ for (let i = 0; i < str.length; i++) {
36
+ const char = str.charCodeAt(i);
37
+ hash = (hash << 5) - hash + char;
38
+ hash |= 0; // Convert to 32bit integer
39
+ }
40
+ return `hash-${hash}`;
41
+ }
42
+ /**
43
+ * Get an item from cache
44
+ */
45
+ get(hash) {
46
+ const item = this.cache.get(hash);
47
+ if (!item)
48
+ return null;
49
+ if (this.ttl > 0 && Date.now() - item.timestamp > this.ttl) {
50
+ this.cache.delete(hash);
51
+ return null;
52
+ }
53
+ return item.data;
54
+ }
55
+ /**
56
+ * Store an item in cache
57
+ */
58
+ set(hash, data) {
59
+ this.cache.set(hash, {
60
+ data,
61
+ timestamp: Date.now(),
62
+ });
63
+ }
64
+ /**
65
+ * Clear the cache
66
+ */
67
+ clear() {
68
+ this.cache.clear();
69
+ }
70
+ }
71
+ export const snapshotCache = SnapshotCache.getInstance();
package/dist/css.d.ts ADDED
@@ -0,0 +1,83 @@
1
+ /**
2
+ * CSS properties supported by Satori
3
+ * This is a subset of React.CSSProperties optimized for OG image generation
4
+ */
5
+ export interface CSSProperties {
6
+ display?: "flex" | "none";
7
+ position?: "relative" | "absolute";
8
+ flexDirection?: "row" | "row-reverse" | "column" | "column-reverse";
9
+ flexWrap?: "nowrap" | "wrap" | "wrap-reverse";
10
+ flexGrow?: number;
11
+ flexShrink?: number;
12
+ flexBasis?: number | string;
13
+ alignItems?: "flex-start" | "flex-end" | "center" | "baseline" | "stretch";
14
+ alignContent?: "flex-start" | "flex-end" | "center" | "space-between" | "space-around" | "stretch";
15
+ alignSelf?: "auto" | "flex-start" | "flex-end" | "center" | "baseline" | "stretch";
16
+ justifyContent?: "flex-start" | "flex-end" | "center" | "space-between" | "space-around" | "space-evenly";
17
+ gap?: number | string;
18
+ columnGap?: number | string;
19
+ rowGap?: number | string;
20
+ width?: number | string;
21
+ height?: number | string;
22
+ minWidth?: number | string;
23
+ minHeight?: number | string;
24
+ maxWidth?: number | string;
25
+ maxHeight?: number | string;
26
+ margin?: number | string;
27
+ marginTop?: number | string;
28
+ marginRight?: number | string;
29
+ marginBottom?: number | string;
30
+ marginLeft?: number | string;
31
+ padding?: number | string;
32
+ paddingTop?: number | string;
33
+ paddingRight?: number | string;
34
+ paddingBottom?: number | string;
35
+ paddingLeft?: number | string;
36
+ top?: number | string;
37
+ right?: number | string;
38
+ bottom?: number | string;
39
+ left?: number | string;
40
+ border?: string;
41
+ borderWidth?: number | string;
42
+ borderStyle?: "solid" | "dashed";
43
+ borderColor?: string;
44
+ borderTop?: string;
45
+ borderRight?: string;
46
+ borderBottom?: string;
47
+ borderLeft?: string;
48
+ borderRadius?: number | string;
49
+ borderTopLeftRadius?: number | string;
50
+ borderTopRightRadius?: number | string;
51
+ borderBottomLeftRadius?: number | string;
52
+ borderBottomRightRadius?: number | string;
53
+ backgroundColor?: string;
54
+ backgroundImage?: string;
55
+ backgroundPosition?: string;
56
+ backgroundSize?: string;
57
+ backgroundClip?: "border-box" | "text";
58
+ backgroundRepeat?: "repeat" | "repeat-x" | "repeat-y" | "no-repeat";
59
+ color?: string;
60
+ fontFamily?: string;
61
+ fontSize?: number | string;
62
+ fontWeight?: number | string;
63
+ fontStyle?: "normal" | "italic";
64
+ lineHeight?: number | string;
65
+ letterSpacing?: number | string;
66
+ textAlign?: "left" | "right" | "center" | "justify";
67
+ textTransform?: "none" | "uppercase" | "lowercase" | "capitalize";
68
+ textDecoration?: string;
69
+ textOverflow?: "clip" | "ellipsis";
70
+ textShadow?: string;
71
+ whiteSpace?: "normal" | "pre" | "pre-wrap" | "pre-line" | "nowrap";
72
+ wordBreak?: "normal" | "break-all" | "break-word" | "keep-all";
73
+ opacity?: number;
74
+ overflow?: "visible" | "hidden";
75
+ boxShadow?: string;
76
+ transform?: string;
77
+ transformOrigin?: string;
78
+ objectFit?: "contain" | "cover" | "none";
79
+ objectPosition?: string;
80
+ filter?: string;
81
+ clipPath?: string;
82
+ }
83
+ //# sourceMappingURL=css.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"css.d.ts","sourceRoot":"","sources":["../src/css.ts"],"names":[],"mappings":"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"}
package/dist/css.js ADDED
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,34 @@
1
+ import type { FontConfig } from "./types";
2
+ /**
3
+ * Global registry for fonts to avoid reloading and simplify configuration
4
+ */
5
+ export declare class FontRegistry {
6
+ private static instance;
7
+ private fonts;
8
+ private constructor();
9
+ static getInstance(): FontRegistry;
10
+ /**
11
+ * Register one or more fonts to be available globally
12
+ */
13
+ register(font: FontConfig | FontConfig[]): void;
14
+ /**
15
+ * Helper to register Inter fonts with specified weights (local files)
16
+ * Only works in Bun/Node without bundlers
17
+ */
18
+ registerInter(weights?: (300 | 400 | 500 | 600 | 700)[]): Promise<void>;
19
+ /**
20
+ * Helper to register Inter fonts from Google Fonts CDN
21
+ * Works with all bundlers (Next.js, Vite, etc.)
22
+ */
23
+ registerInterFromUrl(weights?: (300 | 400 | 500 | 600 | 700)[]): Promise<void>;
24
+ /**
25
+ * Get all registered fonts
26
+ */
27
+ getFonts(): FontConfig[];
28
+ /**
29
+ * Clear the registry
30
+ */
31
+ clear(): void;
32
+ }
33
+ export declare const fontRegistry: FontRegistry;
34
+ //# sourceMappingURL=font-registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"font-registry.d.ts","sourceRoot":"","sources":["../src/font-registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAE1C;;GAEG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAe;IACtC,OAAO,CAAC,KAAK,CAAoB;IAEjC,OAAO;IAEP,MAAM,CAAC,WAAW,IAAI,YAAY;IAOlC;;OAEG;IACH,QAAQ,CAAC,IAAI,EAAE,UAAU,GAAG,UAAU,EAAE,GAAG,IAAI;IAgB/C;;;OAGG;IACG,aAAa,CACjB,OAAO,GAAE,CAAC,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC,EAAe,GACpD,OAAO,CAAC,IAAI,CAAC;IAMhB;;;OAGG;IACG,oBAAoB,CACxB,OAAO,GAAE,CAAC,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC,EAAe,GACpD,OAAO,CAAC,IAAI,CAAC;IAMhB;;OAEG;IACH,QAAQ,IAAI,UAAU,EAAE;IAIxB;;OAEG;IACH,KAAK,IAAI,IAAI;CAGd;AAED,eAAO,MAAM,YAAY,cAA6B,CAAC"}