@ewanc26/og 0.1.4 → 0.1.5

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/index.cjs CHANGED
@@ -48,33 +48,82 @@ __export(index_exports, {
48
48
  });
49
49
  module.exports = __toCommonJS(index_exports);
50
50
 
51
+ // ../../node_modules/.pnpm/tsup@8.5.1_jiti@2.6.1_postcss@8.5.8_typescript@5.9.3/node_modules/tsup/assets/cjs_shims.js
52
+ var getImportMetaUrl = () => typeof document === "undefined" ? new URL(`file:${__filename}`).href : document.currentScript && document.currentScript.tagName.toUpperCase() === "SCRIPT" ? document.currentScript.src : new URL("main.js", document.baseURI).href;
53
+ var importMetaUrl = /* @__PURE__ */ getImportMetaUrl();
54
+
51
55
  // src/generate.ts
52
56
  var import_satori = __toESM(require("satori"), 1);
53
57
  var import_resvg_js = require("@resvg/resvg-js");
54
58
 
55
59
  // src/fonts.ts
56
- var import_promises = require("fs/promises");
60
+ var import_promises2 = require("fs/promises");
57
61
  var import_node_fs = require("fs");
62
+ var import_node_path2 = require("path");
63
+ var import_node_url2 = require("url");
64
+
65
+ // src/fonts-data.ts
66
+ var import_promises = require("fs/promises");
58
67
  var import_node_path = require("path");
59
68
  var import_node_url = require("url");
60
69
  var import_meta = {};
61
70
  function getModuleDir() {
62
- if (typeof import_meta !== "undefined" && import_meta.url) {
63
- return (0, import_node_path.dirname)((0, import_node_url.fileURLToPath)(import_meta.url));
71
+ if (typeof import_meta !== "undefined" && importMetaUrl) {
72
+ return (0, import_node_path.dirname)((0, import_node_url.fileURLToPath)(importMetaUrl));
64
73
  }
65
74
  if (typeof __dirname !== "undefined") {
66
75
  return __dirname;
67
76
  }
68
77
  return (0, import_node_path.resolve)(process.cwd(), "node_modules/@ewanc26/og/dist");
69
78
  }
79
+ async function loadEmbeddedFonts() {
80
+ const moduleDir = getModuleDir();
81
+ const paths = [
82
+ {
83
+ heading: (0, import_node_path.resolve)(moduleDir, "fonts/Inter-Bold.ttf"),
84
+ body: (0, import_node_path.resolve)(moduleDir, "fonts/Inter-Regular.ttf")
85
+ },
86
+ {
87
+ heading: (0, import_node_path.resolve)(moduleDir, "../fonts/Inter-Bold.ttf"),
88
+ body: (0, import_node_path.resolve)(moduleDir, "../fonts/Inter-Regular.ttf")
89
+ }
90
+ ];
91
+ for (const p of paths) {
92
+ try {
93
+ const [headingBuf, bodyBuf] = await Promise.all([
94
+ (0, import_promises.readFile)(p.heading),
95
+ (0, import_promises.readFile)(p.body)
96
+ ]);
97
+ return {
98
+ heading: headingBuf.buffer.slice(headingBuf.byteOffset, headingBuf.byteOffset + headingBuf.byteLength),
99
+ body: bodyBuf.buffer.slice(bodyBuf.byteOffset, bodyBuf.byteOffset + bodyBuf.byteLength)
100
+ };
101
+ } catch {
102
+ continue;
103
+ }
104
+ }
105
+ return null;
106
+ }
107
+
108
+ // src/fonts.ts
109
+ var import_meta2 = {};
110
+ function getModuleDir2() {
111
+ if (typeof import_meta2 !== "undefined" && importMetaUrl) {
112
+ return (0, import_node_path2.dirname)((0, import_node_url2.fileURLToPath)(importMetaUrl));
113
+ }
114
+ if (typeof __dirname !== "undefined") {
115
+ return __dirname;
116
+ }
117
+ return (0, import_node_path2.resolve)(process.cwd(), "node_modules/@ewanc26/og/dist");
118
+ }
70
119
  function getFontsDir() {
71
120
  const candidates = [
72
121
  // Standard: fonts next to dist
73
- (0, import_node_path.resolve)(getModuleDir(), "../fonts"),
122
+ (0, import_node_path2.resolve)(getModuleDir2(), "../fonts"),
74
123
  // Vercel serverless: fonts inside dist
75
- (0, import_node_path.resolve)(getModuleDir(), "fonts"),
124
+ (0, import_node_path2.resolve)(getModuleDir2(), "fonts"),
76
125
  // Fallback: node_modules path
77
- (0, import_node_path.resolve)(process.cwd(), "node_modules/@ewanc26/og/fonts")
126
+ (0, import_node_path2.resolve)(process.cwd(), "node_modules/@ewanc26/og/fonts")
78
127
  ];
79
128
  for (const dir of candidates) {
80
129
  if ((0, import_node_fs.existsSync)(dir)) {
@@ -85,12 +134,15 @@ function getFontsDir() {
85
134
  }
86
135
  var BUNDLED_FONTS = {
87
136
  get heading() {
88
- return (0, import_node_path.resolve)(getFontsDir(), "Inter-Bold.ttf");
137
+ return (0, import_node_path2.resolve)(getFontsDir(), "Inter-Bold.ttf");
89
138
  },
90
139
  get body() {
91
- return (0, import_node_path.resolve)(getFontsDir(), "Inter-Regular.ttf");
140
+ return (0, import_node_path2.resolve)(getFontsDir(), "Inter-Regular.ttf");
92
141
  }
93
142
  };
143
+ function toArrayBuffer(buf) {
144
+ return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength);
145
+ }
94
146
  async function loadFonts(config) {
95
147
  const headingPath = config?.heading ?? BUNDLED_FONTS.heading;
96
148
  const bodyPath = config?.body ?? BUNDLED_FONTS.body;
@@ -102,20 +154,14 @@ async function loadFonts(config) {
102
154
  }
103
155
  async function loadFontFile(source) {
104
156
  try {
105
- const buffer = await (0, import_promises.readFile)(source);
106
- return buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength);
157
+ const buffer = await (0, import_promises2.readFile)(source);
158
+ return toArrayBuffer(buffer);
107
159
  } catch (error) {
108
- const filename = source.split("/").pop();
109
- const cdnUrl = `https://raw.githubusercontent.com/rsms/inter/master/docs/font-files/${filename}`;
110
- try {
111
- const response = await fetch(cdnUrl);
112
- if (!response.ok) {
113
- throw new Error(`CDN fetch failed: ${response.status}`);
114
- }
115
- return response.arrayBuffer();
116
- } catch (cdnError) {
117
- throw new Error(`Failed to load font ${filename} from both local path and CDN: ${cdnError}`);
160
+ const embedded = await loadEmbeddedFonts();
161
+ if (embedded) {
162
+ return source.includes("Bold") ? embedded.heading : embedded.body;
118
163
  }
164
+ throw new Error(`Failed to load font from ${source}`);
119
165
  }
120
166
  }
121
167
  function createSatoriFonts(fonts) {
@@ -261,6 +307,7 @@ function blogTemplate({
261
307
  description,
262
308
  siteName,
263
309
  colors,
310
+ noiseDataUrl,
264
311
  width,
265
312
  height
266
313
  }) {
@@ -268,6 +315,7 @@ function blogTemplate({
268
315
  type: "div",
269
316
  props: {
270
317
  style: {
318
+ position: "relative",
271
319
  display: "flex",
272
320
  flexDirection: "column",
273
321
  alignItems: "center",
@@ -277,51 +325,83 @@ function blogTemplate({
277
325
  backgroundColor: colors.background
278
326
  },
279
327
  children: [
280
- {
281
- type: "h1",
328
+ noiseDataUrl ? {
329
+ type: "img",
282
330
  props: {
331
+ src: noiseDataUrl,
332
+ width,
333
+ height,
283
334
  style: {
284
- fontSize: 64,
285
- fontWeight: 700,
286
- color: colors.text,
287
- letterSpacing: "-0.02em",
288
- margin: 0,
289
- textAlign: "center",
290
- lineHeight: 1.1,
291
- maxWidth: 1e3
292
- },
293
- children: title
294
- }
295
- },
296
- description ? {
297
- type: "p",
298
- props: {
299
- style: {
300
- fontSize: 28,
301
- fontWeight: 400,
302
- color: colors.accent,
303
- marginTop: 28,
304
- marginBottom: 0,
305
- textAlign: "center",
306
- lineHeight: 1.4,
307
- maxWidth: 900
308
- },
309
- children: description
335
+ position: "absolute",
336
+ top: 0,
337
+ left: 0,
338
+ width,
339
+ height
340
+ }
310
341
  }
311
342
  } : null,
312
343
  {
313
- type: "p",
344
+ type: "div",
314
345
  props: {
315
346
  style: {
316
- fontSize: 24,
317
- fontWeight: 400,
318
- color: colors.accent,
319
- marginTop: 56,
320
- marginBottom: 0,
321
- textAlign: "center",
322
- opacity: 0.7
347
+ position: "relative",
348
+ display: "flex",
349
+ flexDirection: "column",
350
+ alignItems: "center",
351
+ justifyContent: "center",
352
+ width,
353
+ height,
354
+ padding: "0 60px"
323
355
  },
324
- children: siteName
356
+ children: [
357
+ {
358
+ type: "h1",
359
+ props: {
360
+ style: {
361
+ fontSize: 64,
362
+ fontWeight: 700,
363
+ color: colors.text,
364
+ letterSpacing: "-0.02em",
365
+ margin: 0,
366
+ textAlign: "center",
367
+ lineHeight: 1.1,
368
+ maxWidth: 1e3
369
+ },
370
+ children: title
371
+ }
372
+ },
373
+ description ? {
374
+ type: "p",
375
+ props: {
376
+ style: {
377
+ fontSize: 28,
378
+ fontWeight: 400,
379
+ color: colors.accent,
380
+ marginTop: 28,
381
+ marginBottom: 0,
382
+ textAlign: "center",
383
+ lineHeight: 1.4,
384
+ maxWidth: 900
385
+ },
386
+ children: description
387
+ }
388
+ } : null,
389
+ {
390
+ type: "p",
391
+ props: {
392
+ style: {
393
+ fontSize: 24,
394
+ fontWeight: 400,
395
+ color: colors.accent,
396
+ marginTop: 56,
397
+ marginBottom: 0,
398
+ textAlign: "center",
399
+ opacity: 0.7
400
+ },
401
+ children: siteName
402
+ }
403
+ }
404
+ ].filter(Boolean)
325
405
  }
326
406
  }
327
407
  ].filter(Boolean)
@@ -336,12 +416,13 @@ function profileTemplate({
336
416
  siteName,
337
417
  image,
338
418
  colors,
419
+ noiseDataUrl,
339
420
  width,
340
421
  height
341
422
  }) {
342
- const children = [];
423
+ const contentChildren = [];
343
424
  if (image) {
344
- children.push({
425
+ contentChildren.push({
345
426
  type: "img",
346
427
  props: {
347
428
  src: image,
@@ -355,7 +436,7 @@ function profileTemplate({
355
436
  }
356
437
  });
357
438
  }
358
- children.push({
439
+ contentChildren.push({
359
440
  type: "h1",
360
441
  props: {
361
442
  style: {
@@ -372,7 +453,7 @@ function profileTemplate({
372
453
  }
373
454
  });
374
455
  if (description) {
375
- children.push({
456
+ contentChildren.push({
376
457
  type: "p",
377
458
  props: {
378
459
  style: {
@@ -389,7 +470,7 @@ function profileTemplate({
389
470
  }
390
471
  });
391
472
  }
392
- children.push({
473
+ contentChildren.push({
393
474
  type: "p",
394
475
  props: {
395
476
  style: {
@@ -408,6 +489,7 @@ function profileTemplate({
408
489
  type: "div",
409
490
  props: {
410
491
  style: {
492
+ position: "relative",
411
493
  display: "flex",
412
494
  flexDirection: "column",
413
495
  alignItems: "center",
@@ -416,7 +498,39 @@ function profileTemplate({
416
498
  height,
417
499
  backgroundColor: colors.background
418
500
  },
419
- children
501
+ children: [
502
+ noiseDataUrl ? {
503
+ type: "img",
504
+ props: {
505
+ src: noiseDataUrl,
506
+ width,
507
+ height,
508
+ style: {
509
+ position: "absolute",
510
+ top: 0,
511
+ left: 0,
512
+ width,
513
+ height
514
+ }
515
+ }
516
+ } : null,
517
+ {
518
+ type: "div",
519
+ props: {
520
+ style: {
521
+ position: "relative",
522
+ display: "flex",
523
+ flexDirection: "column",
524
+ alignItems: "center",
525
+ justifyContent: "center",
526
+ width,
527
+ height,
528
+ padding: "0 60px"
529
+ },
530
+ children: contentChildren
531
+ }
532
+ }
533
+ ].filter(Boolean)
420
534
  }
421
535
  };
422
536
  }
@@ -427,6 +541,7 @@ function defaultTemplate({
427
541
  description,
428
542
  siteName,
429
543
  colors,
544
+ noiseDataUrl,
430
545
  width,
431
546
  height
432
547
  }) {
@@ -434,6 +549,7 @@ function defaultTemplate({
434
549
  type: "div",
435
550
  props: {
436
551
  style: {
552
+ position: "relative",
437
553
  display: "flex",
438
554
  flexDirection: "column",
439
555
  alignItems: "center",
@@ -443,48 +559,80 @@ function defaultTemplate({
443
559
  backgroundColor: colors.background
444
560
  },
445
561
  children: [
446
- {
447
- type: "h1",
562
+ noiseDataUrl ? {
563
+ type: "img",
448
564
  props: {
565
+ src: noiseDataUrl,
566
+ width,
567
+ height,
449
568
  style: {
450
- fontSize: 72,
451
- fontWeight: 700,
452
- color: colors.text,
453
- letterSpacing: "-0.02em",
454
- margin: 0,
455
- textAlign: "center"
456
- },
457
- children: title
458
- }
459
- },
460
- description ? {
461
- type: "p",
462
- props: {
463
- style: {
464
- fontSize: 32,
465
- fontWeight: 400,
466
- color: colors.accent,
467
- marginTop: 24,
468
- marginBottom: 0,
469
- textAlign: "center",
470
- maxWidth: 900
471
- },
472
- children: description
569
+ position: "absolute",
570
+ top: 0,
571
+ left: 0,
572
+ width,
573
+ height
574
+ }
473
575
  }
474
576
  } : null,
475
577
  {
476
- type: "p",
578
+ type: "div",
477
579
  props: {
478
580
  style: {
479
- fontSize: 28,
480
- fontWeight: 400,
481
- color: colors.accent,
482
- marginTop: 64,
483
- marginBottom: 0,
484
- textAlign: "center",
485
- opacity: 0.7
581
+ position: "relative",
582
+ display: "flex",
583
+ flexDirection: "column",
584
+ alignItems: "center",
585
+ justifyContent: "center",
586
+ width,
587
+ height,
588
+ padding: "0 60px"
486
589
  },
487
- children: siteName
590
+ children: [
591
+ {
592
+ type: "h1",
593
+ props: {
594
+ style: {
595
+ fontSize: 72,
596
+ fontWeight: 700,
597
+ color: colors.text,
598
+ letterSpacing: "-0.02em",
599
+ margin: 0,
600
+ textAlign: "center"
601
+ },
602
+ children: title
603
+ }
604
+ },
605
+ description ? {
606
+ type: "p",
607
+ props: {
608
+ style: {
609
+ fontSize: 32,
610
+ fontWeight: 400,
611
+ color: colors.accent,
612
+ marginTop: 24,
613
+ marginBottom: 0,
614
+ textAlign: "center",
615
+ maxWidth: 900
616
+ },
617
+ children: description
618
+ }
619
+ } : null,
620
+ {
621
+ type: "p",
622
+ props: {
623
+ style: {
624
+ fontSize: 28,
625
+ fontWeight: 400,
626
+ color: colors.accent,
627
+ marginTop: 64,
628
+ marginBottom: 0,
629
+ textAlign: "center",
630
+ opacity: 0.7
631
+ },
632
+ children: siteName
633
+ }
634
+ }
635
+ ].filter(Boolean)
488
636
  }
489
637
  }
490
638
  ].filter(Boolean)
@@ -612,6 +760,8 @@ function createOgEndpoint(options) {
612
760
  const description = url.searchParams.get("description") ?? void 0;
613
761
  const image = url.searchParams.get("image") ?? void 0;
614
762
  const noiseSeed = url.searchParams.get("seed") ?? void 0;
763
+ const templateParam = url.searchParams.get("template");
764
+ const resolvedTemplate = templateParam ?? template;
615
765
  if (!title) {
616
766
  return new Response("Missing title parameter", { status: 400 });
617
767
  }
@@ -622,7 +772,7 @@ function createOgEndpoint(options) {
622
772
  description,
623
773
  siteName,
624
774
  image,
625
- template,
775
+ template: resolvedTemplate,
626
776
  colors,
627
777
  fonts,
628
778
  noise,