diff --git a/public/brand/devrodri-wordmark-w1-black.svg b/public/brand/devrodri-wordmark-w1-black.svg
new file mode 100644
index 0000000..2dae3d9
--- /dev/null
+++ b/public/brand/devrodri-wordmark-w1-black.svg
@@ -0,0 +1,5 @@
+
\ No newline at end of file
diff --git a/scripts/verify-http.mjs b/scripts/verify-http.mjs
index 31e54e3..fcfb4a6 100644
--- a/scripts/verify-http.mjs
+++ b/scripts/verify-http.mjs
@@ -1,4 +1,5 @@
import assert from "node:assert/strict";
+import { createHash } from "node:crypto";
import { once } from "node:events";
import { readdir, readFile } from "node:fs/promises";
import path from "node:path";
@@ -340,6 +341,23 @@ try {
assert.ok(!sitemap.includes("/gracias"));
assert.ok(!sitemap.includes("/en/thank-you"));
+ const brandLogoResponse = await request(
+ "/brand/devrodri-wordmark-w1-black.svg",
+ );
+ assert.equal(brandLogoResponse.status, 200, "brand logo");
+ assert.equal(
+ brandLogoResponse.headers.get("content-type"),
+ "image/svg+xml",
+ "brand logo content type",
+ );
+ const brandLogo = Buffer.from(await brandLogoResponse.arrayBuffer());
+ assert.equal(brandLogo.byteLength, 3968, "brand logo byte length");
+ assert.equal(
+ createHash("sha256").update(brandLogo).digest("hex"),
+ "3be5eaecfa9569652886dc812f4f34e6c9b1c5f4407ac6e476b16300fed9715f",
+ "brand logo SHA-256",
+ );
+
const homeHtml = await readFile(
path.join(projectRoot, "dist", "index.html"),
"utf8",
diff --git a/scripts/verify-prerender.mjs b/scripts/verify-prerender.mjs
index 0a03879..8980cd2 100644
--- a/scripts/verify-prerender.mjs
+++ b/scripts/verify-prerender.mjs
@@ -279,22 +279,38 @@ const expectedStructuredData = new Map([
[
"/",
{
- types: ["WebSite", "Person", "EducationalOccupationalCredential"],
+ types: [
+ "WebSite",
+ "Person",
+ "EducationalOccupationalCredential",
+ "Brand",
+ "ImageObject",
+ ],
ids: [
"https://www.devrodri.com/#website",
"https://www.devrodri.com/#person",
"https://www.devrodri.com/#ibm-full-stack-credential",
+ "https://www.devrodri.com/#brand",
+ "https://www.devrodri.com/#brand-logo",
],
},
],
[
"/en",
{
- types: ["WebSite", "Person", "EducationalOccupationalCredential"],
+ types: [
+ "WebSite",
+ "Person",
+ "EducationalOccupationalCredential",
+ "Brand",
+ "ImageObject",
+ ],
ids: [
"https://www.devrodri.com/#website",
"https://www.devrodri.com/#person",
"https://www.devrodri.com/#ibm-full-stack-credential",
+ "https://www.devrodri.com/#brand",
+ "https://www.devrodri.com/#brand-logo",
],
},
],
@@ -877,6 +893,52 @@ for (const route of expectedRoutes) {
personContent.jobTitle,
`${route.pathname}: Person jobTitle`,
);
+ assert.deepEqual(person.sameAs, [
+ "https://github.com/devrodri-com",
+ "https://www.linkedin.com/in/rodrigo-opalo-b56685390/",
+ ]);
+ assert.deepEqual(person.brand, {
+ "@id": "https://www.devrodri.com/#brand",
+ });
+
+ const website = parsed["@graph"].find(
+ (node) => node["@type"] === "WebSite",
+ );
+ assert.deepEqual(website.creator, {
+ "@id": "https://www.devrodri.com/#person",
+ });
+ assert.deepEqual(website.publisher, {
+ "@id": "https://www.devrodri.com/#person",
+ });
+ assert.deepEqual(website.mainEntity, {
+ "@id": "https://www.devrodri.com/#person",
+ });
+ assert.deepEqual(website.about, {
+ "@id": "https://www.devrodri.com/#brand",
+ });
+
+ const brand = parsed["@graph"].find(
+ (node) => node["@type"] === "Brand",
+ );
+ assert.deepEqual(brand, {
+ "@type": "Brand",
+ "@id": "https://www.devrodri.com/#brand",
+ name: "devrodri",
+ url: "https://www.devrodri.com/",
+ owner: { "@id": "https://www.devrodri.com/#person" },
+ logo: { "@id": "https://www.devrodri.com/#brand-logo" },
+ });
+
+ const brandLogo = parsed["@graph"].find(
+ (node) => node["@type"] === "ImageObject",
+ );
+ assert.deepEqual(brandLogo, {
+ "@type": "ImageObject",
+ "@id": "https://www.devrodri.com/#brand-logo",
+ contentUrl:
+ "https://www.devrodri.com/brand/devrodri-wordmark-w1-black.svg",
+ encodingFormat: "image/svg+xml",
+ });
}
const hash = sha256Source(jsonLd);
liveInlineScriptHashes.add(hash);
@@ -896,6 +958,10 @@ for (const route of expectedRoutes) {
'"review"',
'"operatingSystem"',
"SoftwareApplication",
+ '"@type":"Organization"',
+ '"@type":"ProfessionalService"',
+ '"@type":"LocalBusiness"',
+ '"@type":"ProfilePage"',
]) {
assert.ok(!jsonLd.includes(forbidden), `${route.pathname}: ${forbidden}`);
}
@@ -914,6 +980,34 @@ for (const route of expectedRoutes) {
}
}
+const brandLogoBuffer = await readFile(
+ path.join(distDirectory, "brand", "devrodri-wordmark-w1-black.svg"),
+);
+assert.equal(brandLogoBuffer.byteLength, 3968, "brand logo byte length");
+assert.equal(
+ createHash("sha256").update(brandLogoBuffer).digest("hex"),
+ "3be5eaecfa9569652886dc812f4f34e6c9b1c5f4407ac6e476b16300fed9715f",
+ "brand logo SHA-256",
+);
+const brandLogoSource = brandLogoBuffer.toString("utf8");
+assert.equal(count(brandLogoSource, "