mcp-scraper 0.58.0 → 0.60.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/CHANGELOG.md +18 -0
- package/README.md +1 -1
- package/dist/bin/api-server.cjs +415 -100
- package/dist/bin/api-server.cjs.map +1 -1
- package/dist/bin/api-server.js +1 -1
- package/dist/bin/mcp-scraper-cli.cjs +1 -1
- package/dist/bin/mcp-scraper-cli.cjs.map +1 -1
- package/dist/bin/mcp-scraper-cli.js +1 -1
- package/dist/bin/mcp-scraper-install.cjs +1 -1
- package/dist/bin/mcp-scraper-install.cjs.map +1 -1
- package/dist/bin/mcp-scraper-install.js +1 -1
- package/dist/bin/mcp-stdio-server.cjs +7 -6
- package/dist/bin/mcp-stdio-server.cjs.map +1 -1
- package/dist/bin/mcp-stdio-server.js +2 -2
- package/dist/{chunk-P32KEY3D.js → chunk-AIA3MFT2.js} +8 -7
- package/dist/chunk-AIA3MFT2.js.map +1 -0
- package/dist/chunk-AQA2ZL4X.js +7 -0
- package/dist/chunk-AQA2ZL4X.js.map +1 -0
- package/dist/editorial-reading-room/assets/app.js +17 -3
- package/dist/{server-J4YGBOTS.js → server-IRKNU6LO.js} +395 -96
- package/dist/server-IRKNU6LO.js.map +1 -0
- package/package.json +1 -1
- package/dist/chunk-EJ6KU4PC.js +0 -7
- package/dist/chunk-EJ6KU4PC.js.map +0 -1
- package/dist/chunk-P32KEY3D.js.map +0 -1
- package/dist/server-J4YGBOTS.js.map +0 -1
|
@@ -170,7 +170,7 @@ import {
|
|
|
170
170
|
resolveDeploymentProfile,
|
|
171
171
|
resolveLocalSourcebookSchemaType,
|
|
172
172
|
transcribeMediaUrl
|
|
173
|
-
} from "./chunk-
|
|
173
|
+
} from "./chunk-AIA3MFT2.js";
|
|
174
174
|
import {
|
|
175
175
|
auditImageUrls,
|
|
176
176
|
auditImages,
|
|
@@ -226,7 +226,7 @@ import {
|
|
|
226
226
|
} from "./chunk-FG6LJGJ7.js";
|
|
227
227
|
import {
|
|
228
228
|
PACKAGE_VERSION
|
|
229
|
-
} from "./chunk-
|
|
229
|
+
} from "./chunk-AQA2ZL4X.js";
|
|
230
230
|
import {
|
|
231
231
|
abandonExtractSettlement,
|
|
232
232
|
countSuccessfulPages,
|
|
@@ -32752,9 +32752,7 @@ function socialMeta(input) {
|
|
|
32752
32752
|
];
|
|
32753
32753
|
return tags.join("\n ");
|
|
32754
32754
|
}
|
|
32755
|
-
function
|
|
32756
|
-
const sourceBytes = input.articles.reduce((total, article) => total + Buffer.byteLength(article.markdown), 0);
|
|
32757
|
-
if (sourceBytes > 2e6) throw new Error("Editorial reading-room Markdown must be 2,000,000 bytes or fewer in total.");
|
|
32755
|
+
function buildEditorialArticles(input) {
|
|
32758
32756
|
const seenSlugs = /* @__PURE__ */ new Set();
|
|
32759
32757
|
const seenOrders = /* @__PURE__ */ new Set();
|
|
32760
32758
|
const parser = markdownRenderer();
|
|
@@ -32781,7 +32779,19 @@ function renderEditorialReadingRoom(input, now = /* @__PURE__ */ new Date()) {
|
|
|
32781
32779
|
html: rendered
|
|
32782
32780
|
};
|
|
32783
32781
|
});
|
|
32782
|
+
return { articles, warnings, totalWordCount };
|
|
32783
|
+
}
|
|
32784
|
+
function renderEditorialArticleModels(input) {
|
|
32785
|
+
return buildEditorialArticles(input).articles;
|
|
32786
|
+
}
|
|
32787
|
+
function renderEditorialReadingRoom(input, now = /* @__PURE__ */ new Date()) {
|
|
32788
|
+
const sourceBytes = input.articles.reduce((total, article) => total + Buffer.byteLength(article.markdown), 0);
|
|
32789
|
+
if (sourceBytes > 2e6) throw new Error("Editorial reading-room Markdown must be 2,000,000 bytes or fewer in total.");
|
|
32784
32790
|
const generatedAt = now.toISOString();
|
|
32791
|
+
const built = buildEditorialArticles(input);
|
|
32792
|
+
const articles = built.articles;
|
|
32793
|
+
const warnings = built.warnings;
|
|
32794
|
+
const totalWordCount = built.totalWordCount;
|
|
32785
32795
|
const data = { ...input, generatedAt, articles };
|
|
32786
32796
|
const template = readAsset("index.html");
|
|
32787
32797
|
const html = template.replace("<title>Editorial Reading Room</title>", `<title>${escapeHtml5(input.site.title)}</title>`).replace('content="A mobile-first editorial reading room."', `content="${escapeHtml5(input.deck || input.site.heroTitle)}"`).replace("<!--__READING_ROOM_SOCIAL_META__-->", socialMeta(input)).replace("/*__READING_ROOM_STYLES__*/", readAsset("styles.css")).replace("/*__READING_ROOM_DATA__*/", escapedJsonForHtml(data)).replace("/*__READING_ROOM_SCRIPT__*/", readAsset("app.js"));
|
|
@@ -33230,6 +33240,134 @@ async function hostEntityImages(input) {
|
|
|
33230
33240
|
return rewrite;
|
|
33231
33241
|
}
|
|
33232
33242
|
|
|
33243
|
+
// src/api/commons-embeddings.ts
|
|
33244
|
+
import { neon } from "@neondatabase/serverless";
|
|
33245
|
+
var COMMONS_EMBED_PROVIDER = "jina";
|
|
33246
|
+
var _vectorSql = null;
|
|
33247
|
+
var vectorSchemaReady = false;
|
|
33248
|
+
function commonsEmbedModel() {
|
|
33249
|
+
return (process.env.JINA_EMBED_MODEL ?? "jina-embeddings-v5-omni-small").trim();
|
|
33250
|
+
}
|
|
33251
|
+
function commonsEmbedDim() {
|
|
33252
|
+
return Number((process.env.JINA_EMBED_DIM ?? "1024").trim());
|
|
33253
|
+
}
|
|
33254
|
+
function commonsSemanticSearchConfigured() {
|
|
33255
|
+
return Boolean(process.env.JINA_API_KEY?.trim() && process.env.MEMORY_DATABASE_URL?.trim());
|
|
33256
|
+
}
|
|
33257
|
+
function vectorSql() {
|
|
33258
|
+
if (_vectorSql) return _vectorSql;
|
|
33259
|
+
const url = process.env.MEMORY_DATABASE_URL?.trim();
|
|
33260
|
+
if (!url) throw new Error("MEMORY_DATABASE_URL is not set; Commons semantic search needs the shared Postgres.");
|
|
33261
|
+
_vectorSql = neon(url);
|
|
33262
|
+
return _vectorSql;
|
|
33263
|
+
}
|
|
33264
|
+
async function ensureCommonsVectorSchema() {
|
|
33265
|
+
if (vectorSchemaReady) return;
|
|
33266
|
+
const dimension = commonsEmbedDim();
|
|
33267
|
+
await vectorSql().query("CREATE EXTENSION IF NOT EXISTS vector");
|
|
33268
|
+
await vectorSql().query(`
|
|
33269
|
+
CREATE TABLE IF NOT EXISTS commons_index_vectors (
|
|
33270
|
+
document_id TEXT PRIMARY KEY,
|
|
33271
|
+
entity_id TEXT NOT NULL,
|
|
33272
|
+
document_type TEXT NOT NULL,
|
|
33273
|
+
title TEXT NOT NULL,
|
|
33274
|
+
embedding vector(${dimension}) NOT NULL,
|
|
33275
|
+
model TEXT NOT NULL,
|
|
33276
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
33277
|
+
)
|
|
33278
|
+
`);
|
|
33279
|
+
await vectorSql().query("CREATE INDEX IF NOT EXISTS commons_index_vectors_entity ON commons_index_vectors(entity_id)");
|
|
33280
|
+
vectorSchemaReady = true;
|
|
33281
|
+
}
|
|
33282
|
+
async function embedCommonsTexts(texts) {
|
|
33283
|
+
const apiKey = process.env.JINA_API_KEY?.trim();
|
|
33284
|
+
if (!apiKey) throw new Error("JINA_API_KEY is not set; Commons semantic search cannot embed.");
|
|
33285
|
+
if (!texts.length) return [];
|
|
33286
|
+
const response = await fetch("https://api.jina.ai/v1/embeddings", {
|
|
33287
|
+
method: "POST",
|
|
33288
|
+
headers: { authorization: `Bearer ${apiKey}`, "content-type": "application/json" },
|
|
33289
|
+
body: JSON.stringify({
|
|
33290
|
+
model: commonsEmbedModel(),
|
|
33291
|
+
dimensions: commonsEmbedDim(),
|
|
33292
|
+
input: texts.map((text2) => ({ text: text2.slice(0, 8e3) }))
|
|
33293
|
+
}),
|
|
33294
|
+
signal: AbortSignal.timeout(6e4)
|
|
33295
|
+
});
|
|
33296
|
+
if (!response.ok) {
|
|
33297
|
+
throw new Error(`Jina embedding request failed with HTTP ${response.status}: ${(await response.text()).slice(0, 200)}`);
|
|
33298
|
+
}
|
|
33299
|
+
const payload = await response.json();
|
|
33300
|
+
const vectors = (payload.data ?? []).map((item) => item.embedding);
|
|
33301
|
+
if (vectors.length !== texts.length) {
|
|
33302
|
+
throw new Error(`Jina returned ${vectors.length} embeddings for ${texts.length} inputs.`);
|
|
33303
|
+
}
|
|
33304
|
+
return vectors;
|
|
33305
|
+
}
|
|
33306
|
+
async function embedQueuedCommonsDocuments(limit = 50) {
|
|
33307
|
+
if (!commonsSemanticSearchConfigured()) return { claimed: 0, embedded: 0, failed: 0, remaining: 0 };
|
|
33308
|
+
await ensureCommonsVectorSchema();
|
|
33309
|
+
const bounded = Math.max(1, Math.min(200, Math.floor(limit)));
|
|
33310
|
+
const queued = await getDb().execute({
|
|
33311
|
+
sql: `SELECT id, entity_id, document_type, title, text FROM commons_index_documents
|
|
33312
|
+
WHERE embedding_status IN ('queued', 'failed') ORDER BY updated_at ASC LIMIT ?`,
|
|
33313
|
+
args: [bounded]
|
|
33314
|
+
});
|
|
33315
|
+
const rows = queued.rows;
|
|
33316
|
+
if (!rows.length) return { claimed: 0, embedded: 0, failed: 0, remaining: await queuedCommonsDocumentCount() };
|
|
33317
|
+
let embedded = 0;
|
|
33318
|
+
let failed = 0;
|
|
33319
|
+
const model = commonsEmbedModel();
|
|
33320
|
+
try {
|
|
33321
|
+
const vectors = await embedCommonsTexts(rows.map((row) => `${row.title}
|
|
33322
|
+
|
|
33323
|
+
${row.text}`));
|
|
33324
|
+
for (const [index, row] of rows.entries()) {
|
|
33325
|
+
const literal = `[${vectors[index].join(",")}]`;
|
|
33326
|
+
await vectorSql().query(
|
|
33327
|
+
`INSERT INTO commons_index_vectors (document_id, entity_id, document_type, title, embedding, model, updated_at)
|
|
33328
|
+
VALUES ($1, $2, $3, $4, $5::vector, $6, now())
|
|
33329
|
+
ON CONFLICT (document_id) DO UPDATE SET entity_id = EXCLUDED.entity_id, document_type = EXCLUDED.document_type,
|
|
33330
|
+
title = EXCLUDED.title, embedding = EXCLUDED.embedding, model = EXCLUDED.model, updated_at = now()`,
|
|
33331
|
+
[row.id, row.entity_id, row.document_type, row.title, literal, model]
|
|
33332
|
+
);
|
|
33333
|
+
await getDb().execute({
|
|
33334
|
+
sql: `UPDATE commons_index_documents SET embedding_status = 'indexed', embedding_provider = ?, embedding_model = ?,
|
|
33335
|
+
vector_ref = ?, indexed_at = ?, error = NULL WHERE id = ?`,
|
|
33336
|
+
args: [COMMONS_EMBED_PROVIDER, model, row.id, (/* @__PURE__ */ new Date()).toISOString(), row.id]
|
|
33337
|
+
});
|
|
33338
|
+
embedded += 1;
|
|
33339
|
+
}
|
|
33340
|
+
} catch (error) {
|
|
33341
|
+
failed = rows.length - embedded;
|
|
33342
|
+
const message = (error instanceof Error ? error.message : String(error)).slice(0, 500);
|
|
33343
|
+
for (const row of rows.slice(embedded)) {
|
|
33344
|
+
await getDb().execute({
|
|
33345
|
+
sql: `UPDATE commons_index_documents SET embedding_status = 'failed', error = ? WHERE id = ?`,
|
|
33346
|
+
args: [message, row.id]
|
|
33347
|
+
}).catch(() => void 0);
|
|
33348
|
+
}
|
|
33349
|
+
}
|
|
33350
|
+
return { claimed: rows.length, embedded, failed, remaining: await queuedCommonsDocumentCount() };
|
|
33351
|
+
}
|
|
33352
|
+
async function queuedCommonsDocumentCount() {
|
|
33353
|
+
const result = await getDb().execute(`SELECT COUNT(*) AS n FROM commons_index_documents WHERE embedding_status IN ('queued', 'failed')`);
|
|
33354
|
+
return Number(result.rows[0]?.n ?? 0);
|
|
33355
|
+
}
|
|
33356
|
+
async function semanticCommonsEntityScores(query, limit = 40) {
|
|
33357
|
+
const scores = /* @__PURE__ */ new Map();
|
|
33358
|
+
if (!commonsSemanticSearchConfigured() || !query.trim()) return scores;
|
|
33359
|
+
await ensureCommonsVectorSchema();
|
|
33360
|
+
const [vector] = await embedCommonsTexts([query]);
|
|
33361
|
+
if (!vector) return scores;
|
|
33362
|
+
const rows = await vectorSql().query(
|
|
33363
|
+
`SELECT entity_id, MAX(1 - (embedding <=> $1::vector)) AS score
|
|
33364
|
+
FROM commons_index_vectors GROUP BY entity_id ORDER BY score DESC LIMIT $2`,
|
|
33365
|
+
[`[${vector.join(",")}]`, Math.max(1, Math.min(100, limit))]
|
|
33366
|
+
);
|
|
33367
|
+
for (const row of rows) scores.set(String(row.entity_id), Number(row.score));
|
|
33368
|
+
return scores;
|
|
33369
|
+
}
|
|
33370
|
+
|
|
33233
33371
|
// src/api/schema-presence.ts
|
|
33234
33372
|
var cache = null;
|
|
33235
33373
|
async function loadSchemaObjects() {
|
|
@@ -33884,17 +34022,35 @@ async function searchCommonsEntities(filters = {}, userId) {
|
|
|
33884
34022
|
args.push(mergedFilters.updatedAfter);
|
|
33885
34023
|
}
|
|
33886
34024
|
const terms = tokenize(mergedFilters.query);
|
|
33887
|
-
|
|
33888
|
-
|
|
33889
|
-
|
|
33890
|
-
|
|
33891
|
-
|
|
33892
|
-
|
|
33893
|
-
|
|
33894
|
-
|
|
33895
|
-
|
|
33896
|
-
|
|
33897
|
-
|
|
34025
|
+
const searchMode = mergedFilters.mode === "lexical" || mergedFilters.mode === "semantic" ? mergedFilters.mode : "hybrid";
|
|
34026
|
+
const semanticScores = !terms.length || searchMode === "lexical" || !commonsSemanticSearchConfigured() ? /* @__PURE__ */ new Map() : await semanticCommonsEntityScores(String(mergedFilters.query ?? ""), SEARCH_CANDIDATE_LIMIT).catch(() => /* @__PURE__ */ new Map());
|
|
34027
|
+
const semanticIds = [...semanticScores.entries()].filter(([, score]) => score >= 0.6).sort((left, right) => right[1] - left[1]).slice(0, 60).map(([id]) => id);
|
|
34028
|
+
if (terms.length) {
|
|
34029
|
+
const termClauses = [];
|
|
34030
|
+
for (const term of terms) {
|
|
34031
|
+
termClauses.push(`(
|
|
34032
|
+
search_text LIKE ?
|
|
34033
|
+
OR EXISTS (
|
|
34034
|
+
SELECT 1 FROM commons_claims
|
|
34035
|
+
WHERE commons_claims.subject_entity_id = commons_entities.id
|
|
34036
|
+
AND (commons_claims.predicate LIKE ? OR commons_claims.predicate_label LIKE ? OR commons_claims.title LIKE ? OR commons_claims.object_url LIKE ?)
|
|
34037
|
+
)
|
|
34038
|
+
)`);
|
|
34039
|
+
const pattern = `%${escapeLike(term)}%`;
|
|
34040
|
+
args.push(pattern, pattern, pattern, pattern, pattern);
|
|
34041
|
+
}
|
|
34042
|
+
const lexicalClause = `(${termClauses.join(" AND ")})`;
|
|
34043
|
+
if (searchMode === "semantic") {
|
|
34044
|
+
if (!semanticIds.length) return { results: [], filters: mergedFilters, limit, offset };
|
|
34045
|
+
args.length -= terms.length * 5;
|
|
34046
|
+
clauses.push(`id IN (${semanticIds.map(() => "?").join(", ")})`);
|
|
34047
|
+
args.push(...semanticIds);
|
|
34048
|
+
} else if (semanticIds.length) {
|
|
34049
|
+
clauses.push(`(${lexicalClause} OR id IN (${semanticIds.map(() => "?").join(", ")}))`);
|
|
34050
|
+
args.push(...semanticIds);
|
|
34051
|
+
} else {
|
|
34052
|
+
clauses.push(lexicalClause);
|
|
34053
|
+
}
|
|
33898
34054
|
}
|
|
33899
34055
|
if (!terms.length) {
|
|
33900
34056
|
args.push(limit, offset);
|
|
@@ -33931,6 +34087,7 @@ async function searchCommonsEntities(filters = {}, userId) {
|
|
|
33931
34087
|
`,
|
|
33932
34088
|
args
|
|
33933
34089
|
});
|
|
34090
|
+
const mode = searchMode;
|
|
33934
34091
|
const ranked = candidates.rows.map((row) => {
|
|
33935
34092
|
const record = row;
|
|
33936
34093
|
const score = relevanceScore(terms, {
|
|
@@ -33941,8 +34098,10 @@ async function searchCommonsEntities(filters = {}, userId) {
|
|
|
33941
34098
|
searchText: String(record.search_text ?? ""),
|
|
33942
34099
|
claimText: String(record.claim_text ?? "")
|
|
33943
34100
|
});
|
|
33944
|
-
|
|
33945
|
-
|
|
34101
|
+
const semantic = semanticScores.get(String(record.id)) ?? 0;
|
|
34102
|
+
const fused = mode === "semantic" ? semantic * 100 : score + semantic * 60;
|
|
34103
|
+
return { id: String(record.id), updatedAt: String(record.updated_at ?? ""), title: String(record.title ?? ""), score: fused, lexical: score, semantic };
|
|
34104
|
+
}).filter((candidate) => mode === "semantic" ? candidate.semantic > 0 : candidate.lexical > 0 || candidate.semantic >= 0.62).sort((left, right) => right.score - left.score || right.updatedAt.localeCompare(left.updatedAt) || left.title.localeCompare(right.title));
|
|
33946
34105
|
const pageIds = ranked.slice(offset, offset + limit).map((candidate) => candidate.id);
|
|
33947
34106
|
if (!pageIds.length) return { results: [], filters: mergedFilters, limit, offset };
|
|
33948
34107
|
const page = await getDb().execute({
|
|
@@ -35429,6 +35588,7 @@ function normalizeRelatedEntities(related) {
|
|
|
35429
35588
|
}
|
|
35430
35589
|
function sanitizeSearchFilters(filters) {
|
|
35431
35590
|
return {
|
|
35591
|
+
mode: filters.mode === "lexical" || filters.mode === "semantic" ? filters.mode : "hybrid",
|
|
35432
35592
|
query: optionalText2(filters.query, 300) ?? void 0,
|
|
35433
35593
|
entityType: filters.entityType ? normalizeEntityType(filters.entityType) : void 0,
|
|
35434
35594
|
tag: optionalText2(filters.tag, 80) ?? void 0,
|
|
@@ -35702,6 +35862,97 @@ var CommonsRepositoryError = class extends Error {
|
|
|
35702
35862
|
|
|
35703
35863
|
// src/api/commons-publication-repository.ts
|
|
35704
35864
|
import { createHash as createHash16, randomUUID as randomUUID18 } from "crypto";
|
|
35865
|
+
|
|
35866
|
+
// src/editorial-reading-room/article-page.ts
|
|
35867
|
+
function escapeHtml6(value) {
|
|
35868
|
+
return String(value ?? "").replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
35869
|
+
}
|
|
35870
|
+
function articlePath(origin, slug4) {
|
|
35871
|
+
return `${origin.replace(/\/+$/, "")}/${encodeURIComponent(slug4)}`;
|
|
35872
|
+
}
|
|
35873
|
+
function renderEditorialArticlePage(input) {
|
|
35874
|
+
const articles = renderEditorialArticleModels(input.edition);
|
|
35875
|
+
const index = articles.findIndex((article2) => article2.slug === input.articleSlug);
|
|
35876
|
+
if (index === -1) return null;
|
|
35877
|
+
const article = articles[index];
|
|
35878
|
+
const previous = index > 0 ? articles[index - 1] : null;
|
|
35879
|
+
const next = index < articles.length - 1 ? articles[index + 1] : null;
|
|
35880
|
+
const canonicalUrl = articlePath(input.origin, article.slug);
|
|
35881
|
+
const site = input.edition.site;
|
|
35882
|
+
const description = article.summary || input.edition.deck || site.title;
|
|
35883
|
+
const jsonLd = JSON.stringify({
|
|
35884
|
+
"@context": "https://schema.org",
|
|
35885
|
+
"@type": "Article",
|
|
35886
|
+
"@id": `${canonicalUrl}#article`,
|
|
35887
|
+
headline: article.title,
|
|
35888
|
+
description,
|
|
35889
|
+
articleSection: article.category,
|
|
35890
|
+
wordCount: article.wordCount,
|
|
35891
|
+
url: canonicalUrl,
|
|
35892
|
+
isPartOf: { "@type": "CollectionPage", "@id": `${input.editionUrl}#collection`, name: site.title, url: input.editionUrl },
|
|
35893
|
+
publisher: { "@type": "Organization", name: input.publicationTitle, url: input.origin }
|
|
35894
|
+
}).replace(/</g, "\\u003c");
|
|
35895
|
+
const jumps = article.toc.length ? `<nav class="article-jumps" aria-label="On this page">${article.toc.map((item) => `<a href="#${escapeHtml6(item.id)}">${escapeHtml6(item.title)}</a>`).join("")}</nav>` : "";
|
|
35896
|
+
const neighbour = (item, label) => item ? `<a class="neighbour" href="${escapeHtml6(articlePath(input.origin, item.slug))}"><span>${label}</span><strong>${escapeHtml6(item.title)}</strong></a>` : "";
|
|
35897
|
+
const html = `<!doctype html>
|
|
35898
|
+
<html lang="en">
|
|
35899
|
+
<head>
|
|
35900
|
+
<meta charset="utf-8">
|
|
35901
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
35902
|
+
<title>${escapeHtml6(article.title)} \u2014 ${escapeHtml6(input.publicationTitle)}</title>
|
|
35903
|
+
<meta name="description" content="${escapeHtml6(description)}">
|
|
35904
|
+
<link rel="canonical" href="${escapeHtml6(canonicalUrl)}">
|
|
35905
|
+
<meta property="og:type" content="article">
|
|
35906
|
+
<meta property="og:title" content="${escapeHtml6(article.title)}">
|
|
35907
|
+
<meta property="og:description" content="${escapeHtml6(description)}">
|
|
35908
|
+
<meta property="og:url" content="${escapeHtml6(canonicalUrl)}">
|
|
35909
|
+
<meta property="og:site_name" content="${escapeHtml6(input.publicationTitle)}">
|
|
35910
|
+
<meta name="twitter:card" content="summary_large_image">
|
|
35911
|
+
<meta name="twitter:title" content="${escapeHtml6(article.title)}">
|
|
35912
|
+
<meta name="twitter:description" content="${escapeHtml6(description)}">
|
|
35913
|
+
<script type="application/ld+json">${jsonLd}</script>
|
|
35914
|
+
<style>
|
|
35915
|
+
:root{color-scheme:light dark;--ink:#12171f;--muted:#5b6672;--rule:#dfe4ea;--bg:#fbfbfa;--accent:#8a6a2f}
|
|
35916
|
+
*{box-sizing:border-box}
|
|
35917
|
+
body{margin:0;background:var(--bg);color:var(--ink);font:17px/1.65 Georgia,"Times New Roman",serif}
|
|
35918
|
+
a{color:inherit}
|
|
35919
|
+
header.masthead{border-bottom:1px solid var(--rule);padding:18px 20px}
|
|
35920
|
+
header.masthead a{font:600 13px/1 ui-sans-serif,system-ui,sans-serif;letter-spacing:.08em;text-transform:uppercase;text-decoration:none;color:var(--muted)}
|
|
35921
|
+
main{max-width:44rem;margin:0 auto;padding:34px 20px 64px}
|
|
35922
|
+
.kicker{font:600 12px/1 ui-sans-serif,system-ui,sans-serif;letter-spacing:.1em;text-transform:uppercase;color:var(--accent)}
|
|
35923
|
+
h1{font-size:2.1rem;line-height:1.18;margin:12px 0 10px}
|
|
35924
|
+
.summary{color:var(--muted);font-size:1.06rem;margin:0 0 18px}
|
|
35925
|
+
.meta{font:12px/1 ui-sans-serif,system-ui,sans-serif;letter-spacing:.06em;text-transform:uppercase;color:var(--muted);border-top:1px solid var(--rule);border-bottom:1px solid var(--rule);padding:11px 0;margin-bottom:26px}
|
|
35926
|
+
.article-jumps{display:flex;flex-wrap:wrap;gap:10px;margin:0 0 26px}
|
|
35927
|
+
.article-jumps a{font:13px/1 ui-sans-serif,system-ui,sans-serif;color:var(--muted);text-decoration:none;border:1px solid var(--rule);border-radius:999px;padding:6px 11px}
|
|
35928
|
+
article h2{font-size:1.4rem;margin:32px 0 10px}
|
|
35929
|
+
article h3{font-size:1.15rem;margin:24px 0 8px}
|
|
35930
|
+
article p{margin:0 0 17px}
|
|
35931
|
+
.neighbours{display:grid;gap:12px;margin-top:44px;padding-top:22px;border-top:1px solid var(--rule)}
|
|
35932
|
+
.neighbour{display:block;text-decoration:none;border:1px solid var(--rule);border-radius:10px;padding:13px 15px;background:#fff}
|
|
35933
|
+
.neighbour span{display:block;font:11px/1 ui-sans-serif,system-ui,sans-serif;letter-spacing:.09em;text-transform:uppercase;color:var(--muted);margin-bottom:5px}
|
|
35934
|
+
footer{border-top:1px solid var(--rule);padding:20px;text-align:center;color:var(--muted);font:13px/1.5 ui-sans-serif,system-ui,sans-serif}
|
|
35935
|
+
@media (prefers-color-scheme:dark){:root{--ink:#eef1f5;--muted:#9aa4b1;--rule:#2b323b;--bg:#12151a}.neighbour{background:#171b21}}
|
|
35936
|
+
</style>
|
|
35937
|
+
</head>
|
|
35938
|
+
<body>
|
|
35939
|
+
<header class="masthead"><a href="${escapeHtml6(input.origin)}">${escapeHtml6(input.publicationTitle)}</a></header>
|
|
35940
|
+
<main>
|
|
35941
|
+
<p class="kicker">${escapeHtml6(article.kicker || article.category)}</p>
|
|
35942
|
+
<h1>${escapeHtml6(article.title)}</h1>
|
|
35943
|
+
<p class="summary">${escapeHtml6(article.summary)}</p>
|
|
35944
|
+
<p class="meta">${escapeHtml6(article.category)} \xB7 ${article.wordCount} words \xB7 ${article.readingMinutes} min \xB7 <a href="${escapeHtml6(input.editionUrl)}">${escapeHtml6(site.title)}</a></p>
|
|
35945
|
+
${jumps}
|
|
35946
|
+
<article>${article.html}</article>
|
|
35947
|
+
<div class="neighbours">${neighbour(previous, "Previous")}${neighbour(next, "Next")}</div>
|
|
35948
|
+
</main>
|
|
35949
|
+
<footer>${escapeHtml6(input.publicationTitle)} \xB7 <a href="${escapeHtml6(input.editionUrl)}">All articles in ${escapeHtml6(site.title)}</a></footer>
|
|
35950
|
+
</body>
|
|
35951
|
+
</html>`;
|
|
35952
|
+
return { html, article, canonicalUrl };
|
|
35953
|
+
}
|
|
35954
|
+
|
|
35955
|
+
// src/api/commons-publication-repository.ts
|
|
35705
35956
|
var PUBLICATION_ROOT_DOMAIN = process.env.COMMONS_PUBLICATION_ROOT_DOMAIN || "transparent-commons.cc";
|
|
35706
35957
|
var RESERVED_SUBDOMAINS = /* @__PURE__ */ new Set([
|
|
35707
35958
|
"admin",
|
|
@@ -36032,6 +36283,20 @@ async function listCommonsPublicationEditions(publicationId) {
|
|
|
36032
36283
|
if (!publication) return [];
|
|
36033
36284
|
return result.rows.map((row) => rowToEdition(row, publication.subdomain));
|
|
36034
36285
|
}
|
|
36286
|
+
async function getCommonsPublicationArticleHtml(subdomainInput, articleSlug, editionSlugInput) {
|
|
36287
|
+
const found = await getCommonsPublicationEditionHtml(subdomainInput, editionSlugInput);
|
|
36288
|
+
if (!found) return null;
|
|
36289
|
+
const { publication, edition } = found;
|
|
36290
|
+
const page = renderEditorialArticlePage({
|
|
36291
|
+
edition: { site: edition.site, deck: edition.deck, articles: edition.articles },
|
|
36292
|
+
articleSlug,
|
|
36293
|
+
origin: publicationPublicUrl(publication.subdomain),
|
|
36294
|
+
editionUrl: editionPublicUrl(publication.subdomain, edition.editionSlug),
|
|
36295
|
+
publicationTitle: publication.title
|
|
36296
|
+
});
|
|
36297
|
+
if (!page) return null;
|
|
36298
|
+
return { publication, edition, html: page.html, canonicalUrl: page.canonicalUrl };
|
|
36299
|
+
}
|
|
36035
36300
|
async function getCommonsPublicationEditionHtml(subdomainInput, editionSlugInput) {
|
|
36036
36301
|
const publication = await getCommonsPublicationBySubdomain(subdomainInput);
|
|
36037
36302
|
if (!publication) return null;
|
|
@@ -36177,6 +36442,7 @@ function addPublicMetadata(html, canonicalUrl, publicationTitle) {
|
|
|
36177
36442
|
var commonsApp = new Hono31();
|
|
36178
36443
|
var auth2 = createApiKeyAuth();
|
|
36179
36444
|
var SearchBodySchema = z32.object({
|
|
36445
|
+
mode: z32.enum(["lexical", "semantic", "hybrid"]).optional(),
|
|
36180
36446
|
query: z32.string().max(300).optional(),
|
|
36181
36447
|
entityType: z32.string().max(120).optional(),
|
|
36182
36448
|
tag: z32.string().max(80).optional(),
|
|
@@ -36340,6 +36606,14 @@ var ValidatePublicationSchema = z32.object(CommonsValidatePublicationInputSchema
|
|
|
36340
36606
|
var ClaimPublicationSchema = z32.object(CommonsClaimPublicationInputSchema).strict();
|
|
36341
36607
|
var PublishEditorialSchema = z32.object(CommonsPublishEditorialInputSchema).strict();
|
|
36342
36608
|
var UpdateEditorialArticleSchema = z32.object(CommonsUpdateEditorialArticleInputSchema).strict();
|
|
36609
|
+
commonsApp.post("/index/embed", auth2, async (c) => {
|
|
36610
|
+
const body = await c.req.json().catch(() => ({}));
|
|
36611
|
+
const result = await embedQueuedCommonsDocuments(Number(body.limit) || 50);
|
|
36612
|
+
return c.json({ ok: true, data: result });
|
|
36613
|
+
});
|
|
36614
|
+
commonsApp.get("/index/status", auth2, async (c) => {
|
|
36615
|
+
return c.json({ ok: true, data: { queued: await queuedCommonsDocumentCount(), semanticSearchConfigured: commonsSemanticSearchConfigured() } });
|
|
36616
|
+
});
|
|
36343
36617
|
commonsApp.get("/health", async (c) => {
|
|
36344
36618
|
await ensureCommonsSchema();
|
|
36345
36619
|
return c.json({ ok: true, data: commonsDatabaseReport() });
|
|
@@ -36398,6 +36672,28 @@ commonsApp.get("/publications/:subdomain/site", async (c) => {
|
|
|
36398
36672
|
return publicationError(c, error);
|
|
36399
36673
|
}
|
|
36400
36674
|
});
|
|
36675
|
+
commonsApp.get("/publications/:subdomain/articles/:articleSlug/site", async (c) => {
|
|
36676
|
+
try {
|
|
36677
|
+
const result = await getCommonsPublicationArticleHtml(c.req.param("subdomain"), c.req.param("articleSlug"));
|
|
36678
|
+
if (!result) return c.json({ ok: false, error: "article_not_found", message: "No published article matched that publication and slug." }, 404);
|
|
36679
|
+
return c.html(result.html, 200, {
|
|
36680
|
+
"cache-control": "public, max-age=60, s-maxage=300",
|
|
36681
|
+
"x-robots-tag": "index, follow",
|
|
36682
|
+
link: `<${result.canonicalUrl}>; rel="canonical"`
|
|
36683
|
+
});
|
|
36684
|
+
} catch (error) {
|
|
36685
|
+
return publicationError(c, error);
|
|
36686
|
+
}
|
|
36687
|
+
});
|
|
36688
|
+
commonsApp.get("/publications/:subdomain/editions/:editionSlug/articles/:articleSlug/site", async (c) => {
|
|
36689
|
+
try {
|
|
36690
|
+
const result = await getCommonsPublicationArticleHtml(c.req.param("subdomain"), c.req.param("articleSlug"), c.req.param("editionSlug"));
|
|
36691
|
+
if (!result) return c.json({ ok: false, error: "article_not_found", message: "No published article matched that publication, edition, and slug." }, 404);
|
|
36692
|
+
return c.html(result.html, 200, { "cache-control": "public, max-age=60, s-maxage=300", "x-robots-tag": "index, follow" });
|
|
36693
|
+
} catch (error) {
|
|
36694
|
+
return publicationError(c, error);
|
|
36695
|
+
}
|
|
36696
|
+
});
|
|
36401
36697
|
commonsApp.get("/publications/:subdomain/editions/:editionSlug/site", async (c) => {
|
|
36402
36698
|
try {
|
|
36403
36699
|
const result = await getCommonsPublicationEditionHtml(c.req.param("subdomain"), c.req.param("editionSlug"));
|
|
@@ -36600,6 +36896,7 @@ ${urls.join("\n")}
|
|
|
36600
36896
|
});
|
|
36601
36897
|
function filtersFromQuery(query) {
|
|
36602
36898
|
return {
|
|
36899
|
+
mode: query.mode === "lexical" || query.mode === "semantic" ? query.mode : void 0,
|
|
36603
36900
|
query: query.query || query.q,
|
|
36604
36901
|
entityType: query.entityType,
|
|
36605
36902
|
tag: query.tag,
|
|
@@ -37249,7 +37546,7 @@ function pixelSnippet(publicId) {
|
|
|
37249
37546
|
function formSnippet(publicId) {
|
|
37250
37547
|
return `<div data-mcp-form="${publicId}"></div><script async src="https://mcpscraper.dev/analytics/v1/form.js?form=${publicId}"></script>`;
|
|
37251
37548
|
}
|
|
37252
|
-
function
|
|
37549
|
+
function escapeHtml7(value) {
|
|
37253
37550
|
return String(value ?? "").replace(
|
|
37254
37551
|
/[&<>"']/g,
|
|
37255
37552
|
(character) => ({ "&": "&", "<": "<", ">": ">", '"': """, "'": "'" })[character]
|
|
@@ -37261,13 +37558,13 @@ function renderPublicForm(form, placementUrl) {
|
|
|
37261
37558
|
const fields = form.fields.map((field) => {
|
|
37262
37559
|
const required = field.required ? " required" : "";
|
|
37263
37560
|
const options = (field.options ?? []).map(
|
|
37264
|
-
(option) => `<option value="${
|
|
37561
|
+
(option) => `<option value="${escapeHtml7(option)}">${escapeHtml7(option)}</option>`
|
|
37265
37562
|
).join("");
|
|
37266
|
-
const control = field.type === "textarea" ? `<textarea id="${
|
|
37267
|
-
return `<label${field.type === "checkbox" ? ' class="check"' : ""}><span>${
|
|
37563
|
+
const control = field.type === "textarea" ? `<textarea id="${escapeHtml7(field.id)}" name="${escapeHtml7(field.id)}"${required}></textarea>` : field.type === "select" ? `<select id="${escapeHtml7(field.id)}" name="${escapeHtml7(field.id)}"${required}><option value="">Choose\u2026</option>${options}</select>` : field.type === "checkbox" ? `<input id="${escapeHtml7(field.id)}" name="${escapeHtml7(field.id)}" type="checkbox" value="true"${required}>` : `<input id="${escapeHtml7(field.id)}" name="${escapeHtml7(field.id)}" type="${escapeHtml7(field.type)}"${required}>`;
|
|
37564
|
+
return `<label${field.type === "checkbox" ? ' class="check"' : ""}><span>${escapeHtml7(field.label)}${field.required ? " *" : ""}</span>${control}</label>`;
|
|
37268
37565
|
}).join("");
|
|
37269
37566
|
const brand = form.brand;
|
|
37270
|
-
return `<!doctype html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><style>:root{font-family:ui-sans-serif,system-ui;color:${
|
|
37567
|
+
return `<!doctype html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><style>:root{font-family:ui-sans-serif,system-ui;color:${escapeHtml7(brand.textColor)};background:${escapeHtml7(brand.backgroundColor)}}*{box-sizing:border-box}body{margin:0;padding:18px}form{display:grid;gap:14px}label{display:grid;gap:6px;font-size:13px;font-weight:650}.check{grid-template-columns:auto 1fr;align-items:center}.check span{grid-column:2}.check input{grid-column:1;grid-row:1}input,textarea,select{width:100%;min-height:44px;padding:10px 12px;border:1px solid #ccd3df;border-radius:${brand.radius}px;background:white;color:inherit;font:inherit}textarea{min-height:110px;resize:vertical}button{min-height:46px;border:0;border-radius:${brand.radius}px;color:white;background:${escapeHtml7(brand.primaryColor)};font:inherit;font-weight:750;cursor:pointer}.consent{margin:0;color:#667085;font-size:11px;line-height:1.45}.notice{display:none;padding:12px;border-radius:${brand.radius}px;background:#edf8f2;color:#17613c}.hp{position:absolute!important;left:-9999px!important}</style></head><body><form id="mcp-form">${fields}<label class="hp">Website<input name="website" autocomplete="off" tabindex="-1"></label>${form.consent_text ? `<p class="consent">${escapeHtml7(form.consent_text)}</p>` : ""}<button>${escapeHtml7(form.submit_label)}</button><div class="notice" role="status"></div></form><script>(()=>{const form=document.querySelector('#mcp-form'),notice=form.querySelector('.notice'),q=new URLSearchParams(location.search);form.addEventListener('submit',async event=>{event.preventDefault();const button=form.querySelector('button');button.disabled=true;const raw=Object.fromEntries(new FormData(form).entries()),website=String(raw.website||''),clickIds={};delete raw.website;for(const k of ['fbclid','gclid','gbraid','wbraid','ttclid','rdt_cid','msclkid']){const v=q.get(k);if(v)clickIds[k]=v}try{const response=await fetch('/analytics/forms/${escapeHtml7(form.public_id)}/submissions',{method:'POST',headers:{'content-type':'application/json'},body:JSON.stringify({data:raw,website,placementUrl:${JSON.stringify(placementUrl)},visitorId:q.get('visitor')||undefined,sessionId:q.get('session')||undefined,source:q.get('source')||undefined,medium:q.get('medium')||undefined,campaign:q.get('campaign')||undefined,clickIds})});if(!response.ok)throw new Error('submit');notice.textContent=${JSON.stringify(form.success_message)};notice.style.display='block';form.reset();${form.redirect_url ? `setTimeout(()=>{top.location.href=${JSON.stringify(form.redirect_url)}},700);` : ""}}catch{notice.textContent='Your response could not be submitted. Please try again.';notice.style.display='block'}finally{button.disabled=false}})})()</script></body></html>`;
|
|
37271
37568
|
}
|
|
37272
37569
|
analyticsApp.get(
|
|
37273
37570
|
"/health/live",
|
|
@@ -38523,7 +38820,7 @@ async function revokeScheduledRunViewLink(ownerId, runId, shareId, now = /* @__P
|
|
|
38523
38820
|
|
|
38524
38821
|
// src/personal-authority/render.ts
|
|
38525
38822
|
import { createHash as createHash21 } from "crypto";
|
|
38526
|
-
function
|
|
38823
|
+
function escapeHtml8(value) {
|
|
38527
38824
|
return value.replace(/[&<>"']/g, (character) => ({
|
|
38528
38825
|
"&": "&",
|
|
38529
38826
|
"<": "<",
|
|
@@ -38534,13 +38831,13 @@ function escapeHtml7(value) {
|
|
|
38534
38831
|
}
|
|
38535
38832
|
function safeHref(value) {
|
|
38536
38833
|
const trimmed = value.trim();
|
|
38537
|
-
return /^(?:https?:|mailto:|tel:|#|\/)/i.test(trimmed) ?
|
|
38834
|
+
return /^(?:https?:|mailto:|tel:|#|\/)/i.test(trimmed) ? escapeHtml8(trimmed) : "#";
|
|
38538
38835
|
}
|
|
38539
38836
|
function initials(name) {
|
|
38540
38837
|
return name.split(/\s+/).filter(Boolean).slice(0, 2).map((part) => part[0]?.toUpperCase()).join("") || "PA";
|
|
38541
38838
|
}
|
|
38542
38839
|
function action(action3, secondary = false) {
|
|
38543
|
-
return `<a class="button${secondary ? " button--secondary" : ""}" href="${safeHref(action3.href)}">${
|
|
38840
|
+
return `<a class="button${secondary ? " button--secondary" : ""}" href="${safeHref(action3.href)}">${escapeHtml8(action3.label)} <span aria-hidden="true">\u2197</span></a>`;
|
|
38544
38841
|
}
|
|
38545
38842
|
function section(enabled, html) {
|
|
38546
38843
|
return enabled ? html : "";
|
|
@@ -38549,7 +38846,7 @@ function renderPersonalAuthorityV1(input, config, generatedAt) {
|
|
|
38549
38846
|
const flags = config.featureFlags;
|
|
38550
38847
|
const brand = config.brandName || input.name;
|
|
38551
38848
|
const generatedAtIso = generatedAt.toISOString();
|
|
38552
|
-
const social = flags.socialLinks && input.socialLinks.length > 0 ? `<nav class="social" aria-label="Professional profiles">${input.socialLinks.map((link) => `<a href="${safeHref(link.href)}">${
|
|
38849
|
+
const social = flags.socialLinks && input.socialLinks.length > 0 ? `<nav class="social" aria-label="Professional profiles">${input.socialLinks.map((link) => `<a href="${safeHref(link.href)}">${escapeHtml8(link.label)}</a>`).join("")}</nav>` : "";
|
|
38553
38850
|
const navigation = flags.navigation ? `<button class="menu" type="button" aria-expanded="false" aria-controls="nav">Menu</button><nav id="nav" class="nav" aria-label="Primary navigation"><a href="#about">About</a><a href="#services">Work</a><a href="#proof">Proof</a><a href="#contact">Contact</a></nav>` : "";
|
|
38554
38851
|
const authority = input.authority;
|
|
38555
38852
|
const consultation = input.consultation;
|
|
@@ -38561,21 +38858,21 @@ function renderPersonalAuthorityV1(input, config, generatedAt) {
|
|
|
38561
38858
|
<html lang="en" data-theme="${config.theme}">
|
|
38562
38859
|
<head>
|
|
38563
38860
|
<meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
|
|
38564
|
-
<meta name="description" content="${
|
|
38861
|
+
<meta name="description" content="${escapeHtml8(input.summary)}"><title>${escapeHtml8(input.name)} \u2014 ${escapeHtml8(input.professionalTitle)}</title>
|
|
38565
38862
|
<style>
|
|
38566
38863
|
:root{--blue:#2f66eb;--blue-soft:#dbe6ff;--ink:#050708;--paper:#f7f8fb;--white:#fff;--gray:#9ca5b5;--line:#27303b;--serif:Georgia,'Times New Roman',serif;--sans:Arial,Helvetica,sans-serif}*{box-sizing:border-box}html{scroll-behavior:smooth}body{margin:0;background:var(--ink);color:var(--white);font-family:var(--sans);line-height:1.55}a{color:inherit}.skip{position:absolute;left:-9999px}.skip:focus{left:16px;top:16px;z-index:9;background:#fff;color:#000;padding:10px}.header{height:88px;display:flex;align-items:center;justify-content:space-between;padding:0 clamp(20px,4vw,72px);border-bottom:1px solid var(--line);position:relative;z-index:3;background:rgba(5,7,8,.96)}.brand{display:flex;align-items:center;gap:12px;text-decoration:none;font-family:var(--serif);font-size:24px}.mark{width:40px;height:40px;border-radius:50%;display:grid;place-items:center;background:var(--blue);font-family:var(--sans);font-weight:700}.nav{display:flex;align-items:center;gap:28px}.nav a{text-decoration:none;color:#c8ced8;font-size:14px}.nav a:hover{color:#fff}.menu{display:none;background:transparent;color:#fff;border:1px solid #5b6471;padding:10px 14px}.hero{display:grid;grid-template-columns:minmax(0,.9fr) minmax(0,1.25fr);min-height:760px;border-bottom:3px solid var(--blue)}.portrait{display:grid;place-items:end center;background:radial-gradient(circle at 50% 38%,#273243 0,#11161d 38%,#060708 70%);overflow:hidden}.portrait-card{width:min(82%,560px);aspect-ratio:4/5;display:grid;place-items:center;align-self:end;border:1px solid #263142;border-bottom:0;background:linear-gradient(145deg,#252d38,#0b0d10 58%);font-family:var(--serif);font-size:clamp(80px,13vw,180px);color:#d9e4ff;text-shadow:0 0 42px rgba(47,102,235,.5)}.hero-copy{padding:clamp(44px,7vw,110px) clamp(24px,6vw,100px);display:flex;flex-direction:column;justify-content:center;background:linear-gradient(135deg,#080a0d,#101318)}h1,h2,h3,p{margin-top:0}.hero h1{font-family:var(--serif);font-size:clamp(58px,8vw,116px);line-height:.92;font-weight:400;color:var(--blue);margin-bottom:24px}.role{font-family:var(--serif);font-size:clamp(28px,3.8vw,52px);line-height:1.05;border-left:5px solid var(--blue);padding-left:22px;max-width:820px}.summary{color:#c6cbd3;font-size:clamp(17px,1.5vw,22px);max-width:760px}.actions{display:flex;gap:12px;flex-wrap:wrap;margin:24px 0}.button{display:inline-flex;align-items:center;justify-content:space-between;gap:28px;min-height:58px;padding:0 26px;background:var(--blue);border:1px solid var(--blue);text-decoration:none;font-weight:700}.button--secondary{background:transparent;border-color:#5c6572}.social{display:flex;gap:10px;flex-wrap:wrap}.social a{border:1px solid #39414d;border-radius:999px;padding:8px 13px;text-decoration:none;color:#d8dce4;font-size:13px}.light{background:var(--paper);color:#111722;padding:clamp(70px,10vw,150px) clamp(20px,6vw,90px)}.light h2,.section h2{font-family:var(--serif);font-size:clamp(42px,6vw,82px);line-height:1.02;font-weight:400;max-width:1080px}.light p{max-width:920px;color:#4e596a;font-size:18px}.section{padding:clamp(70px,9vw,130px) clamp(20px,6vw,90px);border-bottom:1px solid var(--line)}.section-head{max-width:920px;margin-bottom:46px}.eyebrow{text-transform:uppercase;letter-spacing:.18em;font-size:12px;color:#aab2bf}.consult{display:grid;grid-template-columns:1.3fr .7fr;gap:50px;background:linear-gradient(130deg,#060708,#111721)}.accent-card{min-height:360px;border:1px solid #2a3545;background:linear-gradient(145deg,rgba(47,102,235,.22),transparent 55%);display:grid;place-items:center;font-family:var(--serif);font-size:96px;color:var(--blue)}.grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:14px}.card{border:1px solid #323a46;padding:26px;min-height:220px;background:#0b0e12}.card h3{font-family:var(--serif);font-size:30px}.card p{color:#b9c0ca}.learning{background:#020303}.topic-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:1px;background:#29313c;border:1px solid #29313c}.topic{background:#050708;padding:30px}.topic strong{display:block;color:var(--blue);text-transform:uppercase;font-size:11px;letter-spacing:.15em}.topic h3{font-family:var(--serif);font-size:30px;margin:8px 0}.topic p{color:#aeb6c1}.proof{background:linear-gradient(180deg,#0a0d11,#050607)}.quotes{display:flex;gap:14px;overflow:auto;scroll-snap-type:x mandatory;padding-bottom:12px}.quote{min-width:min(420px,86vw);scroll-snap-align:start;border:1px solid #343d49;padding:30px;background:#0c1015}.quote q{font-family:var(--serif);font-size:30px;line-height:1.25}.quote span{display:block;margin-top:24px;color:#aeb5c0;font-size:12px;text-transform:uppercase;letter-spacing:.12em}.cta{text-align:center;border-top:3px solid var(--blue);background:radial-gradient(circle at 50% 0,rgba(47,102,235,.25),transparent 50%)}.cta h2{margin-left:auto;margin-right:auto}.footer{display:grid;grid-template-columns:1fr auto;gap:40px;padding:46px clamp(20px,6vw,90px);color:#abb3bf}.footer strong{color:#fff;font-family:var(--serif);font-size:26px}.generated{font-size:11px;color:#737d8b;margin-top:10px}html[data-theme='slate']{--blue:#7f95b8;--blue-soft:#dfe6ef}html[data-theme='monochrome']{--blue:#fff;--blue-soft:#e7e7e7}.sr-only{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0,0,0,0)}
|
|
38567
38864
|
@media(max-width:760px){.header{height:78px}.menu{display:block}.nav{display:none;position:absolute;left:0;right:0;top:77px;padding:18px 20px;background:#090b0e;border-bottom:1px solid #303844;flex-direction:column;align-items:stretch}.nav.open{display:flex}.hero{grid-template-columns:1fr;min-height:0}.portrait{min-height:390px}.portrait-card{width:72%;max-height:360px}.hero-copy{padding:48px 20px 66px}.hero h1{font-size:64px}.role{font-size:34px}.actions{display:grid}.button{width:100%}.consult{grid-template-columns:1fr}.accent-card{min-height:220px}.grid,.topic-grid{grid-template-columns:1fr}.light,.section{padding:64px 20px}.light h2,.section h2{font-size:46px}.footer{grid-template-columns:1fr}}
|
|
38568
38865
|
</style></head>
|
|
38569
38866
|
<body><a class="skip" href="#main">Skip to main content</a>
|
|
38570
|
-
<header class="header"><a class="brand" href="#top"><span class="mark">${
|
|
38571
|
-
<main id="main"><section class="hero" id="top"><div class="portrait" aria-label="Portrait placeholder"><div class="portrait-card" aria-hidden="true">${
|
|
38572
|
-
${section(flags.authority && Boolean(authority), `<section class="light" id="about"><h2>${
|
|
38573
|
-
${section(flags.consultation && Boolean(consultation), `<section class="section consult"><div><p class="eyebrow">${
|
|
38574
|
-
${section(flags.learning && Boolean(learning), `<section class="section learning"><div class="section-head"><h2>${
|
|
38575
|
-
${section(flags.services && Boolean(services), `<section class="section" id="services"><div class="section-head"><h2>${
|
|
38576
|
-
${section(flags.proof && Boolean(proof), `<section class="section proof" id="proof"><div class="section-head"><h2>${
|
|
38577
|
-
${section(flags.finalCta && Boolean(finalCta), `<section class="section cta" id="contact"><p class="eyebrow">${
|
|
38578
|
-
</main><footer class="footer"><div><strong>${
|
|
38867
|
+
<header class="header"><a class="brand" href="#top"><span class="mark">${escapeHtml8(initials(input.name).slice(0, 1))}</span><strong>${escapeHtml8(brand)}</strong></a>${navigation}</header>
|
|
38868
|
+
<main id="main"><section class="hero" id="top"><div class="portrait" aria-label="Portrait placeholder"><div class="portrait-card" aria-hidden="true">${escapeHtml8(initials(input.name))}</div></div><div class="hero-copy"><h1>${escapeHtml8(input.name)}</h1><p class="role">${escapeHtml8(input.professionalTitle)}</p><p class="summary">${escapeHtml8(input.summary)}</p><div class="actions">${action(input.primaryAction)}${input.secondaryAction ? action(input.secondaryAction, true) : ""}</div>${social}</div></section>
|
|
38869
|
+
${section(flags.authority && Boolean(authority), `<section class="light" id="about"><h2>${escapeHtml8(authority?.heading ?? "")}</h2>${authority?.paragraphs.map((paragraph) => `<p>${escapeHtml8(paragraph)}</p>`).join("") ?? ""}</section>`)}
|
|
38870
|
+
${section(flags.consultation && Boolean(consultation), `<section class="section consult"><div><p class="eyebrow">${escapeHtml8(consultation?.eyebrow ?? "Start a conversation")}</p><h2>${escapeHtml8(consultation?.heading ?? "")}</h2><p class="summary">${escapeHtml8(consultation?.summary ?? "")}</p>${consultation ? action(consultation.action) : ""}</div><div class="accent-card" aria-label="Image placeholder">${escapeHtml8(initials(input.name))}</div></section>`)}
|
|
38871
|
+
${section(flags.learning && Boolean(learning), `<section class="section learning"><div class="section-head"><h2>${escapeHtml8(learning?.heading ?? "")}</h2><p class="summary">${escapeHtml8(learning?.summary ?? "")}</p></div><div class="topic-grid">${learning?.topics.map((topic) => `<article class="topic"><strong>${escapeHtml8(topic.title)}</strong><h3>${escapeHtml8(topic.headline)}</h3><p>${escapeHtml8(topic.summary)}</p>${topic.href ? `<a href="${safeHref(topic.href)}">Explore \u2192</a>` : ""}</article>`).join("") ?? ""}</div></section>`)}
|
|
38872
|
+
${section(flags.services && Boolean(services), `<section class="section" id="services"><div class="section-head"><h2>${escapeHtml8(services?.heading ?? "")}</h2><p class="summary">${escapeHtml8(services?.summary ?? "")}</p></div><div class="grid">${services?.offers.map((offer) => `<article class="card"><h3>${escapeHtml8(offer.title)}</h3><p>${escapeHtml8(offer.description)}</p>${offer.action ? action(offer.action, true) : ""}</article>`).join("") ?? ""}</div></section>`)}
|
|
38873
|
+
${section(flags.proof && Boolean(proof), `<section class="section proof" id="proof"><div class="section-head"><h2>${escapeHtml8(proof?.heading ?? "")}</h2><p class="summary">${escapeHtml8(proof?.summary ?? "")}</p></div><div class="quotes">${proof?.testimonials.map((item) => `<article class="quote"><q>${escapeHtml8(item.quote)}</q><span>${escapeHtml8(item.person)}${item.role ? ` / ${escapeHtml8(item.role)}` : ""}</span></article>`).join("") ?? ""}</div></section>`)}
|
|
38874
|
+
${section(flags.finalCta && Boolean(finalCta), `<section class="section cta" id="contact"><p class="eyebrow">${escapeHtml8(finalCta?.eyebrow ?? "Ready when you are")}</p><h2>${escapeHtml8(finalCta?.heading ?? "")}</h2><p class="summary">${escapeHtml8(finalCta?.summary ?? "")}</p>${finalCta ? action(finalCta.action) : ""}</section>`)}
|
|
38875
|
+
</main><footer class="footer"><div><strong>${escapeHtml8(input.name)}</strong><div>${escapeHtml8(input.professionalTitle)}</div>${config.showGeneratedAt ? `<div class="generated">Generated ${escapeHtml8(generatedAtIso)}</div>` : ""}</div><div>${input.location ? `<div>${escapeHtml8(input.location)}</div>` : ""}${input.email ? `<a href="mailto:${escapeHtml8(input.email)}">${escapeHtml8(input.email)}</a>` : ""}${input.phone ? `<div>${escapeHtml8(input.phone)}</div>` : ""}</div></footer>
|
|
38579
38876
|
<script>document.querySelector('.menu')?.addEventListener('click',function(){var nav=document.querySelector('.nav');var open=this.getAttribute('aria-expanded')!=='true';this.setAttribute('aria-expanded',String(open));nav?.classList.toggle('open',open)});document.querySelectorAll('.nav a').forEach(function(link){link.addEventListener('click',function(){document.querySelector('.nav')?.classList.remove('open');document.querySelector('.menu')?.setAttribute('aria-expanded','false')})});</script></body></html>`;
|
|
38580
38877
|
const bytes = Buffer.byteLength(html, "utf8");
|
|
38581
38878
|
return {
|
|
@@ -38594,7 +38891,7 @@ var FONT_STACKS = Object.freeze({
|
|
|
38594
38891
|
"modern-sans": "Avenir Next, Avenir, Helvetica Neue, Arial, sans-serif",
|
|
38595
38892
|
"humanist-sans": "Optima, Candara, Segoe UI, sans-serif"
|
|
38596
38893
|
});
|
|
38597
|
-
function
|
|
38894
|
+
function escapeHtml9(value) {
|
|
38598
38895
|
return value.replace(
|
|
38599
38896
|
/[&<>"']/g,
|
|
38600
38897
|
(character) => ({
|
|
@@ -38608,13 +38905,13 @@ function escapeHtml8(value) {
|
|
|
38608
38905
|
}
|
|
38609
38906
|
function safeHref2(value) {
|
|
38610
38907
|
const trimmed = value.trim();
|
|
38611
|
-
return /^(?:https?:|mailto:|tel:|#|\/)/i.test(trimmed) ?
|
|
38908
|
+
return /^(?:https?:|mailto:|tel:|#|\/)/i.test(trimmed) ? escapeHtml9(trimmed) : "#";
|
|
38612
38909
|
}
|
|
38613
38910
|
function initials2(name) {
|
|
38614
38911
|
return name.split(/\s+/).filter(Boolean).slice(0, 2).map((part) => part[0]?.toUpperCase()).join("") || "PA";
|
|
38615
38912
|
}
|
|
38616
38913
|
function action2(action3, secondary = false) {
|
|
38617
|
-
return `<a class="button${secondary ? " button--secondary" : ""}" href="${safeHref2(action3.href)}">${
|
|
38914
|
+
return `<a class="button${secondary ? " button--secondary" : ""}" href="${safeHref2(action3.href)}">${escapeHtml9(action3.label)} <span aria-hidden="true">\u2197</span></a>`;
|
|
38618
38915
|
}
|
|
38619
38916
|
function section2(enabled, html) {
|
|
38620
38917
|
return enabled ? html : "";
|
|
@@ -38658,7 +38955,7 @@ function renderPersonalAuthorityV2(input, config, generatedAt) {
|
|
|
38658
38955
|
const surfaceContrast = bestContrastTextColor(colors.surface);
|
|
38659
38956
|
const accentChannels = hexChannels(colors.accent);
|
|
38660
38957
|
const generatedAtIso = generatedAt.toISOString();
|
|
38661
|
-
const social = flags.socialLinks && input.socialLinks.length > 0 ? `<nav class="social" aria-label="Professional profiles">${input.socialLinks.map((link) => `<a href="${safeHref2(link.href)}">${
|
|
38958
|
+
const social = flags.socialLinks && input.socialLinks.length > 0 ? `<nav class="social" aria-label="Professional profiles">${input.socialLinks.map((link) => `<a href="${safeHref2(link.href)}">${escapeHtml9(link.label)}</a>`).join("")}</nav>` : "";
|
|
38662
38959
|
const navigation = flags.navigation ? `<button class="menu" type="button" aria-expanded="false" aria-controls="nav">Menu</button><nav id="nav" class="nav" aria-label="Primary navigation"><a href="#about">About</a><a href="#services">Work</a><a href="#proof">Proof</a><a href="#contact">Contact</a></nav>` : "";
|
|
38663
38960
|
const authority = input.authority;
|
|
38664
38961
|
const consultation = input.consultation;
|
|
@@ -38670,22 +38967,22 @@ function renderPersonalAuthorityV2(input, config, generatedAt) {
|
|
|
38670
38967
|
<html lang="en" data-theme="${config.theme}">
|
|
38671
38968
|
<head>
|
|
38672
38969
|
<meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
|
|
38673
|
-
<meta name="description" content="${
|
|
38970
|
+
<meta name="description" content="${escapeHtml9(input.summary)}"><title>${escapeHtml9(input.name)} - ${escapeHtml9(input.professionalTitle)}</title>
|
|
38674
38971
|
<style>
|
|
38675
38972
|
:root{--accent:${colors.accent};--accent-rgb:${accentChannels};--accent-contrast:${accentContrast};--background:${colors.background};--surface:${colors.surface};--surface-contrast:${surfaceContrast};--text:${colors.text};--muted:color-mix(in srgb,var(--text) 68%,var(--background));--surface-muted:color-mix(in srgb,var(--surface-contrast) 72%,var(--surface));--line:color-mix(in srgb,var(--text) 16%,var(--background));--display:${displayFont};--body:${bodyFont}}*{box-sizing:border-box}html{scroll-behavior:smooth}body{margin:0;background:var(--background);color:var(--text);font-family:var(--body);line-height:1.55}a{color:inherit}.skip{position:absolute;left:-9999px}.skip:focus{left:16px;top:16px;z-index:9;background:var(--accent);color:var(--accent-contrast);padding:10px 14px;border-radius:999px}.header{height:80px;display:flex;align-items:center;justify-content:space-between;padding:0 clamp(20px,4vw,72px);position:relative;z-index:3;background:var(--surface);color:var(--surface-contrast);border-radius:0 0 24px 24px}.brand{display:flex;align-items:center;gap:12px;text-decoration:none;font-family:var(--display);font-size:24px}.mark{width:40px;height:40px;border-radius:12px;display:grid;place-items:center;background:var(--accent);color:var(--accent-contrast);font-family:var(--body);font-weight:700}.nav{display:flex;align-items:center;gap:28px}.nav a{text-decoration:none;color:var(--surface-muted);font-size:14px}.nav a:hover{color:var(--surface-contrast)}.nav a:focus-visible,.button:focus-visible,.social a:focus-visible,.menu:focus-visible{outline:3px solid var(--accent);outline-offset:4px}.menu{display:none;background:transparent;color:var(--surface-contrast);border:1px solid color-mix(in srgb,var(--surface-contrast) 28%,var(--surface));border-radius:999px;padding:10px 14px}.hero{display:grid;grid-template-columns:minmax(0,.9fr) minmax(0,1.25fr);min-height:min(760px,calc(100dvh - 80px));border-bottom:1px solid var(--line);background:var(--background)}.portrait{margin:clamp(16px,3vw,36px) clamp(12px,2vw,24px) clamp(16px,3vw,36px) clamp(16px,3vw,36px);display:grid;place-items:end center;background:var(--surface);border-radius:28px;overflow:hidden}.portrait-card{width:min(82%,560px);aspect-ratio:4/5;display:grid;place-items:center;align-self:end;border:1px solid color-mix(in srgb,var(--surface-contrast) 18%,var(--surface));border-bottom:0;background:linear-gradient(145deg,color-mix(in srgb,var(--surface-contrast) 12%,var(--surface)),var(--surface) 66%);font-family:var(--display);font-size:clamp(80px,13vw,180px);color:var(--surface-contrast)}.hero-copy{padding:clamp(44px,7vw,110px) clamp(24px,6vw,100px);display:flex;flex-direction:column;justify-content:center;background:var(--background)}h1,h2,h3,p{margin-top:0}.hero h1{font-family:var(--display);font-size:clamp(58px,8vw,116px);line-height:.96;font-weight:500;letter-spacing:-.04em;color:var(--text);margin-bottom:24px;text-wrap:balance}.role{font-family:var(--display);font-size:clamp(28px,3.8vw,52px);line-height:1.08;border-left:5px solid var(--accent);padding-left:22px;max-width:820px;text-wrap:balance}.summary{color:var(--muted);font-size:clamp(17px,1.5vw,22px);max-width:65ch}.actions{display:flex;gap:12px;flex-wrap:wrap;margin:24px 0}.button{display:inline-flex;align-items:center;justify-content:space-between;gap:28px;min-height:58px;padding:0 26px;background:var(--accent);color:var(--accent-contrast);border:1px solid var(--accent);border-radius:999px;text-decoration:none;font-weight:700;transition:transform .2s ease,filter .2s ease}.button:hover{filter:brightness(1.06)}.button:active{transform:translateY(1px)}.button--secondary{background:transparent;color:var(--text);border-color:var(--line)}.social{display:flex;gap:10px;flex-wrap:wrap}.social a{border:1px solid var(--line);border-radius:999px;padding:8px 13px;text-decoration:none;color:var(--muted);font-size:13px}.light{background:var(--background);color:var(--text);padding:clamp(70px,10vw,150px) clamp(20px,6vw,90px)}.light h2,.section h2{font-family:var(--display);font-size:clamp(42px,6vw,82px);line-height:1.05;font-weight:500;letter-spacing:-.035em;max-width:1080px;text-wrap:balance}.light p{max-width:65ch;color:var(--muted);font-size:18px}.section{padding:clamp(70px,9vw,130px) clamp(20px,6vw,90px);border-bottom:1px solid var(--line)}.section-head{max-width:920px;margin-bottom:46px}.eyebrow{text-transform:uppercase;letter-spacing:.18em;font-size:12px;color:var(--accent);font-weight:700}.consult{margin:clamp(20px,4vw,64px);display:grid;grid-template-columns:1.3fr .7fr;gap:50px;background:var(--surface);color:var(--surface-contrast);border:0;border-radius:28px}.consult .summary{color:var(--surface-muted)}.accent-card{min-height:360px;border:1px solid color-mix(in srgb,var(--surface-contrast) 18%,var(--surface));border-radius:24px;background:color-mix(in srgb,var(--accent) 14%,var(--surface));display:grid;place-items:center;font-family:var(--display);font-size:96px;color:var(--surface-contrast)}.grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:20px}.card{padding:30px;min-height:240px;border-radius:28px;background:var(--surface);color:var(--surface-contrast)}.card h3{font-family:var(--display);font-size:30px}.card p{color:var(--surface-muted)}.card .button--secondary{color:var(--surface-contrast);border-color:color-mix(in srgb,var(--surface-contrast) 28%,var(--surface))}.learning{background:var(--background)}.topic-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:20px}.topic{background:color-mix(in srgb,var(--text) 5%,var(--background));color:var(--text);border:1px solid var(--line);border-radius:28px;padding:30px}.topic strong{display:block;color:var(--accent);text-transform:uppercase;font-size:11px;letter-spacing:.15em}.topic h3{font-family:var(--display);font-size:30px;margin:8px 0}.topic p{color:var(--muted)}.topic a{color:var(--text);font-weight:700}.proof{background:color-mix(in srgb,var(--text) 5%,var(--background))}.quotes{display:flex;gap:14px;overflow:auto;scroll-snap-type:x mandatory;padding-bottom:12px}.quote{min-width:min(420px,86vw);scroll-snap-align:start;border:1px solid var(--line);border-radius:24px;padding:30px;background:var(--background)}.quote q{font-family:var(--display);font-size:30px;line-height:1.25}.quote span{display:block;margin-top:24px;color:var(--muted);font-size:12px;text-transform:uppercase;letter-spacing:.12em}.cta{margin:clamp(20px,4vw,64px);text-align:center;border:0;border-radius:28px;background:var(--surface);color:var(--surface-contrast)}.cta .summary{color:var(--surface-muted);margin-left:auto;margin-right:auto}.cta h2{margin-left:auto;margin-right:auto}.footer{display:grid;grid-template-columns:1fr auto;gap:40px;padding:46px clamp(20px,6vw,90px);color:var(--muted);background:var(--background)}.footer strong{color:var(--text);font-family:var(--display);font-size:26px}.generated{font-size:11px;color:var(--muted);margin-top:10px}.sr-only{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0,0,0,0)}
|
|
38676
38973
|
@media(max-width:760px){.header{height:78px;border-radius:0 0 18px 18px}.menu{display:block}.nav{display:none;position:absolute;left:0;right:0;top:77px;padding:18px 20px;background:var(--surface);border-radius:0 0 18px 18px;flex-direction:column;align-items:stretch}.nav.open{display:flex}.hero{grid-template-columns:1fr;min-height:0}.portrait{min-height:390px;margin:16px;border-radius:22px}.portrait-card{width:72%;max-height:360px}.hero-copy{padding:36px 20px 66px}.hero h1{font-size:58px}.role{font-size:34px}.actions{display:grid}.button{width:100%}.consult{grid-template-columns:1fr;margin:16px;border-radius:22px}.cta{margin:16px;border-radius:22px}.accent-card{min-height:220px}.grid,.topic-grid{grid-template-columns:1fr}.card,.topic{border-radius:22px}.light,.section{padding:64px 20px}.consult,.cta{padding:52px 20px}.light h2,.section h2{font-size:46px}.footer{grid-template-columns:1fr}}
|
|
38677
38974
|
@media(prefers-reduced-motion:reduce){html{scroll-behavior:auto}.button{transition:none}}
|
|
38678
38975
|
</style></head>
|
|
38679
38976
|
<body><a class="skip" href="#main">Skip to main content</a>
|
|
38680
|
-
<header class="header"><a class="brand" href="#top"><span class="mark">${
|
|
38681
|
-
<main id="main"><section class="hero" id="top"><div class="portrait" aria-label="Portrait placeholder"><div class="portrait-card" aria-hidden="true">${
|
|
38682
|
-
${section2(flags.authority && Boolean(authority), `<section class="light" id="about"><h2>${
|
|
38683
|
-
${section2(flags.consultation && Boolean(consultation), `<section class="section consult"><div><p class="eyebrow">${
|
|
38684
|
-
${section2(flags.learning && Boolean(learning), `<section class="section learning"><div class="section-head"><h2>${
|
|
38685
|
-
${section2(flags.services && Boolean(services), `<section class="section" id="services"><div class="section-head"><h2>${
|
|
38686
|
-
${section2(flags.proof && Boolean(proof), `<section class="section proof" id="proof"><div class="section-head"><h2>${
|
|
38687
|
-
${section2(flags.finalCta && Boolean(finalCta), `<section class="section cta" id="contact"><p class="eyebrow">${
|
|
38688
|
-
</main><footer class="footer"><div><strong>${
|
|
38977
|
+
<header class="header"><a class="brand" href="#top"><span class="mark">${escapeHtml9(initials2(input.name).slice(0, 1))}</span><strong>${escapeHtml9(brand)}</strong></a>${navigation}</header>
|
|
38978
|
+
<main id="main"><section class="hero" id="top"><div class="portrait" aria-label="Portrait placeholder"><div class="portrait-card" aria-hidden="true">${escapeHtml9(initials2(input.name))}</div></div><div class="hero-copy"><h1>${escapeHtml9(input.name)}</h1><p class="role">${escapeHtml9(input.professionalTitle)}</p><p class="summary">${escapeHtml9(input.summary)}</p><div class="actions">${action2(input.primaryAction)}${input.secondaryAction ? action2(input.secondaryAction, true) : ""}</div>${social}</div></section>
|
|
38979
|
+
${section2(flags.authority && Boolean(authority), `<section class="light" id="about"><h2>${escapeHtml9(authority?.heading ?? "")}</h2>${authority?.paragraphs.map((paragraph) => `<p>${escapeHtml9(paragraph)}</p>`).join("") ?? ""}</section>`)}
|
|
38980
|
+
${section2(flags.consultation && Boolean(consultation), `<section class="section consult"><div><p class="eyebrow">${escapeHtml9(consultation?.eyebrow ?? "Start a conversation")}</p><h2>${escapeHtml9(consultation?.heading ?? "")}</h2><p class="summary">${escapeHtml9(consultation?.summary ?? "")}</p>${consultation ? action2(consultation.action) : ""}</div><div class="accent-card" aria-label="Image placeholder">${escapeHtml9(initials2(input.name))}</div></section>`)}
|
|
38981
|
+
${section2(flags.learning && Boolean(learning), `<section class="section learning"><div class="section-head"><h2>${escapeHtml9(learning?.heading ?? "")}</h2><p class="summary">${escapeHtml9(learning?.summary ?? "")}</p></div><div class="topic-grid">${learning?.topics.map((topic) => `<article class="topic"><strong>${escapeHtml9(topic.title)}</strong><h3>${escapeHtml9(topic.headline)}</h3><p>${escapeHtml9(topic.summary)}</p>${topic.href ? `<a href="${safeHref2(topic.href)}">Explore \u2192</a>` : ""}</article>`).join("") ?? ""}</div></section>`)}
|
|
38982
|
+
${section2(flags.services && Boolean(services), `<section class="section" id="services"><div class="section-head"><h2>${escapeHtml9(services?.heading ?? "")}</h2><p class="summary">${escapeHtml9(services?.summary ?? "")}</p></div><div class="grid">${services?.offers.map((offer) => `<article class="card"><h3>${escapeHtml9(offer.title)}</h3><p>${escapeHtml9(offer.description)}</p>${offer.action ? action2(offer.action, true) : ""}</article>`).join("") ?? ""}</div></section>`)}
|
|
38983
|
+
${section2(flags.proof && Boolean(proof), `<section class="section proof" id="proof"><div class="section-head"><h2>${escapeHtml9(proof?.heading ?? "")}</h2><p class="summary">${escapeHtml9(proof?.summary ?? "")}</p></div><div class="quotes">${proof?.testimonials.map((item) => `<article class="quote"><q>${escapeHtml9(item.quote)}</q><span>${escapeHtml9(item.person)}${item.role ? ` / ${escapeHtml9(item.role)}` : ""}</span></article>`).join("") ?? ""}</div></section>`)}
|
|
38984
|
+
${section2(flags.finalCta && Boolean(finalCta), `<section class="section cta" id="contact"><p class="eyebrow">${escapeHtml9(finalCta?.eyebrow ?? "Ready when you are")}</p><h2>${escapeHtml9(finalCta?.heading ?? "")}</h2><p class="summary">${escapeHtml9(finalCta?.summary ?? "")}</p>${finalCta ? action2(finalCta.action) : ""}</section>`)}
|
|
38985
|
+
</main><footer class="footer"><div><strong>${escapeHtml9(input.name)}</strong><div>${escapeHtml9(input.professionalTitle)}</div>${config.showGeneratedAt ? `<div class="generated">Generated ${escapeHtml9(generatedAtIso)}</div>` : ""}</div><div>${input.location ? `<div>${escapeHtml9(input.location)}</div>` : ""}${input.email ? `<a href="mailto:${escapeHtml9(input.email)}">${escapeHtml9(input.email)}</a>` : ""}${input.phone ? `<div>${escapeHtml9(input.phone)}</div>` : ""}</div></footer>
|
|
38689
38986
|
<script>document.querySelector('.menu')?.addEventListener('click',function(){var nav=document.querySelector('.nav');var open=this.getAttribute('aria-expanded')!=='true';this.setAttribute('aria-expanded',String(open));nav?.classList.toggle('open',open)});document.querySelectorAll('.nav a').forEach(function(link){link.addEventListener('click',function(){document.querySelector('.nav')?.classList.remove('open');document.querySelector('.menu')?.setAttribute('aria-expanded','false')})});</script></body></html>`;
|
|
38690
38987
|
const bytes = Buffer.byteLength(html, "utf8");
|
|
38691
38988
|
return {
|
|
@@ -38699,7 +38996,7 @@ ${section2(flags.finalCta && Boolean(finalCta), `<section class="section cta" id
|
|
|
38699
38996
|
|
|
38700
38997
|
// src/newsroom-publisher/render.ts
|
|
38701
38998
|
import { createHash as createHash23 } from "crypto";
|
|
38702
|
-
function
|
|
38999
|
+
function escapeHtml10(value) {
|
|
38703
39000
|
return value.replace(/[&<>"']/g, (character) => ({
|
|
38704
39001
|
"&": "&",
|
|
38705
39002
|
"<": "<",
|
|
@@ -38710,30 +39007,30 @@ function escapeHtml9(value) {
|
|
|
38710
39007
|
}
|
|
38711
39008
|
function safeHref3(value) {
|
|
38712
39009
|
const trimmed = value.trim();
|
|
38713
|
-
return /^(?:https?:|mailto:|tel:|#|\/)/i.test(trimmed) ?
|
|
39010
|
+
return /^(?:https?:|mailto:|tel:|#|\/)/i.test(trimmed) ? escapeHtml10(trimmed) : "#";
|
|
38714
39011
|
}
|
|
38715
39012
|
function formatDate(value) {
|
|
38716
39013
|
const date = new Date(value);
|
|
38717
|
-
return Number.isNaN(date.getTime()) ?
|
|
39014
|
+
return Number.isNaN(date.getTime()) ? escapeHtml10(value) : new Intl.DateTimeFormat("en", { month: "short", day: "numeric", year: "numeric" }).format(date);
|
|
38718
39015
|
}
|
|
38719
39016
|
function initials3(value) {
|
|
38720
39017
|
return value.split(/\s+/).filter(Boolean).slice(0, 2).map((part) => part[0]).join("").toUpperCase();
|
|
38721
39018
|
}
|
|
38722
39019
|
function storyMedia(story, className = "") {
|
|
38723
39020
|
if (story.imageUrl) {
|
|
38724
|
-
return `<div class="story-media ${className}"><img src="${safeHref3(story.imageUrl)}" alt="${
|
|
39021
|
+
return `<div class="story-media ${className}"><img src="${safeHref3(story.imageUrl)}" alt="${escapeHtml10(story.imageAlt || story.title)}" loading="lazy"></div>`;
|
|
38725
39022
|
}
|
|
38726
39023
|
const tone = [...story.title].reduce((total, character) => total + character.charCodeAt(0), 0) % 5;
|
|
38727
|
-
return `<div class="story-media story-media--placeholder story-media--tone-${tone} ${className}" role="img" aria-label="Editorial image placeholder for ${
|
|
39024
|
+
return `<div class="story-media story-media--placeholder story-media--tone-${tone} ${className}" role="img" aria-label="Editorial image placeholder for ${escapeHtml10(story.title)}"><i></i><b></b><span>${escapeHtml10(story.category)}</span></div>`;
|
|
38728
39025
|
}
|
|
38729
39026
|
function byline(story, showBylines) {
|
|
38730
|
-
const author = story.author.href ? `<a href="${safeHref3(story.author.href)}">${
|
|
38731
|
-
return `<div class="byline">${showBylines ? `<span>By ${author}</span>` : ""}<time datetime="${
|
|
39027
|
+
const author = story.author.href ? `<a href="${safeHref3(story.author.href)}">${escapeHtml10(story.author.name)}</a>` : escapeHtml10(story.author.name);
|
|
39028
|
+
return `<div class="byline">${showBylines ? `<span>By ${author}</span>` : ""}<time datetime="${escapeHtml10(story.publishedAt)}">${formatDate(story.publishedAt)}</time>${story.sponsored ? "<b>Sponsored</b>" : ""}</div>`;
|
|
38732
39029
|
}
|
|
38733
39030
|
function storyCard(story, showBylines, variant = "") {
|
|
38734
39031
|
return `<article class="story-card ${variant}">
|
|
38735
39032
|
<a class="story-card__media" href="${safeHref3(story.href)}">${storyMedia(story)}</a>
|
|
38736
|
-
<div class="story-card__body"><a class="kicker" href="${safeHref3(story.href)}">${
|
|
39033
|
+
<div class="story-card__body"><a class="kicker" href="${safeHref3(story.href)}">${escapeHtml10(story.category)}</a><h3><a href="${safeHref3(story.href)}">${escapeHtml10(story.title)}</a></h3>${story.dek ? `<p>${escapeHtml10(story.dek)}</p>` : ""}${byline(story, showBylines)}</div>
|
|
38737
39034
|
</article>`;
|
|
38738
39035
|
}
|
|
38739
39036
|
function renderNewsroomPublisherV1(input, config, generatedAt) {
|
|
@@ -38750,22 +39047,22 @@ function renderNewsroomPublisherV1(input, config, generatedAt) {
|
|
|
38750
39047
|
input.primaryPages.contact
|
|
38751
39048
|
];
|
|
38752
39049
|
const trustPages = Object.values(input.trustPages);
|
|
38753
|
-
const ticker = flags.breakingTicker && input.ticker ? `<div class="ticker"><div><b>${
|
|
38754
|
-
const masthead = `<nav class="utility-nav" aria-label="Publication pages"><div><span>${
|
|
38755
|
-
<a class="wordmark" href="${safeHref3(input.publication.url)}"><span>${
|
|
39050
|
+
const ticker = flags.breakingTicker && input.ticker ? `<div class="ticker"><div><b>${escapeHtml10(input.ticker.label)}</b><a href="${safeHref3(input.ticker.href || "#latest")}">${escapeHtml10(input.ticker.headline)}</a><span>${formatDate(generatedAtIso)}</span></div></div>` : "";
|
|
39051
|
+
const masthead = `<nav class="utility-nav" aria-label="Publication pages"><div><span>${escapeHtml10(input.publication.location || "Independent newsroom")}</span>${primaryPages.slice(1).map((link) => `<a href="${safeHref3(link.href)}">${escapeHtml10(link.label)}</a>`).join("")}</div></nav><header class="masthead">
|
|
39052
|
+
<a class="wordmark" href="${safeHref3(input.publication.url)}"><span>${escapeHtml10(brand)}</span><small>${escapeHtml10(input.publication.tagline)}</small></a>
|
|
38756
39053
|
<div class="masthead__date"><span>Independent journalism</span><time datetime="${generatedAtIso}">${formatDate(generatedAtIso)}</time></div>
|
|
38757
39054
|
<div class="masthead__tools"><button type="button" aria-label="Search">Search</button><button type="button" aria-label="Open menu">Menu</button></div>
|
|
38758
39055
|
</header>`;
|
|
38759
|
-
const navigation = flags.navigation ? `<nav class="desk-nav" aria-label="Publication categories"><div><a class="desk-nav__home" href="#top">Home</a>${input.categories.map((category) => `<a href="${safeHref3(category.href)}">${
|
|
39056
|
+
const navigation = flags.navigation ? `<nav class="desk-nav" aria-label="Publication categories"><div><a class="desk-nav__home" href="#top">Home</a>${input.categories.map((category) => `<a href="${safeHref3(category.href)}">${escapeHtml10(category.label)}</a>`).join("")}<a class="desk-nav__latest" href="#latest">Latest</a></div></nav>` : "";
|
|
38760
39057
|
const leadGrid = flags.leadGrid ? `<section class="lead-grid" aria-label="Top stories">
|
|
38761
39058
|
<div class="lead-grid__label"><span>Today\u2019s edition</span><b>Top stories</b></div>
|
|
38762
|
-
<article class="lead-story"><a class="lead-story__media" href="${safeHref3(lead.href)}">${storyMedia(lead, "story-media--lead")}</a><div class="lead-story__body"><a class="kicker" href="${safeHref3(lead.href)}">${
|
|
39059
|
+
<article class="lead-story"><a class="lead-story__media" href="${safeHref3(lead.href)}">${storyMedia(lead, "story-media--lead")}</a><div class="lead-story__body"><a class="kicker" href="${safeHref3(lead.href)}">${escapeHtml10(lead.category)}</a><h1><a href="${safeHref3(lead.href)}">${escapeHtml10(lead.title)}</a></h1>${lead.dek ? `<p>${escapeHtml10(lead.dek)}</p>` : ""}${byline(lead, config.showBylines)}<a class="read-story" href="${safeHref3(lead.href)}">Read the full report <span>\u2197</span></a></div></article>
|
|
38763
39060
|
<div class="lead-support">${supporting.slice(0, 4).map((story, index) => `<div class="lead-support__item"><span>${String(index + 1).padStart(2, "0")}</span>${storyCard(story, config.showBylines, "story-card--support")}</div>`).join("")}</div>
|
|
38764
39061
|
</section>` : "";
|
|
38765
39062
|
const latest = flags.latestNews && input.latest.length > 0 ? `<section class="latest" id="latest">
|
|
38766
39063
|
<div class="section-title"><div><span>Live desk</span><h2>Latest news</h2></div><a href="#top">Back to top \u2191</a></div>
|
|
38767
|
-
<div class="latest__layout"><div class="latest__feed">${input.latest.map((story, index) => `<article class="feed-story"><span>${String(index + 1).padStart(2, "0")}</span><div><a class="kicker" href="${safeHref3(story.href)}">${
|
|
38768
|
-
<aside class="editor-note"><span>From the newsroom</span><h3>Reporting with context, sources, and accountable bylines.</h3><p>${
|
|
39064
|
+
<div class="latest__layout"><div class="latest__feed">${input.latest.map((story, index) => `<article class="feed-story"><span>${String(index + 1).padStart(2, "0")}</span><div><a class="kicker" href="${safeHref3(story.href)}">${escapeHtml10(story.category)}</a><h3><a href="${safeHref3(story.href)}">${escapeHtml10(story.title)}</a></h3>${story.dek ? `<p>${escapeHtml10(story.dek)}</p>` : ""}${byline(story, config.showBylines)}</div>${storyMedia(story, "story-media--feed")}</article>`).join("")}</div>
|
|
39065
|
+
<aside class="editor-note"><span>From the newsroom</span><h3>Reporting with context, sources, and accountable bylines.</h3><p>${escapeHtml10(input.editorial.disclosure)}</p>${trustPages.slice(0, 4).map((link) => `<a href="${safeHref3(link.href)}">${escapeHtml10(link.label)} \u2197</a>`).join("")}</aside></div>
|
|
38769
39066
|
</section>` : "";
|
|
38770
39067
|
const sectionLayouts = ["panorama", "mosaic", "tiles"];
|
|
38771
39068
|
const sections = flags.categorySections ? input.sections.map((section3, sectionIndex) => {
|
|
@@ -38776,16 +39073,16 @@ function renderNewsroomPublisherV1(input, config, generatedAt) {
|
|
|
38776
39073
|
layout === "panorama" && index === 0 ? "story-card--panorama" : layout === "mosaic" && index === 0 ? "story-card--mosaic-lead" : ""
|
|
38777
39074
|
)).join("");
|
|
38778
39075
|
return `<section class="desk-section desk-section--${sectionIndex % 2 ? "tint" : "plain"} desk-section--layout-${layout}">
|
|
38779
|
-
<div class="section-title"><div><span>Coverage desk \xB7 ${String(sectionIndex + 1).padStart(2, "0")}</span><h2>${
|
|
39076
|
+
<div class="section-title"><div><span>Coverage desk \xB7 ${String(sectionIndex + 1).padStart(2, "0")}</span><h2>${escapeHtml10(section3.name)}</h2></div>${section3.href ? `<a href="${safeHref3(section3.href)}">View all ${escapeHtml10(section3.name)} \u2192</a>` : ""}</div>
|
|
38780
39077
|
<div class="desk-section__grid desk-section__grid--${layout}">${cards}</div>
|
|
38781
39078
|
</section>`;
|
|
38782
39079
|
}).join("") : "";
|
|
38783
|
-
const newsletter = flags.newsletter && input.newsletter ? `<section class="newsletter"><div><span>${
|
|
38784
|
-
const pressRoom = flags.pressRoom && input.pressRoom ? `<section class="press-room" id="press-room"><div class="press-room__intro"><span>Separate from editorial coverage</span><h2>${
|
|
38785
|
-
const trustCenter = `<section class="trust-center" id="trust"><div class="trust-center__intro"><span>Public record</span><h2>How this newsroom works.</h2><p>Ownership, editorial practice, technology use, commercial relationships, and reader rights should be easy to find\u2014and written to be understood.</p></div><div class="trust-center__grid">${trustPages.map((link, index) => `<a href="${safeHref3(link.href)}"><span>${String(index + 1).padStart(2, "0")}</span><strong>${
|
|
38786
|
-
const trustFooter = flags.trustFooter ? `<footer class="site-footer"><div class="editor"><span class="editor__avatar">${
|
|
39080
|
+
const newsletter = flags.newsletter && input.newsletter ? `<section class="newsletter"><div><span>${escapeHtml10(input.newsletter.eyebrow || "Reader briefing")}</span><h2>${escapeHtml10(input.newsletter.heading)}</h2><p>${escapeHtml10(input.newsletter.summary)}</p></div><a href="${safeHref3(input.newsletter.action.href)}">${escapeHtml10(input.newsletter.action.label)} \u2192</a></section>` : "";
|
|
39081
|
+
const pressRoom = flags.pressRoom && input.pressRoom ? `<section class="press-room" id="press-room"><div class="press-room__intro"><span>Separate from editorial coverage</span><h2>${escapeHtml10(input.pressRoom.heading)}</h2><p>${escapeHtml10(input.pressRoom.summary)}</p><a href="${safeHref3(input.pressRoom.action.href)}">${escapeHtml10(input.pressRoom.action.label)} \u2192</a></div><div class="release-list">${input.pressRoom.releases.map((release) => `<article><time datetime="${escapeHtml10(release.publishedAt)}">${formatDate(release.publishedAt)}</time><span>${escapeHtml10(release.originatingCity)}</span><h3><a href="${safeHref3(release.href)}">${escapeHtml10(release.headline)}</a></h3></article>`).join("") || "<p>No releases are currently published.</p>"}</div></section>` : "";
|
|
39082
|
+
const trustCenter = `<section class="trust-center" id="trust"><div class="trust-center__intro"><span>Public record</span><h2>How this newsroom works.</h2><p>Ownership, editorial practice, technology use, commercial relationships, and reader rights should be easy to find\u2014and written to be understood.</p></div><div class="trust-center__grid">${trustPages.map((link, index) => `<a href="${safeHref3(link.href)}"><span>${String(index + 1).padStart(2, "0")}</span><strong>${escapeHtml10(link.label)}</strong><small>Read \u2192</small></a>`).join("")}</div></section>`;
|
|
39083
|
+
const trustFooter = flags.trustFooter ? `<footer class="site-footer"><div class="editor"><span class="editor__avatar">${escapeHtml10(initials3(input.editorial.managingEditor.name))}</span><div><small>${escapeHtml10(input.editorial.managingEditor.role)}</small><h2>${input.editorial.managingEditor.href ? `<a href="${safeHref3(input.editorial.managingEditor.href)}">${escapeHtml10(input.editorial.managingEditor.name)}</a>` : escapeHtml10(input.editorial.managingEditor.name)}</h2><p>${escapeHtml10(input.editorial.managingEditor.bio)}</p></div></div><div class="footer-links"><h3>${escapeHtml10(brand)}</h3><p>${escapeHtml10(input.publication.tagline)}</p><nav>${primaryPages.map((link) => `<a href="${safeHref3(link.href)}">${escapeHtml10(link.label)}</a>`).join("")}</nav>${config.showGeneratedAt ? `<time datetime="${generatedAtIso}">Updated ${formatDate(generatedAtIso)}</time>` : ""}</div></footer>` : "";
|
|
38787
39084
|
const html = `<!doctype html>
|
|
38788
|
-
<html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><meta name="robots" content="noindex,nofollow"><title>${
|
|
39085
|
+
<html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><meta name="robots" content="noindex,nofollow"><title>${escapeHtml10(brand)} \xB7 News Publisher</title><link rel="preconnect" href="https://fonts.googleapis.com"><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin><link href="https://fonts.googleapis.com/css2?family=Archivo:wdth,wght@75..125,300..900&family=Instrument+Serif:ital@0;1&family=JetBrains+Mono:wght@400;600&display=swap" rel="stylesheet">
|
|
38789
39086
|
<style>
|
|
38790
39087
|
:root{--ink:#0b0b0c;--soft-ink:#222326;--muted:#696b70;--paper:#fff;--cream:#f4f0e8;--wash:#f5f5f3;--line:#d8d8d4;--signal:#275cf3;--acid:#d9ff43;--dark:#0b0b0c;--serif:"Instrument Serif",Georgia,serif;--sans:"Archivo",Arial,sans-serif;--mono:"JetBrains Mono",monospace;font-family:var(--sans);color:var(--ink);background:var(--paper)}*{box-sizing:border-box}html{scroll-behavior:smooth}body{margin:0;background:var(--paper);line-height:1.45}body[data-theme=journal]{--cream:#eee7da;--signal:#9d2d25;--acid:#f0c84f}body[data-theme=midnight]{--paper:#e8e9ec;--cream:#dfe1e6;--wash:#d8dae0;--line:#b9bdc6;--signal:#224bcc}a{color:inherit;text-decoration:none}a,button{transition:color .18s ease,background .18s ease,opacity .18s ease,transform .18s ease}button{font:inherit}.utility-nav{color:#d2d2d2;background:var(--dark);border-bottom:1px solid #292929}.utility-nav>div{max-width:1180px;height:35px;margin:auto;display:flex;align-items:center;justify-content:flex-end;gap:20px;padding:0 18px;overflow:auto}.utility-nav span{margin-right:auto;color:#8d8d8d}.utility-nav a,.utility-nav span{font:600 8px/1 var(--mono);letter-spacing:.08em;text-transform:uppercase;white-space:nowrap}.utility-nav a:hover{color:#fff}.ticker{color:var(--ink);background:var(--acid);padding:0 18px}.ticker>div{max-width:1180px;height:36px;margin:auto;display:flex;align-items:center;gap:16px;font:600 10px/1 var(--mono)}.ticker b{padding:5px 7px;color:#fff;background:var(--ink);font-size:8px;letter-spacing:.1em;text-transform:uppercase}.ticker a{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.ticker a:hover{text-decoration:underline}.ticker span{margin-left:auto;opacity:.58;font-size:8px;text-transform:uppercase}.masthead{max-width:1180px;height:126px;margin:auto;display:grid;grid-template-columns:minmax(0,1fr) auto auto;align-items:center;gap:42px;padding:0 18px}.wordmark{display:grid;justify-self:start}.wordmark span{font:400 clamp(40px,5vw,68px)/.82 var(--serif);letter-spacing:-.055em}.wordmark small{max-width:430px;margin-top:11px;color:var(--muted);font:600 8px/1 var(--mono);letter-spacing:.1em;text-transform:uppercase}.masthead__date{display:grid;gap:3px;text-align:right}.masthead__date span,.masthead__date time{font:600 8px/1.4 var(--mono);letter-spacing:.08em;text-transform:uppercase}.masthead__date span{color:var(--signal)}.masthead__date time{color:var(--muted)}.masthead__tools{display:flex;border:1px solid var(--ink)}.masthead__tools button{height:38px;padding:0 13px;border:0;background:transparent;font:700 9px/1 var(--mono);text-transform:uppercase;cursor:pointer}.masthead__tools button+button{border-left:1px solid var(--ink)}.masthead__tools button:hover{color:#fff;background:var(--ink)}.desk-nav{position:sticky;top:0;z-index:20;color:var(--ink);background:rgba(255,255,255,.96);border-top:1px solid var(--ink);border-bottom:1px solid var(--ink);backdrop-filter:blur(10px)}.desk-nav>div{max-width:1180px;height:43px;margin:auto;display:flex;align-items:center;overflow-x:auto;padding:0 18px}.desk-nav a{height:42px;display:grid;place-items:center;padding:0 17px;border-right:1px solid var(--line);font:650 9px/1 var(--mono);letter-spacing:.04em;text-transform:uppercase;white-space:nowrap}.desk-nav a:first-child{border-left:1px solid var(--line)}.desk-nav a:hover,.desk-nav__home{color:#fff!important;background:var(--ink)}.desk-nav__latest{margin-left:auto;color:var(--signal);border-left:1px solid var(--line)}main{max-width:1180px;margin:auto;padding:30px 18px 90px}.lead-grid{margin:0 -18px;padding:0 18px 42px;color:#fff;background:var(--dark);border-bottom:1px solid var(--ink)}.lead-grid__label{height:50px;display:flex;align-items:center;justify-content:space-between;border-bottom:1px solid #303030}.lead-grid__label span,.lead-grid__label b{font:600 8px/1 var(--mono);letter-spacing:.12em;text-transform:uppercase}.lead-grid__label span{color:var(--acid)}.lead-grid__label b{color:#8f8f8f}.lead-story{display:grid;grid-template-columns:minmax(0,1.28fr) minmax(340px,.72fr);min-height:500px;border-bottom:1px solid #303030}.lead-story__media{display:block;margin-left:calc((1180px - 100vw)/2);min-width:0}.story-media{position:relative;aspect-ratio:16/10;overflow:hidden;background:#e2e2df}.story-media img{width:100%;height:100%;display:block;object-fit:cover;filter:saturate(.88) contrast(1.03);transition:transform .55s cubic-bezier(.2,.7,.2,1)}a:hover .story-media img{transform:scale(1.025)}.story-media--lead{height:100%;min-height:500px;aspect-ratio:auto}.story-media--placeholder{isolation:isolate;display:block;background:#d9d7d1}.story-media--placeholder:after{position:absolute;z-index:1;inset:0;background:linear-gradient(145deg,transparent 35%,rgba(0,0,0,.14));content:""}.story-media--placeholder i,.story-media--placeholder b{position:absolute;display:block}.story-media--placeholder i{width:72%;aspect-ratio:1;right:-20%;top:-32%;border:clamp(22px,5vw,72px) solid currentColor;border-radius:50%;opacity:.78}.story-media--placeholder b{width:42%;height:115%;left:15%;bottom:-45%;background:currentColor;transform:rotate(32deg);opacity:.88}.story-media--placeholder span{position:absolute;z-index:2;left:18px;bottom:15px;padding:6px 8px;color:#fff;background:var(--ink);font:600 8px/1 var(--mono);letter-spacing:.12em;text-transform:uppercase}.story-media--tone-0{color:#123fce;background:#a5c8ff}.story-media--tone-1{color:#ef4d25;background:#ffd9bd}.story-media--tone-2{color:#907000;background:#f3df36}.story-media--tone-3{color:#1a7857;background:#b8e8cc}.story-media--tone-4{color:#7d3de0;background:#dfc5ff}.lead-story__body{display:flex;flex-direction:column;justify-content:center;padding:45px 0 45px 40px}.kicker{display:inline-flex;width:max-content;color:var(--signal);font:700 8px/1 var(--mono);letter-spacing:.11em;text-transform:uppercase}.lead-grid .kicker{color:var(--acid)}.lead-story h1{max-width:540px;margin:13px 0 18px;font:400 clamp(48px,5vw,76px)/.92 var(--serif);letter-spacing:-.052em}.lead-story p{max-width:490px;margin:0;color:#bdbdbd;font-size:15px;line-height:1.55}.byline{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin-top:16px;color:var(--muted);font:600 8px/1.4 var(--mono);letter-spacing:.05em;text-transform:uppercase}.byline span{color:var(--ink);font-weight:700}.lead-grid .byline{color:#848484}.lead-grid .byline span{color:#e7e7e7}.byline b{padding:4px 6px;color:var(--ink);background:var(--acid)}.read-story{width:max-content;margin-top:34px;padding-bottom:6px;border-bottom:1px solid #777;font:650 10px/1 var(--mono);text-transform:uppercase}.read-story span{color:var(--acid)}.read-story:hover{border-color:#fff}.lead-support{display:grid;grid-template-columns:repeat(4,1fr);gap:0}.lead-support__item{display:grid;grid-template-columns:25px minmax(0,1fr);gap:12px;padding:22px 18px 0 0;border-right:1px solid #303030}.lead-support__item+.lead-support__item{padding-left:18px}.lead-support__item:last-child{border-right:0}.lead-support__item>span{color:#666;font:600 9px/1 var(--mono)}.story-card{min-width:0}.story-card h3{margin:7px 0;font:400 26px/1.02 var(--serif);letter-spacing:-.025em}.story-card p{margin:9px 0;color:var(--muted);font-size:12px}.story-card__body{padding-top:11px}.story-card--support .story-card__media{display:none}.story-card--support .story-card__body{padding:0}.story-card--support h3{margin-top:8px;color:#fff;font-size:21px}.story-card--support p,.story-card--support .byline span{display:none}.story-card--support .byline{color:#777}.section-title{display:flex;align-items:end;justify-content:space-between;gap:30px;margin-bottom:24px;padding-bottom:11px;border-bottom:2px solid var(--ink)}.section-title span,.newsletter span,.press-room__intro>span,.trust-center__intro>span{display:block;color:var(--signal);font:700 8px/1 var(--mono);letter-spacing:.12em;text-transform:uppercase}.section-title h2,.newsletter h2,.press-room h2,.trust-center h2,.site-footer h2{margin:7px 0 0;font:400 clamp(38px,5vw,58px)/.95 var(--serif);letter-spacing:-.04em}.section-title>a{padding-bottom:4px;border-bottom:1px solid var(--ink);font:650 9px/1 var(--mono);text-transform:uppercase}.latest{padding:64px 0}.latest__layout{display:grid;grid-template-columns:minmax(0,1fr) 300px;gap:55px}.latest__feed{border-top:1px solid var(--ink)}.feed-story{display:grid;grid-template-columns:34px minmax(0,1fr) 180px;gap:18px;align-items:start;padding:19px 0;border-bottom:1px solid var(--line)}.feed-story>span{color:#a0a0a0;font:600 9px/1 var(--mono)}.feed-story h3{margin:7px 0;font:400 29px/1.02 var(--serif);letter-spacing:-.025em}.feed-story p{margin:8px 0;color:var(--muted);font-size:12px}.story-media--feed{aspect-ratio:4/3}.editor-note{position:sticky;top:68px;align-self:start;padding:25px;color:#fff;background:var(--dark);border-top:5px solid var(--acid)}.editor-note>span{color:var(--acid);font:600 8px/1 var(--mono);letter-spacing:.12em;text-transform:uppercase}.editor-note h3{margin:13px 0;font:400 31px/.98 var(--serif)}.editor-note p{color:#aaa;font-size:12px}.editor-note a{display:block;padding:11px 0;border-top:1px solid #333;font:600 9px/1 var(--mono);text-transform:uppercase}.editor-note a:hover{color:var(--acid)}.desk-section{margin:0 -18px;padding:58px 18px;border-top:1px solid var(--ink)}.desk-section--tint{background:var(--cream)}.desk-section__grid{display:grid;grid-template-columns:repeat(4,1fr);gap:26px 14px}.story-card--wide{grid-column:span 2;grid-row:span 2}.story-card--wide h3{max-width:530px;font-size:40px}.story-card--wide p{max-width:540px;font-size:13px}.desk-section__grid>.story-card:not(.story-card--wide) .story-media{aspect-ratio:1}.newsletter{position:relative;margin:64px 0;display:grid;grid-template-columns:1fr auto;align-items:end;gap:50px;overflow:hidden;padding:clamp(38px,6vw,72px);color:var(--ink);background:var(--acid)}.newsletter:after{position:absolute;width:260px;height:260px;right:18%;top:-160px;border:55px solid var(--ink);border-radius:50%;content:"";opacity:.08}.newsletter span{color:var(--ink)}.newsletter h2{max-width:760px;font-size:clamp(44px,6vw,72px)}.newsletter p{max-width:680px;margin-bottom:0;color:#303030}.newsletter>a,.press-room__intro>a{position:relative;z-index:1;display:inline-flex;padding:14px 18px;color:#fff;background:var(--ink);border:1px solid var(--ink);font:700 9px/1 var(--mono);text-transform:uppercase}.newsletter>a:hover,.press-room__intro>a:hover{color:var(--ink);background:transparent}.press-room{display:grid;grid-template-columns:.7fr 1.3fr;gap:56px;padding:62px 0;border-top:6px solid var(--ink)}.press-room__intro p{max-width:390px;color:var(--muted)}.release-list{border-top:1px solid var(--ink)}.release-list article{display:grid;grid-template-columns:105px 105px 1fr;gap:15px;align-items:start;padding:20px 0;border-bottom:1px solid var(--line)}.release-list time,.release-list span{color:var(--muted);font:500 8px/1.4 var(--mono);text-transform:uppercase}.release-list h3{margin:0;font:400 22px/1.04 var(--serif)}.trust-center{margin:20px -18px -90px;padding:70px max(18px,calc((100vw - 1144px)/2)) 82px;color:#fff;background:var(--dark)}.trust-center__intro{max-width:810px;margin-bottom:38px}.trust-center__intro>span{color:var(--acid)}.trust-center__intro p{max-width:670px;color:#aaa}.trust-center__grid{display:grid;grid-template-columns:repeat(2,1fr);border-top:1px solid #444}.trust-center__grid a{display:grid;grid-template-columns:32px minmax(0,1fr) auto;align-items:center;gap:15px;min-height:70px;padding:0 18px 0 0;border-bottom:1px solid #333}.trust-center__grid a:nth-child(odd){margin-right:28px}.trust-center__grid a:hover{color:var(--acid)}.trust-center__grid span,.trust-center__grid small{color:#696969;font:600 8px/1 var(--mono)}.trust-center__grid strong{font:400 20px/1 var(--serif)}.site-footer{display:grid;grid-template-columns:1.15fr .85fr;gap:80px;padding:70px max(24px,calc((100vw - 1144px)/2));color:var(--ink);background:var(--cream);border-top:1px solid var(--ink)}.editor{display:grid;grid-template-columns:78px 1fr;gap:22px}.editor__avatar{width:78px;height:78px;display:grid;place-items:center;color:#fff;background:var(--signal);font:400 27px/1 var(--serif)}.editor small{color:var(--signal);font:700 8px/1 var(--mono);letter-spacing:.08em;text-transform:uppercase}.editor h2{font-size:38px}.editor p,.footer-links p{max-width:620px;color:var(--muted)}.footer-links h3{margin-top:0;font:400 29px/1 var(--serif)}.footer-links nav{display:grid;grid-template-columns:1fr 1fr;border-top:1px solid var(--ink)}.footer-links nav a{padding:9px 0;border-bottom:1px solid var(--line);font:600 8px/1 var(--mono);text-transform:uppercase}.footer-links time{display:block;margin-top:24px;color:var(--muted);font:500 8px/1 var(--mono)}@media(max-width:900px){.masthead{grid-template-columns:1fr auto;height:110px}.masthead__date{display:none}.lead-story{grid-template-columns:1fr}.lead-story__media{margin:0}.lead-story__body{padding:35px 0}.lead-support{grid-template-columns:1fr 1fr}.lead-support__item:nth-child(2){border-right:0}.lead-support__item:nth-child(n+3){border-top:1px solid #303030}.latest__layout,.press-room,.site-footer{grid-template-columns:1fr}.editor-note{position:static}.desk-section__grid{grid-template-columns:1fr 1fr}.story-card--wide{grid-column:1/-1}.site-footer{gap:40px}.feed-story{grid-template-columns:30px 1fr 150px}}@media(max-width:620px){.utility-nav span,.utility-nav a:nth-of-type(-n+2),.ticker span{display:none}.ticker>div{height:34px}.masthead{height:92px;gap:14px}.wordmark span{font-size:38px}.wordmark small{max-width:220px;font-size:6px}.masthead__tools button:first-child{display:none}.desk-nav>div{padding:0}.desk-nav a{padding:0 13px}.lead-grid{padding-bottom:20px}.lead-grid__label{height:40px}.story-media--lead{min-height:320px}.lead-story{min-height:0}.lead-story h1{font-size:48px}.lead-story__body{padding:27px 0 34px}.lead-support{grid-template-columns:1fr}.lead-support__item,.lead-support__item+.lead-support__item{padding:17px 0;border-right:0;border-top:1px solid #303030}.story-card--support h3{font-size:24px}.section-title{align-items:start}.section-title>a{display:none}.latest{padding:48px 0}.feed-story{grid-template-columns:25px 1fr}.story-media--feed{grid-column:2}.feed-story h3{font-size:26px}.desk-section__grid{grid-template-columns:1fr}.story-card--wide{grid-column:auto;grid-row:auto}.story-card--wide h3{font-size:34px}.newsletter{grid-template-columns:1fr}.newsletter h2{font-size:48px}.release-list article{grid-template-columns:1fr}.trust-center__grid{grid-template-columns:1fr}.trust-center__grid a:nth-child(odd){margin-right:0}.site-footer{padding:50px 20px}.editor{grid-template-columns:1fr}.footer-links nav{grid-template-columns:1fr}}
|
|
38791
39088
|
/* Tampa-inspired publication palette */
|
|
@@ -38802,7 +39099,7 @@ body{overflow-x:hidden}.lead-story__body,.lead-support__item,.story-card__body{m
|
|
|
38802
39099
|
@media(max-width:620px){main{width:100%}.story-media--lead{height:360px;min-height:0}.lead-story__body,.lead-support,.latest,.feed-story{width:100%;max-width:calc(100vw - 36px)}.feed-story>div{min-width:0}.lead-story h1,.story-card h3,.feed-story h3,.story-card h3 a,.feed-story h3 a{white-space:normal;word-break:break-word;overflow-wrap:anywhere}.lead-story h1{max-width:100%;font-size:40px;line-height:.94}.lead-support__item{width:100%;max-width:100%;grid-template-columns:24px minmax(0,1fr);overflow:hidden}.story-card--support,.story-card--support .story-card__body,.story-card--support h3{width:100%;max-width:calc(100vw - 92px)}.feed-story>div,.feed-story h3,.feed-story p{max-width:calc(100vw - 100px)}}
|
|
38803
39100
|
@media(max-width:900px){.story-card--panorama{grid-template-columns:1fr}.desk-section__grid--mosaic{grid-template-columns:repeat(2,1fr)}.desk-section__grid--tiles{grid-template-columns:repeat(2,1fr)}}
|
|
38804
39101
|
@media(max-width:620px){.desk-section__grid--panorama,.desk-section__grid--mosaic,.desk-section__grid--tiles{grid-template-columns:1fr}.story-card--panorama{display:block}.story-card--panorama h3,.story-card--mosaic-lead h3{font-size:34px}.story-card--mosaic-lead{grid-column:auto;grid-row:auto}.desk-section__grid--tiles>.story-card:nth-child(3n+2){margin-top:0}}
|
|
38805
|
-
</style></head><body data-theme="${
|
|
39102
|
+
</style></head><body data-theme="${escapeHtml10(config.theme)}" id="top" data-scheduled-renderer="newsroom_publisher_v1">${ticker}${masthead}${navigation}<main>${leadGrid}${latest}${sections}${newsletter}${pressRoom}${trustCenter}</main>${trustFooter}</body></html>`;
|
|
38806
39103
|
const bytes = Buffer.byteLength(html);
|
|
38807
39104
|
const sha2563 = createHash23("sha256").update(html).digest("hex");
|
|
38808
39105
|
const filename = `${brand.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "") || "newsroom"}-news-site.html`;
|
|
@@ -38811,7 +39108,7 @@ body{overflow-x:hidden}.lead-story__body,.lead-support__item,.story-card__body{m
|
|
|
38811
39108
|
|
|
38812
39109
|
// src/blog-article/render.ts
|
|
38813
39110
|
import { createHash as createHash24 } from "crypto";
|
|
38814
|
-
function
|
|
39111
|
+
function escapeHtml11(value) {
|
|
38815
39112
|
return value.replace(
|
|
38816
39113
|
/[&<>"']/g,
|
|
38817
39114
|
(character) => ({
|
|
@@ -38825,11 +39122,11 @@ function escapeHtml10(value) {
|
|
|
38825
39122
|
}
|
|
38826
39123
|
function safeHref4(value) {
|
|
38827
39124
|
const trimmed = value.trim();
|
|
38828
|
-
return /^(?:https?:|mailto:|tel:|#|\/)/i.test(trimmed) ?
|
|
39125
|
+
return /^(?:https?:|mailto:|tel:|#|\/)/i.test(trimmed) ? escapeHtml11(trimmed) : "#";
|
|
38829
39126
|
}
|
|
38830
39127
|
function formatDate2(value) {
|
|
38831
39128
|
const date = new Date(value);
|
|
38832
|
-
return Number.isNaN(date.getTime()) ?
|
|
39129
|
+
return Number.isNaN(date.getTime()) ? escapeHtml11(value) : new Intl.DateTimeFormat("en", {
|
|
38833
39130
|
month: "long",
|
|
38834
39131
|
day: "numeric",
|
|
38835
39132
|
year: "numeric"
|
|
@@ -38843,15 +39140,15 @@ function jsonForScript(value) {
|
|
|
38843
39140
|
}
|
|
38844
39141
|
function portrait(input) {
|
|
38845
39142
|
if (input.author.portraitUrl) {
|
|
38846
|
-
return `<img class="author-portrait" src="${safeHref4(input.author.portraitUrl)}" alt="${
|
|
39143
|
+
return `<img class="author-portrait" src="${safeHref4(input.author.portraitUrl)}" alt="${escapeHtml11(input.author.portraitAlt || input.author.name)}">`;
|
|
38847
39144
|
}
|
|
38848
|
-
return `<span class="author-portrait author-initials" aria-label="${
|
|
39145
|
+
return `<span class="author-portrait author-initials" aria-label="${escapeHtml11(input.author.name)}">${escapeHtml11(initials4(input.author.name))}</span>`;
|
|
38849
39146
|
}
|
|
38850
39147
|
function sidebarArt(input) {
|
|
38851
39148
|
if (input.sidebarMedia?.imageUrl) {
|
|
38852
|
-
return `<img src="${safeHref4(input.sidebarMedia.imageUrl)}" alt="${
|
|
39149
|
+
return `<img src="${safeHref4(input.sidebarMedia.imageUrl)}" alt="${escapeHtml11(input.sidebarMedia.imageAlt)}">`;
|
|
38853
39150
|
}
|
|
38854
|
-
return `<svg viewBox="0 0 560 330" role="img" aria-label="${
|
|
39151
|
+
return `<svg viewBox="0 0 560 330" role="img" aria-label="${escapeHtml11(input.sidebarMedia?.imageAlt || "Editorial article illustration")}"><defs><linearGradient id="ba-sky" x1="0" x2="1"><stop stop-color="#dbeafe"/><stop offset="1" stop-color="#d1fae5"/></linearGradient></defs><rect width="560" height="330" fill="url(#ba-sky)"/><circle cx="455" cy="72" r="88" fill="#93c5fd" opacity=".35"/><path d="M76 180 280 42l204 138v118H76Z" fill="#fff"/><path d="M52 185 280 28l228 157" fill="none" stroke="#10213d" stroke-width="18" stroke-linecap="round" stroke-linejoin="round"/><rect x="232" y="180" width="96" height="118" rx="8" fill="#bfdbfe"/><circle cx="385" cy="178" r="40" fill="#f8d5b8"/><path d="M335 330v-70c0-39 22-68 50-68s50 29 50 68v70" fill="#2563eb"/><circle cx="458" cy="196" r="34" fill="#8b5e3c"/><path d="M418 330v-64c0-34 18-60 40-60s40 26 40 60v64" fill="#45d5aa"/></svg>`;
|
|
38855
39152
|
}
|
|
38856
39153
|
function citations(input) {
|
|
38857
39154
|
const published = new Date(input.publishedAt);
|
|
@@ -38880,23 +39177,23 @@ function renderBlogArticleV1(input, config, generatedAt) {
|
|
|
38880
39177
|
...flags.faq && input.faq.length ? [{ id: "faq", title: "Frequently asked questions" }] : []
|
|
38881
39178
|
];
|
|
38882
39179
|
const contributorText = [
|
|
38883
|
-
`Written by <a href="${safeHref4(input.author.href || "#author")}">${
|
|
38884
|
-
input.editor ? `Edited by <a href="${safeHref4(input.editor.href || "#")}">${
|
|
38885
|
-
input.reviewer ? `Reviewed by <a href="${safeHref4(input.reviewer.href || "#")}">${
|
|
39180
|
+
`Written by <a href="${safeHref4(input.author.href || "#author")}">${escapeHtml11(input.author.name)}</a>`,
|
|
39181
|
+
input.editor ? `Edited by <a href="${safeHref4(input.editor.href || "#")}">${escapeHtml11(input.editor.name)}</a>` : "",
|
|
39182
|
+
input.reviewer ? `Reviewed by <a href="${safeHref4(input.reviewer.href || "#")}">${escapeHtml11(input.reviewer.name)}${input.reviewer.credential ? `, ${escapeHtml11(input.reviewer.credential)}` : ""}</a>` : ""
|
|
38886
39183
|
].filter(Boolean).join(" \xB7 ");
|
|
38887
39184
|
const sections = input.sections.map(
|
|
38888
|
-
(section3) => `<section id="${
|
|
39185
|
+
(section3) => `<section id="${escapeHtml11(section3.id)}" class="article-section"><header>${section3.eyebrow ? `<span class="eyebrow">${escapeHtml11(section3.eyebrow)}</span>` : ""}<h2>${escapeHtml11(section3.title)}</h2></header>${section3.paragraphs.map((paragraph) => `<p>${escapeHtml11(paragraph)}</p>`).join("")}${section3.bullets?.length ? `<ul>${section3.bullets.map((item) => `<li>${escapeHtml11(item)}</li>`).join("")}</ul>` : ""}${section3.callout ? `<aside class="callout"><span>Worth noting</span><h3>${escapeHtml11(section3.callout.heading)}</h3><p>${escapeHtml11(section3.callout.body)}</p></aside>` : ""}</section>`
|
|
38889
39186
|
).join("");
|
|
38890
|
-
const faq = flags.faq && input.faq.length ? `<section id="faq" class="faq"><span class="eyebrow">Common questions</span><h2>Frequently asked questions</h2><div>${input.faq.map((item, index) => `<article><h3><button type="button" aria-expanded="false" aria-controls="faq-${index}"><span>${
|
|
38891
|
-
const media = flags.sidebarMedia && input.sidebarMedia ? `<figure class="sidebar-media" data-article-media>${sidebarArt(input)}${input.sidebarMedia.caption ? `<figcaption>${
|
|
38892
|
-
const disclosure = flags.disclosure && input.disclosure ? `<section class="disclosure"><button type="button" aria-expanded="false" aria-controls="disclosure-details"><span>${
|
|
38893
|
-
const toc = flags.stickyToc ? `<aside class="toc" data-sticky-toc><header><strong>Table of contents</strong><button type="button" aria-expanded="true" aria-controls="toc-links" aria-label="Collapse table of contents">\u2303</button></header><nav id="toc-links" aria-label="Table of contents">${tocItems.map((item, index) => `<a href="#${
|
|
39187
|
+
const faq = flags.faq && input.faq.length ? `<section id="faq" class="faq"><span class="eyebrow">Common questions</span><h2>Frequently asked questions</h2><div>${input.faq.map((item, index) => `<article><h3><button type="button" aria-expanded="false" aria-controls="faq-${index}"><span>${escapeHtml11(item.question)}</span><b aria-hidden="true">+</b></button></h3><p id="faq-${index}" hidden>${escapeHtml11(item.answer)}</p></article>`).join("")}</div></section>` : "";
|
|
39188
|
+
const media = flags.sidebarMedia && input.sidebarMedia ? `<figure class="sidebar-media" data-article-media>${sidebarArt(input)}${input.sidebarMedia.caption ? `<figcaption>${escapeHtml11(input.sidebarMedia.caption)}</figcaption>` : ""}</figure>` : "";
|
|
39189
|
+
const disclosure = flags.disclosure && input.disclosure ? `<section class="disclosure"><button type="button" aria-expanded="false" aria-controls="disclosure-details"><span>${escapeHtml11(input.disclosure.summary)}</span><b aria-hidden="true">\u2304</b></button><p id="disclosure-details" hidden>${escapeHtml11(input.disclosure.details)}</p></section>` : "";
|
|
39190
|
+
const toc = flags.stickyToc ? `<aside class="toc" data-sticky-toc><header><strong>Table of contents</strong><button type="button" aria-expanded="true" aria-controls="toc-links" aria-label="Collapse table of contents">\u2303</button></header><nav id="toc-links" aria-label="Table of contents">${tocItems.map((item, index) => `<a href="#${escapeHtml11(item.id)}"${index === 0 ? ' aria-current="location"' : ""}><i></i><span>${escapeHtml11(item.title)}</span></a>`).join("")}</nav><button class="back-top" type="button">Back to top \u2191</button></aside>` : "";
|
|
38894
39191
|
const actions = flags.citation || flags.share ? `<div class="article-actions">${flags.citation ? '<button type="button" data-cite aria-haspopup="dialog">\u270E <span>Cite us</span></button>' : ""}${flags.share ? '<button type="button" data-share>\u21E7 <span>Share this article</span></button>' : ""}</div><p class="action-status" aria-live="polite"></p>` : "";
|
|
38895
|
-
const author = flags.authorCard ? `<section id="author" class="author-card">${actions}<div class="author-grid">${portrait(input)}<div><span>Written by</span><h2>${input.author.href ? `<a href="${safeHref4(input.author.href)}">${
|
|
38896
|
-
const citationDialog = flags.citation ? `<dialog id="citation-dialog"><div><button class="dialog-close" type="button" aria-label="Close citation guide">\xD7</button><h2>Quick citation guide</h2><p>Select a citation to automatically copy it to your clipboard.</p><section>${Object.keys(citationValues).map((style) => `<button type="button" data-citation="${style}"><strong>${style}:</strong> ${
|
|
38897
|
-
const html = `<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><meta name="robots" content="noindex,nofollow"><meta name="description" content="${
|
|
39192
|
+
const author = flags.authorCard ? `<section id="author" class="author-card">${actions}<div class="author-grid">${portrait(input)}<div><span>Written by</span><h2>${input.author.href ? `<a href="${safeHref4(input.author.href)}">${escapeHtml11(input.author.name)}</a>` : escapeHtml11(input.author.name)}</h2><p>${escapeHtml11(input.author.role)}</p>${input.author.socialLinks.length || input.author.email ? `<nav aria-label="Author links">${input.author.socialLinks.map((link) => `<a href="${safeHref4(link.href)}">${escapeHtml11(link.label)}</a>`).join("")}${input.author.email ? `<a href="mailto:${escapeHtml11(input.author.email)}">Email</a>` : ""}</nav>` : ""}</div>${input.author.href ? `<a class="author-more" href="${safeHref4(input.author.href)}">Read more from ${escapeHtml11(input.author.name.split(/\s+/)[0] || input.author.name)}</a>` : ""}</div><p class="author-bio">${escapeHtml11(input.author.bio)}</p></section>` : actions;
|
|
39193
|
+
const citationDialog = flags.citation ? `<dialog id="citation-dialog"><div><button class="dialog-close" type="button" aria-label="Close citation guide">\xD7</button><h2>Quick citation guide</h2><p>Select a citation to automatically copy it to your clipboard.</p><section>${Object.keys(citationValues).map((style) => `<button type="button" data-citation="${style}"><strong>${style}:</strong> ${escapeHtml11(citationValues[style])}</button>`).join("")}</section><p class="citation-status" aria-live="polite"></p></div></dialog>` : "";
|
|
39194
|
+
const html = `<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><meta name="robots" content="noindex,nofollow"><meta name="description" content="${escapeHtml11(input.dek || input.keyTakeaways[0])}"><title>${escapeHtml11(input.title)} \xB7 ${escapeHtml11(brand)}</title><style>
|
|
38898
39195
|
:root{--ink:#10213d;--ink2:#1c355a;--blue:#2563eb;--blue2:#1749b6;--mint:#45d5aa;--paper:#f7f5f0;--line:#dce4ef;--card:#fff;--body:#475569;--serif:Iowan Old Style,Palatino Linotype,Palatino,Georgia,serif;--sans:Inter,Avenir Next,ui-sans-serif,system-ui,sans-serif}body[data-theme="slate"]{--ink:#1e293b;--ink2:#334155;--blue:#475569;--blue2:#1e293b;--mint:#94a3b8;--paper:#f8fafc}body[data-theme="forest"]{--ink:#12352e;--ink2:#23584c;--blue:#147d64;--blue2:#0c5b48;--mint:#79d8bd;--paper:#f4f8f3}*{box-sizing:border-box}html{scroll-behavior:smooth;background:var(--paper)}body{margin:0;color:#252a33;background:var(--paper);font-family:var(--sans);line-height:1.6}a{color:inherit}button{font:inherit}button:focus-visible,a:focus-visible{outline:3px solid var(--mint);outline-offset:3px}.progress{position:fixed;z-index:50;top:0;left:0;height:4px;width:0;background:var(--mint)}.hero{position:relative;overflow:hidden;color:#fff;background:var(--ink)}.hero:after{position:absolute;right:-110px;top:-150px;width:420px;height:420px;border:1px solid #ffffff1a;border-radius:50%;content:""}.hero-inner{position:relative;z-index:1;max-width:1240px;margin:auto;padding:58px 42px 126px}.breadcrumb{display:flex;gap:8px;margin-bottom:34px;color:#dbeafecc;font-size:14px}.eyebrow{display:block;color:var(--blue);font-size:12px;font-weight:800;letter-spacing:.16em;text-transform:uppercase}.hero .eyebrow{color:var(--mint)}h1,h2,h3,p{margin-top:0}.hero h1{max-width:1000px;margin:14px 0 24px;font:700 clamp(44px,6vw,78px)/.98 var(--serif);letter-spacing:-.035em}.hero .dek{max-width:780px;color:#dbeafe;font-size:20px}.contributors{margin-top:30px;color:#eff6ff;font-size:14px}.contributors a{font-weight:800}.meta{display:flex;flex-wrap:wrap;gap:12px;margin-top:6px;color:#dbeafecc}.layout{position:relative;z-index:2;display:grid;grid-template-columns:minmax(0,760px) 290px;gap:64px;max-width:1240px;margin:-78px auto 0;padding:0 42px 80px}.main{min-width:0}.takeaways{padding:38px 44px;border-radius:24px;background:#fff;box-shadow:0 24px 70px #10213d24}.takeaways h2{margin:5px 0 20px;font:700 32px/1.1 var(--serif);color:var(--ink)}.takeaways ul{display:grid;gap:16px;margin:0;padding:0;list-style:none}.takeaways li{position:relative;padding-left:26px;color:var(--body);font-size:17px}.takeaways li:before{position:absolute;left:2px;top:.7em;width:8px;height:8px;border-radius:50%;background:var(--blue);content:""}.intro{padding:40px 0 4px}.intro p,.article-section>p{margin-bottom:22px;color:var(--body);font:400 18px/1.75 var(--sans)}.article-section{scroll-margin-top:28px;padding-top:45px}.article-section h2,.faq h2{margin:6px 0 20px;color:var(--ink);font:700 38px/1.08 var(--serif);letter-spacing:-.02em}.article-section ul{display:grid;gap:10px;margin:22px 0;padding-left:24px;color:var(--body);font-size:17px}.article-section li::marker{color:var(--blue)}.callout{margin:34px 0;padding:24px 28px;border-left:4px solid var(--blue);border-radius:0 16px 16px 0;background:#fff}.callout span{color:var(--blue);font-size:11px;font-weight:800;letter-spacing:.13em;text-transform:uppercase}.callout h3{margin:5px 0 8px;color:var(--ink);font:700 24px/1.15 var(--serif)}.callout p{margin:0;color:var(--body)}.rail{padding-top:0}.sidebar-media{overflow:hidden;margin:0 0 18px;border:1px solid #dbeafe;border-radius:16px;background:#fff}.sidebar-media img,.sidebar-media svg{display:block;width:100%;aspect-ratio:16/9;object-fit:cover}.sidebar-media figcaption{padding:10px 13px;color:#64748b;font-size:11px}.disclosure{margin-bottom:28px;border-top:1px solid #dbeafe;border-bottom:1px solid #dbeafe}.disclosure button{display:flex;width:100%;align-items:center;justify-content:space-between;gap:14px;padding:15px 0;border:0;color:#64748b;background:transparent;text-align:left;font-size:12px;cursor:pointer}.disclosure button b{color:var(--blue);font-size:18px;transition:transform .2s}.disclosure button[aria-expanded="true"] b{transform:rotate(180deg)}.disclosure p{padding:0 0 16px;margin:0;color:#64748b;font-size:12px}.toc{position:sticky;top:30px;padding:22px;border:1px solid var(--line);border-radius:16px;background:#fff;box-shadow:0 2px 5px #10213d12}.toc header{display:flex;align-items:center;justify-content:space-between}.toc header strong{color:var(--ink);font:700 21px/1 var(--serif)}.toc header button{width:34px;height:34px;border:0;border-radius:50%;color:var(--blue);background:transparent;cursor:pointer}.toc nav{display:grid;margin-top:14px}.toc nav a{display:flex;align-items:flex-start;gap:11px;padding:8px 0;color:#64748b;text-decoration:none;font-size:13px;line-height:1.35}.toc nav i{width:8px;height:8px;margin-top:5px;border:2px solid #bfdbfe;border-radius:50%}.toc nav a[aria-current="location"]{color:var(--ink);font-weight:800}.toc nav a[aria-current="location"] i{border-color:var(--blue);background:var(--blue)}.back-top{width:100%;margin-top:18px;padding:16px 0 0;border:0;border-top:1px solid var(--line);color:var(--blue);background:transparent;text-align:right;font-size:13px;font-weight:800;cursor:pointer}.faq{scroll-margin-top:28px;padding-top:64px}.faq>div{border-top:1px solid var(--line);border-bottom:1px solid var(--line)}.faq article+article{border-top:1px solid var(--line)}.faq h3{margin:0}.faq h3 button{display:flex;width:100%;align-items:center;justify-content:space-between;gap:18px;padding:19px 0;border:0;color:var(--ink);background:transparent;text-align:left;font-weight:800;cursor:pointer}.faq h3 b{color:var(--blue);font-size:22px}.faq article>p{padding:0 0 20px;margin:0;color:var(--body);font-size:16px}.author-card{margin-top:64px;padding:32px 36px;border-radius:18px;background:#fff}.article-actions{display:flex;flex-wrap:wrap;justify-content:space-between;gap:14px}.article-actions button{display:inline-flex;min-height:46px;align-items:center;justify-content:center;gap:8px;padding:8px 18px;border:2px solid var(--blue);border-radius:999px;color:var(--ink);background:#fff;font-weight:800;cursor:pointer}.article-actions button:hover{color:#fff;background:var(--blue)}.action-status{min-height:20px;margin:8px 0 0;color:var(--blue);text-align:right;font-size:13px;font-weight:700}.author-grid{display:grid;grid-template-columns:auto 1fr auto;gap:22px;align-items:center;margin-top:24px}.author-portrait{width:88px;height:88px;border-radius:50%;object-fit:cover}.author-initials{display:grid;place-items:center;color:var(--ink);background:#fecdd3;font-size:22px;font-weight:900}.author-grid span{color:#64748b;font-size:13px}.author-grid h2{margin:2px 0;color:var(--ink);font:700 27px/1 var(--serif)}.author-grid h2 a{text-decoration:none}.author-grid p{margin:8px 0;color:#64748b;font-size:14px}.author-grid nav{display:flex;flex-wrap:wrap;gap:14px}.author-grid nav a{color:#64748b;font-size:12px}.author-more{display:inline-flex;min-height:48px;align-items:center;justify-content:center;padding:10px 24px;border:2px solid var(--blue);color:var(--blue);text-align:center;text-decoration:none;font-size:13px;font-weight:800}.author-bio{margin:24px 0 0!important;padding-top:20px;border-top:1px solid var(--line);color:var(--body);font-size:16px}dialog{width:min(720px,calc(100% - 30px));max-height:calc(100dvh - 30px);padding:0;border:0;border-radius:18px;color:var(--ink);background:#fff;box-shadow:0 24px 70px #10213d38}dialog::backdrop{background:#0f172a7a;backdrop-filter:blur(2px)}dialog>div{position:relative;padding:30px}dialog h2{margin:0 50px 2px 0;font:700 30px/1.1 var(--serif)}dialog>div>p{color:#64748b}.dialog-close{position:absolute;top:13px;right:13px;width:44px;height:44px;border:0;border-radius:50%;color:var(--blue);background:transparent;font-size:29px;cursor:pointer}dialog section{border-top:1px solid var(--line)}dialog section button{display:block;width:100%;padding:17px 5px;border:0;border-bottom:1px solid var(--line);color:var(--body);background:#fff;text-align:left;line-height:1.65;cursor:pointer}.citation-status{min-height:22px;margin:14px 0 0!important;color:var(--blue)!important;font-size:13px;font-weight:800}.generated{max-width:1156px;margin:-52px auto 50px;padding:0 42px;color:#94a3b8;font-size:11px}@media(max-width:900px){.layout{display:block}.rail{display:none}.hero-inner{padding-bottom:116px}}@media(max-width:620px){.hero-inner{padding:36px 20px 104px}.hero h1{font-size:46px}.hero .dek{font-size:17px}.layout{margin-top:-70px;padding:0 16px 54px}.takeaways{padding:28px 24px}.article-section h2,.faq h2{font-size:32px}.author-card{padding:24px}.article-actions{display:grid;justify-content:start}.author-grid{grid-template-columns:1fr;gap:12px}.author-more{width:100%}dialog>div{padding:24px}.generated{padding:0 20px}}
|
|
38899
|
-
</style></head><body data-theme="${
|
|
39196
|
+
</style></head><body data-theme="${escapeHtml11(config.theme)}" data-scheduled-renderer="blog_article_v1"><div class="progress" aria-hidden="true"></div><header class="hero"><div class="hero-inner"><nav class="breadcrumb" aria-label="Breadcrumb"><a href="${safeHref4(input.canonicalUrl)}">${escapeHtml11(input.category)}</a><span>/</span><span>Article</span></nav><span class="eyebrow">${escapeHtml11(input.eyebrow)}</span><h1>${escapeHtml11(input.title)}</h1>${input.dek ? `<p class="dek">${escapeHtml11(input.dek)}</p>` : ""}<div class="contributors">${contributorText}<div class="meta"><time datetime="${escapeHtml11(articleDate)}">Updated ${formatDate2(articleDate)}</time><span>\u2022</span><span>${input.readTimeMinutes} min read</span>${input.reviewer ? "<span>\u2022</span><strong>Expert reviewed</strong>" : ""}</div></div></div></header><main class="layout"><article class="main"><section class="takeaways"><span class="eyebrow">The short answer</span><h2>Key takeaways</h2><ul>${input.keyTakeaways.map((item) => `<li>${escapeHtml11(item)}</li>`).join("")}</ul></section><section class="intro">${input.introduction.map((paragraph) => `<p>${escapeHtml11(paragraph)}</p>`).join("")}</section>${sections}${faq}${author}</article><div class="rail">${media}${disclosure}${toc}</div></main>${config.showGeneratedAt ? `<p class="generated">Rendered ${formatDate2(generatedAtIso)} by MCP Scraper.</p>` : ""}${citationDialog}<script>(()=>{const citations=${jsonForScript(citationValues)};const canonical=${jsonForScript(input.canonicalUrl)};const title=${jsonForScript(input.title)};const progress=document.querySelector('.progress');const tocLinks=[...document.querySelectorAll('.toc nav a')];const targets=tocLinks.map(link=>document.querySelector(link.hash)).filter(Boolean);const update=()=>{const max=document.documentElement.scrollHeight-innerHeight;if(progress)progress.style.width=(max>0?scrollY/max*100:0)+'%';let active=targets[0]?.id;for(const target of targets){if(target.getBoundingClientRect().top<=innerHeight*.55)active=target.id}tocLinks.forEach(link=>link.toggleAttribute('aria-current',link.hash==='#'+active));tocLinks.forEach(link=>{if(link.hash==='#'+active)link.setAttribute('aria-current','location');else link.removeAttribute('aria-current')})};addEventListener('scroll',update,{passive:true});addEventListener('resize',update);update();document.querySelectorAll('.faq h3 button').forEach(button=>button.addEventListener('click',()=>{const panel=document.getElementById(button.getAttribute('aria-controls'));const open=button.getAttribute('aria-expanded')==='true';button.setAttribute('aria-expanded',String(!open));panel.hidden=open;button.querySelector('b').textContent=open?'+':'\u2212'}));const disclosure=document.querySelector('.disclosure button');disclosure?.addEventListener('click',()=>{const panel=document.getElementById(disclosure.getAttribute('aria-controls'));const open=disclosure.getAttribute('aria-expanded')==='true';disclosure.setAttribute('aria-expanded',String(!open));panel.hidden=open});const tocToggle=document.querySelector('.toc header button');tocToggle?.addEventListener('click',()=>{const nav=document.getElementById('toc-links');const open=tocToggle.getAttribute('aria-expanded')==='true';tocToggle.setAttribute('aria-expanded',String(!open));nav.hidden=open;tocToggle.textContent=open?'\u2304':'\u2303'});document.querySelector('.back-top')?.addEventListener('click',()=>scrollTo({top:0,behavior:'smooth'}));const copy=async text=>{try{await navigator.clipboard.writeText(text)}catch{const area=document.createElement('textarea');area.value=text;area.style.position='fixed';area.style.opacity='0';document.body.append(area);area.select();document.execCommand('copy');area.remove()}};const dialog=document.getElementById('citation-dialog');document.querySelector('[data-cite]')?.addEventListener('click',()=>dialog.showModal());document.querySelector('.dialog-close')?.addEventListener('click',()=>dialog.close());dialog?.addEventListener('click',event=>{if(event.target===dialog)dialog.close()});document.querySelectorAll('[data-citation]').forEach(button=>button.addEventListener('click',async()=>{const style=button.dataset.citation;await copy(citations[style]);document.querySelector('.citation-status').textContent=style+' citation copied to clipboard.'}));document.querySelector('[data-share]')?.addEventListener('click',async()=>{const status=document.querySelector('.action-status');if(navigator.share){try{await navigator.share({title,url:canonical});status.textContent='Sharing options opened.';return}catch(error){if(error.name==='AbortError')return}}await copy(canonical);status.textContent='Article link copied to clipboard.'})})()</script></body></html>`;
|
|
38900
39197
|
const bytes = Buffer.byteLength(html);
|
|
38901
39198
|
const sha2563 = createHash24("sha256").update(html).digest("hex");
|
|
38902
39199
|
return {
|
|
@@ -41496,7 +41793,7 @@ async function getFreeCreditBreakdown(userId) {
|
|
|
41496
41793
|
}
|
|
41497
41794
|
|
|
41498
41795
|
// src/api/memory-db.ts
|
|
41499
|
-
import { neon } from "@neondatabase/serverless";
|
|
41796
|
+
import { neon as neon2 } from "@neondatabase/serverless";
|
|
41500
41797
|
|
|
41501
41798
|
// src/api/memory-universe.ts
|
|
41502
41799
|
var SEP = "\n";
|
|
@@ -41593,7 +41890,7 @@ function sql() {
|
|
|
41593
41890
|
if (_sql) return _sql;
|
|
41594
41891
|
const url = process.env.MEMORY_DATABASE_URL?.trim();
|
|
41595
41892
|
if (!url) throw new Error("MEMORY_DATABASE_URL is not set (paa-crawler needs mcp-memory Neon URL for reads)");
|
|
41596
|
-
_sql =
|
|
41893
|
+
_sql = neon2(url);
|
|
41597
41894
|
return _sql;
|
|
41598
41895
|
}
|
|
41599
41896
|
function physicalVault(owner, vault) {
|
|
@@ -47296,7 +47593,7 @@ app.get("/cron/tick", async (c) => {
|
|
|
47296
47593
|
const budget = { maxJobs: 10, deadlineMs: startedAt + CRON_TICK_DRAIN_BUDGET_MS };
|
|
47297
47594
|
const origin = `${new URL(c.req.url).protocol}//${new URL(c.req.url).host}`;
|
|
47298
47595
|
const unfinished = [];
|
|
47299
|
-
const [results, sweepResult, reapResult, expiredResult, blobCleanup, connectedDataArtifactCleanup, connectedAccountBilling, directoryWorkflowDispatch, directoryWorkflowReconciliation, directoryArtifactCleanup, siteExtractArtifactCleanup, siteExtractRedispatch, siteExtractReconciliation, paaHarvestRedispatch, paaHarvestReconciliation, localSourcebookRedispatch, analyticsRollup, analyticsFormDelivery, workflowDispatchResult, scheduledRunReconciliation, retentionSweep] = await Promise.all([
|
|
47596
|
+
const [results, sweepResult, reapResult, expiredResult, blobCleanup, connectedDataArtifactCleanup, connectedAccountBilling, directoryWorkflowDispatch, directoryWorkflowReconciliation, directoryArtifactCleanup, siteExtractArtifactCleanup, siteExtractRedispatch, siteExtractReconciliation, paaHarvestRedispatch, paaHarvestReconciliation, commonsEmbeddingDrain, localSourcebookRedispatch, analyticsRollup, analyticsFormDelivery, workflowDispatchResult, scheduledRunReconciliation, retentionSweep] = await Promise.all([
|
|
47300
47597
|
settleWithinTickBudget("drainQueue", unfinished, drainQueue(budget), []),
|
|
47301
47598
|
settleWithinTickBudget("monthlyRefreshSweep", unfinished, runMonthlyRefreshSweep(), { status: "skipped_deadline" }),
|
|
47302
47599
|
settleWithinTickBudget("reapBrowserSessions", unfinished, reapIdleBrowserSessions(120), { reaped: 0 }),
|
|
@@ -47313,6 +47610,7 @@ app.get("/cron/tick", async (c) => {
|
|
|
47313
47610
|
settleWithinTickBudget("siteExtractReconcile", unfinished, reconcileSiteExtractSettlements(10), { checked: 0, settled: 0, failed: 0 }),
|
|
47314
47611
|
settleWithinTickBudget("paaRedispatch", unfinished, redispatchPendingPaaHarvests(10), { checked: 0, dispatched: 0, failed: 0 }),
|
|
47315
47612
|
settleWithinTickBudget("paaReconcile", unfinished, reconcilePaaHarvestSettlements(10), { checked: 0, staleFailed: 0, settled: 0, failed: 0 }),
|
|
47613
|
+
settleWithinTickBudget("commonsEmbeddingDrain", unfinished, embedQueuedCommonsDocuments(50), { claimed: 0, embedded: 0, failed: 0, remaining: 0 }),
|
|
47316
47614
|
settleWithinTickBudget("localSourcebookRedispatch", unfinished, redispatchQueuedLocalSourcebookAcquisitions(5), { checked: 0, dispatched: 0, failed: 0 }),
|
|
47317
47615
|
settleWithinTickBudget("analyticsRollup", unfinished, refreshAnalyticsDailyRollupsIfDue(), { status: "failed", rows: 0 }),
|
|
47318
47616
|
settleWithinTickBudget("analyticsForms", unfinished, deliverPendingAnalyticsForms(10), { claimed: 0, delivered: 0, deferred: 0 }),
|
|
@@ -47343,6 +47641,7 @@ app.get("/cron/tick", async (c) => {
|
|
|
47343
47641
|
siteExtractReconciliation,
|
|
47344
47642
|
paaHarvestRedispatch,
|
|
47345
47643
|
paaHarvestReconciliation,
|
|
47644
|
+
commonsEmbeddingDrain,
|
|
47346
47645
|
localSourcebookRedispatch,
|
|
47347
47646
|
analyticsRollup,
|
|
47348
47647
|
analyticsFormDelivery,
|
|
@@ -47575,4 +47874,4 @@ app.get("/blog/:slug/", (c) => {
|
|
|
47575
47874
|
export {
|
|
47576
47875
|
app
|
|
47577
47876
|
};
|
|
47578
|
-
//# sourceMappingURL=server-
|
|
47877
|
+
//# sourceMappingURL=server-IRKNU6LO.js.map
|