mcp-scraper 0.57.3 → 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 +29 -0
- package/README.md +2 -2
- package/dist/bin/api-server.cjs +549 -107
- package/dist/bin/api-server.cjs.map +1 -1
- package/dist/bin/api-server.js +2 -2
- 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 +2 -2
- package/dist/bin/mcp-scraper-install.cjs.map +1 -1
- package/dist/bin/mcp-scraper-install.js +2 -2
- package/dist/bin/mcp-stdio-server.cjs +36 -8
- package/dist/bin/mcp-stdio-server.cjs.map +1 -1
- package/dist/bin/mcp-stdio-server.js +4 -4
- package/dist/{chunk-R6CO77BN.js → chunk-2U2ZDDSI.js} +3 -3
- package/dist/{chunk-R6CO77BN.js.map → chunk-2U2ZDDSI.js.map} +1 -1
- package/dist/{chunk-QSUSTYB3.js → chunk-AIA3MFT2.js} +38 -9
- 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/{chunk-HU4R6BP2.js → chunk-IMBMDZUO.js} +2 -2
- package/dist/{chunk-HU4R6BP2.js.map → chunk-IMBMDZUO.js.map} +1 -1
- package/dist/{chunk-5XYBKE3X.js → chunk-KMGRM4FL.js} +2 -2
- package/dist/editorial-reading-room/assets/app.js +17 -3
- package/dist/{extract-bundle-H7JEELY7.js → extract-bundle-XRRN6NAZ.js} +3 -3
- package/dist/{server-EP2SK2ID.js → server-IRKNU6LO.js} +505 -105
- package/dist/server-IRKNU6LO.js.map +1 -0
- package/dist/{site-extract-repository-CFMSWAVL.js → site-extract-repository-XAA2FVDN.js} +3 -3
- package/dist/{worker-S2WXELUC.js → worker-QFSOMF2N.js} +2 -2
- package/package.json +1 -1
- package/dist/chunk-LHH3GX3W.js +0 -7
- package/dist/chunk-LHH3GX3W.js.map +0 -1
- package/dist/chunk-QSUSTYB3.js.map +0 -1
- package/dist/server-EP2SK2ID.js.map +0 -1
- /package/dist/{chunk-5XYBKE3X.js.map → chunk-KMGRM4FL.js.map} +0 -0
- /package/dist/{extract-bundle-H7JEELY7.js.map → extract-bundle-XRRN6NAZ.js.map} +0 -0
- /package/dist/{site-extract-repository-CFMSWAVL.js.map → site-extract-repository-XAA2FVDN.js.map} +0 -0
- /package/dist/{worker-S2WXELUC.js.map → worker-QFSOMF2N.js.map} +0 -0
|
@@ -115,6 +115,7 @@ import {
|
|
|
115
115
|
CommonsClaimPublicationInputSchema,
|
|
116
116
|
CommonsPreparePublicationInputSchema,
|
|
117
117
|
CommonsPublishEditorialInputSchema,
|
|
118
|
+
CommonsUpdateEditorialArticleInputSchema,
|
|
118
119
|
CommonsValidatePublicationInputSchema,
|
|
119
120
|
CreateArtifactTemplateInputSchema,
|
|
120
121
|
CreateEditorialReadingRoomInputSchema,
|
|
@@ -169,7 +170,7 @@ import {
|
|
|
169
170
|
resolveDeploymentProfile,
|
|
170
171
|
resolveLocalSourcebookSchemaType,
|
|
171
172
|
transcribeMediaUrl
|
|
172
|
-
} from "./chunk-
|
|
173
|
+
} from "./chunk-AIA3MFT2.js";
|
|
173
174
|
import {
|
|
174
175
|
auditImageUrls,
|
|
175
176
|
auditImages,
|
|
@@ -225,7 +226,7 @@ import {
|
|
|
225
226
|
} from "./chunk-FG6LJGJ7.js";
|
|
226
227
|
import {
|
|
227
228
|
PACKAGE_VERSION
|
|
228
|
-
} from "./chunk-
|
|
229
|
+
} from "./chunk-AQA2ZL4X.js";
|
|
229
230
|
import {
|
|
230
231
|
abandonExtractSettlement,
|
|
231
232
|
countSuccessfulPages,
|
|
@@ -248,7 +249,7 @@ import {
|
|
|
248
249
|
setExtractJobTotal,
|
|
249
250
|
settleExtractJob,
|
|
250
251
|
terminalExtractJobStatus
|
|
251
|
-
} from "./chunk-
|
|
252
|
+
} from "./chunk-KMGRM4FL.js";
|
|
252
253
|
import {
|
|
253
254
|
BROWSER_OPEN_MIN_BALANCE_MC,
|
|
254
255
|
CONCURRENCY_PACK_INVOICE_DESCRIPTION,
|
|
@@ -301,7 +302,7 @@ import {
|
|
|
301
302
|
tierChangeLeavesPrivateOffer,
|
|
302
303
|
tierCreditsPerInterval,
|
|
303
304
|
vendorCostUsdToMc
|
|
304
|
-
} from "./chunk-
|
|
305
|
+
} from "./chunk-2U2ZDDSI.js";
|
|
305
306
|
import {
|
|
306
307
|
CaptchaError,
|
|
307
308
|
MapsSearchIncompletePageError,
|
|
@@ -9393,7 +9394,7 @@ var siteExtractFn = inngest.createFunction(
|
|
|
9393
9394
|
});
|
|
9394
9395
|
}) : null;
|
|
9395
9396
|
const finalized = await step.run("finalize", async () => {
|
|
9396
|
-
const { assembleExtractArtifacts } = await import("./extract-bundle-
|
|
9397
|
+
const { assembleExtractArtifacts } = await import("./extract-bundle-XRRN6NAZ.js");
|
|
9397
9398
|
const current = await getExtractJob(jobId2);
|
|
9398
9399
|
if (!current) throw new Error("extract job disappeared before finalization");
|
|
9399
9400
|
const stored = await assembleExtractArtifacts(current, { branding, imageAudit });
|
|
@@ -32751,9 +32752,7 @@ function socialMeta(input) {
|
|
|
32751
32752
|
];
|
|
32752
32753
|
return tags.join("\n ");
|
|
32753
32754
|
}
|
|
32754
|
-
function
|
|
32755
|
-
const sourceBytes = input.articles.reduce((total, article) => total + Buffer.byteLength(article.markdown), 0);
|
|
32756
|
-
if (sourceBytes > 2e6) throw new Error("Editorial reading-room Markdown must be 2,000,000 bytes or fewer in total.");
|
|
32755
|
+
function buildEditorialArticles(input) {
|
|
32757
32756
|
const seenSlugs = /* @__PURE__ */ new Set();
|
|
32758
32757
|
const seenOrders = /* @__PURE__ */ new Set();
|
|
32759
32758
|
const parser = markdownRenderer();
|
|
@@ -32780,7 +32779,19 @@ function renderEditorialReadingRoom(input, now = /* @__PURE__ */ new Date()) {
|
|
|
32780
32779
|
html: rendered
|
|
32781
32780
|
};
|
|
32782
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.");
|
|
32783
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;
|
|
32784
32795
|
const data = { ...input, generatedAt, articles };
|
|
32785
32796
|
const template = readAsset("index.html");
|
|
32786
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"));
|
|
@@ -33229,6 +33240,134 @@ async function hostEntityImages(input) {
|
|
|
33229
33240
|
return rewrite;
|
|
33230
33241
|
}
|
|
33231
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
|
+
|
|
33232
33371
|
// src/api/schema-presence.ts
|
|
33233
33372
|
var cache = null;
|
|
33234
33373
|
async function loadSchemaObjects() {
|
|
@@ -33883,17 +34022,35 @@ async function searchCommonsEntities(filters = {}, userId) {
|
|
|
33883
34022
|
args.push(mergedFilters.updatedAfter);
|
|
33884
34023
|
}
|
|
33885
34024
|
const terms = tokenize(mergedFilters.query);
|
|
33886
|
-
|
|
33887
|
-
|
|
33888
|
-
|
|
33889
|
-
|
|
33890
|
-
|
|
33891
|
-
|
|
33892
|
-
|
|
33893
|
-
|
|
33894
|
-
|
|
33895
|
-
|
|
33896
|
-
|
|
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
|
+
}
|
|
33897
34054
|
}
|
|
33898
34055
|
if (!terms.length) {
|
|
33899
34056
|
args.push(limit, offset);
|
|
@@ -33930,6 +34087,7 @@ async function searchCommonsEntities(filters = {}, userId) {
|
|
|
33930
34087
|
`,
|
|
33931
34088
|
args
|
|
33932
34089
|
});
|
|
34090
|
+
const mode = searchMode;
|
|
33933
34091
|
const ranked = candidates.rows.map((row) => {
|
|
33934
34092
|
const record = row;
|
|
33935
34093
|
const score = relevanceScore(terms, {
|
|
@@ -33940,8 +34098,10 @@ async function searchCommonsEntities(filters = {}, userId) {
|
|
|
33940
34098
|
searchText: String(record.search_text ?? ""),
|
|
33941
34099
|
claimText: String(record.claim_text ?? "")
|
|
33942
34100
|
});
|
|
33943
|
-
|
|
33944
|
-
|
|
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));
|
|
33945
34105
|
const pageIds = ranked.slice(offset, offset + limit).map((candidate) => candidate.id);
|
|
33946
34106
|
if (!pageIds.length) return { results: [], filters: mergedFilters, limit, offset };
|
|
33947
34107
|
const page = await getDb().execute({
|
|
@@ -35428,6 +35588,7 @@ function normalizeRelatedEntities(related) {
|
|
|
35428
35588
|
}
|
|
35429
35589
|
function sanitizeSearchFilters(filters) {
|
|
35430
35590
|
return {
|
|
35591
|
+
mode: filters.mode === "lexical" || filters.mode === "semantic" ? filters.mode : "hybrid",
|
|
35431
35592
|
query: optionalText2(filters.query, 300) ?? void 0,
|
|
35432
35593
|
entityType: filters.entityType ? normalizeEntityType(filters.entityType) : void 0,
|
|
35433
35594
|
tag: optionalText2(filters.tag, 80) ?? void 0,
|
|
@@ -35701,6 +35862,97 @@ var CommonsRepositoryError = class extends Error {
|
|
|
35701
35862
|
|
|
35702
35863
|
// src/api/commons-publication-repository.ts
|
|
35703
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
|
|
35704
35956
|
var PUBLICATION_ROOT_DOMAIN = process.env.COMMONS_PUBLICATION_ROOT_DOMAIN || "transparent-commons.cc";
|
|
35705
35957
|
var RESERVED_SUBDOMAINS = /* @__PURE__ */ new Set([
|
|
35706
35958
|
"admin",
|
|
@@ -35917,6 +36169,92 @@ async function publishCommonsEditorial(input, user) {
|
|
|
35917
36169
|
if (!edition) throw new CommonsPublicationError("publication_publish_failed", "The published edition was not persisted.");
|
|
35918
36170
|
return publicationResult({ ...publication, latestEditionId: editionId, updatedAt: now }, edition, false);
|
|
35919
36171
|
}
|
|
36172
|
+
async function updateCommonsEditorialArticle(input, user) {
|
|
36173
|
+
await ensureCommonsSchema();
|
|
36174
|
+
const subdomain = normalizePublicationSubdomain(input.publicationSubdomain);
|
|
36175
|
+
const publication = await getCommonsPublicationBySubdomain(subdomain);
|
|
36176
|
+
if (!publication) throw new CommonsPublicationError("publication_not_found", "Claim this publication name before editing an edition.", 404);
|
|
36177
|
+
if (publication.ownerUserId !== Number(user.id)) {
|
|
36178
|
+
throw new CommonsPublicationError("publication_not_owned", "Only the account that claimed this publication can edit it.", 404);
|
|
36179
|
+
}
|
|
36180
|
+
const idempotencyKey3 = requiredIdempotencyKey(input.idempotencyKey);
|
|
36181
|
+
const replay = await getEditionByIdempotency(Number(user.id), idempotencyKey3);
|
|
36182
|
+
if (replay) return publicationResult(publication, replay, true);
|
|
36183
|
+
const latestOverall = publication.latestEditionId ? await getPublicationEditionById(publication.latestEditionId) : null;
|
|
36184
|
+
const editionSlug = normalizeEditionSlug(input.editionSlug || latestOverall?.editionSlug || "");
|
|
36185
|
+
if (!editionSlug) throw new CommonsPublicationError("publication_edition_required", "This publication has no edition yet; publish one before editing an article.", 409);
|
|
36186
|
+
const latest = await getLatestEdition(publication.id, editionSlug);
|
|
36187
|
+
if (!latest) throw new CommonsPublicationError("publication_edition_not_found", `Edition ${editionSlug} does not exist.`, 404);
|
|
36188
|
+
if (input.baseRevision !== latest.revision) {
|
|
36189
|
+
throw new CommonsPublicationError("publication_revision_conflict", `Edition ${editionSlug} is revision ${latest.revision}; read it again before editing.`, 409);
|
|
36190
|
+
}
|
|
36191
|
+
const articles = latest.articles;
|
|
36192
|
+
const index = articles.findIndex((article) => article.slug === input.articleSlug);
|
|
36193
|
+
if (index === -1) {
|
|
36194
|
+
throw new CommonsPublicationError("publication_article_not_found", `Edition ${editionSlug} has no article with slug ${input.articleSlug}. Known slugs: ${articles.map((article) => article.slug).join(", ")}.`, 404);
|
|
36195
|
+
}
|
|
36196
|
+
const current = articles[index];
|
|
36197
|
+
const nextArticles = [...articles];
|
|
36198
|
+
nextArticles[index] = {
|
|
36199
|
+
...current,
|
|
36200
|
+
...input.markdown === void 0 ? {} : { markdown: input.markdown },
|
|
36201
|
+
...input.title === void 0 ? {} : { title: input.title },
|
|
36202
|
+
...input.summary === void 0 ? {} : { summary: input.summary },
|
|
36203
|
+
...input.category === void 0 ? {} : { category: input.category },
|
|
36204
|
+
...input.kicker === void 0 ? {} : { kicker: input.kicker },
|
|
36205
|
+
...input.order === void 0 ? {} : { order: input.order }
|
|
36206
|
+
};
|
|
36207
|
+
const editionInput = { site: latest.site, deck: latest.deck, articles: nextArticles };
|
|
36208
|
+
const canonicalUrl = editionPublicUrl(subdomain, editionSlug);
|
|
36209
|
+
const rendered = renderEditorialReadingRoom(editionInput);
|
|
36210
|
+
const html = addPublicMetadata(rendered.html, canonicalUrl, publication.title);
|
|
36211
|
+
const editionId = `tced_${randomUUID18()}`;
|
|
36212
|
+
const revision = latest.revision + 1;
|
|
36213
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
36214
|
+
await getDb().batch([
|
|
36215
|
+
{
|
|
36216
|
+
sql: `
|
|
36217
|
+
INSERT INTO commons_publication_editions (
|
|
36218
|
+
id, publication_id, owner_user_id, edition_slug, revision, title, site_json, deck,
|
|
36219
|
+
articles_json, html, filename, sha256, article_count, word_count, bytes, warnings_json,
|
|
36220
|
+
idempotency_key, created_at, published_at
|
|
36221
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
36222
|
+
`,
|
|
36223
|
+
args: [
|
|
36224
|
+
editionId,
|
|
36225
|
+
publication.id,
|
|
36226
|
+
Number(user.id),
|
|
36227
|
+
editionSlug,
|
|
36228
|
+
revision,
|
|
36229
|
+
latest.site.title,
|
|
36230
|
+
JSON.stringify(latest.site),
|
|
36231
|
+
latest.deck,
|
|
36232
|
+
JSON.stringify(nextArticles),
|
|
36233
|
+
html,
|
|
36234
|
+
rendered.filename,
|
|
36235
|
+
createHash16("sha256").update(html).digest("hex"),
|
|
36236
|
+
rendered.articleCount,
|
|
36237
|
+
rendered.wordCount,
|
|
36238
|
+
Buffer.byteLength(html),
|
|
36239
|
+
JSON.stringify(rendered.warnings),
|
|
36240
|
+
idempotencyKey3,
|
|
36241
|
+
now,
|
|
36242
|
+
now
|
|
36243
|
+
]
|
|
36244
|
+
},
|
|
36245
|
+
{
|
|
36246
|
+
sql: "UPDATE commons_publications SET latest_edition_id = ?, updated_at = ? WHERE id = ? AND owner_user_id = ?",
|
|
36247
|
+
args: [editionId, now, publication.id, Number(user.id)]
|
|
36248
|
+
}
|
|
36249
|
+
], "write");
|
|
36250
|
+
const edition = await getPublicationEditionById(editionId);
|
|
36251
|
+
if (!edition) throw new CommonsPublicationError("publication_publish_failed", "The edited edition was not persisted.");
|
|
36252
|
+
return {
|
|
36253
|
+
...publicationResult({ ...publication, latestEditionId: editionId, updatedAt: now }, edition, false),
|
|
36254
|
+
updatedArticle: { slug: input.articleSlug, previousRevision: latest.revision, revision },
|
|
36255
|
+
unchangedArticles: articles.length - 1
|
|
36256
|
+
};
|
|
36257
|
+
}
|
|
35920
36258
|
async function getCommonsPublicationBySubdomain(subdomainInput) {
|
|
35921
36259
|
await ensureCommonsSchema();
|
|
35922
36260
|
const subdomain = normalizePublicationSubdomain(subdomainInput);
|
|
@@ -35945,6 +36283,20 @@ async function listCommonsPublicationEditions(publicationId) {
|
|
|
35945
36283
|
if (!publication) return [];
|
|
35946
36284
|
return result.rows.map((row) => rowToEdition(row, publication.subdomain));
|
|
35947
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
|
+
}
|
|
35948
36300
|
async function getCommonsPublicationEditionHtml(subdomainInput, editionSlugInput) {
|
|
35949
36301
|
const publication = await getCommonsPublicationBySubdomain(subdomainInput);
|
|
35950
36302
|
if (!publication) return null;
|
|
@@ -36014,6 +36366,7 @@ function rowToEdition(row, subdomain) {
|
|
|
36014
36366
|
revision: Number(row.revision),
|
|
36015
36367
|
title: String(row.title),
|
|
36016
36368
|
site: parseJson4(row.site_json, {}),
|
|
36369
|
+
articles: parseJson4(row.articles_json, []),
|
|
36017
36370
|
deck: String(row.deck),
|
|
36018
36371
|
filename: String(row.filename),
|
|
36019
36372
|
sha256: String(row.sha256),
|
|
@@ -36089,6 +36442,7 @@ function addPublicMetadata(html, canonicalUrl, publicationTitle) {
|
|
|
36089
36442
|
var commonsApp = new Hono31();
|
|
36090
36443
|
var auth2 = createApiKeyAuth();
|
|
36091
36444
|
var SearchBodySchema = z32.object({
|
|
36445
|
+
mode: z32.enum(["lexical", "semantic", "hybrid"]).optional(),
|
|
36092
36446
|
query: z32.string().max(300).optional(),
|
|
36093
36447
|
entityType: z32.string().max(120).optional(),
|
|
36094
36448
|
tag: z32.string().max(80).optional(),
|
|
@@ -36251,6 +36605,15 @@ var PreparePublicationSchema = z32.object(CommonsPreparePublicationInputSchema).
|
|
|
36251
36605
|
var ValidatePublicationSchema = z32.object(CommonsValidatePublicationInputSchema).strict();
|
|
36252
36606
|
var ClaimPublicationSchema = z32.object(CommonsClaimPublicationInputSchema).strict();
|
|
36253
36607
|
var PublishEditorialSchema = z32.object(CommonsPublishEditorialInputSchema).strict();
|
|
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
|
+
});
|
|
36254
36617
|
commonsApp.get("/health", async (c) => {
|
|
36255
36618
|
await ensureCommonsSchema();
|
|
36256
36619
|
return c.json({ ok: true, data: commonsDatabaseReport() });
|
|
@@ -36286,11 +36649,16 @@ commonsApp.post("/publications/publish", auth2, async (c) => {
|
|
|
36286
36649
|
if (!parsed.success) return validationError(c, parsed.error);
|
|
36287
36650
|
return publicationOperation(c, () => publishCommonsEditorial(parsed.data, c.get("user")), 201);
|
|
36288
36651
|
});
|
|
36652
|
+
commonsApp.post("/publications/articles", auth2, async (c) => {
|
|
36653
|
+
const parsed = UpdateEditorialArticleSchema.safeParse(await c.req.json().catch(() => ({})));
|
|
36654
|
+
if (!parsed.success) return validationError(c, parsed.error);
|
|
36655
|
+
return publicationOperation(c, () => updateCommonsEditorialArticle(parsed.data, c.get("user")), 201);
|
|
36656
|
+
});
|
|
36289
36657
|
commonsApp.get("/publications/me", auth2, async (c) => {
|
|
36290
36658
|
const publication = await getCommonsPublicationForOwner(Number(c.get("user").id));
|
|
36291
36659
|
if (!publication) return c.json({ ok: false, error: "publication_not_found", message: "This account has not claimed a Commons publication yet." }, 404);
|
|
36292
36660
|
const editions = c.req.query("includeEditions") === "false" ? [] : await listCommonsPublicationEditions(publication.id);
|
|
36293
|
-
return c.json({ ok: true, data: { publication, editions } });
|
|
36661
|
+
return c.json({ ok: true, data: { publication, editions: withArticleSources(editions, c.req.query("includeArticles") === "true") } });
|
|
36294
36662
|
});
|
|
36295
36663
|
commonsApp.get("/publications/:subdomain/site", async (c) => {
|
|
36296
36664
|
try {
|
|
@@ -36304,6 +36672,28 @@ commonsApp.get("/publications/:subdomain/site", async (c) => {
|
|
|
36304
36672
|
return publicationError(c, error);
|
|
36305
36673
|
}
|
|
36306
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
|
+
});
|
|
36307
36697
|
commonsApp.get("/publications/:subdomain/editions/:editionSlug/site", async (c) => {
|
|
36308
36698
|
try {
|
|
36309
36699
|
const result = await getCommonsPublicationEditionHtml(c.req.param("subdomain"), c.req.param("editionSlug"));
|
|
@@ -36330,7 +36720,7 @@ commonsApp.get("/publications/:subdomain", async (c) => {
|
|
|
36330
36720
|
const publication = await getCommonsPublicationBySubdomain(c.req.param("subdomain"));
|
|
36331
36721
|
if (!publication) return c.json({ ok: false, error: "publication_not_found", message: "No Commons publication matched that name." }, 404);
|
|
36332
36722
|
const editions = c.req.query("includeEditions") === "false" ? [] : await listCommonsPublicationEditions(publication.id);
|
|
36333
|
-
return c.json({ ok: true, data: { publication, editions } });
|
|
36723
|
+
return c.json({ ok: true, data: { publication, editions: withArticleSources(editions, false) } });
|
|
36334
36724
|
} catch (error) {
|
|
36335
36725
|
return publicationError(c, error);
|
|
36336
36726
|
}
|
|
@@ -36506,6 +36896,7 @@ ${urls.join("\n")}
|
|
|
36506
36896
|
});
|
|
36507
36897
|
function filtersFromQuery(query) {
|
|
36508
36898
|
return {
|
|
36899
|
+
mode: query.mode === "lexical" || query.mode === "semantic" ? query.mode : void 0,
|
|
36509
36900
|
query: query.query || query.q,
|
|
36510
36901
|
entityType: query.entityType,
|
|
36511
36902
|
tag: query.tag,
|
|
@@ -36561,6 +36952,13 @@ function publicationError(c, error) {
|
|
|
36561
36952
|
}
|
|
36562
36953
|
throw error;
|
|
36563
36954
|
}
|
|
36955
|
+
function withArticleSources(editions, include) {
|
|
36956
|
+
if (include) return editions;
|
|
36957
|
+
return editions.map((edition) => {
|
|
36958
|
+
const { articles: _articles, ...rest } = edition;
|
|
36959
|
+
return rest;
|
|
36960
|
+
});
|
|
36961
|
+
}
|
|
36564
36962
|
function xmlEscape(value) {
|
|
36565
36963
|
return value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
36566
36964
|
}
|
|
@@ -37148,7 +37546,7 @@ function pixelSnippet(publicId) {
|
|
|
37148
37546
|
function formSnippet(publicId) {
|
|
37149
37547
|
return `<div data-mcp-form="${publicId}"></div><script async src="https://mcpscraper.dev/analytics/v1/form.js?form=${publicId}"></script>`;
|
|
37150
37548
|
}
|
|
37151
|
-
function
|
|
37549
|
+
function escapeHtml7(value) {
|
|
37152
37550
|
return String(value ?? "").replace(
|
|
37153
37551
|
/[&<>"']/g,
|
|
37154
37552
|
(character) => ({ "&": "&", "<": "<", ">": ">", '"': """, "'": "'" })[character]
|
|
@@ -37160,13 +37558,13 @@ function renderPublicForm(form, placementUrl) {
|
|
|
37160
37558
|
const fields = form.fields.map((field) => {
|
|
37161
37559
|
const required = field.required ? " required" : "";
|
|
37162
37560
|
const options = (field.options ?? []).map(
|
|
37163
|
-
(option) => `<option value="${
|
|
37561
|
+
(option) => `<option value="${escapeHtml7(option)}">${escapeHtml7(option)}</option>`
|
|
37164
37562
|
).join("");
|
|
37165
|
-
const control = field.type === "textarea" ? `<textarea id="${
|
|
37166
|
-
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>`;
|
|
37167
37565
|
}).join("");
|
|
37168
37566
|
const brand = form.brand;
|
|
37169
|
-
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>`;
|
|
37170
37568
|
}
|
|
37171
37569
|
analyticsApp.get(
|
|
37172
37570
|
"/health/live",
|
|
@@ -38422,7 +38820,7 @@ async function revokeScheduledRunViewLink(ownerId, runId, shareId, now = /* @__P
|
|
|
38422
38820
|
|
|
38423
38821
|
// src/personal-authority/render.ts
|
|
38424
38822
|
import { createHash as createHash21 } from "crypto";
|
|
38425
|
-
function
|
|
38823
|
+
function escapeHtml8(value) {
|
|
38426
38824
|
return value.replace(/[&<>"']/g, (character) => ({
|
|
38427
38825
|
"&": "&",
|
|
38428
38826
|
"<": "<",
|
|
@@ -38433,13 +38831,13 @@ function escapeHtml7(value) {
|
|
|
38433
38831
|
}
|
|
38434
38832
|
function safeHref(value) {
|
|
38435
38833
|
const trimmed = value.trim();
|
|
38436
|
-
return /^(?:https?:|mailto:|tel:|#|\/)/i.test(trimmed) ?
|
|
38834
|
+
return /^(?:https?:|mailto:|tel:|#|\/)/i.test(trimmed) ? escapeHtml8(trimmed) : "#";
|
|
38437
38835
|
}
|
|
38438
38836
|
function initials(name) {
|
|
38439
38837
|
return name.split(/\s+/).filter(Boolean).slice(0, 2).map((part) => part[0]?.toUpperCase()).join("") || "PA";
|
|
38440
38838
|
}
|
|
38441
38839
|
function action(action3, secondary = false) {
|
|
38442
|
-
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>`;
|
|
38443
38841
|
}
|
|
38444
38842
|
function section(enabled, html) {
|
|
38445
38843
|
return enabled ? html : "";
|
|
@@ -38448,7 +38846,7 @@ function renderPersonalAuthorityV1(input, config, generatedAt) {
|
|
|
38448
38846
|
const flags = config.featureFlags;
|
|
38449
38847
|
const brand = config.brandName || input.name;
|
|
38450
38848
|
const generatedAtIso = generatedAt.toISOString();
|
|
38451
|
-
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>` : "";
|
|
38452
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>` : "";
|
|
38453
38851
|
const authority = input.authority;
|
|
38454
38852
|
const consultation = input.consultation;
|
|
@@ -38460,21 +38858,21 @@ function renderPersonalAuthorityV1(input, config, generatedAt) {
|
|
|
38460
38858
|
<html lang="en" data-theme="${config.theme}">
|
|
38461
38859
|
<head>
|
|
38462
38860
|
<meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
|
|
38463
|
-
<meta name="description" content="${
|
|
38861
|
+
<meta name="description" content="${escapeHtml8(input.summary)}"><title>${escapeHtml8(input.name)} \u2014 ${escapeHtml8(input.professionalTitle)}</title>
|
|
38464
38862
|
<style>
|
|
38465
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)}
|
|
38466
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}}
|
|
38467
38865
|
</style></head>
|
|
38468
38866
|
<body><a class="skip" href="#main">Skip to main content</a>
|
|
38469
|
-
<header class="header"><a class="brand" href="#top"><span class="mark">${
|
|
38470
|
-
<main id="main"><section class="hero" id="top"><div class="portrait" aria-label="Portrait placeholder"><div class="portrait-card" aria-hidden="true">${
|
|
38471
|
-
${section(flags.authority && Boolean(authority), `<section class="light" id="about"><h2>${
|
|
38472
|
-
${section(flags.consultation && Boolean(consultation), `<section class="section consult"><div><p class="eyebrow">${
|
|
38473
|
-
${section(flags.learning && Boolean(learning), `<section class="section learning"><div class="section-head"><h2>${
|
|
38474
|
-
${section(flags.services && Boolean(services), `<section class="section" id="services"><div class="section-head"><h2>${
|
|
38475
|
-
${section(flags.proof && Boolean(proof), `<section class="section proof" id="proof"><div class="section-head"><h2>${
|
|
38476
|
-
${section(flags.finalCta && Boolean(finalCta), `<section class="section cta" id="contact"><p class="eyebrow">${
|
|
38477
|
-
</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>
|
|
38478
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>`;
|
|
38479
38877
|
const bytes = Buffer.byteLength(html, "utf8");
|
|
38480
38878
|
return {
|
|
@@ -38493,7 +38891,7 @@ var FONT_STACKS = Object.freeze({
|
|
|
38493
38891
|
"modern-sans": "Avenir Next, Avenir, Helvetica Neue, Arial, sans-serif",
|
|
38494
38892
|
"humanist-sans": "Optima, Candara, Segoe UI, sans-serif"
|
|
38495
38893
|
});
|
|
38496
|
-
function
|
|
38894
|
+
function escapeHtml9(value) {
|
|
38497
38895
|
return value.replace(
|
|
38498
38896
|
/[&<>"']/g,
|
|
38499
38897
|
(character) => ({
|
|
@@ -38507,13 +38905,13 @@ function escapeHtml8(value) {
|
|
|
38507
38905
|
}
|
|
38508
38906
|
function safeHref2(value) {
|
|
38509
38907
|
const trimmed = value.trim();
|
|
38510
|
-
return /^(?:https?:|mailto:|tel:|#|\/)/i.test(trimmed) ?
|
|
38908
|
+
return /^(?:https?:|mailto:|tel:|#|\/)/i.test(trimmed) ? escapeHtml9(trimmed) : "#";
|
|
38511
38909
|
}
|
|
38512
38910
|
function initials2(name) {
|
|
38513
38911
|
return name.split(/\s+/).filter(Boolean).slice(0, 2).map((part) => part[0]?.toUpperCase()).join("") || "PA";
|
|
38514
38912
|
}
|
|
38515
38913
|
function action2(action3, secondary = false) {
|
|
38516
|
-
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>`;
|
|
38517
38915
|
}
|
|
38518
38916
|
function section2(enabled, html) {
|
|
38519
38917
|
return enabled ? html : "";
|
|
@@ -38557,7 +38955,7 @@ function renderPersonalAuthorityV2(input, config, generatedAt) {
|
|
|
38557
38955
|
const surfaceContrast = bestContrastTextColor(colors.surface);
|
|
38558
38956
|
const accentChannels = hexChannels(colors.accent);
|
|
38559
38957
|
const generatedAtIso = generatedAt.toISOString();
|
|
38560
|
-
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>` : "";
|
|
38561
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>` : "";
|
|
38562
38960
|
const authority = input.authority;
|
|
38563
38961
|
const consultation = input.consultation;
|
|
@@ -38569,22 +38967,22 @@ function renderPersonalAuthorityV2(input, config, generatedAt) {
|
|
|
38569
38967
|
<html lang="en" data-theme="${config.theme}">
|
|
38570
38968
|
<head>
|
|
38571
38969
|
<meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
|
|
38572
|
-
<meta name="description" content="${
|
|
38970
|
+
<meta name="description" content="${escapeHtml9(input.summary)}"><title>${escapeHtml9(input.name)} - ${escapeHtml9(input.professionalTitle)}</title>
|
|
38573
38971
|
<style>
|
|
38574
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)}
|
|
38575
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}}
|
|
38576
38974
|
@media(prefers-reduced-motion:reduce){html{scroll-behavior:auto}.button{transition:none}}
|
|
38577
38975
|
</style></head>
|
|
38578
38976
|
<body><a class="skip" href="#main">Skip to main content</a>
|
|
38579
|
-
<header class="header"><a class="brand" href="#top"><span class="mark">${
|
|
38580
|
-
<main id="main"><section class="hero" id="top"><div class="portrait" aria-label="Portrait placeholder"><div class="portrait-card" aria-hidden="true">${
|
|
38581
|
-
${section2(flags.authority && Boolean(authority), `<section class="light" id="about"><h2>${
|
|
38582
|
-
${section2(flags.consultation && Boolean(consultation), `<section class="section consult"><div><p class="eyebrow">${
|
|
38583
|
-
${section2(flags.learning && Boolean(learning), `<section class="section learning"><div class="section-head"><h2>${
|
|
38584
|
-
${section2(flags.services && Boolean(services), `<section class="section" id="services"><div class="section-head"><h2>${
|
|
38585
|
-
${section2(flags.proof && Boolean(proof), `<section class="section proof" id="proof"><div class="section-head"><h2>${
|
|
38586
|
-
${section2(flags.finalCta && Boolean(finalCta), `<section class="section cta" id="contact"><p class="eyebrow">${
|
|
38587
|
-
</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>
|
|
38588
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>`;
|
|
38589
38987
|
const bytes = Buffer.byteLength(html, "utf8");
|
|
38590
38988
|
return {
|
|
@@ -38598,7 +38996,7 @@ ${section2(flags.finalCta && Boolean(finalCta), `<section class="section cta" id
|
|
|
38598
38996
|
|
|
38599
38997
|
// src/newsroom-publisher/render.ts
|
|
38600
38998
|
import { createHash as createHash23 } from "crypto";
|
|
38601
|
-
function
|
|
38999
|
+
function escapeHtml10(value) {
|
|
38602
39000
|
return value.replace(/[&<>"']/g, (character) => ({
|
|
38603
39001
|
"&": "&",
|
|
38604
39002
|
"<": "<",
|
|
@@ -38609,30 +39007,30 @@ function escapeHtml9(value) {
|
|
|
38609
39007
|
}
|
|
38610
39008
|
function safeHref3(value) {
|
|
38611
39009
|
const trimmed = value.trim();
|
|
38612
|
-
return /^(?:https?:|mailto:|tel:|#|\/)/i.test(trimmed) ?
|
|
39010
|
+
return /^(?:https?:|mailto:|tel:|#|\/)/i.test(trimmed) ? escapeHtml10(trimmed) : "#";
|
|
38613
39011
|
}
|
|
38614
39012
|
function formatDate(value) {
|
|
38615
39013
|
const date = new Date(value);
|
|
38616
|
-
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);
|
|
38617
39015
|
}
|
|
38618
39016
|
function initials3(value) {
|
|
38619
39017
|
return value.split(/\s+/).filter(Boolean).slice(0, 2).map((part) => part[0]).join("").toUpperCase();
|
|
38620
39018
|
}
|
|
38621
39019
|
function storyMedia(story, className = "") {
|
|
38622
39020
|
if (story.imageUrl) {
|
|
38623
|
-
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>`;
|
|
38624
39022
|
}
|
|
38625
39023
|
const tone = [...story.title].reduce((total, character) => total + character.charCodeAt(0), 0) % 5;
|
|
38626
|
-
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>`;
|
|
38627
39025
|
}
|
|
38628
39026
|
function byline(story, showBylines) {
|
|
38629
|
-
const author = story.author.href ? `<a href="${safeHref3(story.author.href)}">${
|
|
38630
|
-
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>`;
|
|
38631
39029
|
}
|
|
38632
39030
|
function storyCard(story, showBylines, variant = "") {
|
|
38633
39031
|
return `<article class="story-card ${variant}">
|
|
38634
39032
|
<a class="story-card__media" href="${safeHref3(story.href)}">${storyMedia(story)}</a>
|
|
38635
|
-
<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>
|
|
38636
39034
|
</article>`;
|
|
38637
39035
|
}
|
|
38638
39036
|
function renderNewsroomPublisherV1(input, config, generatedAt) {
|
|
@@ -38649,22 +39047,22 @@ function renderNewsroomPublisherV1(input, config, generatedAt) {
|
|
|
38649
39047
|
input.primaryPages.contact
|
|
38650
39048
|
];
|
|
38651
39049
|
const trustPages = Object.values(input.trustPages);
|
|
38652
|
-
const ticker = flags.breakingTicker && input.ticker ? `<div class="ticker"><div><b>${
|
|
38653
|
-
const masthead = `<nav class="utility-nav" aria-label="Publication pages"><div><span>${
|
|
38654
|
-
<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>
|
|
38655
39053
|
<div class="masthead__date"><span>Independent journalism</span><time datetime="${generatedAtIso}">${formatDate(generatedAtIso)}</time></div>
|
|
38656
39054
|
<div class="masthead__tools"><button type="button" aria-label="Search">Search</button><button type="button" aria-label="Open menu">Menu</button></div>
|
|
38657
39055
|
</header>`;
|
|
38658
|
-
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>` : "";
|
|
38659
39057
|
const leadGrid = flags.leadGrid ? `<section class="lead-grid" aria-label="Top stories">
|
|
38660
39058
|
<div class="lead-grid__label"><span>Today\u2019s edition</span><b>Top stories</b></div>
|
|
38661
|
-
<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>
|
|
38662
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>
|
|
38663
39061
|
</section>` : "";
|
|
38664
39062
|
const latest = flags.latestNews && input.latest.length > 0 ? `<section class="latest" id="latest">
|
|
38665
39063
|
<div class="section-title"><div><span>Live desk</span><h2>Latest news</h2></div><a href="#top">Back to top \u2191</a></div>
|
|
38666
|
-
<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)}">${
|
|
38667
|
-
<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>
|
|
38668
39066
|
</section>` : "";
|
|
38669
39067
|
const sectionLayouts = ["panorama", "mosaic", "tiles"];
|
|
38670
39068
|
const sections = flags.categorySections ? input.sections.map((section3, sectionIndex) => {
|
|
@@ -38675,16 +39073,16 @@ function renderNewsroomPublisherV1(input, config, generatedAt) {
|
|
|
38675
39073
|
layout === "panorama" && index === 0 ? "story-card--panorama" : layout === "mosaic" && index === 0 ? "story-card--mosaic-lead" : ""
|
|
38676
39074
|
)).join("");
|
|
38677
39075
|
return `<section class="desk-section desk-section--${sectionIndex % 2 ? "tint" : "plain"} desk-section--layout-${layout}">
|
|
38678
|
-
<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>
|
|
38679
39077
|
<div class="desk-section__grid desk-section__grid--${layout}">${cards}</div>
|
|
38680
39078
|
</section>`;
|
|
38681
39079
|
}).join("") : "";
|
|
38682
|
-
const newsletter = flags.newsletter && input.newsletter ? `<section class="newsletter"><div><span>${
|
|
38683
|
-
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>${
|
|
38684
|
-
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>${
|
|
38685
|
-
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>` : "";
|
|
38686
39084
|
const html = `<!doctype html>
|
|
38687
|
-
<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">
|
|
38688
39086
|
<style>
|
|
38689
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}}
|
|
38690
39088
|
/* Tampa-inspired publication palette */
|
|
@@ -38701,7 +39099,7 @@ body{overflow-x:hidden}.lead-story__body,.lead-support__item,.story-card__body{m
|
|
|
38701
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)}}
|
|
38702
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)}}
|
|
38703
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}}
|
|
38704
|
-
</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>`;
|
|
38705
39103
|
const bytes = Buffer.byteLength(html);
|
|
38706
39104
|
const sha2563 = createHash23("sha256").update(html).digest("hex");
|
|
38707
39105
|
const filename = `${brand.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "") || "newsroom"}-news-site.html`;
|
|
@@ -38710,7 +39108,7 @@ body{overflow-x:hidden}.lead-story__body,.lead-support__item,.story-card__body{m
|
|
|
38710
39108
|
|
|
38711
39109
|
// src/blog-article/render.ts
|
|
38712
39110
|
import { createHash as createHash24 } from "crypto";
|
|
38713
|
-
function
|
|
39111
|
+
function escapeHtml11(value) {
|
|
38714
39112
|
return value.replace(
|
|
38715
39113
|
/[&<>"']/g,
|
|
38716
39114
|
(character) => ({
|
|
@@ -38724,11 +39122,11 @@ function escapeHtml10(value) {
|
|
|
38724
39122
|
}
|
|
38725
39123
|
function safeHref4(value) {
|
|
38726
39124
|
const trimmed = value.trim();
|
|
38727
|
-
return /^(?:https?:|mailto:|tel:|#|\/)/i.test(trimmed) ?
|
|
39125
|
+
return /^(?:https?:|mailto:|tel:|#|\/)/i.test(trimmed) ? escapeHtml11(trimmed) : "#";
|
|
38728
39126
|
}
|
|
38729
39127
|
function formatDate2(value) {
|
|
38730
39128
|
const date = new Date(value);
|
|
38731
|
-
return Number.isNaN(date.getTime()) ?
|
|
39129
|
+
return Number.isNaN(date.getTime()) ? escapeHtml11(value) : new Intl.DateTimeFormat("en", {
|
|
38732
39130
|
month: "long",
|
|
38733
39131
|
day: "numeric",
|
|
38734
39132
|
year: "numeric"
|
|
@@ -38742,15 +39140,15 @@ function jsonForScript(value) {
|
|
|
38742
39140
|
}
|
|
38743
39141
|
function portrait(input) {
|
|
38744
39142
|
if (input.author.portraitUrl) {
|
|
38745
|
-
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)}">`;
|
|
38746
39144
|
}
|
|
38747
|
-
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>`;
|
|
38748
39146
|
}
|
|
38749
39147
|
function sidebarArt(input) {
|
|
38750
39148
|
if (input.sidebarMedia?.imageUrl) {
|
|
38751
|
-
return `<img src="${safeHref4(input.sidebarMedia.imageUrl)}" alt="${
|
|
39149
|
+
return `<img src="${safeHref4(input.sidebarMedia.imageUrl)}" alt="${escapeHtml11(input.sidebarMedia.imageAlt)}">`;
|
|
38752
39150
|
}
|
|
38753
|
-
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>`;
|
|
38754
39152
|
}
|
|
38755
39153
|
function citations(input) {
|
|
38756
39154
|
const published = new Date(input.publishedAt);
|
|
@@ -38779,23 +39177,23 @@ function renderBlogArticleV1(input, config, generatedAt) {
|
|
|
38779
39177
|
...flags.faq && input.faq.length ? [{ id: "faq", title: "Frequently asked questions" }] : []
|
|
38780
39178
|
];
|
|
38781
39179
|
const contributorText = [
|
|
38782
|
-
`Written by <a href="${safeHref4(input.author.href || "#author")}">${
|
|
38783
|
-
input.editor ? `Edited by <a href="${safeHref4(input.editor.href || "#")}">${
|
|
38784
|
-
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>` : ""
|
|
38785
39183
|
].filter(Boolean).join(" \xB7 ");
|
|
38786
39184
|
const sections = input.sections.map(
|
|
38787
|
-
(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>`
|
|
38788
39186
|
).join("");
|
|
38789
|
-
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>${
|
|
38790
|
-
const media = flags.sidebarMedia && input.sidebarMedia ? `<figure class="sidebar-media" data-article-media>${sidebarArt(input)}${input.sidebarMedia.caption ? `<figcaption>${
|
|
38791
|
-
const disclosure = flags.disclosure && input.disclosure ? `<section class="disclosure"><button type="button" aria-expanded="false" aria-controls="disclosure-details"><span>${
|
|
38792
|
-
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>` : "";
|
|
38793
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>` : "";
|
|
38794
|
-
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)}">${
|
|
38795
|
-
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> ${
|
|
38796
|
-
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>
|
|
38797
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}}
|
|
38798
|
-
</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>`;
|
|
38799
39197
|
const bytes = Buffer.byteLength(html);
|
|
38800
39198
|
const sha2563 = createHash24("sha256").update(html).digest("hex");
|
|
38801
39199
|
return {
|
|
@@ -41395,7 +41793,7 @@ async function getFreeCreditBreakdown(userId) {
|
|
|
41395
41793
|
}
|
|
41396
41794
|
|
|
41397
41795
|
// src/api/memory-db.ts
|
|
41398
|
-
import { neon } from "@neondatabase/serverless";
|
|
41796
|
+
import { neon as neon2 } from "@neondatabase/serverless";
|
|
41399
41797
|
|
|
41400
41798
|
// src/api/memory-universe.ts
|
|
41401
41799
|
var SEP = "\n";
|
|
@@ -41492,7 +41890,7 @@ function sql() {
|
|
|
41492
41890
|
if (_sql) return _sql;
|
|
41493
41891
|
const url = process.env.MEMORY_DATABASE_URL?.trim();
|
|
41494
41892
|
if (!url) throw new Error("MEMORY_DATABASE_URL is not set (paa-crawler needs mcp-memory Neon URL for reads)");
|
|
41495
|
-
_sql =
|
|
41893
|
+
_sql = neon2(url);
|
|
41496
41894
|
return _sql;
|
|
41497
41895
|
}
|
|
41498
41896
|
function physicalVault(owner, vault) {
|
|
@@ -47191,11 +47589,11 @@ app.get("/cron/tick", async (c) => {
|
|
|
47191
47589
|
return c.json({ error: "Unauthorized" }, 401);
|
|
47192
47590
|
}
|
|
47193
47591
|
const startedAt = Date.now();
|
|
47194
|
-
const { drainQueue } = await import("./worker-
|
|
47592
|
+
const { drainQueue } = await import("./worker-QFSOMF2N.js");
|
|
47195
47593
|
const budget = { maxJobs: 10, deadlineMs: startedAt + CRON_TICK_DRAIN_BUDGET_MS };
|
|
47196
47594
|
const origin = `${new URL(c.req.url).protocol}//${new URL(c.req.url).host}`;
|
|
47197
47595
|
const unfinished = [];
|
|
47198
|
-
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([
|
|
47199
47597
|
settleWithinTickBudget("drainQueue", unfinished, drainQueue(budget), []),
|
|
47200
47598
|
settleWithinTickBudget("monthlyRefreshSweep", unfinished, runMonthlyRefreshSweep(), { status: "skipped_deadline" }),
|
|
47201
47599
|
settleWithinTickBudget("reapBrowserSessions", unfinished, reapIdleBrowserSessions(120), { reaped: 0 }),
|
|
@@ -47212,6 +47610,7 @@ app.get("/cron/tick", async (c) => {
|
|
|
47212
47610
|
settleWithinTickBudget("siteExtractReconcile", unfinished, reconcileSiteExtractSettlements(10), { checked: 0, settled: 0, failed: 0 }),
|
|
47213
47611
|
settleWithinTickBudget("paaRedispatch", unfinished, redispatchPendingPaaHarvests(10), { checked: 0, dispatched: 0, failed: 0 }),
|
|
47214
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 }),
|
|
47215
47614
|
settleWithinTickBudget("localSourcebookRedispatch", unfinished, redispatchQueuedLocalSourcebookAcquisitions(5), { checked: 0, dispatched: 0, failed: 0 }),
|
|
47216
47615
|
settleWithinTickBudget("analyticsRollup", unfinished, refreshAnalyticsDailyRollupsIfDue(), { status: "failed", rows: 0 }),
|
|
47217
47616
|
settleWithinTickBudget("analyticsForms", unfinished, deliverPendingAnalyticsForms(10), { claimed: 0, delivered: 0, deferred: 0 }),
|
|
@@ -47242,6 +47641,7 @@ app.get("/cron/tick", async (c) => {
|
|
|
47242
47641
|
siteExtractReconciliation,
|
|
47243
47642
|
paaHarvestRedispatch,
|
|
47244
47643
|
paaHarvestReconciliation,
|
|
47644
|
+
commonsEmbeddingDrain,
|
|
47245
47645
|
localSourcebookRedispatch,
|
|
47246
47646
|
analyticsRollup,
|
|
47247
47647
|
analyticsFormDelivery,
|
|
@@ -47261,8 +47661,8 @@ app.post("/api/internal/extract-refinalize/:id", async (c) => {
|
|
|
47261
47661
|
finishExtractJob: finishExtractJob2,
|
|
47262
47662
|
terminalExtractJobStatus: terminalExtractJobStatus2,
|
|
47263
47663
|
extractJobLimitInfo: extractJobLimitInfo2
|
|
47264
|
-
} = await import("./site-extract-repository-
|
|
47265
|
-
const { assembleExtractArtifacts } = await import("./extract-bundle-
|
|
47664
|
+
} = await import("./site-extract-repository-XAA2FVDN.js");
|
|
47665
|
+
const { assembleExtractArtifacts } = await import("./extract-bundle-XRRN6NAZ.js");
|
|
47266
47666
|
const existing = await getExtractJob2(jobId2);
|
|
47267
47667
|
if (!existing) return c.json({ error: "job not found" }, 404);
|
|
47268
47668
|
if (existing.status !== "failed") {
|
|
@@ -47289,7 +47689,7 @@ app.post("/api/internal/extract-refinalize/:id", async (c) => {
|
|
|
47289
47689
|
if (!updated) return c.json({ error: "job state changed during re-finalization" }, 409);
|
|
47290
47690
|
let settlement = "already_settled_or_refunded";
|
|
47291
47691
|
if (job.billedMc == null && job.userId != null) {
|
|
47292
|
-
const { settleExtractJob: settleExtractJob3, countSuccessfulPages: countSuccessfulPages2 } = await import("./site-extract-repository-
|
|
47692
|
+
const { settleExtractJob: settleExtractJob3, countSuccessfulPages: countSuccessfulPages2 } = await import("./site-extract-repository-XAA2FVDN.js");
|
|
47293
47693
|
const heldMc = Number(job.options.heldMc ?? 0);
|
|
47294
47694
|
const successful = await countSuccessfulPages2(jobId2);
|
|
47295
47695
|
const usedMc = Math.min(successful * MC_COSTS.page_scrape, heldMc);
|
|
@@ -47474,4 +47874,4 @@ app.get("/blog/:slug/", (c) => {
|
|
|
47474
47874
|
export {
|
|
47475
47875
|
app
|
|
47476
47876
|
};
|
|
47477
|
-
//# sourceMappingURL=server-
|
|
47877
|
+
//# sourceMappingURL=server-IRKNU6LO.js.map
|