apptvty 0.3.1 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-RNZYGUMF.mjs → chunk-2UCECX7X.mjs} +65 -36
- package/dist/chunk-2UCECX7X.mjs.map +1 -0
- package/dist/{chunk-DFSZAE6R.mjs → chunk-INZJVNUI.mjs} +43 -20
- package/dist/chunk-INZJVNUI.mjs.map +1 -0
- package/dist/{chunk-EZYPAN7G.mjs → chunk-LHLZDTTY.mjs} +28 -2
- package/dist/chunk-LHLZDTTY.mjs.map +1 -0
- package/dist/cli.js +66 -1
- package/dist/index.d.mts +16 -2
- package/dist/index.d.ts +16 -2
- package/dist/index.js +133 -55
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +3 -3
- package/dist/middleware/express.d.mts +1 -1
- package/dist/middleware/express.d.ts +1 -1
- package/dist/middleware/express.js +68 -19
- package/dist/middleware/express.js.map +1 -1
- package/dist/middleware/express.mjs +2 -2
- package/dist/middleware/nextjs.d.mts +1 -1
- package/dist/middleware/nextjs.d.ts +1 -1
- package/dist/middleware/nextjs.js +90 -35
- package/dist/middleware/nextjs.js.map +1 -1
- package/dist/middleware/nextjs.mjs +2 -2
- package/dist/setup.d.mts +1 -1
- package/dist/setup.d.ts +1 -1
- package/dist/{types-DwAWwqqD.d.mts → types-Bz3fBGpw.d.mts} +6 -1
- package/dist/{types-DwAWwqqD.d.ts → types-Bz3fBGpw.d.ts} +6 -1
- package/package.json +1 -1
- package/dist/chunk-DFSZAE6R.mjs.map +0 -1
- package/dist/chunk-EZYPAN7G.mjs.map +0 -1
- package/dist/chunk-RNZYGUMF.mjs.map +0 -1
|
@@ -119,6 +119,28 @@ var ApptvtyClient = class {
|
|
|
119
119
|
this.warn("Failed to log impression (billing may be delayed):", err);
|
|
120
120
|
}
|
|
121
121
|
}
|
|
122
|
+
// ─── Programmatic Indexing ───────────────────────────────────────────────────
|
|
123
|
+
/**
|
|
124
|
+
* Manually push text or markdown directly into your site's RAG vector database.
|
|
125
|
+
* This instantly embeds the content for AI agents to query, bypassing the
|
|
126
|
+
* need for a scheduled HTML crawl. This is ideal for Client-Side Rendered (CSR)
|
|
127
|
+
* Apps or for injecting private institutional facts/databases.
|
|
128
|
+
*
|
|
129
|
+
* @example
|
|
130
|
+
* const result = await client.pushKnowledge({
|
|
131
|
+
* title: "Capitol Technology University Profile",
|
|
132
|
+
* content: "Here are all the detailed specs, majors, and acceptances...",
|
|
133
|
+
* url: "https://thecollegeradar.com/institution/499" // Optional reference
|
|
134
|
+
* });
|
|
135
|
+
*/
|
|
136
|
+
async pushKnowledge(params) {
|
|
137
|
+
const payload = {
|
|
138
|
+
title: params.title,
|
|
139
|
+
content: params.content,
|
|
140
|
+
url: params.url
|
|
141
|
+
};
|
|
142
|
+
return this.post(`/v1/sites/${this.siteId}/knowledge`, payload);
|
|
143
|
+
}
|
|
122
144
|
// ─── Analytics (for coding agents) ───────────────────────────────────────────
|
|
123
145
|
// These allow agents to check activity, logs, and errors without a human.
|
|
124
146
|
/** Get 30-day traffic overview (requests, AI %, crawlers, queries). */
|
|
@@ -366,8 +388,12 @@ var ApptvtyClient = class {
|
|
|
366
388
|
let dashboardUrl = (typeof process !== "undefined" ? process.env?.DASHBOARD_URL : void 0) ?? "https://dashboard.apptvty.com/login";
|
|
367
389
|
try {
|
|
368
390
|
const json = JSON.parse(text);
|
|
391
|
+
if (json?.error?.code === "INSUFFICIENT_BALANCE") {
|
|
392
|
+
throw new ApptvtyApiError(402, path, text);
|
|
393
|
+
}
|
|
369
394
|
dashboardUrl = json?.error?.details?.dashboard_url ?? dashboardUrl;
|
|
370
|
-
} catch {
|
|
395
|
+
} catch (e) {
|
|
396
|
+
if (e instanceof ApptvtyApiError) throw e;
|
|
371
397
|
}
|
|
372
398
|
throw new ApptvtyTrialExpiredError(dashboardUrl);
|
|
373
399
|
}
|
|
@@ -1179,7 +1205,8 @@ function withApptvty(config, next) {
|
|
|
1179
1205
|
const crawlerInfo = detectCrawler(userAgent);
|
|
1180
1206
|
const scraperService = detectScraperService(userAgent);
|
|
1181
1207
|
const aiCrawlerParam = parseBoolParam(request.nextUrl.searchParams.get("ai_crawler"), false);
|
|
1182
|
-
const
|
|
1208
|
+
const isAi = crawlerInfo.isAi || aiCrawlerParam;
|
|
1209
|
+
const isScraper = isAi || scraperService.isScraperService || crawlerInfo.name === "unknown_bot";
|
|
1183
1210
|
if (request.nextUrl.pathname === "/api/apptvty/verify") {
|
|
1184
1211
|
const challenge = request.nextUrl.searchParams.get("challenge");
|
|
1185
1212
|
if (challenge) {
|
|
@@ -1224,11 +1251,12 @@ function withApptvty(config, next) {
|
|
|
1224
1251
|
ip_address: getClientIp(headers),
|
|
1225
1252
|
user_agent: userAgent,
|
|
1226
1253
|
referrer: request.headers.get("referer"),
|
|
1227
|
-
is_ai_crawler:
|
|
1254
|
+
is_ai_crawler: isAi,
|
|
1228
1255
|
crawler_type: crawlerInfo.name,
|
|
1229
1256
|
crawler_organization: crawlerInfo.organization,
|
|
1230
1257
|
confidence_score: crawlerInfo.confidence,
|
|
1231
|
-
scraper_service: scraperService.name
|
|
1258
|
+
scraper_service: scraperService.name,
|
|
1259
|
+
attribution_id: request.nextUrl.searchParams.get("atid")
|
|
1232
1260
|
};
|
|
1233
1261
|
const isInternalRequest = request.headers.get("x-apptvty-internal") === "true";
|
|
1234
1262
|
if (!isInternalRequest && !pathname.startsWith(queryPath)) {
|
|
@@ -1237,46 +1265,73 @@ function withApptvty(config, next) {
|
|
|
1237
1265
|
event.waitUntil(logger.flush());
|
|
1238
1266
|
}
|
|
1239
1267
|
}
|
|
1240
|
-
if (
|
|
1268
|
+
if (!isInternalRequest && !pathname.startsWith(queryPath) && response.status === 200) {
|
|
1241
1269
|
try {
|
|
1242
|
-
const
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1270
|
+
const pageAds = await client.getAdsForPage({ site_id: config.siteId, page_path: pathname });
|
|
1271
|
+
if (pageAds.ads && pageAds.ads.length > 0) {
|
|
1272
|
+
const ad = pageAds.ads[0];
|
|
1273
|
+
client.logImpression({
|
|
1274
|
+
impression_id: ad.impression_id,
|
|
1275
|
+
site_id: config.siteId,
|
|
1276
|
+
page_path: pathname,
|
|
1277
|
+
agent_ua: userAgent,
|
|
1278
|
+
agent_ip: getClientIp(headers),
|
|
1279
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
1280
|
+
}).catch(() => {
|
|
1281
|
+
});
|
|
1282
|
+
if (isAi || scraperService.isScraperService) {
|
|
1283
|
+
const proxyReq = new Request(request.url, { headers: new Headers(request.headers) });
|
|
1284
|
+
proxyReq.headers.set("x-apptvty-internal", "true");
|
|
1285
|
+
const res = await fetch(proxyReq);
|
|
1286
|
+
const contentType = res.headers.get("content-type") ?? "";
|
|
1287
|
+
if (contentType.includes("text/html")) {
|
|
1288
|
+
const html = await res.text();
|
|
1289
|
+
let markdown = convertHtmlToMarkdown(html);
|
|
1290
|
+
markdown += `
|
|
1255
1291
|
|
|
1256
1292
|
---
|
|
1257
1293
|
> **Sponsored:** [${ad.text}](${ad.url}) - ${ad.advertiser}
|
|
1258
1294
|
`;
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
}
|
|
1295
|
+
return new import_server.NextResponse(markdown, {
|
|
1296
|
+
status: res.status,
|
|
1297
|
+
headers: {
|
|
1298
|
+
"Content-Type": "text/markdown",
|
|
1299
|
+
"X-Apptvty-AEO": "true",
|
|
1300
|
+
"X-Sponsored-Content": `${ad.text}; url=${ad.url}`
|
|
1301
|
+
}
|
|
1302
|
+
});
|
|
1303
|
+
}
|
|
1268
1304
|
}
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1305
|
+
const originalHeaders = headersToRecord(response.headers);
|
|
1306
|
+
if (originalHeaders["content-type"]?.includes("text/html")) {
|
|
1307
|
+
const html = await response.text();
|
|
1308
|
+
const jsonLd = `
|
|
1309
|
+
<script type="application/ld+json">{"@context":"https://schema.org","@type":"CreativeWork","author":{"@type":"Organization","name":"${ad.advertiser}"},"mainEntityOfPage":{"@type":"WebPage","@id":"${ad.url}"},"headline":"Sponsored: ${ad.text}"}</script>
|
|
1310
|
+
`;
|
|
1311
|
+
const stealthDiv = `
|
|
1312
|
+
<div style="display:none !important;visibility:hidden;height:0;width:0;overflow:hidden;" aria-hidden="true" data-apptvty-ad="${ad.impression_id}">Sponsored by ${ad.advertiser}: <a href="${ad.url}">${ad.text}</a></div>
|
|
1313
|
+
`;
|
|
1314
|
+
let modifiedHtml = html;
|
|
1315
|
+
if (html.includes("</head>")) {
|
|
1316
|
+
modifiedHtml = html.replace("</head>", `${jsonLd}</head>`);
|
|
1274
1317
|
}
|
|
1275
|
-
|
|
1318
|
+
if (modifiedHtml.includes("</body>")) {
|
|
1319
|
+
modifiedHtml = modifiedHtml.replace("</body>", `${stealthDiv}</body>`);
|
|
1320
|
+
} else {
|
|
1321
|
+
modifiedHtml += stealthDiv;
|
|
1322
|
+
}
|
|
1323
|
+
return new import_server.NextResponse(modifiedHtml, {
|
|
1324
|
+
status: response.status,
|
|
1325
|
+
headers: {
|
|
1326
|
+
...originalHeaders,
|
|
1327
|
+
"X-Sponsored-Content": `${ad.text}; url=${ad.url}`
|
|
1328
|
+
}
|
|
1329
|
+
});
|
|
1330
|
+
}
|
|
1331
|
+
response.headers.set("X-Sponsored-Content", `${ad.text}; url=${ad.url}`);
|
|
1276
1332
|
}
|
|
1277
|
-
return res;
|
|
1278
1333
|
} catch (err) {
|
|
1279
|
-
if (config.debug) console.warn("[apptvty]
|
|
1334
|
+
if (config.debug) console.warn("[apptvty] Stealth injection failed:", err);
|
|
1280
1335
|
}
|
|
1281
1336
|
}
|
|
1282
1337
|
return response;
|