mcp-scraper 0.45.0 → 0.47.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/README.md +6 -2
  2. package/dist/bin/api-server.cjs +1098 -198
  3. package/dist/bin/api-server.cjs.map +1 -1
  4. package/dist/bin/api-server.js +3 -3
  5. package/dist/bin/mcp-scraper-cli.cjs +1 -1
  6. package/dist/bin/mcp-scraper-cli.cjs.map +1 -1
  7. package/dist/bin/mcp-scraper-cli.js +1 -1
  8. package/dist/bin/mcp-scraper-install.cjs +3 -2
  9. package/dist/bin/mcp-scraper-install.cjs.map +1 -1
  10. package/dist/bin/mcp-scraper-install.js +2 -2
  11. package/dist/bin/mcp-stdio-server.cjs +251 -34
  12. package/dist/bin/mcp-stdio-server.cjs.map +1 -1
  13. package/dist/bin/mcp-stdio-server.js +5 -5
  14. package/dist/bin/paa-harvest.cjs.map +1 -1
  15. package/dist/bin/paa-harvest.js +3 -3
  16. package/dist/{chunk-5X7CJEK3.js → chunk-5S6LYQQO.js} +2 -2
  17. package/dist/chunk-5S6LYQQO.js.map +1 -0
  18. package/dist/{chunk-OVD4E4AP.js → chunk-GV5EGE5M.js} +2 -2
  19. package/dist/chunk-H4NWAF5B.js +7 -0
  20. package/dist/chunk-H4NWAF5B.js.map +1 -0
  21. package/dist/{chunk-T5AFM4G5.js → chunk-IWYYZXBR.js} +2 -2
  22. package/dist/{chunk-RJMOOII7.js → chunk-JH7A4HA7.js} +2 -2
  23. package/dist/{chunk-JFOT5JEL.js → chunk-MW3ET532.js} +2 -2
  24. package/dist/{chunk-GRODXRUY.js → chunk-QSUGPYGQ.js} +3 -2
  25. package/dist/chunk-QSUGPYGQ.js.map +1 -0
  26. package/dist/{chunk-WT2UHDSE.js → chunk-TV6KPZ6J.js} +2 -2
  27. package/dist/{chunk-FQIICRR4.js → chunk-XCGQBGDA.js} +296 -38
  28. package/dist/chunk-XCGQBGDA.js.map +1 -0
  29. package/dist/{db-4ABEYNDM.js → db-W3RPRILW.js} +2 -2
  30. package/dist/{extract-bundle-DYMQRQWG.js → extract-bundle-DXWWQER6.js} +3 -3
  31. package/dist/index.cjs.map +1 -1
  32. package/dist/index.js +3 -3
  33. package/dist/{location-data-repository-HDNCU4Z4.js → location-data-repository-2FJVMTZ2.js} +3 -3
  34. package/dist/{server-7B75SDNG.js → server-OHMZJRSB.js} +778 -141
  35. package/dist/server-OHMZJRSB.js.map +1 -0
  36. package/dist/{site-extract-repository-G723PZIL.js → site-extract-repository-UULQAGO4.js} +3 -3
  37. package/dist/{worker-4LZGRHDA.js → worker-3QX7LG62.js} +5 -5
  38. package/package.json +2 -2
  39. package/dist/chunk-5X7CJEK3.js.map +0 -1
  40. package/dist/chunk-CEZ3NFBP.js +0 -7
  41. package/dist/chunk-CEZ3NFBP.js.map +0 -1
  42. package/dist/chunk-FQIICRR4.js.map +0 -1
  43. package/dist/chunk-GRODXRUY.js.map +0 -1
  44. package/dist/server-7B75SDNG.js.map +0 -1
  45. /package/dist/{chunk-OVD4E4AP.js.map → chunk-GV5EGE5M.js.map} +0 -0
  46. /package/dist/{chunk-T5AFM4G5.js.map → chunk-IWYYZXBR.js.map} +0 -0
  47. /package/dist/{chunk-RJMOOII7.js.map → chunk-JH7A4HA7.js.map} +0 -0
  48. /package/dist/{chunk-JFOT5JEL.js.map → chunk-MW3ET532.js.map} +0 -0
  49. /package/dist/{chunk-WT2UHDSE.js.map → chunk-TV6KPZ6J.js.map} +0 -0
  50. /package/dist/{db-4ABEYNDM.js.map → db-W3RPRILW.js.map} +0 -0
  51. /package/dist/{extract-bundle-DYMQRQWG.js.map → extract-bundle-DXWWQER6.js.map} +0 -0
  52. /package/dist/{location-data-repository-HDNCU4Z4.js.map → location-data-repository-2FJVMTZ2.js.map} +0 -0
  53. /package/dist/{site-extract-repository-G723PZIL.js.map → site-extract-repository-UULQAGO4.js.map} +0 -0
  54. /package/dist/{worker-4LZGRHDA.js.map → worker-3QX7LG62.js.map} +0 -0
@@ -10,14 +10,14 @@ import {
10
10
  importHostedCensusPlacesCsv,
11
11
  importHostedZipGroupsCsv,
12
12
  listActiveHostedLocationDatasets
13
- } from "./chunk-WT2UHDSE.js";
13
+ } from "./chunk-TV6KPZ6J.js";
14
14
  import {
15
15
  classifyHarvestProblem,
16
16
  createHarvestAttemptRecorder,
17
17
  deliverWebhook,
18
18
  harvestProblemResponse,
19
19
  serializeHarvestProblem
20
- } from "./chunk-OVD4E4AP.js";
20
+ } from "./chunk-GV5EGE5M.js";
21
21
  import {
22
22
  AIModeSelectors,
23
23
  AIOverviewSelectors,
@@ -44,22 +44,29 @@ import {
44
44
  resolveKernelProxyId,
45
45
  serpArrivalUrl,
46
46
  withRuntimeUserAgent
47
- } from "./chunk-RJMOOII7.js";
47
+ } from "./chunk-JH7A4HA7.js";
48
48
  import {
49
49
  ApiErrorResponseSchema,
50
- ArtifactTemplateConfigSchema,
50
+ CommonsClaimPublicationInputSchema,
51
+ CommonsPreparePublicationInputSchema,
52
+ CommonsPublishEditorialInputSchema,
53
+ CommonsValidatePublicationInputSchema,
51
54
  CreateArtifactTemplateInputSchema,
52
55
  CreateEditorialReadingRoomInputSchema,
53
56
  CreateScheduledRunViewLinkInputSchema,
57
+ EDITORIAL_READING_ROOM_TEMPLATE_PRESET,
58
+ EditorialArtifactTemplateConfigSchema,
54
59
  EditorialReadingRoomV1InputSchema,
55
60
  GetScheduledRunResponseSchema,
56
61
  HttpMcpToolExecutor,
57
62
  InternalScheduledArtifactRenderRequestSchema,
58
63
  ListScheduledRunsQuerySchema,
59
64
  LocalSourcebookSchemaTypeSchema,
65
+ PERSONAL_AUTHORITY_TEMPLATE_PRESET,
66
+ PersonalAuthorityTemplateConfigSchema,
67
+ PersonalAuthorityV1InputSchema,
60
68
  PublicScheduledRunTokenSchema,
61
69
  RenewEditorialReadingRoomDownloadInputSchema,
62
- SCHEDULED_ARTIFACT_TEMPLATE_PRESET,
63
70
  ScheduledResultsMcpExecutor,
64
71
  UpdateArtifactTemplateInputSchema,
65
72
  WIZPER_LANGUAGES,
@@ -90,7 +97,7 @@ import {
90
97
  resolveDeploymentProfile,
91
98
  resolveLocalSourcebookSchemaType,
92
99
  transcribeMediaUrl
93
- } from "./chunk-FQIICRR4.js";
100
+ } from "./chunk-XCGQBGDA.js";
94
101
  import {
95
102
  auditImageUrls,
96
103
  auditImages,
@@ -118,7 +125,7 @@ import {
118
125
  recordKernelSession,
119
126
  recordVendorUsage,
120
127
  runWithCostContext
121
- } from "./chunk-T5AFM4G5.js";
128
+ } from "./chunk-IWYYZXBR.js";
122
129
  import {
123
130
  listWorkflowDefinitions,
124
131
  runWorkflow,
@@ -146,7 +153,7 @@ import {
146
153
  } from "./chunk-3ZUBQQPQ.js";
147
154
  import {
148
155
  PACKAGE_VERSION
149
- } from "./chunk-CEZ3NFBP.js";
156
+ } from "./chunk-H4NWAF5B.js";
150
157
  import {
151
158
  abandonExtractSettlement,
152
159
  countSuccessfulPages,
@@ -169,7 +176,7 @@ import {
169
176
  setExtractJobTotal,
170
177
  settleExtractJob,
171
178
  terminalExtractJobStatus
172
- } from "./chunk-JFOT5JEL.js";
179
+ } from "./chunk-MW3ET532.js";
173
180
  import {
174
181
  BROWSER_OPEN_MIN_BALANCE_MC,
175
182
  CONCURRENCY_PRICE_ID,
@@ -326,7 +333,7 @@ import {
326
333
  startHarvestAttempt,
327
334
  upsertPageSnapshot,
328
335
  verifyPassword
329
- } from "./chunk-5X7CJEK3.js";
336
+ } from "./chunk-5S6LYQQO.js";
330
337
 
331
338
  // src/blog/registry.ts
332
339
  var posts = [
@@ -2686,38 +2693,38 @@ function renderCard(card) {
2686
2693
  </div>
2687
2694
  </div>`;
2688
2695
  }
2689
- function renderSection(section, tocTitle) {
2690
- const calloutHtml = section.callout ? `
2696
+ function renderSection(section2, tocTitle) {
2697
+ const calloutHtml = section2.callout ? `
2691
2698
  <div class="callout">
2692
- <p class="callout-eyebrow">${section.callout.eyebrow}</p>
2693
- <h3 class="callout-heading">${section.callout.heading}</h3>
2694
- <p class="callout-body">${section.callout.body}</p>
2699
+ <p class="callout-eyebrow">${section2.callout.eyebrow}</p>
2700
+ <h3 class="callout-heading">${section2.callout.heading}</h3>
2701
+ <p class="callout-body">${section2.callout.body}</p>
2695
2702
  </div>` : "";
2696
- const cardsHtml = section.cards.map(renderCard).join("\n ");
2697
- const interactiveHtml = section.interactiveHtml ? `
2698
- <div class="section-interactive">${section.interactiveHtml}</div>` : "";
2699
- return `<section class="post-section" id="${section.id}" aria-label="${tocTitle}">
2703
+ const cardsHtml = section2.cards.map(renderCard).join("\n ");
2704
+ const interactiveHtml = section2.interactiveHtml ? `
2705
+ <div class="section-interactive">${section2.interactiveHtml}</div>` : "";
2706
+ return `<section class="post-section" id="${section2.id}" aria-label="${tocTitle}">
2700
2707
  <div class="section-header">
2701
- <span class="section-num">${section.num}</span>
2702
- <h2 class="section-title">${section.title}${section.titleItalic ? ` <em>${section.titleItalic}</em>` : ""}</h2>
2703
- <p class="section-deck">${section.deck}</p>
2708
+ <span class="section-num">${section2.num}</span>
2709
+ <h2 class="section-title">${section2.title}${section2.titleItalic ? ` <em>${section2.titleItalic}</em>` : ""}</h2>
2710
+ <p class="section-deck">${section2.deck}</p>
2704
2711
  </div>${calloutHtml}
2705
2712
  <div class="card-stack">
2706
2713
  ${cardsHtml}
2707
2714
  </div>${interactiveHtml}
2708
2715
  </section>`;
2709
2716
  }
2710
- function tocItem(section) {
2711
- const label = `${section.title}${section.titleItalic ? " " + section.titleItalic : ""}`;
2712
- const subItems = section.cards.map((card) => `<li>
2717
+ function tocItem(section2) {
2718
+ const label = `${section2.title}${section2.titleItalic ? " " + section2.titleItalic : ""}`;
2719
+ const subItems = section2.cards.map((card) => `<li>
2713
2720
  <a href="#${card.id}" class="toc-sub-link" data-toc="${card.id}">
2714
2721
  <span class="toc-sub-num">${card.num}</span>
2715
2722
  <span class="toc-sub-label">${card.question}</span>
2716
2723
  </a>
2717
2724
  </li>`).join("\n ");
2718
2725
  return `<li>
2719
- <a href="#${section.id}" class="toc-link" data-toc="${section.id}">
2720
- <span class="toc-num">${section.num}</span>
2726
+ <a href="#${section2.id}" class="toc-link" data-toc="${section2.id}">
2727
+ <span class="toc-num">${section2.num}</span>
2721
2728
  <span class="toc-label">${label}</span>
2722
2729
  </a>
2723
2730
  <ul class="toc-sub-list">
@@ -3643,7 +3650,7 @@ async function generateOgImage(post) {
3643
3650
 
3644
3651
  // src/api/server.ts
3645
3652
  import { Resend as Resend3 } from "resend";
3646
- import { randomUUID as randomUUID22 } from "crypto";
3653
+ import { randomUUID as randomUUID23 } from "crypto";
3647
3654
 
3648
3655
  // src/api/kpo-extractor.ts
3649
3656
  import TurndownService from "turndown";
@@ -8672,7 +8679,7 @@ var siteExtractFn = inngest.createFunction(
8672
8679
  });
8673
8680
  }) : null;
8674
8681
  const finalized = await step.run("finalize", async () => {
8675
- const { assembleExtractArtifacts } = await import("./extract-bundle-DYMQRQWG.js");
8682
+ const { assembleExtractArtifacts } = await import("./extract-bundle-DXWWQER6.js");
8676
8683
  const current = await getExtractJob(jobId2);
8677
8684
  if (!current) throw new Error("extract job disappeared before finalization");
8678
8685
  const stored = await assembleExtractArtifacts(current, { branding, imageAudit });
@@ -9614,7 +9621,7 @@ async function resolveUsZipsPath(requestedPath) {
9614
9621
  async function loadZipGroups(stateAbbr, requestedPath, warnings, sourceMode) {
9615
9622
  const mode = resolvedLocationDataMode({ zipSource: sourceMode });
9616
9623
  if (mode === "hosted") {
9617
- const { getHostedZipGroups } = await import("./location-data-repository-HDNCU4Z4.js");
9624
+ const { getHostedZipGroups } = await import("./location-data-repository-2FJVMTZ2.js");
9618
9625
  const hosted = await getHostedZipGroups(stateAbbr);
9619
9626
  if (!hosted.dataset) {
9620
9627
  throw new DirectoryLocationError(
@@ -9677,7 +9684,7 @@ async function resolveDirectoryMarkets(options, config = {}) {
9677
9684
  const sourceUrl = censusStateUrl(state.fips);
9678
9685
  const warnings = [];
9679
9686
  if (resolvedLocationDataMode(config) === "hosted") {
9680
- const { queryHostedLocationMarkets } = await import("./location-data-repository-HDNCU4Z4.js");
9687
+ const { queryHostedLocationMarkets } = await import("./location-data-repository-2FJVMTZ2.js");
9681
9688
  const hosted = await queryHostedLocationMarkets({
9682
9689
  state: state.abbr,
9683
9690
  minPopulation: options.minPopulation,
@@ -16067,8 +16074,8 @@ var YouTubeExtractor = class {
16067
16074
  const sections = slr?.contents ?? [];
16068
16075
  const videos = [];
16069
16076
  const channels = [];
16070
- for (const section of sections) {
16071
- const contents = section.itemSectionRenderer?.contents ?? [];
16077
+ for (const section2 of sections) {
16078
+ const contents = section2.itemSectionRenderer?.contents ?? [];
16072
16079
  for (const item of contents) {
16073
16080
  const rec = item;
16074
16081
  if (rec.videoRenderer) {
@@ -27474,10 +27481,10 @@ oauthApp.post("/oauth/authorize", async (c) => {
27474
27481
  return typeof v === "string" ? v : void 0;
27475
27482
  };
27476
27483
  const p = parseAuthParams(get);
27477
- const action = get("action") ?? "";
27484
+ const action2 = get("action") ?? "";
27478
27485
  const valid = await validateAuthRequest(p);
27479
27486
  if (!valid.ok) return c.text(valid.message, valid.status);
27480
- if (action === "login") {
27487
+ if (action2 === "login") {
27481
27488
  const email = (get("email") ?? "").trim().toLowerCase();
27482
27489
  const password = get("password") ?? "";
27483
27490
  const user2 = email ? await withOAuthDatabaseDeadline("login-user", getUserByEmail(email)) : void 0;
@@ -27491,8 +27498,8 @@ oauthApp.post("/oauth/authorize", async (c) => {
27491
27498
  }
27492
27499
  const user = await sessionUser(getCookie(c, "session"));
27493
27500
  if (!user) return c.html(renderLogin(p, "Your session expired. Please sign in again."));
27494
- if (action === "deny") return redirectWithError(p.redirect_uri, p.state, "access_denied");
27495
- if (action !== "approve") return c.text("unsupported action", 400);
27501
+ if (action2 === "deny") return redirectWithError(p.redirect_uri, p.state, "access_denied");
27502
+ if (action2 !== "approve") return c.text("unsupported action", 400);
27496
27503
  const scope = negotiateScope(p.scope, user, p.resource);
27497
27504
  const code = `code_${randomBytes2(32).toString("base64url")}`;
27498
27505
  const expiresAt = new Date(Date.now() + CODE_TTL_SECONDS * 1e3).toISOString();
@@ -28548,12 +28555,12 @@ vaultApp.post("/api/communications/review", async (c) => {
28548
28555
  const token4 = typeof body.token === "string" ? body.token : void 0;
28549
28556
  if (!validToken(token4)) return c.json({ ok: false, error: "missing or malformed Vault App link" }, 401);
28550
28557
  const path5 = stringValue(body.path, 320);
28551
- const action = stringValue(body.action, 24);
28558
+ const action2 = stringValue(body.action, 24);
28552
28559
  const title = typeof body.title === "string" ? stringValue(body.title, 320) : void 0;
28553
28560
  const content = typeof body.content === "string" && body.content.length <= 1e5 ? body.content : void 0;
28554
28561
  const feedback = typeof body.feedback === "string" ? body.feedback.trim().slice(0, 1e4) : void 0;
28555
28562
  const baseRevision = typeof body.baseRevision === "number" && Number.isInteger(body.baseRevision) ? body.baseRevision : void 0;
28556
- const normalizedAction = action === "accept" ? "approve" : action;
28563
+ const normalizedAction = action2 === "accept" ? "approve" : action2;
28557
28564
  if (!path5 || !normalizedAction || !["approve", "deny", "edit"].includes(normalizedAction) || body.title !== void 0 && !title) {
28558
28565
  return c.json({ ok: false, error: "valid path, action, and optional draft fields are required" }, 400);
28559
28566
  }
@@ -30686,30 +30693,30 @@ function renderEditorialReadingRoomV1(input, config, now = /* @__PURE__ */ new D
30686
30693
  startLabel: "Start reading"
30687
30694
  },
30688
30695
  deck: input.dek ?? `Prepared for ${input.generatedFor}.`,
30689
- articles: input.sections.map((section, index) => {
30696
+ articles: input.sections.map((section2, index) => {
30690
30697
  const provenance = [
30691
30698
  "",
30692
30699
  "## Sources",
30693
30700
  "",
30694
- ...section.sourceLabels.map((label) => `- ${label}`),
30695
- ...section.sourceRefs.map((ref) => `- ${scheduledSourceRef(ref)}`)
30701
+ ...section2.sourceLabels.map((label) => `- ${label}`),
30702
+ ...section2.sourceRefs.map((ref) => `- ${scheduledSourceRef(ref)}`)
30696
30703
  ].join("\n");
30697
- const withFiles = index === input.sections.length - 1 && filesMarkdown ? `${section.markdown}
30704
+ const withFiles = index === input.sections.length - 1 && filesMarkdown ? `${section2.markdown}
30698
30705
 
30699
30706
  ${provenance}
30700
30707
 
30701
- ${filesMarkdown}` : `${section.markdown}
30708
+ ${filesMarkdown}` : `${section2.markdown}
30702
30709
 
30703
30710
  ${provenance}`;
30704
30711
  return {
30705
- slug: section.id,
30712
+ slug: section2.id,
30706
30713
  category: "Report",
30707
- kicker: section.summary ?? "Scheduled result",
30714
+ kicker: section2.summary ?? "Scheduled result",
30708
30715
  order: index + 1,
30709
- title: section.title,
30710
- summary: section.summary ?? section.title,
30716
+ title: section2.title,
30717
+ summary: section2.summary ?? section2.title,
30711
30718
  sourceType: "Scheduled result",
30712
- sourceLabel: section.sourceLabels.join(" \xB7 ").slice(0, 500),
30719
+ sourceLabel: section2.sourceLabels.join(" \xB7 ").slice(0, 500),
30713
30720
  markdown: withFiles
30714
30721
  };
30715
30722
  }),
@@ -30845,7 +30852,7 @@ import { z as z32 } from "zod";
30845
30852
 
30846
30853
  // src/api/commons-repository.ts
30847
30854
  import { createHash as createHash12, randomUUID as randomUUID15 } from "crypto";
30848
- var COMMONS_SCHEMA_VERSION = "2026-08-04.2";
30855
+ var COMMONS_SCHEMA_VERSION = "2026-08-04.3";
30849
30856
  var DEFAULT_COMMONS_BASE_URL = "https://transparent-commons.cc";
30850
30857
  var DEFAULT_ENTITY_TYPE = "PublicArticle";
30851
30858
  var COMMONS_ENTITY_PROFILES = {
@@ -31127,6 +31134,54 @@ async function ensureCommonsSchema() {
31127
31134
  },
31128
31135
  { sql: `CREATE INDEX IF NOT EXISTS commons_index_documents_status_updated ON commons_index_documents(embedding_status, updated_at DESC)`, args: [] },
31129
31136
  { sql: `CREATE INDEX IF NOT EXISTS commons_index_documents_entity_type ON commons_index_documents(entity_id, document_type)`, args: [] },
31137
+ {
31138
+ sql: `
31139
+ CREATE TABLE IF NOT EXISTS commons_publications (
31140
+ id TEXT PRIMARY KEY,
31141
+ owner_user_id INTEGER NOT NULL REFERENCES users(id),
31142
+ subdomain TEXT NOT NULL UNIQUE,
31143
+ title TEXT NOT NULL,
31144
+ description TEXT NOT NULL DEFAULT '',
31145
+ claim_idempotency_key TEXT NOT NULL,
31146
+ latest_edition_id TEXT,
31147
+ created_at TEXT NOT NULL,
31148
+ updated_at TEXT NOT NULL,
31149
+ UNIQUE(owner_user_id),
31150
+ UNIQUE(owner_user_id, claim_idempotency_key)
31151
+ )
31152
+ `,
31153
+ args: []
31154
+ },
31155
+ { sql: `CREATE INDEX IF NOT EXISTS commons_publications_updated ON commons_publications(updated_at DESC)`, args: [] },
31156
+ {
31157
+ sql: `
31158
+ CREATE TABLE IF NOT EXISTS commons_publication_editions (
31159
+ id TEXT PRIMARY KEY,
31160
+ publication_id TEXT NOT NULL REFERENCES commons_publications(id),
31161
+ owner_user_id INTEGER NOT NULL REFERENCES users(id),
31162
+ edition_slug TEXT NOT NULL,
31163
+ revision INTEGER NOT NULL,
31164
+ title TEXT NOT NULL,
31165
+ site_json TEXT NOT NULL,
31166
+ deck TEXT NOT NULL,
31167
+ articles_json TEXT NOT NULL,
31168
+ html TEXT NOT NULL,
31169
+ filename TEXT NOT NULL,
31170
+ sha256 TEXT NOT NULL,
31171
+ article_count INTEGER NOT NULL,
31172
+ word_count INTEGER NOT NULL,
31173
+ bytes INTEGER NOT NULL,
31174
+ warnings_json TEXT NOT NULL DEFAULT '[]',
31175
+ idempotency_key TEXT NOT NULL,
31176
+ created_at TEXT NOT NULL,
31177
+ published_at TEXT NOT NULL,
31178
+ UNIQUE(publication_id, edition_slug, revision),
31179
+ UNIQUE(owner_user_id, idempotency_key)
31180
+ )
31181
+ `,
31182
+ args: []
31183
+ },
31184
+ { sql: `CREATE INDEX IF NOT EXISTS commons_publication_editions_publication_published ON commons_publication_editions(publication_id, published_at DESC)`, args: [] },
31130
31185
  {
31131
31186
  sql: "INSERT OR IGNORE INTO schema_migrations (version) VALUES (?)",
31132
31187
  args: [COMMONS_SCHEMA_VERSION]
@@ -31243,7 +31298,7 @@ async function prepareCommonsEntity(input, user) {
31243
31298
  presentHeadings: headings,
31244
31299
  recommendedSections: contract.recommendedSections,
31245
31300
  optionalSections: contract.optionalSections,
31246
- missingRecommendedSections: contract.recommendedSections.filter((section) => !presentHeadingLabels.has(section.toLowerCase())),
31301
+ missingRecommendedSections: contract.recommendedSections.filter((section2) => !presentHeadingLabels.has(section2.toLowerCase())),
31247
31302
  rule: "Use the entity profile as a guide, but omit any section or subsection that is not supported by source evidence."
31248
31303
  },
31249
31304
  instructions: [
@@ -31316,8 +31371,8 @@ async function validateCommonsEntity(input, user) {
31316
31371
  headings,
31317
31372
  placeholderSections,
31318
31373
  requiredOmissionRule: "Omit unsupported profile sections; do not publish sections whose only content is that the source lacks evidence.",
31319
- supportedRecommendedSections: contract.recommendedSections.filter((section) => headings.some((heading) => heading.text.toLowerCase() === section.toLowerCase())),
31320
- unsupportedRecommendedSections: contract.recommendedSections.filter((section) => !headings.some((heading) => heading.text.toLowerCase() === section.toLowerCase()))
31374
+ supportedRecommendedSections: contract.recommendedSections.filter((section2) => headings.some((heading) => heading.text.toLowerCase() === section2.toLowerCase())),
31375
+ unsupportedRecommendedSections: contract.recommendedSections.filter((section2) => !headings.some((heading) => heading.text.toLowerCase() === section2.toLowerCase()))
31321
31376
  },
31322
31377
  tagResolutions: resolveCommonsTags(
31323
31378
  uniqueStrings([...input.tags ?? [], ...input.keywords ?? []]).slice(0, 20),
@@ -31842,7 +31897,7 @@ function unsupportedPlaceholderSections(markdown) {
31842
31897
  /insufficient evidence/i,
31843
31898
  /source material does not/i
31844
31899
  ];
31845
- return sections.filter((section) => placeholderPatterns.some((pattern) => pattern.test(section.body)) && wordCount(section.body) <= 160).map((section) => section.heading);
31900
+ return sections.filter((section2) => placeholderPatterns.some((pattern) => pattern.test(section2.body)) && wordCount(section2.body) <= 160).map((section2) => section2.heading);
31846
31901
  }
31847
31902
  function markdownSectionBodies(markdown) {
31848
31903
  const lines = String(markdown || "").split(/\r?\n/);
@@ -32326,18 +32381,18 @@ function normalizeBody(bodyMarkdown, contentSections) {
32326
32381
  const body = String(bodyMarkdown ?? "").trim();
32327
32382
  if (body) return body.slice(0, 5e5);
32328
32383
  const sections = normalizeContentSections(contentSections);
32329
- return sections.map((section) => `## ${section.heading}
32384
+ return sections.map((section2) => `## ${section2.heading}
32330
32385
 
32331
- ${section.body}`).join("\n\n").slice(0, 5e5);
32386
+ ${section2.body}`).join("\n\n").slice(0, 5e5);
32332
32387
  }
32333
32388
  function normalizeContentSections(sections) {
32334
32389
  if (!Array.isArray(sections)) return [];
32335
- return sections.map((section, index) => ({
32336
- id: normalizeSlug(section.id || section.heading),
32337
- heading: requiredText(section.heading, "section.heading", 1, 180),
32338
- body: requiredText(section.body, "section.body", 1, 1e5),
32339
- position: Number.isFinite(section.position) ? Number(section.position) : index + 1,
32340
- citations: normalizeCitations(section.citations)
32390
+ return sections.map((section2, index) => ({
32391
+ id: normalizeSlug(section2.id || section2.heading),
32392
+ heading: requiredText(section2.heading, "section.heading", 1, 180),
32393
+ body: requiredText(section2.body, "section.body", 1, 1e5),
32394
+ position: Number.isFinite(section2.position) ? Number(section2.position) : index + 1,
32395
+ citations: normalizeCitations(section2.citations)
32341
32396
  })).slice(0, 80);
32342
32397
  }
32343
32398
  function normalizeArticleSections(sections) {
@@ -32704,6 +32759,392 @@ var CommonsRepositoryError = class extends Error {
32704
32759
  httpStatus;
32705
32760
  };
32706
32761
 
32762
+ // src/api/commons-publication-repository.ts
32763
+ import { createHash as createHash13, randomUUID as randomUUID16 } from "crypto";
32764
+ var PUBLICATION_ROOT_DOMAIN = process.env.COMMONS_PUBLICATION_ROOT_DOMAIN || "transparent-commons.cc";
32765
+ var RESERVED_SUBDOMAINS = /* @__PURE__ */ new Set([
32766
+ "admin",
32767
+ "api",
32768
+ "app",
32769
+ "assets",
32770
+ "auth",
32771
+ "blog",
32772
+ "cdn",
32773
+ "docs",
32774
+ "help",
32775
+ "login",
32776
+ "mail",
32777
+ "mcp",
32778
+ "signup",
32779
+ "sitemap",
32780
+ "static",
32781
+ "support",
32782
+ "transparent-commons",
32783
+ "transparentcommons",
32784
+ "www",
32785
+ "wiki"
32786
+ ]);
32787
+ var CommonsPublicationError = class extends Error {
32788
+ constructor(code, message, httpStatus = 400) {
32789
+ super(message);
32790
+ this.code = code;
32791
+ this.httpStatus = httpStatus;
32792
+ this.name = "CommonsPublicationError";
32793
+ }
32794
+ code;
32795
+ httpStatus;
32796
+ };
32797
+ async function prepareCommonsPublication(input, user) {
32798
+ await ensureCommonsSchema();
32799
+ const subdomain = normalizePublicationSubdomain(input.requestedSubdomain);
32800
+ const [owned, claimed] = await Promise.all([
32801
+ getCommonsPublicationForOwner(Number(user.id)),
32802
+ getCommonsPublicationBySubdomain(subdomain)
32803
+ ]);
32804
+ const availability = claimed ? claimed.ownerUserId === Number(user.id) ? "owned_by_caller" : "unavailable" : "available";
32805
+ return {
32806
+ requestedSubdomain: input.requestedSubdomain,
32807
+ normalizedSubdomain: subdomain,
32808
+ availability,
32809
+ requestedPublicUrl: publicationPublicUrl(subdomain),
32810
+ currentPublication: owned,
32811
+ contract: {
32812
+ ownership: "One publication per authenticated MCP Scraper account.",
32813
+ permanence: "Claimed names are stable and globally unique.",
32814
+ renderer: "Published editions use the MCP Scraper editorial reading-room renderer.",
32815
+ revisionRule: "Editing an existing edition requires its current baseRevision.",
32816
+ publicRoutes: ["/", "/archive", "/editions/{editionSlug}"],
32817
+ workflow: [
32818
+ "commons_prepare_publication",
32819
+ "commons_validate_publication",
32820
+ "commons_claim_publication",
32821
+ "commons_publish_editorial"
32822
+ ]
32823
+ },
32824
+ proposed: {
32825
+ title: cleanText(input.title, 140) || publicationTitleFromSubdomain(subdomain),
32826
+ description: cleanText(input.description, 500)
32827
+ }
32828
+ };
32829
+ }
32830
+ async function validateCommonsPublication(input, user) {
32831
+ await ensureCommonsSchema();
32832
+ const errors = [];
32833
+ const warnings = [];
32834
+ let subdomain = "";
32835
+ try {
32836
+ subdomain = normalizePublicationSubdomain(input.requestedSubdomain || input.publicationSubdomain || "");
32837
+ } catch (error) {
32838
+ errors.push(error instanceof Error ? error.message : String(error));
32839
+ }
32840
+ const publication = subdomain ? await getCommonsPublicationBySubdomain(subdomain) : null;
32841
+ if (input.operation === "claim") {
32842
+ const owned = await getCommonsPublicationForOwner(Number(user.id));
32843
+ if (publication && publication.ownerUserId !== Number(user.id)) errors.push("That publication name is already claimed by another account.");
32844
+ if (owned && owned.subdomain !== subdomain) errors.push(`This account already owns ${owned.publicUrl}.`);
32845
+ if (!cleanText(input.title, 140)) warnings.push("No display title was supplied; the publication name will be title-cased.");
32846
+ } else {
32847
+ if (!publication) errors.push("Claim this publication name before publishing an edition.");
32848
+ else if (publication.ownerUserId !== Number(user.id)) errors.push("Only the account that claimed this publication can publish to it.");
32849
+ if (!input.edition) errors.push("A complete editorial reading-room edition is required for publish validation.");
32850
+ if (input.edition) {
32851
+ try {
32852
+ renderEditorialReadingRoom(input.edition);
32853
+ } catch (error) {
32854
+ errors.push(error instanceof Error ? error.message : String(error));
32855
+ }
32856
+ const slug2 = normalizeEditionSlug(input.editionSlug || input.edition.site.slug);
32857
+ const latest = publication ? await getLatestEdition(publication.id, slug2) : null;
32858
+ if (latest && input.baseRevision === void 0) errors.push(`Edition ${slug2} already exists at revision ${latest.revision}; supply baseRevision to edit it.`);
32859
+ if (latest && input.baseRevision !== void 0 && latest.revision !== input.baseRevision) {
32860
+ errors.push(`Edition ${slug2} is revision ${latest.revision}; the proposed edit targeted ${input.baseRevision}.`);
32861
+ }
32862
+ }
32863
+ }
32864
+ return {
32865
+ valid: errors.length === 0,
32866
+ operation: input.operation,
32867
+ normalizedSubdomain: subdomain || null,
32868
+ publicUrl: subdomain ? publicationPublicUrl(subdomain) : null,
32869
+ errors,
32870
+ warnings,
32871
+ publication
32872
+ };
32873
+ }
32874
+ async function claimCommonsPublication(input, user) {
32875
+ await ensureCommonsSchema();
32876
+ const subdomain = normalizePublicationSubdomain(input.requestedSubdomain);
32877
+ const userId = Number(user.id);
32878
+ const existingOwned = await getCommonsPublicationForOwner(userId);
32879
+ if (existingOwned) {
32880
+ if (existingOwned.subdomain === subdomain) return { publication: existingOwned, idempotentReplay: true };
32881
+ throw new CommonsPublicationError("publication_already_claimed", `This account already owns ${existingOwned.publicUrl}.`, 409);
32882
+ }
32883
+ const existingName = await getCommonsPublicationBySubdomain(subdomain);
32884
+ if (existingName) throw new CommonsPublicationError("publication_name_unavailable", "That publication name is already claimed.", 409);
32885
+ const id = `tcpub_${randomUUID16()}`;
32886
+ const now = (/* @__PURE__ */ new Date()).toISOString();
32887
+ try {
32888
+ await getDb().execute({
32889
+ sql: `
32890
+ INSERT INTO commons_publications (
32891
+ id, owner_user_id, subdomain, title, description, claim_idempotency_key, created_at, updated_at
32892
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
32893
+ `,
32894
+ args: [
32895
+ id,
32896
+ userId,
32897
+ subdomain,
32898
+ cleanText(input.title, 140) || publicationTitleFromSubdomain(subdomain),
32899
+ cleanText(input.description, 500),
32900
+ requiredIdempotencyKey(input.idempotencyKey),
32901
+ now,
32902
+ now
32903
+ ]
32904
+ });
32905
+ } catch (error) {
32906
+ const replay = await getCommonsPublicationForOwner(userId);
32907
+ if (replay?.subdomain === subdomain) return { publication: replay, idempotentReplay: true };
32908
+ throw error;
32909
+ }
32910
+ const publication = await getCommonsPublicationBySubdomain(subdomain);
32911
+ if (!publication) throw new CommonsPublicationError("publication_claim_failed", "The publication claim was not persisted.");
32912
+ return { publication, idempotentReplay: false };
32913
+ }
32914
+ async function publishCommonsEditorial(input, user) {
32915
+ await ensureCommonsSchema();
32916
+ const subdomain = normalizePublicationSubdomain(input.publicationSubdomain);
32917
+ const publication = await getCommonsPublicationBySubdomain(subdomain);
32918
+ if (!publication) throw new CommonsPublicationError("publication_not_found", "Claim this publication name before publishing an edition.", 404);
32919
+ if (publication.ownerUserId !== Number(user.id)) {
32920
+ throw new CommonsPublicationError("publication_not_owned", "Only the account that claimed this publication can publish to it.", 404);
32921
+ }
32922
+ const idempotencyKey3 = requiredIdempotencyKey(input.idempotencyKey);
32923
+ const replay = await getEditionByIdempotency(Number(user.id), idempotencyKey3);
32924
+ if (replay) return publicationResult(publication, replay, true);
32925
+ const editionSlug = normalizeEditionSlug(input.editionSlug || input.site.slug);
32926
+ const latest = await getLatestEdition(publication.id, editionSlug);
32927
+ if (latest && input.baseRevision === void 0) {
32928
+ throw new CommonsPublicationError("publication_base_revision_required", `Edition ${editionSlug} already exists at revision ${latest.revision}; supply baseRevision to edit it.`, 409);
32929
+ }
32930
+ if (latest && input.baseRevision !== latest.revision) {
32931
+ throw new CommonsPublicationError("publication_revision_conflict", `Edition ${editionSlug} is revision ${latest.revision}; refresh it before publishing an edit.`, 409);
32932
+ }
32933
+ const { publicationSubdomain: _publicationSubdomain, editionSlug: _editionSlug, idempotencyKey: _idempotencyKey, baseRevision: _baseRevision, ...editionInput } = input;
32934
+ const canonicalUrl = editionPublicUrl(subdomain, editionSlug);
32935
+ const rendered = renderEditorialReadingRoom(editionInput);
32936
+ const html = addPublicMetadata(rendered.html, canonicalUrl, publication.title);
32937
+ const editionId = `tced_${randomUUID16()}`;
32938
+ const revision = (latest?.revision ?? 0) + 1;
32939
+ const now = (/* @__PURE__ */ new Date()).toISOString();
32940
+ await getDb().batch([
32941
+ {
32942
+ sql: `
32943
+ INSERT INTO commons_publication_editions (
32944
+ id, publication_id, owner_user_id, edition_slug, revision, title, site_json, deck,
32945
+ articles_json, html, filename, sha256, article_count, word_count, bytes, warnings_json,
32946
+ idempotency_key, created_at, published_at
32947
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
32948
+ `,
32949
+ args: [
32950
+ editionId,
32951
+ publication.id,
32952
+ Number(user.id),
32953
+ editionSlug,
32954
+ revision,
32955
+ editionInput.site.title,
32956
+ JSON.stringify(editionInput.site),
32957
+ editionInput.deck,
32958
+ JSON.stringify(editionInput.articles),
32959
+ html,
32960
+ rendered.filename,
32961
+ createHash13("sha256").update(html).digest("hex"),
32962
+ rendered.articleCount,
32963
+ rendered.wordCount,
32964
+ Buffer.byteLength(html),
32965
+ JSON.stringify(rendered.warnings),
32966
+ idempotencyKey3,
32967
+ now,
32968
+ now
32969
+ ]
32970
+ },
32971
+ {
32972
+ sql: "UPDATE commons_publications SET latest_edition_id = ?, updated_at = ? WHERE id = ? AND owner_user_id = ?",
32973
+ args: [editionId, now, publication.id, Number(user.id)]
32974
+ }
32975
+ ], "write");
32976
+ const edition = await getPublicationEditionById(editionId);
32977
+ if (!edition) throw new CommonsPublicationError("publication_publish_failed", "The published edition was not persisted.");
32978
+ return publicationResult({ ...publication, latestEditionId: editionId, updatedAt: now }, edition, false);
32979
+ }
32980
+ async function getCommonsPublicationBySubdomain(subdomainInput) {
32981
+ await ensureCommonsSchema();
32982
+ const subdomain = normalizePublicationSubdomain(subdomainInput);
32983
+ const result = await getDb().execute({ sql: "SELECT * FROM commons_publications WHERE subdomain = ? LIMIT 1", args: [subdomain] });
32984
+ return result.rows[0] ? rowToPublication(result.rows[0]) : null;
32985
+ }
32986
+ async function getCommonsPublicationForOwner(userId) {
32987
+ await ensureCommonsSchema();
32988
+ const result = await getDb().execute({ sql: "SELECT * FROM commons_publications WHERE owner_user_id = ? LIMIT 1", args: [userId] });
32989
+ return result.rows[0] ? rowToPublication(result.rows[0]) : null;
32990
+ }
32991
+ async function listCommonsPublicationEditions(publicationId) {
32992
+ await ensureCommonsSchema();
32993
+ const result = await getDb().execute({
32994
+ sql: `
32995
+ SELECT edition.* FROM commons_publication_editions edition
32996
+ JOIN (
32997
+ SELECT edition_slug, MAX(revision) AS revision
32998
+ FROM commons_publication_editions WHERE publication_id = ? GROUP BY edition_slug
32999
+ ) latest ON latest.edition_slug = edition.edition_slug AND latest.revision = edition.revision
33000
+ WHERE edition.publication_id = ? ORDER BY edition.published_at DESC
33001
+ `,
33002
+ args: [publicationId, publicationId]
33003
+ });
33004
+ const publication = await getPublicationById(publicationId);
33005
+ if (!publication) return [];
33006
+ return result.rows.map((row) => rowToEdition(row, publication.subdomain));
33007
+ }
33008
+ async function getCommonsPublicationEditionHtml(subdomainInput, editionSlugInput) {
33009
+ const publication = await getCommonsPublicationBySubdomain(subdomainInput);
33010
+ if (!publication) return null;
33011
+ const result = editionSlugInput ? await getDb().execute({
33012
+ sql: "SELECT * FROM commons_publication_editions WHERE publication_id = ? AND edition_slug = ? ORDER BY revision DESC LIMIT 1",
33013
+ args: [publication.id, normalizeEditionSlug(editionSlugInput)]
33014
+ }) : await getDb().execute({
33015
+ sql: "SELECT * FROM commons_publication_editions WHERE id = ? AND publication_id = ? LIMIT 1",
33016
+ args: [publication.latestEditionId || "", publication.id]
33017
+ });
33018
+ if (!result.rows[0]) return null;
33019
+ const record = result.rows[0];
33020
+ return { publication, edition: rowToEdition(record, publication.subdomain), html: String(record.html || "") };
33021
+ }
33022
+ async function getPublicationById(id) {
33023
+ const result = await getDb().execute({ sql: "SELECT * FROM commons_publications WHERE id = ? LIMIT 1", args: [id] });
33024
+ return result.rows[0] ? rowToPublication(result.rows[0]) : null;
33025
+ }
33026
+ async function getLatestEdition(publicationId, editionSlug) {
33027
+ const publication = await getPublicationById(publicationId);
33028
+ if (!publication) return null;
33029
+ const result = await getDb().execute({
33030
+ sql: "SELECT * FROM commons_publication_editions WHERE publication_id = ? AND edition_slug = ? ORDER BY revision DESC LIMIT 1",
33031
+ args: [publicationId, editionSlug]
33032
+ });
33033
+ return result.rows[0] ? rowToEdition(result.rows[0], publication.subdomain) : null;
33034
+ }
33035
+ async function getEditionByIdempotency(userId, idempotencyKey3) {
33036
+ const result = await getDb().execute({
33037
+ sql: `SELECT edition.*, publication.subdomain FROM commons_publication_editions edition JOIN commons_publications publication ON publication.id = edition.publication_id WHERE edition.owner_user_id = ? AND edition.idempotency_key = ? LIMIT 1`,
33038
+ args: [userId, idempotencyKey3]
33039
+ });
33040
+ if (!result.rows[0]) return null;
33041
+ const record = result.rows[0];
33042
+ return rowToEdition(record, String(record.subdomain));
33043
+ }
33044
+ async function getPublicationEditionById(id) {
33045
+ const result = await getDb().execute({
33046
+ sql: `SELECT edition.*, publication.subdomain FROM commons_publication_editions edition JOIN commons_publications publication ON publication.id = edition.publication_id WHERE edition.id = ? LIMIT 1`,
33047
+ args: [id]
33048
+ });
33049
+ if (!result.rows[0]) return null;
33050
+ const record = result.rows[0];
33051
+ return rowToEdition(record, String(record.subdomain));
33052
+ }
33053
+ function rowToPublication(row) {
33054
+ const subdomain = String(row.subdomain);
33055
+ return {
33056
+ id: String(row.id),
33057
+ ownerUserId: Number(row.owner_user_id),
33058
+ subdomain,
33059
+ title: String(row.title),
33060
+ description: String(row.description || ""),
33061
+ latestEditionId: row.latest_edition_id ? String(row.latest_edition_id) : null,
33062
+ createdAt: String(row.created_at),
33063
+ updatedAt: String(row.updated_at),
33064
+ publicUrl: publicationPublicUrl(subdomain),
33065
+ archiveUrl: `${publicationPublicUrl(subdomain)}/archive`
33066
+ };
33067
+ }
33068
+ function rowToEdition(row, subdomain) {
33069
+ const editionSlug = String(row.edition_slug);
33070
+ return {
33071
+ id: String(row.id),
33072
+ publicationId: String(row.publication_id),
33073
+ editionSlug,
33074
+ revision: Number(row.revision),
33075
+ title: String(row.title),
33076
+ site: parseJson4(row.site_json, {}),
33077
+ deck: String(row.deck),
33078
+ filename: String(row.filename),
33079
+ sha256: String(row.sha256),
33080
+ articleCount: Number(row.article_count),
33081
+ wordCount: Number(row.word_count),
33082
+ bytes: Number(row.bytes),
33083
+ warnings: parseJson4(row.warnings_json, []),
33084
+ createdAt: String(row.created_at),
33085
+ publishedAt: String(row.published_at),
33086
+ publicUrl: editionPublicUrl(subdomain, editionSlug)
33087
+ };
33088
+ }
33089
+ function publicationResult(publication, edition, idempotentReplay) {
33090
+ return {
33091
+ publication,
33092
+ edition,
33093
+ publicUrl: publication.publicUrl,
33094
+ archiveUrl: publication.archiveUrl,
33095
+ editionUrl: edition.publicUrl,
33096
+ idempotentReplay
33097
+ };
33098
+ }
33099
+ function normalizePublicationSubdomain(value) {
33100
+ const normalized = String(value || "").trim().toLowerCase().replace(/\s+/g, "-").replace(/[^a-z0-9-]/g, "").replace(/-+/g, "-").replace(/^-|-$/g, "");
33101
+ if (!/^[a-z0-9](?:[a-z0-9-]{1,48}[a-z0-9])$/.test(normalized)) {
33102
+ throw new CommonsPublicationError("publication_name_invalid", "Choose a publication name between 3 and 50 characters using letters, numbers, and interior hyphens.");
33103
+ }
33104
+ if (RESERVED_SUBDOMAINS.has(normalized)) throw new CommonsPublicationError("publication_name_reserved", "That publication name is reserved; choose a more specific name.", 409);
33105
+ return normalized;
33106
+ }
33107
+ function normalizeEditionSlug(value) {
33108
+ const normalized = String(value || "").trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").slice(0, 80);
33109
+ if (!normalized) throw new CommonsPublicationError("edition_slug_invalid", "A published edition needs a stable slug.");
33110
+ return normalized;
33111
+ }
33112
+ function requiredIdempotencyKey(value) {
33113
+ const normalized = cleanText(value, 200);
33114
+ if (normalized.length < 8) throw new CommonsPublicationError("idempotency_key_invalid", "Use an idempotency key of at least 8 characters and reuse it only when retrying the same write.");
33115
+ return normalized;
33116
+ }
33117
+ function publicationPublicUrl(subdomain) {
33118
+ return `https://${subdomain}.${PUBLICATION_ROOT_DOMAIN}`;
33119
+ }
33120
+ function editionPublicUrl(subdomain, editionSlug) {
33121
+ return `${publicationPublicUrl(subdomain)}/editions/${encodeURIComponent(editionSlug)}`;
33122
+ }
33123
+ function publicationTitleFromSubdomain(subdomain) {
33124
+ return subdomain.split("-").map((part) => part ? `${part[0]?.toUpperCase()}${part.slice(1)}` : "").join(" ");
33125
+ }
33126
+ function cleanText(value, max) {
33127
+ return String(value || "").replace(/\s+/g, " ").trim().slice(0, max);
33128
+ }
33129
+ function parseJson4(value, fallback) {
33130
+ try {
33131
+ return JSON.parse(String(value || ""));
33132
+ } catch {
33133
+ return fallback;
33134
+ }
33135
+ }
33136
+ function addPublicMetadata(html, canonicalUrl, publicationTitle) {
33137
+ const escapedUrl = canonicalUrl.replace(/&/g, "&amp;").replace(/"/g, "&quot;");
33138
+ const escapedTitle = publicationTitle.replace(/&/g, "&amp;").replace(/"/g, "&quot;");
33139
+ return html.replace("</head>", [
33140
+ ` <link rel="canonical" href="${escapedUrl}">`,
33141
+ ` <meta property="og:url" content="${escapedUrl}">`,
33142
+ ` <meta property="og:site_name" content="${escapedTitle}">`,
33143
+ ' <meta name="robots" content="index,follow">',
33144
+ "</head>"
33145
+ ].join("\n"));
33146
+ }
33147
+
32707
33148
  // src/api/commons-routes.ts
32708
33149
  var commonsApp = new Hono31();
32709
33150
  var auth2 = createApiKeyAuth();
@@ -32865,10 +33306,83 @@ var NeedsLinkBodySchema = z32.object({
32865
33306
  limit: z32.number().int().min(1).max(100).optional(),
32866
33307
  offset: z32.number().int().min(0).max(1e4).optional()
32867
33308
  }).strict();
33309
+ var PreparePublicationSchema = z32.object(CommonsPreparePublicationInputSchema).strict();
33310
+ var ValidatePublicationSchema = z32.object(CommonsValidatePublicationInputSchema).strict();
33311
+ var ClaimPublicationSchema = z32.object(CommonsClaimPublicationInputSchema).strict();
33312
+ var PublishEditorialSchema = z32.object(CommonsPublishEditorialInputSchema).strict();
32868
33313
  commonsApp.get("/health", async (c) => {
32869
33314
  await ensureCommonsSchema();
32870
33315
  return c.json({ ok: true, data: commonsDatabaseReport() });
32871
33316
  });
33317
+ commonsApp.post("/publications/prepare", auth2, async (c) => {
33318
+ const parsed = PreparePublicationSchema.safeParse(await c.req.json().catch(() => ({})));
33319
+ if (!parsed.success) return validationError(c, parsed.error);
33320
+ return publicationOperation(c, () => prepareCommonsPublication(parsed.data, c.get("user")));
33321
+ });
33322
+ commonsApp.post("/publications/validate", auth2, async (c) => {
33323
+ const parsed = ValidatePublicationSchema.safeParse(await c.req.json().catch(() => ({})));
33324
+ if (!parsed.success) return validationError(c, parsed.error);
33325
+ return publicationOperation(c, () => validateCommonsPublication(parsed.data, c.get("user")));
33326
+ });
33327
+ commonsApp.post("/publications/claim", auth2, async (c) => {
33328
+ const parsed = ClaimPublicationSchema.safeParse(await c.req.json().catch(() => ({})));
33329
+ if (!parsed.success) return validationError(c, parsed.error);
33330
+ return publicationOperation(c, () => claimCommonsPublication(parsed.data, c.get("user")), 201);
33331
+ });
33332
+ commonsApp.post("/publications/publish", auth2, async (c) => {
33333
+ const parsed = PublishEditorialSchema.safeParse(await c.req.json().catch(() => ({})));
33334
+ if (!parsed.success) return validationError(c, parsed.error);
33335
+ return publicationOperation(c, () => publishCommonsEditorial(parsed.data, c.get("user")), 201);
33336
+ });
33337
+ commonsApp.get("/publications/me", auth2, async (c) => {
33338
+ const publication = await getCommonsPublicationForOwner(Number(c.get("user").id));
33339
+ if (!publication) return c.json({ ok: false, error: "publication_not_found", message: "This account has not claimed a Commons publication yet." }, 404);
33340
+ const editions = c.req.query("includeEditions") === "false" ? [] : await listCommonsPublicationEditions(publication.id);
33341
+ return c.json({ ok: true, data: { publication, editions } });
33342
+ });
33343
+ commonsApp.get("/publications/:subdomain/site", async (c) => {
33344
+ try {
33345
+ const result = await getCommonsPublicationEditionHtml(c.req.param("subdomain"));
33346
+ if (!result) return c.json({ ok: false, error: "publication_not_published", message: "No published edition exists for this publication." }, 404);
33347
+ return c.html(result.html, 200, {
33348
+ "cache-control": "public, max-age=60, s-maxage=300",
33349
+ "x-robots-tag": "index, follow"
33350
+ });
33351
+ } catch (error) {
33352
+ return publicationError(c, error);
33353
+ }
33354
+ });
33355
+ commonsApp.get("/publications/:subdomain/editions/:editionSlug/site", async (c) => {
33356
+ try {
33357
+ const result = await getCommonsPublicationEditionHtml(c.req.param("subdomain"), c.req.param("editionSlug"));
33358
+ if (!result) return c.json({ ok: false, error: "edition_not_found", message: "No published edition matched that publication and slug." }, 404);
33359
+ return c.html(result.html, 200, {
33360
+ "cache-control": "public, max-age=60, s-maxage=300",
33361
+ "x-robots-tag": "index, follow"
33362
+ });
33363
+ } catch (error) {
33364
+ return publicationError(c, error);
33365
+ }
33366
+ });
33367
+ commonsApp.get("/publications/:subdomain/editions", async (c) => {
33368
+ try {
33369
+ const publication = await getCommonsPublicationBySubdomain(c.req.param("subdomain"));
33370
+ if (!publication) return c.json({ ok: false, error: "publication_not_found", message: "No Commons publication matched that name." }, 404);
33371
+ return c.json({ ok: true, data: { publication, editions: await listCommonsPublicationEditions(publication.id) } });
33372
+ } catch (error) {
33373
+ return publicationError(c, error);
33374
+ }
33375
+ });
33376
+ commonsApp.get("/publications/:subdomain", async (c) => {
33377
+ try {
33378
+ const publication = await getCommonsPublicationBySubdomain(c.req.param("subdomain"));
33379
+ if (!publication) return c.json({ ok: false, error: "publication_not_found", message: "No Commons publication matched that name." }, 404);
33380
+ const editions = c.req.query("includeEditions") === "false" ? [] : await listCommonsPublicationEditions(publication.id);
33381
+ return c.json({ ok: true, data: { publication, editions } });
33382
+ } catch (error) {
33383
+ return publicationError(c, error);
33384
+ }
33385
+ });
32872
33386
  commonsApp.get("/entities", async (c) => {
32873
33387
  const result = await searchCommonsEntities(filtersFromQuery(c.req.query()));
32874
33388
  return c.json({ ok: true, data: result });
@@ -33030,6 +33544,19 @@ function repositoryStatus(error) {
33030
33544
  if (error.httpStatus === 409) return 409;
33031
33545
  return 400;
33032
33546
  }
33547
+ async function publicationOperation(c, operation, successStatus = 200) {
33548
+ try {
33549
+ return c.json({ ok: true, data: await operation() }, successStatus);
33550
+ } catch (error) {
33551
+ return publicationError(c, error);
33552
+ }
33553
+ }
33554
+ function publicationError(c, error) {
33555
+ if (error instanceof CommonsPublicationError) {
33556
+ return c.json({ ok: false, error: error.code, message: error.message }, error.httpStatus);
33557
+ }
33558
+ throw error;
33559
+ }
33033
33560
  function xmlEscape(value) {
33034
33561
  return value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&apos;");
33035
33562
  }
@@ -33039,13 +33566,13 @@ import { Hono as Hono32 } from "hono";
33039
33566
  import { z as z33 } from "zod";
33040
33567
 
33041
33568
  // src/api/scheduled-artifact-owner.ts
33042
- import { createHash as createHash13 } from "crypto";
33569
+ import { createHash as createHash14 } from "crypto";
33043
33570
  function scheduledArtifactOwnerIdForApiKey(apiKey) {
33044
- return createHash13("sha256").update(apiKey).digest("hex").slice(0, 24);
33571
+ return createHash14("sha256").update(apiKey).digest("hex").slice(0, 24);
33045
33572
  }
33046
33573
 
33047
33574
  // src/api/scheduled-run-view-links.ts
33048
- import { createHash as createHash14, randomBytes as randomBytes3, randomUUID as randomUUID16 } from "crypto";
33575
+ import { createHash as createHash15, randomBytes as randomBytes3, randomUUID as randomUUID17 } from "crypto";
33049
33576
  var schemaReady3 = false;
33050
33577
  async function ensureScheduledRunViewLinksSchema() {
33051
33578
  if (schemaReady3) return;
@@ -33058,13 +33585,36 @@ async function ensureScheduledRunViewLinksSchema() {
33058
33585
  artifact_id TEXT NOT NULL,
33059
33586
  title TEXT NOT NULL,
33060
33587
  summary TEXT NOT NULL,
33061
- renderer_key TEXT NOT NULL CHECK (renderer_key = 'editorial_reading_room_v1'),
33588
+ renderer_key TEXT NOT NULL CHECK (renderer_key IN ('editorial_reading_room_v1','personal_authority_v1')),
33062
33589
  token_hash TEXT NOT NULL UNIQUE,
33063
33590
  expires_at TEXT NOT NULL,
33064
33591
  revoked_at TEXT,
33065
33592
  created_at TEXT NOT NULL
33066
33593
  )
33067
33594
  `);
33595
+ const schema = await db.execute({
33596
+ sql: `SELECT sql FROM sqlite_master WHERE type = 'table' AND name = 'scheduled_run_view_links' LIMIT 1`,
33597
+ args: []
33598
+ });
33599
+ const createSql = String(schema.rows[0]?.sql ?? "");
33600
+ if (createSql.includes("renderer_key = 'editorial_reading_room_v1'")) {
33601
+ await db.batch([
33602
+ `DROP TABLE IF EXISTS scheduled_run_view_links_v2`,
33603
+ `CREATE TABLE scheduled_run_view_links_v2 (
33604
+ share_id TEXT PRIMARY KEY, owner_id TEXT NOT NULL, run_id TEXT NOT NULL,
33605
+ artifact_id TEXT NOT NULL, title TEXT NOT NULL, summary TEXT NOT NULL,
33606
+ renderer_key TEXT NOT NULL CHECK (renderer_key IN ('editorial_reading_room_v1','personal_authority_v1')),
33607
+ token_hash TEXT NOT NULL UNIQUE, expires_at TEXT NOT NULL, revoked_at TEXT,
33608
+ created_at TEXT NOT NULL
33609
+ )`,
33610
+ `INSERT INTO scheduled_run_view_links_v2
33611
+ SELECT share_id, owner_id, run_id, artifact_id, title, summary, renderer_key,
33612
+ token_hash, expires_at, revoked_at, created_at
33613
+ FROM scheduled_run_view_links`,
33614
+ `DROP TABLE scheduled_run_view_links`,
33615
+ `ALTER TABLE scheduled_run_view_links_v2 RENAME TO scheduled_run_view_links`
33616
+ ], "write");
33617
+ }
33068
33618
  await db.execute(`
33069
33619
  CREATE INDEX IF NOT EXISTS scheduled_run_view_links_owner_run
33070
33620
  ON scheduled_run_view_links(owner_id, run_id, created_at DESC)
@@ -33076,7 +33626,7 @@ async function ensureScheduledRunViewLinksSchema() {
33076
33626
  schemaReady3 = true;
33077
33627
  }
33078
33628
  function tokenHash2(token4) {
33079
- return createHash14("sha256").update(token4).digest("hex");
33629
+ return createHash15("sha256").update(token4).digest("hex");
33080
33630
  }
33081
33631
  function mapRow(row) {
33082
33632
  return {
@@ -33086,7 +33636,7 @@ function mapRow(row) {
33086
33636
  artifactId: String(row.artifact_id),
33087
33637
  title: String(row.title),
33088
33638
  summary: String(row.summary),
33089
- rendererKey: "editorial_reading_room_v1",
33639
+ rendererKey: row.renderer_key === "personal_authority_v1" ? "personal_authority_v1" : "editorial_reading_room_v1",
33090
33640
  tokenHash: String(row.token_hash),
33091
33641
  expiresAt: String(row.expires_at),
33092
33642
  revokedAt: row.revoked_at == null ? null : String(row.revoked_at),
@@ -33098,7 +33648,7 @@ async function createScheduledRunViewLink(input) {
33098
33648
  const now = input.now ?? /* @__PURE__ */ new Date();
33099
33649
  const token4 = randomBytes3(32).toString("base64url");
33100
33650
  const record = {
33101
- shareId: randomUUID16(),
33651
+ shareId: randomUUID17(),
33102
33652
  ownerId: input.ownerId,
33103
33653
  runId: input.runId,
33104
33654
  artifactId: input.artifactId,
@@ -33162,6 +33712,121 @@ async function revokeScheduledRunViewLink(ownerId, runId, shareId, now = /* @__P
33162
33712
  return result.rowsAffected > 0;
33163
33713
  }
33164
33714
 
33715
+ // src/personal-authority/render.ts
33716
+ import { createHash as createHash16 } from "crypto";
33717
+ function escapeHtml6(value) {
33718
+ return value.replace(/[&<>"']/g, (character) => ({
33719
+ "&": "&amp;",
33720
+ "<": "&lt;",
33721
+ ">": "&gt;",
33722
+ '"': "&quot;",
33723
+ "'": "&#39;"
33724
+ })[character] ?? character);
33725
+ }
33726
+ function safeHref(value) {
33727
+ const trimmed = value.trim();
33728
+ return /^(?:https?:|mailto:|tel:|#|\/)/i.test(trimmed) ? escapeHtml6(trimmed) : "#";
33729
+ }
33730
+ function initials(name) {
33731
+ return name.split(/\s+/).filter(Boolean).slice(0, 2).map((part) => part[0]?.toUpperCase()).join("") || "PA";
33732
+ }
33733
+ function action(action2, secondary = false) {
33734
+ return `<a class="button${secondary ? " button--secondary" : ""}" href="${safeHref(action2.href)}">${escapeHtml6(action2.label)} <span aria-hidden="true">\u2197</span></a>`;
33735
+ }
33736
+ function section(enabled, html) {
33737
+ return enabled ? html : "";
33738
+ }
33739
+ function renderPersonalAuthorityV1(input, config, generatedAt) {
33740
+ const flags = config.featureFlags;
33741
+ const brand = config.brandName || input.name;
33742
+ const generatedAtIso = generatedAt.toISOString();
33743
+ const social = flags.socialLinks && input.socialLinks.length > 0 ? `<nav class="social" aria-label="Professional profiles">${input.socialLinks.map((link) => `<a href="${safeHref(link.href)}">${escapeHtml6(link.label)}</a>`).join("")}</nav>` : "";
33744
+ 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>` : "";
33745
+ const authority = input.authority;
33746
+ const consultation = input.consultation;
33747
+ const learning = input.learning;
33748
+ const services = input.services;
33749
+ const proof = input.proof;
33750
+ const finalCta = input.finalCta;
33751
+ const html = `<!doctype html>
33752
+ <html lang="en" data-theme="${config.theme}">
33753
+ <head>
33754
+ <meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
33755
+ <meta name="description" content="${escapeHtml6(input.summary)}"><title>${escapeHtml6(input.name)} \u2014 ${escapeHtml6(input.professionalTitle)}</title>
33756
+ <style>
33757
+ :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)}
33758
+ @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}}
33759
+ </style></head>
33760
+ <body><a class="skip" href="#main">Skip to main content</a>
33761
+ <header class="header"><a class="brand" href="#top"><span class="mark">${escapeHtml6(initials(input.name).slice(0, 1))}</span><strong>${escapeHtml6(brand)}</strong></a>${navigation}</header>
33762
+ <main id="main"><section class="hero" id="top"><div class="portrait" aria-label="Portrait placeholder"><div class="portrait-card" aria-hidden="true">${escapeHtml6(initials(input.name))}</div></div><div class="hero-copy"><h1>${escapeHtml6(input.name)}</h1><p class="role">${escapeHtml6(input.professionalTitle)}</p><p class="summary">${escapeHtml6(input.summary)}</p><div class="actions">${action(input.primaryAction)}${input.secondaryAction ? action(input.secondaryAction, true) : ""}</div>${social}</div></section>
33763
+ ${section(flags.authority && Boolean(authority), `<section class="light" id="about"><h2>${escapeHtml6(authority?.heading ?? "")}</h2>${authority?.paragraphs.map((paragraph) => `<p>${escapeHtml6(paragraph)}</p>`).join("") ?? ""}</section>`)}
33764
+ ${section(flags.consultation && Boolean(consultation), `<section class="section consult"><div><p class="eyebrow">${escapeHtml6(consultation?.eyebrow ?? "Start a conversation")}</p><h2>${escapeHtml6(consultation?.heading ?? "")}</h2><p class="summary">${escapeHtml6(consultation?.summary ?? "")}</p>${consultation ? action(consultation.action) : ""}</div><div class="accent-card" aria-label="Image placeholder">${escapeHtml6(initials(input.name))}</div></section>`)}
33765
+ ${section(flags.learning && Boolean(learning), `<section class="section learning"><div class="section-head"><h2>${escapeHtml6(learning?.heading ?? "")}</h2><p class="summary">${escapeHtml6(learning?.summary ?? "")}</p></div><div class="topic-grid">${learning?.topics.map((topic) => `<article class="topic"><strong>${escapeHtml6(topic.title)}</strong><h3>${escapeHtml6(topic.headline)}</h3><p>${escapeHtml6(topic.summary)}</p>${topic.href ? `<a href="${safeHref(topic.href)}">Explore \u2192</a>` : ""}</article>`).join("") ?? ""}</div></section>`)}
33766
+ ${section(flags.services && Boolean(services), `<section class="section" id="services"><div class="section-head"><h2>${escapeHtml6(services?.heading ?? "")}</h2><p class="summary">${escapeHtml6(services?.summary ?? "")}</p></div><div class="grid">${services?.offers.map((offer) => `<article class="card"><h3>${escapeHtml6(offer.title)}</h3><p>${escapeHtml6(offer.description)}</p>${offer.action ? action(offer.action, true) : ""}</article>`).join("") ?? ""}</div></section>`)}
33767
+ ${section(flags.proof && Boolean(proof), `<section class="section proof" id="proof"><div class="section-head"><h2>${escapeHtml6(proof?.heading ?? "")}</h2><p class="summary">${escapeHtml6(proof?.summary ?? "")}</p></div><div class="quotes">${proof?.testimonials.map((item) => `<article class="quote"><q>${escapeHtml6(item.quote)}</q><span>${escapeHtml6(item.person)}${item.role ? ` / ${escapeHtml6(item.role)}` : ""}</span></article>`).join("") ?? ""}</div></section>`)}
33768
+ ${section(flags.finalCta && Boolean(finalCta), `<section class="section cta" id="contact"><p class="eyebrow">${escapeHtml6(finalCta?.eyebrow ?? "Ready when you are")}</p><h2>${escapeHtml6(finalCta?.heading ?? "")}</h2><p class="summary">${escapeHtml6(finalCta?.summary ?? "")}</p>${finalCta ? action(finalCta.action) : ""}</section>`)}
33769
+ </main><footer class="footer"><div><strong>${escapeHtml6(input.name)}</strong><div>${escapeHtml6(input.professionalTitle)}</div>${config.showGeneratedAt ? `<div class="generated">Generated ${escapeHtml6(generatedAtIso)}</div>` : ""}</div><div>${input.location ? `<div>${escapeHtml6(input.location)}</div>` : ""}${input.email ? `<a href="mailto:${escapeHtml6(input.email)}">${escapeHtml6(input.email)}</a>` : ""}${input.phone ? `<div>${escapeHtml6(input.phone)}</div>` : ""}</div></footer>
33770
+ <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>`;
33771
+ const bytes = Buffer.byteLength(html, "utf8");
33772
+ return {
33773
+ html,
33774
+ filename: `${input.name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "") || "personal-authority"}.html`,
33775
+ bytes,
33776
+ sha256: createHash16("sha256").update(html).digest("hex"),
33777
+ generatedAt: generatedAtIso
33778
+ };
33779
+ }
33780
+
33781
+ // src/scheduled-artifacts/scheduled-artifact-renderer-registry.ts
33782
+ var editorialReadingRoomV1 = {
33783
+ rendererKey: "editorial_reading_room_v1",
33784
+ rendererVersion: 1,
33785
+ async render(rawInput, rawConfig, generatedAt) {
33786
+ const input = EditorialReadingRoomV1InputSchema.parse(rawInput);
33787
+ const config = EditorialArtifactTemplateConfigSchema.parse(rawConfig);
33788
+ const rendered = renderEditorialReadingRoomV1(input, config, generatedAt);
33789
+ if (rendered.bytes > 2e6) {
33790
+ throw new Error("Scheduled artifact HTML must be 2,000,000 bytes or fewer.");
33791
+ }
33792
+ return {
33793
+ html: rendered.html,
33794
+ filename: rendered.filename,
33795
+ title: input.title,
33796
+ bytes: rendered.bytes,
33797
+ sha256: rendered.sha256,
33798
+ generatedAt: rendered.generatedAt
33799
+ };
33800
+ }
33801
+ };
33802
+ var personalAuthorityV1 = {
33803
+ rendererKey: "personal_authority_v1",
33804
+ rendererVersion: 1,
33805
+ async render(rawInput, rawConfig, generatedAt) {
33806
+ const input = PersonalAuthorityV1InputSchema.parse(rawInput);
33807
+ const config = PersonalAuthorityTemplateConfigSchema.parse(rawConfig);
33808
+ const rendered = renderPersonalAuthorityV1(input, config, generatedAt);
33809
+ if (rendered.bytes > 2e6) {
33810
+ throw new Error("Scheduled artifact HTML must be 2,000,000 bytes or fewer.");
33811
+ }
33812
+ return {
33813
+ ...rendered,
33814
+ title: input.name
33815
+ };
33816
+ }
33817
+ };
33818
+ var scheduledArtifactRendererRegistry = Object.freeze({
33819
+ "editorial_reading_room_v1:1": editorialReadingRoomV1,
33820
+ "personal_authority_v1:1": personalAuthorityV1
33821
+ });
33822
+ function getScheduledArtifactRenderer(rendererKey, rendererVersion) {
33823
+ return scheduledArtifactRendererRegistry[`${rendererKey}:${rendererVersion}`] ?? null;
33824
+ }
33825
+ var scheduledArtifactTemplatePresets = [
33826
+ EDITORIAL_READING_ROOM_TEMPLATE_PRESET,
33827
+ PERSONAL_AUTHORITY_TEMPLATE_PRESET
33828
+ ];
33829
+
33165
33830
  // src/api/scheduled-result-routes.ts
33166
33831
  var TemplateParamsSchema = z33.object({ templateId: z33.string().uuid() }).strict();
33167
33832
  var RunParamsSchema = z33.object({ runId: z33.string().min(1).max(200) }).strict();
@@ -33213,7 +33878,7 @@ scheduledResultApp.get("/artifact-templates", async (c) => {
33213
33878
  c.header("Cache-Control", "private, no-store");
33214
33879
  return c.json({
33215
33880
  ...result,
33216
- presets: Array.isArray(result.presets) ? result.presets : [SCHEDULED_ARTIFACT_TEMPLATE_PRESET]
33881
+ presets: Array.isArray(result.presets) ? result.presets : scheduledArtifactTemplatePresets
33217
33882
  });
33218
33883
  });
33219
33884
  scheduledResultApp.post("/artifact-templates", async (c) => {
@@ -33335,7 +34000,7 @@ scheduledResultApp.delete("/schedule-runs/:runId/view-links/:shareId", async (c)
33335
34000
  import { Hono as Hono33 } from "hono";
33336
34001
 
33337
34002
  // src/scheduled-artifacts/scheduled-run-artifact-store.ts
33338
- import { createHash as createHash15 } from "crypto";
34003
+ import { createHash as createHash17 } from "crypto";
33339
34004
  var SCHEDULED_RUN_ARTIFACT_PREFIX = "scheduled-run-artifacts/";
33340
34005
  var SCHEDULED_RUN_ARTIFACT_DOWNLOAD_TTL_MS = 15 * 60 * 1e3;
33341
34006
  var SCHEDULED_RUN_ARTIFACT_MAX_BYTES = 2e6;
@@ -33351,7 +34016,7 @@ function policy3() {
33351
34016
  };
33352
34017
  }
33353
34018
  function runStorageSegment(runId) {
33354
- return /^[a-zA-Z0-9_-]{1,160}$/.test(runId) ? runId : `run-${createHash15("sha256").update(runId).digest("hex").slice(0, 32)}`;
34019
+ return /^[a-zA-Z0-9_-]{1,160}$/.test(runId) ? runId : `run-${createHash17("sha256").update(runId).digest("hex").slice(0, 32)}`;
33355
34020
  }
33356
34021
  async function createScheduledRunArtifact(args) {
33357
34022
  if (args.rendered.bytes > SCHEDULED_RUN_ARTIFACT_MAX_BYTES) {
@@ -33458,10 +34123,10 @@ publicScheduledResultApp.get("/scheduled-run-view-links/:token/content", async (
33458
34123
  import { Hono as Hono34 } from "hono";
33459
34124
 
33460
34125
  // src/api/scheduler-integration-auth.ts
33461
- import { createHash as createHash16, createHmac as createHmac4, timingSafeEqual as timingSafeEqual3 } from "crypto";
34126
+ import { createHash as createHash18, createHmac as createHmac4, timingSafeEqual as timingSafeEqual3 } from "crypto";
33462
34127
 
33463
34128
  // src/api/service-connections.ts
33464
- import { randomUUID as randomUUID17 } from "crypto";
34129
+ import { randomUUID as randomUUID18 } from "crypto";
33465
34130
  var schemaReady4 = null;
33466
34131
  var schemaDb3 = null;
33467
34132
  function ensureServiceConnectionsSchema() {
@@ -33603,7 +34268,7 @@ async function reconcileDiscoveredNangoConnections(identity, discovered) {
33603
34268
  updated_at = excluded.updated_at
33604
34269
  `,
33605
34270
  args: [
33606
- randomUUID17(),
34271
+ randomUUID18(),
33607
34272
  userId,
33608
34273
  connection.providerConfigKey,
33609
34274
  connection.provider,
@@ -33674,7 +34339,7 @@ async function recordServiceConnectionHealth(args) {
33674
34339
  });
33675
34340
  await getDb().execute({
33676
34341
  sql: `INSERT INTO service_connection_health_events (id, connection_id, operational_status, failure_code, retryable, evidence_source) VALUES (?, ?, ?, ?, ?, ?)`,
33677
- args: [randomUUID17(), args.connectionId, args.operationalStatus, args.failureCode ?? null, args.retryable == null ? null : args.retryable ? 1 : 0, args.evidenceSource]
34342
+ args: [randomUUID18(), args.connectionId, args.operationalStatus, args.failureCode ?? null, args.retryable == null ? null : args.retryable ? 1 : 0, args.evidenceSource]
33678
34343
  });
33679
34344
  }
33680
34345
  async function setServiceConnectionActions(identity, connectionId, enabled) {
@@ -33714,7 +34379,7 @@ async function claimServiceConnectionAction(args) {
33714
34379
  if (!connection) throw new Error("service_connection_not_found");
33715
34380
  const inserted = await getDb().execute({
33716
34381
  sql: `INSERT OR IGNORE INTO service_connection_action_audit (id, connection_id, user_id, tool, request_id, status, request_digest) VALUES (?, ?, ?, ?, ?, 'started', ?)`,
33717
- args: [randomUUID17(), connection.id, connection.userId, args.tool, args.requestId, args.requestDigest]
34382
+ args: [randomUUID18(), connection.id, connection.userId, args.tool, args.requestId, args.requestDigest]
33718
34383
  });
33719
34384
  if (Number(inserted.rowsAffected ?? 0) === 1) return { claimed: true };
33720
34385
  const existing = await getDb().execute({
@@ -33756,7 +34421,7 @@ function signingSecret() {
33756
34421
  return secret2;
33757
34422
  }
33758
34423
  function schedulerIntegrationSignature(args) {
33759
- const bodyHash = createHash16("sha256").update(args.body).digest("hex");
34424
+ const bodyHash = createHash18("sha256").update(args.body).digest("hex");
33760
34425
  return createHmac4("sha256", args.secret).update(`${args.method.toUpperCase()}
33761
34426
  ${args.path}
33762
34427
  ${args.timestamp}
@@ -33811,34 +34476,6 @@ async function verifySchedulerIntegrationRequest(request, rawBody) {
33811
34476
  return { requestId };
33812
34477
  }
33813
34478
 
33814
- // src/scheduled-artifacts/scheduled-artifact-renderer-registry.ts
33815
- var editorialReadingRoomV1 = {
33816
- rendererKey: "editorial_reading_room_v1",
33817
- rendererVersion: 1,
33818
- async render(rawInput, rawConfig, generatedAt) {
33819
- const input = EditorialReadingRoomV1InputSchema.parse(rawInput);
33820
- const config = ArtifactTemplateConfigSchema.parse(rawConfig);
33821
- const rendered = renderEditorialReadingRoomV1(input, config, generatedAt);
33822
- if (rendered.bytes > 2e6) {
33823
- throw new Error("Scheduled artifact HTML must be 2,000,000 bytes or fewer.");
33824
- }
33825
- return {
33826
- html: rendered.html,
33827
- filename: rendered.filename,
33828
- title: input.title,
33829
- bytes: rendered.bytes,
33830
- sha256: rendered.sha256,
33831
- generatedAt: rendered.generatedAt
33832
- };
33833
- }
33834
- };
33835
- var scheduledArtifactRendererRegistry = Object.freeze({
33836
- "editorial_reading_room_v1:1": editorialReadingRoomV1
33837
- });
33838
- function getScheduledArtifactRenderer(rendererKey, rendererVersion) {
33839
- return scheduledArtifactRendererRegistry[`${rendererKey}:${rendererVersion}`] ?? null;
33840
- }
33841
-
33842
34479
  // src/api/scheduled-artifact-internal-routes.ts
33843
34480
  var scheduledArtifactInternalApp = new Hono34();
33844
34481
  function errorPayload(errorCode, error, requestId) {
@@ -34040,13 +34677,13 @@ async function reconcileSiteExtractSettlements(limit = 25) {
34040
34677
  }
34041
34678
 
34042
34679
  // src/api/page-diff.ts
34043
- import { createHash as createHash17 } from "crypto";
34680
+ import { createHash as createHash19 } from "crypto";
34044
34681
  import { diffLines } from "diff";
34045
34682
  var MAX_SNAPSHOT_CONTENT_CHARS = 25e4;
34046
34683
  var MAX_DIFF_HUNKS = 200;
34047
34684
  var MAX_DIFF_LINES_PER_RESPONSE = 2e3;
34048
34685
  function sha256Hex(value) {
34049
- return createHash17("sha256").update(value).digest("hex");
34686
+ return createHash19("sha256").update(value).digest("hex");
34050
34687
  }
34051
34688
  function truncateForStorage(value, maxChars = MAX_SNAPSHOT_CONTENT_CHARS) {
34052
34689
  if (value.length <= maxChars) return { value, truncated: false };
@@ -34160,10 +34797,10 @@ async function persistScrapeBody(user, opts) {
34160
34797
  }
34161
34798
 
34162
34799
  // src/api/scrape-image-sink.ts
34163
- import { createHash as createHash18 } from "crypto";
34800
+ import { createHash as createHash20 } from "crypto";
34164
34801
  var MAX_IMAGES_PER_SCRAPE = 25;
34165
34802
  function idempotencyKey2(userId, vault, input) {
34166
- return `scrape-image-${createHash18("sha256").update(`${userId}\0${vault}\0${input.sourceKind}\0${input.sourceUrl}\0${input.imageUrl ?? ""}\0${input.imageBase64 ?? ""}`).digest("hex")}`;
34803
+ return `scrape-image-${createHash20("sha256").update(`${userId}\0${vault}\0${input.sourceKind}\0${input.sourceUrl}\0${input.imageUrl ?? ""}\0${input.imageBase64 ?? ""}`).digest("hex")}`;
34167
34804
  }
34168
34805
  async function persistScrapeImagesToMemory(user, inputs, vault) {
34169
34806
  const selected = inputs.slice(0, MAX_IMAGES_PER_SCRAPE);
@@ -34635,7 +35272,7 @@ function inferredWaybackCapturedAt(content) {
34635
35272
  }
34636
35273
 
34637
35274
  // src/api/connection-memory-import.ts
34638
- import { createHash as createHash19 } from "crypto";
35275
+ import { createHash as createHash21 } from "crypto";
34639
35276
  var CONNECTION_MEMORY_IMPORT_MAX_ARGS_BYTES = 64 * 1024;
34640
35277
  var CONNECTION_MEMORY_IMPORT_MAX_RESULT_BYTES = 1e6;
34641
35278
  var CONNECTION_MEMORY_IMPORT_MAX_STRING_CHARS = 256e3;
@@ -34665,7 +35302,7 @@ function canonicalJson(value) {
34665
35302
  return JSON.stringify(value);
34666
35303
  }
34667
35304
  function sha2562(value) {
34668
- return createHash19("sha256").update(value).digest("hex");
35305
+ return createHash21("sha256").update(value).digest("hex");
34669
35306
  }
34670
35307
  function sensitiveKey(key) {
34671
35308
  const normalized = key.toLowerCase().replace(/[^a-z0-9]/g, "");
@@ -34934,7 +35571,7 @@ async function cleanupExpiredScrapeBlobs(maxAgeMs = SCRAPE_BLOB_TTL_MS) {
34934
35571
  }
34935
35572
 
34936
35573
  // src/api/connected-data-export.ts
34937
- import { randomUUID as randomUUID18 } from "crypto";
35574
+ import { randomUUID as randomUUID19 } from "crypto";
34938
35575
  var CONNECTED_DATA_INLINE_BUDGET_BYTES = Number(
34939
35576
  process.env.MCP_SCRAPER_CONNECTED_DATA_INLINE_BUDGET_BYTES ?? 5e4
34940
35577
  );
@@ -35105,7 +35742,7 @@ function finitePositive(value, fallback) {
35105
35742
  return Number.isFinite(value) && value > 0 ? value : fallback;
35106
35743
  }
35107
35744
  async function collectConnectedDataExport(args) {
35108
- const exportId = randomUUID18();
35745
+ const exportId = randomUUID19();
35109
35746
  const now = args.now ?? Date.now;
35110
35747
  const startedAt = now();
35111
35748
  const budgetMs = finitePositive(CONNECTED_DATA_EXPORT_BUDGET_MS, 24e4);
@@ -35221,7 +35858,7 @@ ${lines.length ? `${lines.join("\n")}
35221
35858
  }
35222
35859
 
35223
35860
  // src/api/search-console-table-export.ts
35224
- import { randomUUID as randomUUID19 } from "crypto";
35861
+ import { randomUUID as randomUUID20 } from "crypto";
35225
35862
  var SEARCH_CONSOLE_TABLE_EXPORT_MAX_ROWS = 5e4;
35226
35863
  var SEARCH_CONSOLE_TABLE_EXPORT_PAGE_SIZE = 2e3;
35227
35864
  var SEARCH_CONSOLE_TABLE_EXPORT_MAX_BYTES = 50 * 1024 * 1024;
@@ -35321,7 +35958,7 @@ async function exportSearchConsoleTableData(args) {
35321
35958
  offset += rows.length;
35322
35959
  if (stoppedForBytes || rows.length < limit || offset >= matchedRows) break;
35323
35960
  }
35324
- const exportId = randomUUID19();
35961
+ const exportId = randomUUID20();
35325
35962
  const artifact = await args.writeArtifact({
35326
35963
  ownerId: args.ownerId,
35327
35964
  exportId,
@@ -35676,7 +36313,7 @@ async function dbUsage(identity, plan) {
35676
36313
  }
35677
36314
 
35678
36315
  // src/api/nango-control.ts
35679
- import { createHash as createHash21, randomUUID as randomUUID21 } from "crypto";
36316
+ import { createHash as createHash23, randomUUID as randomUUID22 } from "crypto";
35680
36317
 
35681
36318
  // src/api/slack-archive-analysis.ts
35682
36319
  function isRecord2(value) {
@@ -36050,7 +36687,7 @@ async function exportSlackChannelPage(input, dependencies) {
36050
36687
  }
36051
36688
 
36052
36689
  // src/api/main-nango-transport.ts
36053
- import { createHash as createHash20, randomUUID as randomUUID20 } from "crypto";
36690
+ import { createHash as createHash22, randomUUID as randomUUID21 } from "crypto";
36054
36691
  import { Client, StreamableHTTPClientTransport } from "@modelcontextprotocol/client";
36055
36692
 
36056
36693
  // src/api/connected-tool-policy.ts
@@ -36443,7 +37080,7 @@ async function listNangoToolsDirect(identity, connectionId) {
36443
37080
  });
36444
37081
  const readTools = [...policies.values()].filter((policy4) => policy4.classification === "read").map((policy4) => policy4.name);
36445
37082
  const actionTools = [...policies.values()].filter((policy4) => policy4.classification === "action").map((policy4) => policy4.name);
36446
- const revision = createHash20("sha256").update(JSON.stringify(tools.map((tool) => ({ name: tool.name, inputSchema: tool.inputSchema })))).digest("hex");
37083
+ const revision = createHash22("sha256").update(JSON.stringify(tools.map((tool) => ({ name: tool.name, inputSchema: tool.inputSchema })))).digest("hex");
36447
37084
  await updateServiceConnectionTools(connection.id, readTools, actionTools, revision);
36448
37085
  const refreshed = await getOwnedServiceConnection(identity, connection.id);
36449
37086
  return { connection: refreshed ?? { ...connection, readTools, actionTools, toolRevision: revision }, tools };
@@ -36470,8 +37107,8 @@ async function callNangoToolDirect(args) {
36470
37107
  identity: args.identity,
36471
37108
  ratePolicyVersion: CONNECTED_USAGE_RATE_POLICY_VERSION
36472
37109
  });
36473
- const requestId = args.requestId?.trim() || randomUUID20();
36474
- const idempotencyKey3 = `main-nango:${createHash20("sha256").update(args.identity.toLowerCase()).update("\0").update(connection.id).update("\0").update(args.tool).update("\0").update(requestId).digest("hex")}`;
37110
+ const requestId = args.requestId?.trim() || randomUUID21();
37111
+ const idempotencyKey3 = `main-nango:${createHash22("sha256").update(args.identity.toLowerCase()).update("\0").update(connection.id).update("\0").update(args.tool).update("\0").update(requestId).digest("hex")}`;
36475
37112
  const startedAt = /* @__PURE__ */ new Date();
36476
37113
  const started = performance.now();
36477
37114
  let result;
@@ -36496,7 +37133,7 @@ async function callNangoToolDirect(args) {
36496
37133
  toolName: args.tool,
36497
37134
  operationKind: args.operationKind ?? args.classification,
36498
37135
  outcome: providerError ? "error" : "partial",
36499
- requestId: requestId.length <= 200 ? requestId : createHash20("sha256").update(requestId).digest("hex"),
37136
+ requestId: requestId.length <= 200 ? requestId : createHash22("sha256").update(requestId).digest("hex"),
36500
37137
  startedAt: startedAt.toISOString(),
36501
37138
  completedAt: completedAt.toISOString()
36502
37139
  }
@@ -36538,7 +37175,7 @@ async function describeNangoToolDirect(identity, connectionId, toolName) {
36538
37175
  providerContractHash: MAIN_INTEGRATION_CONTRACT_HASH,
36539
37176
  protocolVersion: null,
36540
37177
  schemaSource: "live_tools_list",
36541
- schemaHash: createHash20("sha256").update(JSON.stringify(projected)).digest("hex"),
37178
+ schemaHash: createHash22("sha256").update(JSON.stringify(projected)).digest("hex"),
36542
37179
  fetchedAt: (/* @__PURE__ */ new Date()).toISOString()
36543
37180
  };
36544
37181
  }
@@ -37262,8 +37899,8 @@ async function setScheduleConnectionActionsEnabled(identity, connectionId, enabl
37262
37899
  return data.connection.actionsEnabled === true;
37263
37900
  }
37264
37901
  async function callScheduleConnectionAction(identity, connectionId, input, tool, idempotencyKey3) {
37265
- const requestId = `main-connected-action:${createHash21("sha256").update(identity).update("\0").update(idempotencyKey3?.trim() || randomUUID21()).digest("hex")}`;
37266
- const requestDigest = createHash21("sha256").update(connectionId).update("\0").update(tool?.trim() ?? "").update("\0").update(canonicalJson2(input)).digest("hex");
37902
+ const requestId = `main-connected-action:${createHash23("sha256").update(identity).update("\0").update(idempotencyKey3?.trim() || randomUUID22()).digest("hex")}`;
37903
+ const requestDigest = createHash23("sha256").update(connectionId).update("\0").update(tool?.trim() ?? "").update("\0").update(canonicalJson2(input)).digest("hex");
37267
37904
  if (mainOwnsIntegrations()) {
37268
37905
  const selectedTool = tool?.trim();
37269
37906
  if (!selectedTool) throw new NangoControlError("An action tool is required.", 400, "invalid_request", false);
@@ -37414,7 +38051,7 @@ function canonicalJson2(value) {
37414
38051
  return JSON.stringify(value);
37415
38052
  }
37416
38053
  function projectedToolSchemaHash(tool) {
37417
- return createHash21("sha256").update(canonicalJson2(tool)).digest("hex");
38054
+ return createHash23("sha256").update(canonicalJson2(tool)).digest("hex");
37418
38055
  }
37419
38056
  async function describeNangoTool(identity, connectionId, tool, fresh) {
37420
38057
  if (mainOwnsIntegrations()) {
@@ -37693,7 +38330,7 @@ async function callMainOwnedExportPage(identity, input) {
37693
38330
  }
37694
38331
 
37695
38332
  // src/api/resend-control.ts
37696
- import { createHash as createHash22 } from "crypto";
38333
+ import { createHash as createHash24 } from "crypto";
37697
38334
  var DEFAULT_CONNECTION_CONTROL_URL = "https://mcp-scraper-scheduler.vercel.app";
37698
38335
  var RESEND_PROVIDER_CONFIG_KEY = "resend";
37699
38336
  var RESEND_LOGO_URL = "https://cdn.resend.com/brand/resend-icon-black.svg";
@@ -37952,7 +38589,7 @@ async function callResendRead(identity, connectionId, tool, args) {
37952
38589
  return isRecord5(data) ? data.result ?? data : data;
37953
38590
  }
37954
38591
  async function callResendAction(identity, connectionId, tool, input, idempotencyKey3) {
37955
- const requestId = `main-resend-action:${createHash22("sha256").update(identity).update("\0").update(idempotencyKey3.trim()).digest("hex")}`;
38592
+ const requestId = `main-resend-action:${createHash24("sha256").update(identity).update("\0").update(idempotencyKey3.trim()).digest("hex")}`;
37956
38593
  const body = await controlRequest2("/api/internal/resend/actions/call", {
37957
38594
  method: "POST",
37958
38595
  headers: { "x-request-id": requestId },
@@ -39489,12 +40126,12 @@ app.get("/schedule-actions", auth3, async (c) => {
39489
40126
  const r = await memoryCall("listScheduledActionsTool", {}, key);
39490
40127
  if (!r.ok || !Array.isArray(r.actions)) return c.json(r);
39491
40128
  try {
39492
- const actions = await Promise.all(r.actions.map(async (action) => {
39493
- const id = typeof action.id === "string" ? action.id : "";
39494
- const executionMode = action.executionMode === "connection_sync" ? "connection_sync" : "agent";
39495
- if (!id) return { ...action, executionMode, connections: [] };
40129
+ const actions = await Promise.all(r.actions.map(async (action2) => {
40130
+ const id = typeof action2.id === "string" ? action2.id : "";
40131
+ const executionMode = action2.executionMode === "connection_sync" ? "connection_sync" : "agent";
40132
+ if (!id) return { ...action2, executionMode, connections: [] };
39496
40133
  const bindings = await getScheduleConnectionBindings(user.email, id);
39497
- return { ...action, executionMode, connections: bindingsForSchedule(bindings, id) };
40134
+ return { ...action2, executionMode, connections: bindingsForSchedule(bindings, id) };
39498
40135
  }));
39499
40136
  return c.json({
39500
40137
  ...r,
@@ -39504,7 +40141,7 @@ app.get("/schedule-actions", auth3, async (c) => {
39504
40141
  console.warn("[schedule-actions] connection bindings unavailable:", err instanceof Error ? err.message : String(err));
39505
40142
  return c.json({
39506
40143
  ...r,
39507
- actions: r.actions.map((action) => ({ ...action, executionMode: action.executionMode === "connection_sync" ? "connection_sync" : "agent", connections: [] })),
40144
+ actions: r.actions.map((action2) => ({ ...action2, executionMode: action2.executionMode === "connection_sync" ? "connection_sync" : "agent", connections: [] })),
39508
40145
  connectionBindingsUnavailable: true
39509
40146
  });
39510
40147
  }
@@ -39587,7 +40224,7 @@ app.put("/schedule-actions/:id/connections", auth3, requireIntegrationsTier, asy
39587
40224
  if (!key) return c.json({ ok: false, error: error ?? "memory unavailable" }, 503);
39588
40225
  const schedules = await memoryCall("listScheduledActionsTool", {}, key);
39589
40226
  if (!schedules.ok || !Array.isArray(schedules.actions)) return c.json(schedules, 502);
39590
- const schedule = schedules.actions.find((action) => action.id === scheduleActionId);
40227
+ const schedule = schedules.actions.find((action2) => action2.id === scheduleActionId);
39591
40228
  if (!schedule) return c.json({ ok: false, error: "scheduled action not found" }, 404);
39592
40229
  if (schedule.executionMode === "connection_sync") {
39593
40230
  const policyError = connectionSyncSelectionError(connections);
@@ -39786,7 +40423,7 @@ app.post("/harvest", auth3, async (c) => {
39786
40423
  if (!harvestOk) return c.json(insufficientBalanceResponse(harvestBal, harvestCost), 402);
39787
40424
  jobId2 = await createJob(user.id, options.query, { ...options, billingHoldMc: harvestCost }, body.callback_url);
39788
40425
  } else {
39789
- jobId2 = randomUUID22();
40426
+ jobId2 = randomUUID23();
39790
40427
  const billingDebitKey = `paa-harvest:${jobId2}:hold`;
39791
40428
  const description = `PAA harvest: ${options.query}`.slice(0, 500);
39792
40429
  const hold = await debitMcIdempotent(
@@ -41004,7 +41641,7 @@ app.get("/cron/tick", async (c) => {
41004
41641
  if (!process.env.CRON_SECRET || secret2 !== `Bearer ${process.env.CRON_SECRET}`) {
41005
41642
  return c.json({ error: "Unauthorized" }, 401);
41006
41643
  }
41007
- const { drainQueue } = await import("./worker-4LZGRHDA.js");
41644
+ const { drainQueue } = await import("./worker-3QX7LG62.js");
41008
41645
  const budget = { maxJobs: 10, deadlineMs: Date.now() + 28e4 };
41009
41646
  const workflowDispatchResult = await dispatchDueWorkflowSchedules(`${new URL(c.req.url).protocol}//${new URL(c.req.url).host}`);
41010
41647
  const [results, sweepResult, reapResult, expiredResult, blobCleanup, connectedDataArtifactCleanup, connectedAccountBilling, directoryWorkflowDispatch, directoryWorkflowReconciliation, directoryArtifactCleanup, siteExtractArtifactCleanup, siteExtractRedispatch, siteExtractReconciliation, paaHarvestRedispatch, paaHarvestReconciliation, localSourcebookRedispatch] = await Promise.all([
@@ -41059,8 +41696,8 @@ app.post("/api/internal/extract-refinalize/:id", async (c) => {
41059
41696
  finishExtractJob: finishExtractJob2,
41060
41697
  terminalExtractJobStatus: terminalExtractJobStatus2,
41061
41698
  extractJobLimitInfo: extractJobLimitInfo2
41062
- } = await import("./site-extract-repository-G723PZIL.js");
41063
- const { assembleExtractArtifacts } = await import("./extract-bundle-DYMQRQWG.js");
41699
+ } = await import("./site-extract-repository-UULQAGO4.js");
41700
+ const { assembleExtractArtifacts } = await import("./extract-bundle-DXWWQER6.js");
41064
41701
  const existing = await getExtractJob2(jobId2);
41065
41702
  if (!existing) return c.json({ error: "job not found" }, 404);
41066
41703
  if (existing.status !== "failed") {
@@ -41087,7 +41724,7 @@ app.post("/api/internal/extract-refinalize/:id", async (c) => {
41087
41724
  if (!updated) return c.json({ error: "job state changed during re-finalization" }, 409);
41088
41725
  let settlement = "already_settled_or_refunded";
41089
41726
  if (job.billedMc == null && job.userId != null) {
41090
- const { settleExtractJob: settleExtractJob3, countSuccessfulPages: countSuccessfulPages2 } = await import("./site-extract-repository-G723PZIL.js");
41727
+ const { settleExtractJob: settleExtractJob3, countSuccessfulPages: countSuccessfulPages2 } = await import("./site-extract-repository-UULQAGO4.js");
41091
41728
  const heldMc = Number(job.options.heldMc ?? 0);
41092
41729
  const successful = await countSuccessfulPages2(jobId2);
41093
41730
  const usedMc = Math.min(successful * MC_COSTS.page_scrape, heldMc);
@@ -41271,4 +41908,4 @@ app.get("/blog/:slug/", (c) => {
41271
41908
  export {
41272
41909
  app
41273
41910
  };
41274
- //# sourceMappingURL=server-7B75SDNG.js.map
41911
+ //# sourceMappingURL=server-OHMZJRSB.js.map