mcp-scraper 0.36.0 → 0.37.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 (53) hide show
  1. package/README.md +1 -1
  2. package/dist/bin/api-server.cjs +766 -168
  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 +1 -1
  9. package/dist/bin/mcp-scraper-install.cjs.map +1 -1
  10. package/dist/bin/mcp-scraper-install.js +1 -1
  11. package/dist/bin/mcp-stdio-server.cjs +52 -8
  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-3LWYPAU5.js +7 -0
  17. package/dist/chunk-3LWYPAU5.js.map +1 -0
  18. package/dist/{chunk-IFYER7O4.js → chunk-CSCD2HNS.js} +132 -2
  19. package/dist/chunk-CSCD2HNS.js.map +1 -0
  20. package/dist/{chunk-D7LM5QZN.js → chunk-FSAXLDB3.js} +2 -2
  21. package/dist/{chunk-5RULXBJ7.js → chunk-JK2FRDAP.js} +55 -11
  22. package/dist/{chunk-5RULXBJ7.js.map → chunk-JK2FRDAP.js.map} +1 -1
  23. package/dist/{chunk-ANCGXUQJ.js → chunk-LOPKN3YL.js} +2 -2
  24. package/dist/{chunk-E5UEELA7.js → chunk-MA5JBAUZ.js} +2 -2
  25. package/dist/{chunk-AN3VQARU.js → chunk-PUJFYJXB.js} +2 -2
  26. package/dist/{chunk-4ZIJ3BKZ.js → chunk-PWPUKR5U.js} +4 -2
  27. package/dist/{chunk-4ZIJ3BKZ.js.map → chunk-PWPUKR5U.js.map} +1 -1
  28. package/dist/{chunk-O2MCWFXQ.js → chunk-Q35WZJJK.js} +3 -3
  29. package/dist/{db-N6MPVMEF.js → db-N3YECFWR.js} +6 -2
  30. package/dist/{extract-bundle-M4SDJG3V.js → extract-bundle-346R6MXD.js} +4 -4
  31. package/dist/index.cjs.map +1 -1
  32. package/dist/index.js +3 -3
  33. package/dist/{location-data-repository-Z4NQOU5Y.js → location-data-repository-O2VII3ON.js} +3 -3
  34. package/dist/{server-ZIGAFKOL.js → server-QKDDEBVQ.js} +500 -99
  35. package/dist/server-QKDDEBVQ.js.map +1 -0
  36. package/dist/{site-extract-repository-PGQZNW6V.js → site-extract-repository-I3VM6WXN.js} +4 -4
  37. package/dist/{worker-EBB6CTGW.js → worker-TTFXPPDK.js} +6 -6
  38. package/docs/mcp-tool-manifest.generated.json +182 -6
  39. package/package.json +2 -2
  40. package/dist/chunk-4HO66323.js +0 -7
  41. package/dist/chunk-4HO66323.js.map +0 -1
  42. package/dist/chunk-IFYER7O4.js.map +0 -1
  43. package/dist/server-ZIGAFKOL.js.map +0 -1
  44. /package/dist/{chunk-D7LM5QZN.js.map → chunk-FSAXLDB3.js.map} +0 -0
  45. /package/dist/{chunk-ANCGXUQJ.js.map → chunk-LOPKN3YL.js.map} +0 -0
  46. /package/dist/{chunk-E5UEELA7.js.map → chunk-MA5JBAUZ.js.map} +0 -0
  47. /package/dist/{chunk-AN3VQARU.js.map → chunk-PUJFYJXB.js.map} +0 -0
  48. /package/dist/{chunk-O2MCWFXQ.js.map → chunk-Q35WZJJK.js.map} +0 -0
  49. /package/dist/{db-N6MPVMEF.js.map → db-N3YECFWR.js.map} +0 -0
  50. /package/dist/{extract-bundle-M4SDJG3V.js.map → extract-bundle-346R6MXD.js.map} +0 -0
  51. /package/dist/{location-data-repository-Z4NQOU5Y.js.map → location-data-repository-O2VII3ON.js.map} +0 -0
  52. /package/dist/{site-extract-repository-PGQZNW6V.js.map → site-extract-repository-I3VM6WXN.js.map} +0 -0
  53. /package/dist/{worker-EBB6CTGW.js.map → worker-TTFXPPDK.js.map} +0 -0
@@ -9,13 +9,13 @@ import {
9
9
  importHostedCensusPlacesCsv,
10
10
  importHostedZipGroupsCsv,
11
11
  listActiveHostedLocationDatasets
12
- } from "./chunk-AN3VQARU.js";
12
+ } from "./chunk-PUJFYJXB.js";
13
13
  import {
14
14
  classifyHarvestProblem,
15
15
  createHarvestAttemptRecorder,
16
16
  harvestProblemResponse,
17
17
  serializeHarvestProblem
18
- } from "./chunk-D7LM5QZN.js";
18
+ } from "./chunk-FSAXLDB3.js";
19
19
  import {
20
20
  BACKUP_LAST_RESORT_ATTEMPTS,
21
21
  BrowserDriver,
@@ -29,7 +29,7 @@ import {
29
29
  resolveBackupKernelProxyId,
30
30
  resolveKernelProxyId,
31
31
  serpArrivalUrl
32
- } from "./chunk-ANCGXUQJ.js";
32
+ } from "./chunk-LOPKN3YL.js";
33
33
  import {
34
34
  HttpMcpToolExecutor,
35
35
  WIZPER_LANGUAGES,
@@ -56,7 +56,7 @@ import {
56
56
  sanitizeAttempts,
57
57
  sanitizeHarvestResult,
58
58
  transcribeMediaUrl
59
- } from "./chunk-5RULXBJ7.js";
59
+ } from "./chunk-JK2FRDAP.js";
60
60
  import {
61
61
  auditImageUrls,
62
62
  auditImages,
@@ -74,7 +74,7 @@ import {
74
74
  recordKernelSession,
75
75
  recordVendorUsage,
76
76
  runWithCostContext
77
- } from "./chunk-E5UEELA7.js";
77
+ } from "./chunk-MA5JBAUZ.js";
78
78
  import {
79
79
  listWorkflowDefinitions,
80
80
  runWorkflow,
@@ -101,7 +101,7 @@ import {
101
101
  RawMapsOverviewSchema,
102
102
  RawMapsReviewStatsSchema
103
103
  } from "./chunk-CB5C3BPB.js";
104
- import "./chunk-4HO66323.js";
104
+ import "./chunk-3LWYPAU5.js";
105
105
  import {
106
106
  abandonExtractSettlement,
107
107
  countSuccessfulPages,
@@ -124,7 +124,7 @@ import {
124
124
  setExtractJobTotal,
125
125
  settleExtractJob,
126
126
  terminalExtractJobStatus
127
- } from "./chunk-O2MCWFXQ.js";
127
+ } from "./chunk-Q35WZJJK.js";
128
128
  import {
129
129
  BROWSER_OPEN_MIN_BALANCE_MC,
130
130
  CONCURRENCY_PRICE_ID,
@@ -169,7 +169,7 @@ import {
169
169
  tierBillingInterval,
170
170
  tierCreditsPerInterval,
171
171
  vendorCostUsdToMc
172
- } from "./chunk-4ZIJ3BKZ.js";
172
+ } from "./chunk-PWPUKR5U.js";
173
173
  import {
174
174
  CaptchaError,
175
175
  ExtractionError,
@@ -195,6 +195,7 @@ import {
195
195
  createWorkflowRun,
196
196
  createWorkflowSchedule,
197
197
  creditMc,
198
+ creditMcIdempotent,
198
199
  deactivateUser,
199
200
  debitMc,
200
201
  debitMcIdempotent,
@@ -264,7 +265,7 @@ import {
264
265
  softDeleteInboxMessage,
265
266
  upsertPageSnapshot,
266
267
  verifyPassword
267
- } from "./chunk-IFYER7O4.js";
268
+ } from "./chunk-CSCD2HNS.js";
268
269
 
269
270
  // src/blog/registry.ts
270
271
  var posts = [
@@ -6186,7 +6187,7 @@ async function extractSite(opts) {
6186
6187
  }
6187
6188
 
6188
6189
  // src/api/server.ts
6189
- import { Hono as Hono27 } from "hono";
6190
+ import { Hono as Hono28 } from "hono";
6190
6191
  import { serve as serveInngest } from "inngest/hono";
6191
6192
 
6192
6193
  // src/inngest/client.ts
@@ -8594,7 +8595,7 @@ var siteExtractFn = inngest.createFunction(
8594
8595
  });
8595
8596
  }) : null;
8596
8597
  const finalized = await step.run("finalize", async () => {
8597
- const { assembleExtractArtifacts } = await import("./extract-bundle-M4SDJG3V.js");
8598
+ const { assembleExtractArtifacts } = await import("./extract-bundle-346R6MXD.js");
8598
8599
  const current = await getExtractJob(jobId2);
8599
8600
  if (!current) throw new Error("extract job disappeared before finalization");
8600
8601
  const stored = await assembleExtractArtifacts(current, { branding, imageAudit });
@@ -9507,7 +9508,7 @@ async function resolveUsZipsPath(requestedPath) {
9507
9508
  async function loadZipGroups(stateAbbr, requestedPath, warnings, sourceMode) {
9508
9509
  const mode = resolvedLocationDataMode({ zipSource: sourceMode });
9509
9510
  if (mode === "hosted") {
9510
- const { getHostedZipGroups } = await import("./location-data-repository-Z4NQOU5Y.js");
9511
+ const { getHostedZipGroups } = await import("./location-data-repository-O2VII3ON.js");
9511
9512
  const hosted = await getHostedZipGroups(stateAbbr);
9512
9513
  if (!hosted.dataset) {
9513
9514
  throw new DirectoryLocationError(
@@ -9570,7 +9571,7 @@ async function resolveDirectoryMarkets(options, config = {}) {
9570
9571
  const sourceUrl = censusStateUrl(state.fips);
9571
9572
  const warnings = [];
9572
9573
  if (resolvedLocationDataMode(config) === "hosted") {
9573
- const { queryHostedLocationMarkets } = await import("./location-data-repository-Z4NQOU5Y.js");
9574
+ const { queryHostedLocationMarkets } = await import("./location-data-repository-O2VII3ON.js");
9574
9575
  const hosted = await queryHostedLocationMarkets({
9575
9576
  state: state.abbr,
9576
9577
  minPopulation: options.minPopulation,
@@ -15960,8 +15961,409 @@ googleAdsApp.post("/transcribe", createApiKeyAuth(), async (c) => {
15960
15961
  }
15961
15962
  });
15962
15963
 
15963
- // src/api/instagram-routes.ts
15964
+ // src/api/admin-auth.ts
15965
+ import { createMiddleware as createMiddleware3 } from "hono/factory";
15966
+ var adminAuth = createMiddleware3(async (c, next) => {
15967
+ const configured = process.env.ADMIN_KEY?.trim();
15968
+ const key = c.req.header("x-admin-key")?.trim();
15969
+ if (!configured) return c.json({ error: "Admin access disabled" }, 503);
15970
+ if (!key || key !== configured) return c.json({ error: "Unauthorized" }, 401);
15971
+ return next();
15972
+ });
15973
+
15974
+ // src/api/admin-credit-routes.ts
15964
15975
  import { Hono as Hono9 } from "hono";
15976
+
15977
+ // src/api/admin-credits.ts
15978
+ import { randomUUID as randomUUID5 } from "crypto";
15979
+ var MIN_ADJUSTMENT_CREDITS = 1;
15980
+ var LARGE_ADJUSTMENT_CREDITS = 1e5;
15981
+ var MAX_ADJUSTMENT_CREDITS = 1e7;
15982
+ var MIN_REASON_LENGTH = 3;
15983
+ var MAX_REASON_LENGTH = 500;
15984
+ var MAX_ACTOR_LENGTH = 120;
15985
+ var AdminCreditError = class extends Error {
15986
+ constructor(status, message, detail) {
15987
+ super(message);
15988
+ this.status = status;
15989
+ this.detail = detail;
15990
+ this.name = "AdminCreditError";
15991
+ }
15992
+ status;
15993
+ detail;
15994
+ };
15995
+ function toCredits(mc) {
15996
+ return mc / MC_PER_CREDIT;
15997
+ }
15998
+ function creditsToMc(credits) {
15999
+ return Math.round(credits * MC_PER_CREDIT);
16000
+ }
16001
+ function validateCredits(credits, confirmLarge) {
16002
+ if (typeof credits !== "number" || !Number.isFinite(credits) || !Number.isInteger(credits)) {
16003
+ throw new AdminCreditError(400, "credits must be a whole number");
16004
+ }
16005
+ if (credits < MIN_ADJUSTMENT_CREDITS) {
16006
+ throw new AdminCreditError(400, `credits must be at least ${MIN_ADJUSTMENT_CREDITS}`);
16007
+ }
16008
+ if (credits > MAX_ADJUSTMENT_CREDITS) {
16009
+ throw new AdminCreditError(400, `credits exceeds the hard ceiling of ${MAX_ADJUSTMENT_CREDITS.toLocaleString()}`);
16010
+ }
16011
+ if (credits > LARGE_ADJUSTMENT_CREDITS && !confirmLarge) {
16012
+ throw new AdminCreditError(422, `adjustments over ${LARGE_ADJUSTMENT_CREDITS.toLocaleString()} credits require confirmLarge: true`, {
16013
+ credits,
16014
+ threshold: LARGE_ADJUSTMENT_CREDITS
16015
+ });
16016
+ }
16017
+ return credits;
16018
+ }
16019
+ function validateReason(reason) {
16020
+ const trimmed = typeof reason === "string" ? reason.trim() : "";
16021
+ if (trimmed.length < MIN_REASON_LENGTH) {
16022
+ throw new AdminCreditError(400, `reason must be at least ${MIN_REASON_LENGTH} characters`);
16023
+ }
16024
+ if (trimmed.length > MAX_REASON_LENGTH) {
16025
+ throw new AdminCreditError(400, `reason must be at most ${MAX_REASON_LENGTH} characters`);
16026
+ }
16027
+ return trimmed;
16028
+ }
16029
+ function validateActor(actor) {
16030
+ const trimmed = typeof actor === "string" ? actor.trim() : "";
16031
+ if (!trimmed) throw new AdminCreditError(400, "actor is required so the adjustment records who made it");
16032
+ if (trimmed.length > MAX_ACTOR_LENGTH) {
16033
+ throw new AdminCreditError(400, `actor must be at most ${MAX_ACTOR_LENGTH} characters`);
16034
+ }
16035
+ return trimmed;
16036
+ }
16037
+ function validateDirection(direction) {
16038
+ if (direction !== "grant" && direction !== "revoke") {
16039
+ throw new AdminCreditError(400, "direction must be either 'grant' or 'revoke'");
16040
+ }
16041
+ return direction;
16042
+ }
16043
+ async function resolveUser2(target) {
16044
+ const email = target.email?.trim().toLowerCase();
16045
+ if (!email && target.userId == null) {
16046
+ throw new AdminCreditError(400, "Provide either email or userId");
16047
+ }
16048
+ const user = email ? await getUserByEmail(email) : await getUserById(target.userId);
16049
+ if (user) return user;
16050
+ const probe = await getDb().execute(
16051
+ email ? { sql: "SELECT active FROM users WHERE email = ? LIMIT 1", args: [email] } : { sql: "SELECT active FROM users WHERE id = ? LIMIT 1", args: [target.userId] }
16052
+ );
16053
+ if (probe.rows.length > 0) {
16054
+ throw new AdminCreditError(409, "Account is deactivated; reactivate it before adjusting credits");
16055
+ }
16056
+ throw new AdminCreditError(404, "No account found for that email or id");
16057
+ }
16058
+ async function moveCredits(userId, direction, mc, reason, key) {
16059
+ if (direction === "grant") {
16060
+ const res2 = await creditMcIdempotent(userId, mc, LedgerOperation.ADMIN_GRANT, reason, key);
16061
+ if (!res2.ok) throw new AdminCreditError(409, "Grant could not be applied");
16062
+ return;
16063
+ }
16064
+ const res = await debitMcIdempotent(userId, mc, LedgerOperation.ADMIN_REVOKE, reason, key);
16065
+ if (!res.ok) {
16066
+ const balance = await reconcileBalanceMc(userId);
16067
+ throw new AdminCreditError(409, "Account does not have enough credits for this revoke", {
16068
+ requested_credits: toCredits(mc),
16069
+ available_credits: toCredits(balance)
16070
+ });
16071
+ }
16072
+ }
16073
+ function flip(direction) {
16074
+ return direction === "grant" ? "revoke" : "grant";
16075
+ }
16076
+ async function loadAdjustment(reference) {
16077
+ const db = getDb();
16078
+ const res = await db.execute({
16079
+ sql: `SELECT a.reference, a.user_id, a.direction, a.amount_mc, a.reason, a.actor, a.status, a.created_at, a.updated_at, u.email
16080
+ FROM admin_credit_adjustments a JOIN users u ON u.id = a.user_id
16081
+ WHERE a.reference = ? LIMIT 1`,
16082
+ args: [reference]
16083
+ });
16084
+ const row = res.rows[0];
16085
+ if (!row) throw new AdminCreditError(404, `No adjustment found with reference ${reference}`);
16086
+ const events = await db.execute({
16087
+ sql: `SELECT seq, kind, from_amount_mc, to_amount_mc, from_reason, to_reason, moved_mc, actor, created_at
16088
+ FROM admin_credit_adjustment_events WHERE reference = ? ORDER BY seq ASC`,
16089
+ args: [reference]
16090
+ });
16091
+ return {
16092
+ reference: String(row.reference),
16093
+ user_id: Number(row.user_id),
16094
+ user_email: String(row.email),
16095
+ direction: String(row.direction),
16096
+ credits: toCredits(Number(row.amount_mc)),
16097
+ amount_mc: Number(row.amount_mc),
16098
+ reason: String(row.reason),
16099
+ actor: String(row.actor),
16100
+ status: String(row.status),
16101
+ created_at: String(row.created_at),
16102
+ updated_at: row.updated_at == null ? null : String(row.updated_at),
16103
+ history: events.rows.map((e) => ({
16104
+ seq: Number(e.seq),
16105
+ kind: String(e.kind),
16106
+ from_credits: e.from_amount_mc == null ? null : toCredits(Number(e.from_amount_mc)),
16107
+ to_credits: e.to_amount_mc == null ? null : toCredits(Number(e.to_amount_mc)),
16108
+ from_reason: e.from_reason == null ? null : String(e.from_reason),
16109
+ to_reason: e.to_reason == null ? null : String(e.to_reason),
16110
+ moved_credits: toCredits(Number(e.moved_mc ?? 0)),
16111
+ actor: String(e.actor),
16112
+ created_at: String(e.created_at)
16113
+ }))
16114
+ };
16115
+ }
16116
+ async function nextSeq(reference) {
16117
+ const res = await getDb().execute({
16118
+ sql: "SELECT COALESCE(MAX(seq), 0) AS max_seq FROM admin_credit_adjustment_events WHERE reference = ?",
16119
+ args: [reference]
16120
+ });
16121
+ return Number(res.rows[0]?.max_seq ?? 0) + 1;
16122
+ }
16123
+ async function applyAdjustment(input) {
16124
+ const direction = validateDirection(input.direction);
16125
+ const credits = validateCredits(input.credits, input.confirmLarge === true);
16126
+ const reason = validateReason(input.reason);
16127
+ const actor = validateActor(input.actor);
16128
+ const reference = input.reference?.trim() || `adj_${randomUUID5()}`;
16129
+ if (reference.length > 120) throw new AdminCreditError(400, "reference must be at most 120 characters");
16130
+ const db = getDb();
16131
+ const existing = await db.execute({
16132
+ sql: "SELECT reference, user_id, direction, amount_mc FROM admin_credit_adjustments WHERE reference = ? LIMIT 1",
16133
+ args: [reference]
16134
+ });
16135
+ if (existing.rows.length > 0) {
16136
+ const prior = existing.rows[0];
16137
+ if (String(prior.direction) !== direction || Number(prior.amount_mc) !== creditsToMc(credits)) {
16138
+ throw new AdminCreditError(409, "reference already exists with different values; use the edit endpoint to change it");
16139
+ }
16140
+ return loadAdjustment(reference);
16141
+ }
16142
+ const user = await resolveUser2({ email: input.email, userId: input.userId });
16143
+ const mc = creditsToMc(credits);
16144
+ await moveCredits(user.id, direction, mc, reason, `${reference}:1`);
16145
+ await db.batch([
16146
+ {
16147
+ sql: `INSERT OR IGNORE INTO admin_credit_adjustments (reference, user_id, direction, amount_mc, reason, actor, status)
16148
+ VALUES (?, ?, ?, ?, ?, ?, 'applied')`,
16149
+ args: [reference, user.id, direction, mc, reason, actor]
16150
+ },
16151
+ {
16152
+ sql: `INSERT OR IGNORE INTO admin_credit_adjustment_events (reference, seq, kind, from_amount_mc, to_amount_mc, from_reason, to_reason, moved_mc, actor)
16153
+ VALUES (?, 1, 'created', NULL, ?, NULL, ?, ?, ?)`,
16154
+ args: [reference, mc, reason, mc, actor]
16155
+ }
16156
+ ], "write");
16157
+ return loadAdjustment(reference);
16158
+ }
16159
+ async function editAdjustment(input) {
16160
+ const actor = validateActor(input.actor);
16161
+ const current = await loadAdjustment(input.reference);
16162
+ if (current.status === "reversed") {
16163
+ throw new AdminCreditError(409, "This adjustment was reversed and can no longer be edited");
16164
+ }
16165
+ if (input.credits === void 0 && input.reason === void 0) {
16166
+ throw new AdminCreditError(400, "Provide credits, reason, or both");
16167
+ }
16168
+ const db = getDb();
16169
+ if (input.reason !== void 0) {
16170
+ const reason = validateReason(input.reason);
16171
+ if (reason !== current.reason) {
16172
+ const seq = await nextSeq(current.reference);
16173
+ await db.batch([
16174
+ {
16175
+ sql: "UPDATE admin_credit_adjustments SET reason = ?, updated_at = datetime('now') WHERE reference = ?",
16176
+ args: [reason, current.reference]
16177
+ },
16178
+ {
16179
+ sql: `INSERT INTO admin_credit_adjustment_events (reference, seq, kind, from_reason, to_reason, moved_mc, actor)
16180
+ VALUES (?, ?, 'reason_edited', ?, ?, 0, ?)`,
16181
+ args: [current.reference, seq, current.reason, reason, actor]
16182
+ }
16183
+ ], "write");
16184
+ }
16185
+ }
16186
+ if (input.credits !== void 0) {
16187
+ const credits = validateCredits(input.credits, input.confirmLarge === true);
16188
+ const targetMc = creditsToMc(credits);
16189
+ if (targetMc !== current.amount_mc) {
16190
+ const deltaMc = targetMc - current.amount_mc;
16191
+ const moveDirection = deltaMc > 0 ? current.direction : flip(current.direction);
16192
+ const moveMc = Math.abs(deltaMc);
16193
+ const seq = await nextSeq(current.reference);
16194
+ const reason = input.reason !== void 0 ? validateReason(input.reason) : current.reason;
16195
+ await moveCredits(current.user_id, moveDirection, moveMc, `edit ${current.reference}: ${reason}`, `${current.reference}:${seq}`);
16196
+ await db.batch([
16197
+ {
16198
+ sql: "UPDATE admin_credit_adjustments SET amount_mc = ?, updated_at = datetime('now') WHERE reference = ?",
16199
+ args: [targetMc, current.reference]
16200
+ },
16201
+ {
16202
+ sql: `INSERT INTO admin_credit_adjustment_events (reference, seq, kind, from_amount_mc, to_amount_mc, moved_mc, actor)
16203
+ VALUES (?, ?, 'amount_edited', ?, ?, ?, ?)`,
16204
+ args: [current.reference, seq, current.amount_mc, targetMc, moveMc, actor]
16205
+ }
16206
+ ], "write");
16207
+ }
16208
+ }
16209
+ return loadAdjustment(input.reference);
16210
+ }
16211
+ async function reverseAdjustment(reference, actor) {
16212
+ const validActor = validateActor(actor);
16213
+ const current = await loadAdjustment(reference);
16214
+ if (current.status === "reversed") return current;
16215
+ const seq = await nextSeq(reference);
16216
+ if (current.amount_mc > 0) {
16217
+ await moveCredits(current.user_id, flip(current.direction), current.amount_mc, `reverse ${reference}: ${current.reason}`, `${reference}:${seq}`);
16218
+ }
16219
+ await getDb().batch([
16220
+ {
16221
+ sql: "UPDATE admin_credit_adjustments SET status = 'reversed', updated_at = datetime('now') WHERE reference = ?",
16222
+ args: [reference]
16223
+ },
16224
+ {
16225
+ sql: `INSERT INTO admin_credit_adjustment_events (reference, seq, kind, from_amount_mc, to_amount_mc, moved_mc, actor)
16226
+ VALUES (?, ?, 'reversed', ?, 0, ?, ?)`,
16227
+ args: [reference, seq, current.amount_mc, current.amount_mc, validActor]
16228
+ }
16229
+ ], "write");
16230
+ return loadAdjustment(reference);
16231
+ }
16232
+ async function lookupAccount(target, limit = 20) {
16233
+ const user = await resolveUser2(target);
16234
+ const db = getDb();
16235
+ const balanceMc = await reconcileBalanceMc(user.id, user.balance_mc);
16236
+ const lots = await db.execute({
16237
+ sql: `SELECT COUNT(*) AS n, COALESCE(SUM(remaining_mc), 0) AS mc, MIN(expires_at) AS next_expiry
16238
+ FROM credit_lots
16239
+ WHERE user_id = ? AND remaining_mc > 0 AND (never_expires = 1 OR expires_at > datetime('now'))`,
16240
+ args: [user.id]
16241
+ });
16242
+ const refs = await db.execute({
16243
+ sql: "SELECT reference FROM admin_credit_adjustments WHERE user_id = ? ORDER BY created_at DESC, rowid DESC LIMIT ?",
16244
+ args: [user.id, limit]
16245
+ });
16246
+ const adjustments = await Promise.all(refs.rows.map((r) => loadAdjustment(String(r.reference))));
16247
+ const ledger = await db.execute({
16248
+ sql: "SELECT created_at, operation, amount_mc, description FROM ledger WHERE user_id = ? ORDER BY id DESC LIMIT ?",
16249
+ args: [user.id, limit]
16250
+ });
16251
+ return {
16252
+ user: {
16253
+ id: user.id,
16254
+ email: user.email,
16255
+ active: Boolean(user.active),
16256
+ balance_credits: toCredits(balanceMc),
16257
+ balance_mc: balanceMc
16258
+ },
16259
+ lots: {
16260
+ active_lots: Number(lots.rows[0]?.n ?? 0),
16261
+ active_credits: toCredits(Number(lots.rows[0]?.mc ?? 0)),
16262
+ next_expiry: lots.rows[0]?.next_expiry == null ? null : String(lots.rows[0].next_expiry)
16263
+ },
16264
+ adjustments,
16265
+ recent_ledger: ledger.rows.map((r) => ({
16266
+ created_at: String(r.created_at),
16267
+ operation: String(r.operation),
16268
+ credits: toCredits(Number(r.amount_mc)),
16269
+ description: r.description == null ? null : String(r.description)
16270
+ }))
16271
+ };
16272
+ }
16273
+
16274
+ // src/api/admin-credit-routes.ts
16275
+ var adminCreditsApp = new Hono9();
16276
+ adminCreditsApp.use("*", adminAuth);
16277
+ function fail(c, err) {
16278
+ if (err instanceof AdminCreditError) {
16279
+ return c.json({ error: err.message, ...err.detail ?? {} }, err.status);
16280
+ }
16281
+ const message = err instanceof Error ? err.message : String(err);
16282
+ if (message.includes("conflicts with another")) {
16283
+ return c.json({ error: "A concurrent adjustment used the same key; re-read the account and retry" }, 409);
16284
+ }
16285
+ console.error("[admin/credits] unexpected failure:", message);
16286
+ return c.json({ error: "Adjustment failed" }, 500);
16287
+ }
16288
+ async function readBody(c) {
16289
+ try {
16290
+ const parsed = await c.req.json();
16291
+ return parsed && typeof parsed === "object" ? parsed : {};
16292
+ } catch {
16293
+ return {};
16294
+ }
16295
+ }
16296
+ function targetFrom(query) {
16297
+ const email = query.email?.trim();
16298
+ const idRaw = query.userId?.trim();
16299
+ const userId = idRaw ? Number(idRaw) : void 0;
16300
+ if (userId !== void 0 && !Number.isInteger(userId)) {
16301
+ throw new AdminCreditError(400, "userId must be an integer");
16302
+ }
16303
+ return { email: email || void 0, userId };
16304
+ }
16305
+ adminCreditsApp.post("/adjust", async (c) => {
16306
+ try {
16307
+ const body = await readBody(c);
16308
+ const record = await applyAdjustment({
16309
+ email: typeof body.email === "string" ? body.email : void 0,
16310
+ userId: typeof body.userId === "number" ? body.userId : void 0,
16311
+ direction: body.direction,
16312
+ credits: body.credits,
16313
+ reason: body.reason,
16314
+ actor: body.actor,
16315
+ reference: typeof body.reference === "string" ? body.reference : void 0,
16316
+ confirmLarge: body.confirmLarge === true
16317
+ });
16318
+ return c.json({ ok: true, adjustment: record });
16319
+ } catch (err) {
16320
+ return fail(c, err);
16321
+ }
16322
+ });
16323
+ adminCreditsApp.post("/adjustments/:reference/edit", async (c) => {
16324
+ try {
16325
+ const body = await readBody(c);
16326
+ const record = await editAdjustment({
16327
+ reference: c.req.param("reference"),
16328
+ credits: typeof body.credits === "number" ? body.credits : void 0,
16329
+ reason: typeof body.reason === "string" ? body.reason : void 0,
16330
+ actor: body.actor,
16331
+ confirmLarge: body.confirmLarge === true
16332
+ });
16333
+ return c.json({ ok: true, adjustment: record });
16334
+ } catch (err) {
16335
+ return fail(c, err);
16336
+ }
16337
+ });
16338
+ adminCreditsApp.post("/adjustments/:reference/reverse", async (c) => {
16339
+ try {
16340
+ const body = await readBody(c);
16341
+ const record = await reverseAdjustment(c.req.param("reference"), body.actor);
16342
+ return c.json({ ok: true, adjustment: record });
16343
+ } catch (err) {
16344
+ return fail(c, err);
16345
+ }
16346
+ });
16347
+ adminCreditsApp.get("/adjustments/:reference", async (c) => {
16348
+ try {
16349
+ return c.json({ ok: true, adjustment: await loadAdjustment(c.req.param("reference")) });
16350
+ } catch (err) {
16351
+ return fail(c, err);
16352
+ }
16353
+ });
16354
+ adminCreditsApp.get("/lookup", async (c) => {
16355
+ try {
16356
+ const target = targetFrom(c.req.query());
16357
+ const limitRaw = c.req.query("limit");
16358
+ const limit = limitRaw ? Math.min(Math.max(Number(limitRaw), 1), 100) : 20;
16359
+ return c.json({ ok: true, ...await lookupAccount(target, limit) });
16360
+ } catch (err) {
16361
+ return fail(c, err);
16362
+ }
16363
+ });
16364
+
16365
+ // src/api/instagram-routes.ts
16366
+ import { Hono as Hono10 } from "hono";
15965
16367
  import { z as z19 } from "zod";
15966
16368
  import { mkdtempSync, readFileSync as readFileSync2, rmSync, writeFileSync } from "fs";
15967
16369
  import { tmpdir } from "os";
@@ -16349,7 +16751,7 @@ var InstagramMediaDownloadBodySchema = z19.object({
16349
16751
  includeTranscript: z19.boolean().default(false),
16350
16752
  mux: z19.boolean().default(true)
16351
16753
  });
16352
- var instagramApp = new Hono9();
16754
+ var instagramApp = new Hono10();
16353
16755
  function invalidRequest3(message) {
16354
16756
  return { error_code: "invalid_request", message };
16355
16757
  }
@@ -16629,7 +17031,7 @@ instagramApp.post("/media-download", createApiKeyAuth(), async (c) => {
16629
17031
  });
16630
17032
 
16631
17033
  // src/api/reddit-routes.ts
16632
- import { Hono as Hono10 } from "hono";
17034
+ import { Hono as Hono11 } from "hono";
16633
17035
  import { z as z20 } from "zod";
16634
17036
 
16635
17037
  // src/api/reddit-trending.ts
@@ -16875,7 +17277,7 @@ async function scrapeOldRedditWithRetries(url, script, accept) {
16875
17277
  }
16876
17278
  return null;
16877
17279
  }
16878
- var redditApp = new Hono10();
17280
+ var redditApp = new Hono11();
16879
17281
  redditApp.post("/thread", createApiKeyAuth(), async (c) => {
16880
17282
  const raw = await c.req.json().catch(() => ({}));
16881
17283
  const parsed = RedditThreadBodySchema.safeParse(raw);
@@ -17076,9 +17478,9 @@ redditApp.post("/trending", createApiKeyAuth(), async (c) => {
17076
17478
  });
17077
17479
 
17078
17480
  // src/api/video-routes.ts
17079
- import { Hono as Hono11 } from "hono";
17481
+ import { Hono as Hono12 } from "hono";
17080
17482
  import { z as z21 } from "zod";
17081
- var videoApp = new Hono11();
17483
+ var videoApp = new Hono12();
17082
17484
  var AnalyzeBodySchema = z21.object({
17083
17485
  sourceUrl: z21.string().trim().url("sourceUrl must be a direct video file URL"),
17084
17486
  intervalS: z21.number().min(1).max(30).optional(),
@@ -17188,7 +17590,7 @@ videoApp.post("/status", createApiKeyAuth(), async (c) => {
17188
17590
  });
17189
17591
 
17190
17592
  // src/api/maps-routes.ts
17191
- import { Hono as Hono12 } from "hono";
17593
+ import { Hono as Hono13 } from "hono";
17192
17594
 
17193
17595
  // src/extractor/MapsNavigator.ts
17194
17596
  var BUSINESS_PANEL_REDIRECT_BASE = "https://serp-redirector.vercel.app";
@@ -17805,7 +18207,7 @@ function mapsErrorResponse(c, err, errorCode) {
17805
18207
  retryable
17806
18208
  }, retryable ? 503 : 500);
17807
18209
  }
17808
- var mapsApp = new Hono12();
18210
+ var mapsApp = new Hono13();
17809
18211
  mapsApp.post("/search", createApiKeyAuth(), async (c) => {
17810
18212
  const user = c.get("user");
17811
18213
  const body = await c.req.json().catch(() => ({}));
@@ -17944,7 +18346,7 @@ mapsApp.post("/place", createApiKeyAuth(), async (c) => {
17944
18346
  });
17945
18347
 
17946
18348
  // src/api/trustpilot-routes.ts
17947
- import { Hono as Hono13 } from "hono";
18349
+ import { Hono as Hono14 } from "hono";
17948
18350
  import { z as z23 } from "zod";
17949
18351
  var TrustpilotReviewsBodySchema = z23.object({
17950
18352
  domain: z23.string().trim().min(1, "domain is required"),
@@ -18013,7 +18415,7 @@ async function extractReviewCards(page) {
18013
18415
  });
18014
18416
  });
18015
18417
  }
18016
- var trustpilotApp = new Hono13();
18418
+ var trustpilotApp = new Hono14();
18017
18419
  trustpilotApp.post("/reviews", createApiKeyAuth(), async (c) => {
18018
18420
  const raw = await c.req.json().catch(() => ({}));
18019
18421
  const parsed = TrustpilotReviewsBodySchema.safeParse(raw);
@@ -18094,7 +18496,7 @@ trustpilotApp.post("/reviews", createApiKeyAuth(), async (c) => {
18094
18496
  });
18095
18497
 
18096
18498
  // src/api/g2-routes.ts
18097
- import { Hono as Hono14 } from "hono";
18499
+ import { Hono as Hono15 } from "hono";
18098
18500
  import { z as z24 } from "zod";
18099
18501
  var G2ReviewsBodySchema = z24.object({
18100
18502
  product: z24.string().trim().min(1, "product is required"),
@@ -18203,7 +18605,7 @@ async function extractG2ReviewCards(page) {
18203
18605
  });
18204
18606
  });
18205
18607
  }
18206
- var g2App = new Hono14();
18608
+ var g2App = new Hono15();
18207
18609
  g2App.post("/reviews", createApiKeyAuth(), async (c) => {
18208
18610
  const raw = await c.req.json().catch(() => ({}));
18209
18611
  const parsed = G2ReviewsBodySchema.safeParse(raw);
@@ -18304,17 +18706,17 @@ g2App.post("/reviews", createApiKeyAuth(), async (c) => {
18304
18706
  });
18305
18707
 
18306
18708
  // src/api/directory-routes.ts
18307
- import { createHash as createHash4, randomUUID as randomUUID6 } from "crypto";
18308
- import { Hono as Hono15 } from "hono";
18709
+ import { createHash as createHash4, randomUUID as randomUUID7 } from "crypto";
18710
+ import { Hono as Hono16 } from "hono";
18309
18711
 
18310
18712
  // src/api/directory-workflow-dispatch.ts
18311
- import { randomUUID as randomUUID5 } from "crypto";
18713
+ import { randomUUID as randomUUID6 } from "crypto";
18312
18714
  function retryDelaySeconds(attempts) {
18313
18715
  return Math.min(60 * 60, Math.max(15, 15 * 2 ** Math.min(8, Math.max(0, attempts - 1))));
18314
18716
  }
18315
18717
  async function dispatchPendingDirectoryWorkflows(limit = 25) {
18316
18718
  const rows = await claimDirectoryWorkflowOutbox({
18317
- workerId: `directory-dispatch-${process.pid}-${randomUUID5().slice(0, 8)}`,
18719
+ workerId: `directory-dispatch-${process.pid}-${randomUUID6().slice(0, 8)}`,
18318
18720
  limit
18319
18721
  });
18320
18722
  const result = { claimed: rows.length, dispatched: 0, failed: 0 };
@@ -18338,7 +18740,7 @@ async function dispatchPendingDirectoryWorkflows(limit = 25) {
18338
18740
  }
18339
18741
 
18340
18742
  // src/api/directory-routes.ts
18341
- var directoryApp = new Hono15();
18743
+ var directoryApp = new Hono16();
18342
18744
  function safeOptions(options) {
18343
18745
  const { kernelApiKey: _kernelApiKey, ...safe } = options;
18344
18746
  return safe;
@@ -18353,14 +18755,14 @@ function idempotencyKey(raw) {
18353
18755
  if (trimmed.length > 500) return { ok: false, message: "Idempotency-Key must be 500 characters or fewer." };
18354
18756
  return { ok: true, key: trimmed };
18355
18757
  }
18356
- return { ok: true, key: `directory-${randomUUID6()}` };
18758
+ return { ok: true, key: `directory-${randomUUID7()}` };
18357
18759
  }
18358
18760
  function debitKeyFor(userId, responseKey) {
18359
18761
  const digest = createHash4("sha256").update(String(userId)).update("\0").update(responseKey).digest("hex");
18360
18762
  return `directory-workflow:${userId}:${digest}`;
18361
18763
  }
18362
18764
  function jobId() {
18363
- return `dir_${randomUUID6().replace(/-/g, "")}`;
18765
+ return `dir_${randomUUID7().replace(/-/g, "")}`;
18364
18766
  }
18365
18767
  function publicStatus(job, result) {
18366
18768
  if (job.status === "failed") return "failed";
@@ -18664,7 +19066,7 @@ directoryApp.get("/jobs/:id", createApiKeyAuth(), async (c) => {
18664
19066
  });
18665
19067
 
18666
19068
  // src/api/location-data-routes.ts
18667
- import { Hono as Hono16 } from "hono";
19069
+ import { Hono as Hono17 } from "hono";
18668
19070
  import { z as z25 } from "zod";
18669
19071
  var LOCATION_IMPORT_MAX_BYTES = 64 * 1024 * 1024;
18670
19072
  var LOCATION_IMPORT_TIMEOUT_MS = 6e4;
@@ -18684,7 +19086,7 @@ var importSchema = z25.object({
18684
19086
  sourceUrl: z25.string().url().max(2e3).optional()
18685
19087
  });
18686
19088
  var censusSyncSchema = z25.object({ state: z25.string().trim().min(2).max(40) });
18687
- var locationDataApp = new Hono16();
19089
+ var locationDataApp = new Hono17();
18688
19090
  function locationAdminAuthorized(header) {
18689
19091
  const expected = process.env.MCP_SCRAPER_LOCATION_ADMIN_KEY?.trim();
18690
19092
  return Boolean(expected && header?.trim() === expected);
@@ -18952,9 +19354,9 @@ async function reconcileDirectoryWorkflowSettlements(limit = 25) {
18952
19354
  // src/api/workflow-routes.ts
18953
19355
  import { createHmac as createHmac3 } from "crypto";
18954
19356
  import { readFile as readFile2 } from "fs/promises";
18955
- import { Hono as Hono17 } from "hono";
19357
+ import { Hono as Hono18 } from "hono";
18956
19358
  import { z as z26 } from "zod";
18957
- var workflowApp = new Hono17();
19359
+ var workflowApp = new Hono18();
18958
19360
  var WorkflowInputSchema = z26.record(z26.unknown()).default({});
18959
19361
  var WorkflowIdSchema = z26.string().min(1);
18960
19362
  var CadenceSchema = z26.enum(["daily", "weekly", "monthly"]);
@@ -19484,8 +19886,8 @@ workflowApp.post("/cron/dispatch", async (c) => {
19484
19886
  });
19485
19887
 
19486
19888
  // src/api/serp-intelligence-routes.ts
19487
- import { Hono as Hono18 } from "hono";
19488
- import { createHash as createHash6, randomUUID as randomUUID7 } from "crypto";
19889
+ import { Hono as Hono19 } from "hono";
19890
+ import { createHash as createHash6, randomUUID as randomUUID8 } from "crypto";
19489
19891
 
19490
19892
  // src/serp-intelligence/page-snapshot-extractor.ts
19491
19893
  import { createHash as createHash5 } from "crypto";
@@ -20217,7 +20619,7 @@ var SERP_INTELLIGENCE_RATE_WINDOW_SECONDS = 60;
20217
20619
  var POST_CAPTURE_ROUTE_LABEL = "POST /capture";
20218
20620
  var POST_PAGE_SNAPSHOTS_ROUTE_LABEL = "POST /page-snapshots";
20219
20621
  var SERP_CAPTURE_BILLING_SOURCE = "serp_intelligence_capture";
20220
- var serpIntelligenceApp = new Hono18();
20622
+ var serpIntelligenceApp = new Hono19();
20221
20623
  serpIntelligenceApp.use("*", createApiKeyAuth());
20222
20624
  function structuredError(input) {
20223
20625
  return {
@@ -20270,7 +20672,7 @@ async function logRequestEventBestEffort(input) {
20270
20672
  }
20271
20673
  }
20272
20674
  function captureBillingKeys(userId, suppliedKey, body) {
20273
- const responseKey = suppliedKey?.trim() || randomUUID7();
20675
+ const responseKey = suppliedKey?.trim() || randomUUID8();
20274
20676
  const requestFingerprint2 = createHash6("sha256").update(JSON.stringify(body)).digest("hex");
20275
20677
  const keyDigest = createHash6("sha256").update(String(userId)).update("\0").update(responseKey).digest("hex");
20276
20678
  return {
@@ -20493,7 +20895,7 @@ serpIntelligenceApp.post("/page-snapshots", async (c) => {
20493
20895
  });
20494
20896
 
20495
20897
  // src/mcp/mcp-routes.ts
20496
- import { Hono as Hono19 } from "hono";
20898
+ import { Hono as Hono20 } from "hono";
20497
20899
  import { WebStandardStreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js";
20498
20900
 
20499
20901
  // src/mcp/memory-mcp-tool-executor.ts
@@ -20787,6 +21189,7 @@ import { addVaultTool } from "mcpscraper-memory-tools/tools/vaults/add-vault";
20787
21189
  import { deleteVaultTool } from "mcpscraper-memory-tools/tools/vaults/delete-vault";
20788
21190
  import { memoryCaptureTool } from "mcpscraper-memory-tools/tools/capture/memory-capture";
20789
21191
  import { upsertTagTool } from "mcpscraper-memory-tools/tools/tags/upsert-tag";
21192
+ import { mergeTagsTool } from "mcpscraper-memory-tools/tools/tags/merge-tags";
20790
21193
  var registered2 = false;
20791
21194
  function registerWriteCutovers() {
20792
21195
  if (registered2) return;
@@ -20935,6 +21338,10 @@ function registerWriteCutovers() {
20935
21338
  const result = await upsertTagTool.execute({ ...input, apiKey }, {});
20936
21339
  return { content: [{ type: "text", text: JSON.stringify(result ?? {}) }], structuredContent: result ?? {}, isError: false };
20937
21340
  });
21341
+ registerCutover("mergeTagsTool", async (input, apiKey) => {
21342
+ const result = await mergeTagsTool.execute({ ...input, apiKey }, {});
21343
+ return { content: [{ type: "text", text: JSON.stringify(result ?? {}) }], structuredContent: result ?? {}, isError: false };
21344
+ });
20938
21345
  }
20939
21346
 
20940
21347
  // src/mcp/memory-cutover/billing.ts
@@ -21144,7 +21551,7 @@ async function requireMcpCallerKey(c) {
21144
21551
  if (!user) return mcpAuthError();
21145
21552
  return { key: callerKey, user };
21146
21553
  }
21147
- var mcpApp = new Hono19();
21554
+ var mcpApp = new Hono20();
21148
21555
  mcpApp.all("/", async (c) => {
21149
21556
  try {
21150
21557
  const keyOrError = await requireMcpCallerKey(c);
@@ -21170,11 +21577,11 @@ mcpApp.all("/", async (c) => {
21170
21577
  });
21171
21578
 
21172
21579
  // src/api/browser-agent-routes.ts
21173
- import { randomUUID as randomUUID9 } from "crypto";
21174
- import { Hono as Hono20 } from "hono";
21580
+ import { randomUUID as randomUUID10 } from "crypto";
21581
+ import { Hono as Hono21 } from "hono";
21175
21582
 
21176
21583
  // src/api/browser-agent-db.ts
21177
- import { randomUUID as randomUUID8 } from "crypto";
21584
+ import { randomUUID as randomUUID9 } from "crypto";
21178
21585
  var _ready = false;
21179
21586
  var _migrationPromise = null;
21180
21587
  async function migrateBrowserAgent() {
@@ -21305,7 +21712,7 @@ async function runBrowserAgentMigration() {
21305
21712
  }
21306
21713
  async function createExtensionRow(input) {
21307
21714
  const db = getDb();
21308
- const id = `bext_${randomUUID8().replace(/-/g, "").slice(0, 20)}`;
21715
+ const id = `bext_${randomUUID9().replace(/-/g, "").slice(0, 20)}`;
21309
21716
  await db.execute({
21310
21717
  sql: `INSERT INTO browser_agent_extensions (id, user_id, name, backend_id, backend_name, source, source_url, size_bytes)
21311
21718
  VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
@@ -21340,7 +21747,7 @@ async function deleteExtensionRow(userId, name) {
21340
21747
  }
21341
21748
  async function createAuthConnectionRow(input) {
21342
21749
  const db = getDb();
21343
- const connectionId = `authc_${randomUUID8().replace(/-/g, "").slice(0, 20)}`;
21750
+ const connectionId = `authc_${randomUUID9().replace(/-/g, "").slice(0, 20)}`;
21344
21751
  await db.execute({
21345
21752
  sql: `INSERT INTO browser_auth_connections (connection_id, domain, profile, account_email, note, status, browser_agent_session_id)
21346
21753
  VALUES (?, ?, ?, ?, ?, 'NEEDS_AUTH', ?)`,
@@ -21425,7 +21832,7 @@ async function deleteProfileLabel(userId, profile) {
21425
21832
  }
21426
21833
  async function createSessionRow(input) {
21427
21834
  const db = getDb();
21428
- const id = `bas_${randomUUID8().replace(/-/g, "").slice(0, 20)}`;
21835
+ const id = `bas_${randomUUID9().replace(/-/g, "").slice(0, 20)}`;
21429
21836
  await db.execute({
21430
21837
  sql: `INSERT INTO browser_agent_sessions (id, runtime_session_id, live_view_url, cdp_ws_url, status, label, user_id, concurrency_lock_id, last_action_at)
21431
21838
  VALUES (?, ?, ?, ?, 'open', ?, ?, ?, datetime('now'))`,
@@ -21494,7 +21901,7 @@ async function recordAction(input) {
21494
21901
  sql: `INSERT INTO browser_agent_actions (id, session_id, type, params_json, ok, error)
21495
21902
  VALUES (?, ?, ?, ?, ?, ?)`,
21496
21903
  args: [
21497
- `baa_${randomUUID8().replace(/-/g, "").slice(0, 20)}`,
21904
+ `baa_${randomUUID9().replace(/-/g, "").slice(0, 20)}`,
21498
21905
  input.sessionId,
21499
21906
  input.type,
21500
21907
  input.params == null ? null : JSON.stringify(input.params),
@@ -22724,7 +23131,7 @@ async function loadOpenSession(id, userId) {
22724
23131
  return row;
22725
23132
  }
22726
23133
  function buildBrowserAgentRoutes() {
22727
- const app2 = new Hono20();
23134
+ const app2 = new Hono21();
22728
23135
  app2.use("*", async (c, next) => {
22729
23136
  await migrateBrowserAgent();
22730
23137
  return next();
@@ -23225,7 +23632,7 @@ function buildBrowserAgentRoutes() {
23225
23632
  }
23226
23633
  const existing = await getExtensionRow(user.id, name);
23227
23634
  if (existing) return c.json({ error: `an extension named "${name}" already exists \u2014 delete it first or pick another name` }, 409);
23228
- const backendName = `u${user.id}_${randomUUID9().replace(/-/g, "")}`;
23635
+ const backendName = `u${user.id}_${randomUUID10().replace(/-/g, "")}`;
23229
23636
  try {
23230
23637
  const imported = await importExtensionFromStore(storeUrl, backendName);
23231
23638
  const row = await createExtensionRow({
@@ -23557,7 +23964,7 @@ if (state.key) { refreshSessions(); if (state.current) selectSession(state.curre
23557
23964
 
23558
23965
  // src/api/stripe-routes.ts
23559
23966
  import Stripe from "stripe";
23560
- import { Hono as Hono21 } from "hono";
23967
+ import { Hono as Hono22 } from "hono";
23561
23968
  var stripe = new Stripe(process.env.STRIPE_SECRET_KEY, { apiVersion: "2026-02-25.clover" });
23562
23969
  async function cancelStandaloneMemorySub(memSubId, baseSubId) {
23563
23970
  if (!memSubId || memSubId === baseSubId) return;
@@ -23572,7 +23979,7 @@ async function cancelStandaloneMemorySub(memSubId, baseSubId) {
23572
23979
  console.error("[stripe] could not wind down standalone memory subscription", memSubId, err instanceof Error ? err.message : err);
23573
23980
  }
23574
23981
  }
23575
- var stripeApp = new Hono21();
23982
+ var stripeApp = new Hono22();
23576
23983
  stripeApp.post("/webhooks", async (c) => {
23577
23984
  const sig = c.req.header("stripe-signature");
23578
23985
  const body = await c.req.text();
@@ -23598,7 +24005,7 @@ stripeApp.post("/webhooks", async (c) => {
23598
24005
  const tierPriceId = liveBasePlanPriceId ?? invoice.lines.data.map(linePriceId).find((id) => id && id in SUBSCRIPTION_TIERS);
23599
24006
  const tier = tierPriceId ? SUBSCRIPTION_TIERS[tierPriceId] : void 0;
23600
24007
  if (tier) {
23601
- const user = await resolveUser2(invoice.customer, invoice.customer_email ?? void 0);
24008
+ const user = await resolveUser3(invoice.customer, invoice.customer_email ?? void 0);
23602
24009
  if (user && invoice.id && !await ledgerExistsForStripePI(invoice.id)) {
23603
24010
  await creditMc(user.id, tier.credits_mc, LedgerOperation.SUBSCRIPTION, `${tier.label} subscription credits`, invoice.id, { neverExpires: tier.credits_never_expire });
23604
24011
  await setSubscriptionTier(user.id, tier.tier, tier.concurrency, subId ?? user.subscription_id);
@@ -23618,7 +24025,7 @@ stripeApp.post("/webhooks", async (c) => {
23618
24025
  const priceId = findBasePlanItem(sub)?.price?.id ?? sub.items.data[0]?.price?.id;
23619
24026
  if (priceId && priceId in MEMORY_PLANS) {
23620
24027
  const mem = MEMORY_PLANS[priceId];
23621
- const user2 = await resolveUser2(sub.customer, sub.customer_email);
24028
+ const user2 = await resolveUser3(sub.customer, sub.customer_email);
23622
24029
  if (user2) {
23623
24030
  const live = sub.status === "active" || sub.status === "trialing";
23624
24031
  const newMemoryPlan = live ? mem.plan : "free";
@@ -23688,7 +24095,7 @@ function linePriceId(line) {
23688
24095
  const l = line;
23689
24096
  return l?.price?.id ?? l?.pricing?.price_details?.price ?? l?.plan?.id;
23690
24097
  }
23691
- async function resolveUser2(customerId, emailFallback) {
24098
+ async function resolveUser3(customerId, emailFallback) {
23692
24099
  let user = await getUserByStripeCustomerId(customerId);
23693
24100
  if (user) return user;
23694
24101
  if (!emailFallback) return void 0;
@@ -23698,9 +24105,9 @@ async function resolveUser2(customerId, emailFallback) {
23698
24105
  }
23699
24106
 
23700
24107
  // src/api/oauth-routes.ts
23701
- import { Hono as Hono22 } from "hono";
24108
+ import { Hono as Hono23 } from "hono";
23702
24109
  import { getCookie, setCookie } from "hono/cookie";
23703
- import { createHash as createHash7, randomBytes as randomBytes2, randomUUID as randomUUID10 } from "crypto";
24110
+ import { createHash as createHash7, randomBytes as randomBytes2, randomUUID as randomUUID11 } from "crypto";
23704
24111
  import { importPKCS8, exportJWK, SignJWT } from "jose";
23705
24112
  var ISSUER = "https://mcpscraper.dev";
23706
24113
  var RESOURCE = () => process.env.MCP_MEMORY_RESOURCE_URL ?? "https://memory.mcpscraper.dev/mcp";
@@ -23867,7 +24274,7 @@ function redirectWithError(redirectUri, state, error) {
23867
24274
  if (state) u.searchParams.set("state", state);
23868
24275
  return new Response(null, { status: 302, headers: { Location: u.toString() } });
23869
24276
  }
23870
- var oauthApp = new Hono22();
24277
+ var oauthApp = new Hono23();
23871
24278
  oauthApp.use("*", async (c, next) => {
23872
24279
  c.header("Access-Control-Allow-Origin", "*");
23873
24280
  c.header("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
@@ -24048,7 +24455,7 @@ function pkceMatches(verifier, challenge) {
24048
24455
  }
24049
24456
  async function mintAccessToken(identity, scope, plan, audience) {
24050
24457
  const { privateKey, kid } = await getKeys();
24051
- return new SignJWT({ scope, plan }).setProtectedHeader({ alg: "RS256", kid }).setIssuer(ISSUER).setSubject(identity).setAudience(audience).setIssuedAt().setJti(randomUUID10()).setExpirationTime(`${ACCESS_TTL_SECONDS}s`).sign(privateKey);
24458
+ return new SignJWT({ scope, plan }).setProtectedHeader({ alg: "RS256", kid }).setIssuer(ISSUER).setSubject(identity).setAudience(audience).setIssuedAt().setJti(randomUUID11()).setExpirationTime(`${ACCESS_TTL_SECONDS}s`).sign(privateKey);
24052
24459
  }
24053
24460
  function tokenErrorResponse(c, error, description, status) {
24054
24461
  return c.json({ error, error_description: description }, status);
@@ -24121,8 +24528,8 @@ oauthApp.post("/oauth/token", async (c) => {
24121
24528
  });
24122
24529
 
24123
24530
  // src/api/chat-routes.ts
24124
- import { Hono as Hono23 } from "hono";
24125
- var chatApp = new Hono23();
24531
+ import { Hono as Hono24 } from "hono";
24532
+ var chatApp = new Hono24();
24126
24533
  function tokenOk(token) {
24127
24534
  return !!token && token.startsWith("mk_") && token.length > 10;
24128
24535
  }
@@ -24792,7 +25199,7 @@ loadChannels();
24792
25199
  }
24793
25200
 
24794
25201
  // src/api/vault-routes.ts
24795
- import { Hono as Hono24 } from "hono";
25202
+ import { Hono as Hono25 } from "hono";
24796
25203
  var VAULTS = ["People", "Organizations", "Deals", "Projects", "Tasks", "Communications", "Calendar"];
24797
25204
  var PROJECT_TYPES = ["codebase", "personal", "work", "client"];
24798
25205
  var PROJECT_KIND_BY_TYPE = {
@@ -24811,7 +25218,7 @@ var PROJECT_TYPE_BY_KIND = {
24811
25218
  var MAX_VAULT_RECORDS = 200;
24812
25219
  var MAX_MEMORY_READ_CONCURRENCY = 4;
24813
25220
  var MAX_MEMORY_READ_ATTEMPTS = 3;
24814
- var vaultApp = new Hono24();
25221
+ var vaultApp = new Hono25();
24815
25222
  function validToken(token) {
24816
25223
  return !!token && token.startsWith("mk_") && token.length > 20 && token.length < 256;
24817
25224
  }
@@ -25160,8 +25567,8 @@ vaultApp.post("/api/activity", async (c) => {
25160
25567
  });
25161
25568
 
25162
25569
  // src/api/schedule-routes.ts
25163
- import { Hono as Hono25 } from "hono";
25164
- var scheduleApp = new Hono25();
25570
+ import { Hono as Hono26 } from "hono";
25571
+ var scheduleApp = new Hono26();
25165
25572
  function tokenOk2(token) {
25166
25573
  return !!token && token.startsWith("mk_") && token.length > 10;
25167
25574
  }
@@ -25492,7 +25899,7 @@ loadActions();
25492
25899
  }
25493
25900
 
25494
25901
  // src/api/resend-inbound-routes.ts
25495
- import { Hono as Hono26 } from "hono";
25902
+ import { Hono as Hono27 } from "hono";
25496
25903
  import { Resend } from "resend";
25497
25904
 
25498
25905
  // src/api/resend-support-thread.ts
@@ -26123,7 +26530,7 @@ async function relayOperatorReply(resend, email, customerEmail, threadAddress, n
26123
26530
  if (sent.error) throw new Error(`support reply relay failed: ${sent.error.message}`);
26124
26531
  return sent.data.id;
26125
26532
  }
26126
- var resendInboundApp = new Hono26();
26533
+ var resendInboundApp = new Hono27();
26127
26534
  resendInboundApp.post("/webhooks", async (c) => {
26128
26535
  const apiKey = process.env.RESEND_API_KEY?.trim();
26129
26536
  const webhookSecret = process.env.RESEND_WEBHOOK_SECRET?.trim();
@@ -26279,7 +26686,7 @@ function startSiteAuditWorker() {
26279
26686
  }
26280
26687
 
26281
26688
  // src/api/server.ts
26282
- import { createMiddleware as createMiddleware3 } from "hono/factory";
26689
+ import { createMiddleware as createMiddleware4 } from "hono/factory";
26283
26690
  import { getCookie as getCookie2, setCookie as setCookie2, deleteCookie } from "hono/cookie";
26284
26691
  import Stripe2 from "stripe";
26285
26692
 
@@ -26771,7 +27178,7 @@ async function cleanupExpiredScrapeBlobs(maxAgeMs = SCRAPE_BLOB_TTL_MS) {
26771
27178
  }
26772
27179
 
26773
27180
  // src/api/connected-data-export.ts
26774
- import { randomUUID as randomUUID11 } from "crypto";
27181
+ import { randomUUID as randomUUID12 } from "crypto";
26775
27182
  var CONNECTED_DATA_INLINE_BUDGET_BYTES = Number(
26776
27183
  process.env.MCP_SCRAPER_CONNECTED_DATA_INLINE_BUDGET_BYTES ?? 5e4
26777
27184
  );
@@ -26897,7 +27304,7 @@ function finitePositive(value, fallback) {
26897
27304
  return Number.isFinite(value) && value > 0 ? value : fallback;
26898
27305
  }
26899
27306
  async function collectConnectedDataExport(args) {
26900
- const exportId = randomUUID11();
27307
+ const exportId = randomUUID12();
26901
27308
  const now = args.now ?? Date.now;
26902
27309
  const startedAt = now();
26903
27310
  const budgetMs = finitePositive(CONNECTED_DATA_EXPORT_BUDGET_MS, 24e4);
@@ -27009,7 +27416,7 @@ ${lines.length ? `${lines.join("\n")}
27009
27416
  }
27010
27417
 
27011
27418
  // src/api/search-console-table-export.ts
27012
- import { randomUUID as randomUUID12 } from "crypto";
27419
+ import { randomUUID as randomUUID13 } from "crypto";
27013
27420
  var SEARCH_CONSOLE_TABLE_EXPORT_MAX_ROWS = 5e4;
27014
27421
  var SEARCH_CONSOLE_TABLE_EXPORT_PAGE_SIZE = 2e3;
27015
27422
  var SEARCH_CONSOLE_TABLE_EXPORT_MAX_BYTES = 50 * 1024 * 1024;
@@ -27109,7 +27516,7 @@ async function exportSearchConsoleTableData(args) {
27109
27516
  offset += rows.length;
27110
27517
  if (stoppedForBytes || rows.length < limit || offset >= matchedRows) break;
27111
27518
  }
27112
- const exportId = randomUUID12();
27519
+ const exportId = randomUUID13();
27113
27520
  const artifact = await args.writeArtifact({
27114
27521
  ownerId: args.ownerId,
27115
27522
  exportId,
@@ -27344,15 +27751,15 @@ async function dbUsage(identity, plan) {
27344
27751
  }
27345
27752
 
27346
27753
  // src/api/nango-control.ts
27347
- import { createHash as createHash12, randomUUID as randomUUID15 } from "crypto";
27754
+ import { createHash as createHash12, randomUUID as randomUUID16 } from "crypto";
27348
27755
 
27349
27756
  // src/api/main-nango-transport.ts
27350
- import { createHash as createHash11, randomUUID as randomUUID14 } from "crypto";
27757
+ import { createHash as createHash11, randomUUID as randomUUID15 } from "crypto";
27351
27758
  import { Client } from "@modelcontextprotocol/sdk/client/index.js";
27352
27759
  import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
27353
27760
 
27354
27761
  // src/api/service-connections.ts
27355
- import { randomUUID as randomUUID13 } from "crypto";
27762
+ import { randomUUID as randomUUID14 } from "crypto";
27356
27763
  var schemaReady2 = null;
27357
27764
  var schemaDb2 = null;
27358
27765
  function ensureServiceConnectionsSchema() {
@@ -27486,7 +27893,7 @@ async function reconcileDiscoveredNangoConnections(identity, discovered) {
27486
27893
  updated_at = excluded.updated_at
27487
27894
  `,
27488
27895
  args: [
27489
- randomUUID13(),
27896
+ randomUUID14(),
27490
27897
  userId,
27491
27898
  connection.providerConfigKey,
27492
27899
  connection.provider,
@@ -27557,7 +27964,7 @@ async function recordServiceConnectionHealth(args) {
27557
27964
  });
27558
27965
  await getDb().execute({
27559
27966
  sql: `INSERT INTO service_connection_health_events (id, connection_id, operational_status, failure_code, retryable, evidence_source) VALUES (?, ?, ?, ?, ?, ?)`,
27560
- args: [randomUUID13(), args.connectionId, args.operationalStatus, args.failureCode ?? null, args.retryable == null ? null : args.retryable ? 1 : 0, args.evidenceSource]
27967
+ args: [randomUUID14(), args.connectionId, args.operationalStatus, args.failureCode ?? null, args.retryable == null ? null : args.retryable ? 1 : 0, args.evidenceSource]
27561
27968
  });
27562
27969
  }
27563
27970
  async function setServiceConnectionActions(identity, connectionId, enabled) {
@@ -27597,7 +28004,7 @@ async function claimServiceConnectionAction(args) {
27597
28004
  if (!connection) throw new Error("service_connection_not_found");
27598
28005
  const inserted = await getDb().execute({
27599
28006
  sql: `INSERT OR IGNORE INTO service_connection_action_audit (id, connection_id, user_id, tool, request_id, status) VALUES (?, ?, ?, ?, ?, 'started')`,
27600
- args: [randomUUID13(), connection.id, connection.userId, args.tool, args.requestId]
28007
+ args: [randomUUID14(), connection.id, connection.userId, args.tool, args.requestId]
27601
28008
  });
27602
28009
  if (Number(inserted.rowsAffected ?? 0) === 1) return { claimed: true };
27603
28010
  const existing = await getDb().execute({
@@ -27959,7 +28366,7 @@ async function callNangoToolDirect(args) {
27959
28366
  identity: args.identity,
27960
28367
  ratePolicyVersion: CONNECTED_USAGE_RATE_POLICY_VERSION
27961
28368
  });
27962
- const requestId = args.requestId?.trim() || randomUUID14();
28369
+ const requestId = args.requestId?.trim() || randomUUID15();
27963
28370
  const idempotencyKey2 = `main-nango:${createHash11("sha256").update(args.identity.toLowerCase()).update("\0").update(connection.id).update("\0").update(args.tool).update("\0").update(requestId).digest("hex")}`;
27964
28371
  const startedAt = /* @__PURE__ */ new Date();
27965
28372
  const started = performance.now();
@@ -28746,7 +29153,7 @@ async function setScheduleConnectionActionsEnabled(identity, connectionId, enabl
28746
29153
  return data.connection.actionsEnabled === true;
28747
29154
  }
28748
29155
  async function callScheduleConnectionAction(identity, connectionId, input, tool, idempotencyKey2) {
28749
- const requestId = `main-connected-action:${createHash12("sha256").update(identity).update("\0").update(idempotencyKey2?.trim() || randomUUID15()).digest("hex")}`;
29156
+ const requestId = `main-connected-action:${createHash12("sha256").update(identity).update("\0").update(idempotencyKey2?.trim() || randomUUID16()).digest("hex")}`;
28750
29157
  if (mainOwnsIntegrations()) {
28751
29158
  const selectedTool = tool?.trim();
28752
29159
  if (!selectedTool) throw new NangoControlError("An action tool is required.", 400, "invalid_request", false);
@@ -29587,13 +29994,13 @@ async function enforceRateLimit(c, scope, key, limit, windowSeconds) {
29587
29994
  { "Retry-After": String(result.resetSeconds) }
29588
29995
  );
29589
29996
  }
29590
- var requireAllowedOrigin = createMiddleware3(async (c, next) => {
29997
+ var requireAllowedOrigin = createMiddleware4(async (c, next) => {
29591
29998
  const origin = c.req.header("origin");
29592
29999
  if (!origin) return next();
29593
30000
  if (!configuredOrigins().has(origin)) return c.json({ error: "Origin not allowed" }, 403);
29594
30001
  return next();
29595
30002
  });
29596
- var auth2 = createMiddleware3(async (c, next) => {
30003
+ var auth2 = createMiddleware4(async (c, next) => {
29597
30004
  const key = c.req.header("x-api-key");
29598
30005
  if (!key) return c.json({ error: "Missing API key" }, 401);
29599
30006
  const user = await getUserByApiKey(key);
@@ -29603,14 +30010,7 @@ var auth2 = createMiddleware3(async (c, next) => {
29603
30010
  c.set("user", { ...refreshed, balance_mc: balanceMc });
29604
30011
  return next();
29605
30012
  });
29606
- var adminAuth = createMiddleware3(async (c, next) => {
29607
- const configured = process.env.ADMIN_KEY?.trim();
29608
- const key = c.req.header("x-admin-key")?.trim();
29609
- if (!configured) return c.json({ error: "Admin access disabled" }, 503);
29610
- if (!key || key !== configured) return c.json({ error: "Unauthorized" }, 401);
29611
- return next();
29612
- });
29613
- var sessionAuth = createMiddleware3(async (c, next) => {
30013
+ var sessionAuth = createMiddleware4(async (c, next) => {
29614
30014
  const token = getCookie2(c, "session");
29615
30015
  if (!token) return c.json({ error: "Not authenticated" }, 401);
29616
30016
  const userId = verifySession(token);
@@ -29622,7 +30022,7 @@ var sessionAuth = createMiddleware3(async (c, next) => {
29622
30022
  c.set("sessionUser", { ...refreshed, balance_mc: balanceMc });
29623
30023
  return next();
29624
30024
  });
29625
- var requireIntegrationsTier = createMiddleware3(async (c, next) => {
30025
+ var requireIntegrationsTier = createMiddleware4(async (c, next) => {
29626
30026
  const user = c.get("user");
29627
30027
  if (!user.subscription_tier) {
29628
30028
  return c.json({
@@ -29633,12 +30033,12 @@ var requireIntegrationsTier = createMiddleware3(async (c, next) => {
29633
30033
  }
29634
30034
  return next();
29635
30035
  });
29636
- var requirePaidSchedulingTier = createMiddleware3(async (c, next) => {
30036
+ var requirePaidSchedulingTier = createMiddleware4(async (c, next) => {
29637
30037
  const user = c.get("user");
29638
30038
  if (!hasPaidSchedulingAccess(user)) return c.json(paidPlanRequiredPayload(), 403);
29639
30039
  return next();
29640
30040
  });
29641
- var app = new Hono27();
30041
+ var app = new Hono28();
29642
30042
  var STRIPE_API_VERSION = "2026-02-25.clover";
29643
30043
  function requireStripeSecret() {
29644
30044
  const secret2 = process.env.STRIPE_SECRET_KEY?.trim();
@@ -32283,7 +32683,7 @@ app.get("/cron/tick", async (c) => {
32283
32683
  if (!process.env.CRON_SECRET || secret2 !== `Bearer ${process.env.CRON_SECRET}`) {
32284
32684
  return c.json({ error: "Unauthorized" }, 401);
32285
32685
  }
32286
- const { drainQueue } = await import("./worker-EBB6CTGW.js");
32686
+ const { drainQueue } = await import("./worker-TTFXPPDK.js");
32287
32687
  const budget = { maxJobs: 10, deadlineMs: Date.now() + 28e4 };
32288
32688
  const workflowDispatchResult = await dispatchDueWorkflowSchedules(`${new URL(c.req.url).protocol}//${new URL(c.req.url).host}`);
32289
32689
  const [results, sweepResult, reapResult, expiredResult, blobCleanup, connectedDataArtifactCleanup, connectedAccountBilling, directoryWorkflowDispatch, directoryWorkflowReconciliation, directoryArtifactCleanup, siteExtractArtifactCleanup, siteExtractRedispatch, siteExtractReconciliation] = await Promise.all([
@@ -32332,8 +32732,8 @@ app.post("/api/internal/extract-refinalize/:id", async (c) => {
32332
32732
  finishExtractJob: finishExtractJob2,
32333
32733
  terminalExtractJobStatus: terminalExtractJobStatus2,
32334
32734
  extractJobLimitInfo: extractJobLimitInfo2
32335
- } = await import("./site-extract-repository-PGQZNW6V.js");
32336
- const { assembleExtractArtifacts } = await import("./extract-bundle-M4SDJG3V.js");
32735
+ } = await import("./site-extract-repository-I3VM6WXN.js");
32736
+ const { assembleExtractArtifacts } = await import("./extract-bundle-346R6MXD.js");
32337
32737
  const existing = await getExtractJob2(jobId2);
32338
32738
  if (!existing) return c.json({ error: "job not found" }, 404);
32339
32739
  if (existing.status !== "failed") {
@@ -32360,7 +32760,7 @@ app.post("/api/internal/extract-refinalize/:id", async (c) => {
32360
32760
  if (!updated) return c.json({ error: "job state changed during re-finalization" }, 409);
32361
32761
  let settlement = "already_settled_or_refunded";
32362
32762
  if (job.billedMc == null && job.userId != null) {
32363
- const { settleExtractJob: settleExtractJob3, countSuccessfulPages: countSuccessfulPages2 } = await import("./site-extract-repository-PGQZNW6V.js");
32763
+ const { settleExtractJob: settleExtractJob3, countSuccessfulPages: countSuccessfulPages2 } = await import("./site-extract-repository-I3VM6WXN.js");
32364
32764
  const heldMc = Number(job.options.heldMc ?? 0);
32365
32765
  const successful = await countSuccessfulPages2(jobId2);
32366
32766
  const usedMc = Math.min(successful * MC_COSTS.page_scrape, heldMc);
@@ -32376,6 +32776,7 @@ app.post("/api/internal/extract-refinalize/:id", async (c) => {
32376
32776
  return c.json({ ok: true, jobId: jobId2, artifacts: stored.length, settlement, bundleUrl: bundle?.url ?? null, bundleBytes: bundle?.bytes ?? null });
32377
32777
  });
32378
32778
  app.on(["GET", "POST", "PUT"], "/api/inngest", serveInngest({ client: inngest, functions: [siteAuditFn, siteExtractFn, directoryWorkflowFn] }));
32779
+ app.route("/admin/credits", adminCreditsApp);
32379
32780
  app.route("/api/internal/site-architecture-auditor", siteAuditApp);
32380
32781
  app.route("/api/internal/memory", internalMemoryApp);
32381
32782
  app.route("/api/internal/billing", internalBillingApp);
@@ -32530,4 +32931,4 @@ app.get("/blog/:slug/", (c) => {
32530
32931
  export {
32531
32932
  app
32532
32933
  };
32533
- //# sourceMappingURL=server-ZIGAFKOL.js.map
32934
+ //# sourceMappingURL=server-QKDDEBVQ.js.map