clixad 0.0.1-beta.46 → 0.0.1-beta.47
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.
|
@@ -13,6 +13,10 @@ function isAdFormat(value) {
|
|
|
13
13
|
// src/sponsor/direct.ts
|
|
14
14
|
var DIRECT_ASK_TIMEOUT_MS = 1500;
|
|
15
15
|
var MAX_TEXT = 200;
|
|
16
|
+
function parseMeasure(body) {
|
|
17
|
+
const raw = body?.measure;
|
|
18
|
+
return typeof raw === "string" && raw.length > 0 && raw.length <= 2e3 ? raw : void 0;
|
|
19
|
+
}
|
|
16
20
|
function sanitizeAdText(raw) {
|
|
17
21
|
return raw.replace(/\u001b\[[0-?]*[ -/]*[@-~]/g, "").replace(/\u001b\][^\u0007\u001b]*(?:\u0007|\u001b\\)?/g, "").replace(/[\u0000-\u001f\u007f-\u009f]/g, " ").replace(/[--]/g, "").replace(/[-]/g, "").replace(/\s+/g, " ").trim();
|
|
18
22
|
}
|
|
@@ -62,7 +66,8 @@ function readServedLine(e) {
|
|
|
62
66
|
} catch {
|
|
63
67
|
return null;
|
|
64
68
|
}
|
|
65
|
-
|
|
69
|
+
const shortUrl = typeof e.short_url === "string" && shortLinkText(e.short_url) ? e.short_url : void 0;
|
|
70
|
+
return { format: e.format, text, serveToken: e.serve_token, clickUrl, ...shortUrl ? { shortUrl } : {} };
|
|
66
71
|
}
|
|
67
72
|
var MAX_LINK_TEXT = 40;
|
|
68
73
|
function shortLinkText(clickUrl) {
|
|
@@ -1140,7 +1145,13 @@ var GatewayClient = class {
|
|
|
1140
1145
|
if (!res.ok) return { supported: true, lines: [], failed: true };
|
|
1141
1146
|
const body = await res.json();
|
|
1142
1147
|
const fallbacks = parseFallbackLines(body);
|
|
1143
|
-
|
|
1148
|
+
const measure = parseMeasure(body);
|
|
1149
|
+
return {
|
|
1150
|
+
supported: true,
|
|
1151
|
+
lines: parseDirectLines(body),
|
|
1152
|
+
...fallbacks.length > 0 ? { fallbacks } : {},
|
|
1153
|
+
...measure ? { measure } : {}
|
|
1154
|
+
};
|
|
1144
1155
|
} catch {
|
|
1145
1156
|
return { supported: true, lines: [], failed: true };
|
|
1146
1157
|
}
|
|
@@ -1157,7 +1168,14 @@ var GatewayClient = class {
|
|
|
1157
1168
|
method: "POST",
|
|
1158
1169
|
headers: this.headers(),
|
|
1159
1170
|
...signal ? { signal } : {},
|
|
1160
|
-
body: JSON.stringify({
|
|
1171
|
+
body: JSON.stringify({
|
|
1172
|
+
impressions: impressions.map((i) => ({
|
|
1173
|
+
format: i.format,
|
|
1174
|
+
serve_token: i.serveToken,
|
|
1175
|
+
...i.visibleMs !== void 0 ? { visible_ms: Math.round(i.visibleMs) } : {},
|
|
1176
|
+
...i.link ? { link: i.link } : {}
|
|
1177
|
+
}))
|
|
1178
|
+
})
|
|
1161
1179
|
});
|
|
1162
1180
|
if (!res.ok) return 0;
|
|
1163
1181
|
const body = await res.json();
|
|
@@ -1166,6 +1184,27 @@ var GatewayClient = class {
|
|
|
1166
1184
|
return 0;
|
|
1167
1185
|
}
|
|
1168
1186
|
}
|
|
1187
|
+
/**
|
|
1188
|
+
* Report how long each place a turn asked about stayed on screen with a
|
|
1189
|
+
* line in it, with the turn's measure token: what a booked week is
|
|
1190
|
+
* forecast on. Never throws; answers how many places counted.
|
|
1191
|
+
*/
|
|
1192
|
+
async reportSponsorViews(measure, places, signal) {
|
|
1193
|
+
if (places.length === 0) return 0;
|
|
1194
|
+
try {
|
|
1195
|
+
const res = await gatewayFetch(`${this.config.gatewayUrl}/v1/sponsor/direct/views`, {
|
|
1196
|
+
method: "POST",
|
|
1197
|
+
headers: this.headers(),
|
|
1198
|
+
...signal ? { signal } : {},
|
|
1199
|
+
body: JSON.stringify({ measure, places: places.map((p) => ({ format: p.format, visible_ms: Math.round(p.visibleMs) })) })
|
|
1200
|
+
});
|
|
1201
|
+
if (!res.ok) return 0;
|
|
1202
|
+
const body = await res.json();
|
|
1203
|
+
return typeof body.counted === "number" ? body.counted : 0;
|
|
1204
|
+
} catch {
|
|
1205
|
+
return 0;
|
|
1206
|
+
}
|
|
1207
|
+
}
|
|
1169
1208
|
/**
|
|
1170
1209
|
* Report the fallback lines a turn drew, in one call, after the turn is
|
|
1171
1210
|
* over. They are counted and earn nothing, because nobody pays for them being
|
package/dist/clixad.mjs
CHANGED
|
@@ -54,7 +54,7 @@ import {
|
|
|
54
54
|
takeConfigNotices,
|
|
55
55
|
toolSchemaFor,
|
|
56
56
|
usd
|
|
57
|
-
} from "./chunk-
|
|
57
|
+
} from "./chunk-TKGMAY4C.mjs";
|
|
58
58
|
|
|
59
59
|
// src/tui/load.ts
|
|
60
60
|
import * as nodeModule from "node:module";
|
|
@@ -133,7 +133,7 @@ async function withProductionReact(load) {
|
|
|
133
133
|
}
|
|
134
134
|
function loadTui() {
|
|
135
135
|
boundInkCaches();
|
|
136
|
-
return withProductionReact(() => import("./tui-
|
|
136
|
+
return withProductionReact(() => import("./tui-US36BPP3.mjs"));
|
|
137
137
|
}
|
|
138
138
|
|
|
139
139
|
// src/title.ts
|
|
@@ -105,7 +105,7 @@ import {
|
|
|
105
105
|
visibleLength,
|
|
106
106
|
webSearchCostLine,
|
|
107
107
|
welcomeBanner
|
|
108
|
-
} from "./chunk-
|
|
108
|
+
} from "./chunk-TKGMAY4C.mjs";
|
|
109
109
|
|
|
110
110
|
// src/tui/index.tsx
|
|
111
111
|
import "react";
|
|
@@ -287,19 +287,25 @@ function sidebarCard(line2, cols, linkText) {
|
|
|
287
287
|
const link = linkText && visibleLength(label) + visibleLength(LINK_SEPARATOR) + visibleLength(linkText) <= SIDEBAR_BODY_COLS ? linkText : null;
|
|
288
288
|
return { rule: SIDEBAR_RULE, label, link, body };
|
|
289
289
|
}
|
|
290
|
-
function sponsorRow(line2, cols, origin, linkText) {
|
|
290
|
+
function sponsorRow(line2, cols, origin, linkText, linkRequired = false) {
|
|
291
291
|
const marker = origin === "house" || cols >= AD_FULL_PREFIX_MIN_COLS ? HOUSE_MARKER_ROW : AD_MARKER_ROW;
|
|
292
292
|
const label = origin === "network" ? LABEL_ROW : null;
|
|
293
293
|
if (origin === "network" && !adFitsWidth(cols)) return null;
|
|
294
294
|
const room = cols - visibleLength(marker) - (label ? visibleLength(label) : 0);
|
|
295
295
|
if (room < MIN_BODY_COLS) return null;
|
|
296
296
|
if (origin === "network" && linkText) {
|
|
297
|
-
const
|
|
297
|
+
const linkCols = visibleLength(LINK_SEPARATOR) + visibleLength(linkText);
|
|
298
|
+
const whole = visibleLength(line2) + linkCols;
|
|
298
299
|
if (whole <= room) return { marker, label, body: line2, link: linkText, origin };
|
|
300
|
+
if (linkRequired && room - linkCols >= MIN_LINKED_COPY_COLS) {
|
|
301
|
+
const copy = room - linkCols;
|
|
302
|
+
return { marker, label, body: `${sliceColumns(line2, copy - 1).trimEnd()}\u2026`, link: linkText, origin };
|
|
303
|
+
}
|
|
299
304
|
}
|
|
300
305
|
const body = visibleLength(line2) <= room ? line2 : `${sliceColumns(line2, room - 1).trimEnd()}\u2026`;
|
|
301
306
|
return { marker, label, body, link: null, origin };
|
|
302
307
|
}
|
|
308
|
+
var MIN_LINKED_COPY_COLS = 12;
|
|
303
309
|
function adColorEnabled({ isTTY, env }) {
|
|
304
310
|
if (!colorEnabled({ isTTY, env })) return false;
|
|
305
311
|
if (env.CI !== void 0 && env.CI !== "") return false;
|
|
@@ -356,6 +362,46 @@ function createSponsorSlot(config, format = "top_bar") {
|
|
|
356
362
|
};
|
|
357
363
|
}
|
|
358
364
|
|
|
365
|
+
// src/sponsor/visibility.ts
|
|
366
|
+
var VisibilityClock = class {
|
|
367
|
+
tracks = /* @__PURE__ */ new Map();
|
|
368
|
+
/** The keys on screen as of `now`. Every key not in `onScreen` is off screen from `now`. */
|
|
369
|
+
observe(onScreen, now) {
|
|
370
|
+
const visible = new Set(onScreen);
|
|
371
|
+
for (const [key, track] of this.tracks) {
|
|
372
|
+
if (track.since !== null && !visible.has(key)) {
|
|
373
|
+
track.done.push([track.since, now]);
|
|
374
|
+
track.since = null;
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
for (const key of visible) {
|
|
378
|
+
const track = this.tracks.get(key) ?? { since: null, done: [] };
|
|
379
|
+
if (track.since === null) track.since = now;
|
|
380
|
+
this.tracks.set(key, track);
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
/**
|
|
384
|
+
* The longest unbroken stretch `key` was on screen up to `now`, counting
|
|
385
|
+
* only time from `from` on (a place is measured from the moment a booked
|
|
386
|
+
* line could first have been drawn in it). Zero for a key never seen.
|
|
387
|
+
*/
|
|
388
|
+
longest(key, now, from = Number.NEGATIVE_INFINITY) {
|
|
389
|
+
const track = this.tracks.get(key);
|
|
390
|
+
if (!track) return 0;
|
|
391
|
+
const stretches = track.since === null ? track.done : [...track.done, [track.since, now]];
|
|
392
|
+
let best = 0;
|
|
393
|
+
for (const [start, end] of stretches) best = Math.max(best, Math.min(end, now) - Math.max(start, from));
|
|
394
|
+
return Math.max(0, best);
|
|
395
|
+
}
|
|
396
|
+
/** Forget everything: a new turn measures from nothing. */
|
|
397
|
+
reset() {
|
|
398
|
+
this.tracks.clear();
|
|
399
|
+
}
|
|
400
|
+
};
|
|
401
|
+
function placeKey(format) {
|
|
402
|
+
return `place:${format}`;
|
|
403
|
+
}
|
|
404
|
+
|
|
359
405
|
// src/sponsor/hyperlink.ts
|
|
360
406
|
function version(v) {
|
|
361
407
|
const m = /^(\d+)(?:\.(\d+))?/.exec(v ?? "");
|
|
@@ -2018,6 +2064,9 @@ function App({
|
|
|
2018
2064
|
const directSupportedRef = useRef(true);
|
|
2019
2065
|
const knownBookedRef = useRef(/* @__PURE__ */ new Set());
|
|
2020
2066
|
const drawnRef = useRef(/* @__PURE__ */ new Set());
|
|
2067
|
+
const visibilityRef = useRef(new VisibilityClock());
|
|
2068
|
+
const linkModeRef = useRef(/* @__PURE__ */ new Map());
|
|
2069
|
+
const measureRef = useRef(null);
|
|
2021
2070
|
const sponsorSlotRef = useRef(
|
|
2022
2071
|
/* @__PURE__ */ new Map()
|
|
2023
2072
|
);
|
|
@@ -2260,6 +2309,9 @@ function App({
|
|
|
2260
2309
|
const nextSponsor = useCallback(
|
|
2261
2310
|
(modelId) => {
|
|
2262
2311
|
const call = ++sponsorCallRef.current;
|
|
2312
|
+
visibilityRef.current.reset();
|
|
2313
|
+
linkModeRef.current = /* @__PURE__ */ new Map();
|
|
2314
|
+
measureRef.current = null;
|
|
2263
2315
|
if (!sponsorEnabled({
|
|
2264
2316
|
isTTY: stdout.isTTY,
|
|
2265
2317
|
env: process.env,
|
|
@@ -2312,11 +2364,14 @@ function App({
|
|
|
2312
2364
|
if (format !== "top_bar" && modalOpenRef.current) return;
|
|
2313
2365
|
const drawnId = `direct:${call}:${format}`;
|
|
2314
2366
|
const link = line2.clickUrl;
|
|
2367
|
+
const linkable2 = hyperlinksEnabled({ isTTY: stdout.isTTY, env: process.env });
|
|
2368
|
+
const linkText = !linkable2 && line2.shortUrl ? shortLinkText(line2.shortUrl) : void 0;
|
|
2369
|
+
const extra = linkText ? { link, linkText, linkRequired: true } : { link };
|
|
2315
2370
|
if (format === "top_bar") {
|
|
2316
|
-
if (!sponsorRow(line2.text, colsRef.current, "network")) return;
|
|
2317
|
-
setSponsor({ text: line2.text, origin: "network", impressionId: drawnId,
|
|
2371
|
+
if (!sponsorRow(line2.text, colsRef.current, "network", linkText, true)) return;
|
|
2372
|
+
setSponsor({ text: line2.text, origin: "network", impressionId: drawnId, ...extra });
|
|
2318
2373
|
} else {
|
|
2319
|
-
setAdSlots((slots) => ({ ...slots, [format]: { text: line2.text, impressionId: drawnId,
|
|
2374
|
+
setAdSlots((slots) => ({ ...slots, [format]: { text: line2.text, impressionId: drawnId, ...extra } }));
|
|
2320
2375
|
}
|
|
2321
2376
|
pendingDirectRef.current.set(format, { call, serveToken: line2.serveToken, drawnId });
|
|
2322
2377
|
};
|
|
@@ -2354,6 +2409,9 @@ function App({
|
|
|
2354
2409
|
failed2 = answer.failed === true;
|
|
2355
2410
|
direct = answer.lines;
|
|
2356
2411
|
fallbacks = answer.fallbacks ?? [];
|
|
2412
|
+
if (answer.measure && call === sponsorCallRef.current) {
|
|
2413
|
+
measureRef.current = { call, token: answer.measure, answeredAt: Date.now(), formats: [...fitting] };
|
|
2414
|
+
}
|
|
2357
2415
|
if (!failed2) knownBookedRef.current = new Set(direct.map((line2) => line2.format));
|
|
2358
2416
|
}
|
|
2359
2417
|
if (call !== sponsorCallRef.current) return;
|
|
@@ -2374,12 +2432,29 @@ function App({
|
|
|
2374
2432
|
const pendingDirect = [...pendingDirectRef.current.entries()];
|
|
2375
2433
|
const pendingFallback = [...pendingFallbackRef.current.entries()];
|
|
2376
2434
|
const drawn = drawnRef.current;
|
|
2435
|
+
const clock = visibilityRef.current;
|
|
2436
|
+
const linkModes = linkModeRef.current;
|
|
2437
|
+
const measure = measureRef.current;
|
|
2438
|
+
const at = Date.now();
|
|
2377
2439
|
pendingImpressionRef.current = /* @__PURE__ */ new Map();
|
|
2378
2440
|
pendingDirectRef.current = /* @__PURE__ */ new Map();
|
|
2379
2441
|
pendingFallbackRef.current = /* @__PURE__ */ new Map();
|
|
2380
2442
|
drawnRef.current = /* @__PURE__ */ new Set();
|
|
2381
|
-
|
|
2443
|
+
measureRef.current = null;
|
|
2444
|
+
const directReports = pendingDirect.filter(([, p]) => p.call === sponsorCallRef.current && drawn.has(p.drawnId)).map(([format, p]) => ({
|
|
2445
|
+
format,
|
|
2446
|
+
serveToken: p.serveToken,
|
|
2447
|
+
visibleMs: clock.longest(p.drawnId, at),
|
|
2448
|
+
link: linkModes.get(p.drawnId) ?? "none"
|
|
2449
|
+
}));
|
|
2382
2450
|
if (directReports.length > 0) void client.reportDirectImpressions(directReports);
|
|
2451
|
+
if (measure && measure.call === sponsorCallRef.current) {
|
|
2452
|
+
const places = measure.formats.map((format) => ({
|
|
2453
|
+
format,
|
|
2454
|
+
visibleMs: clock.longest(placeKey(format), at, measure.answeredAt)
|
|
2455
|
+
}));
|
|
2456
|
+
void client.reportSponsorViews(measure.token, places);
|
|
2457
|
+
}
|
|
2383
2458
|
const fallbackReports = pendingFallback.filter(([, p]) => p.call === sponsorCallRef.current && drawn.has(p.drawnId)).map(([format, p]) => ({ format, serveToken: p.serveToken }));
|
|
2384
2459
|
if (fallbackReports.length > 0) void client.reportAffiliateImpressions(fallbackReports);
|
|
2385
2460
|
const reports = pending.filter((p) => p.call === sponsorCallRef.current).filter((p) => drawn.has(p.impression.impressionId)).map((p) => p.impression);
|
|
@@ -4023,13 +4098,13 @@ ${dropped.map((l) => ` \xB7 ${l}`).join("\n")}`
|
|
|
4023
4098
|
});
|
|
4024
4099
|
const elapsed = busy && startedAt ? Math.floor((Date.now() - startedAt) / 1e3) : 0;
|
|
4025
4100
|
const spinner = spinnerRef.current[Math.floor(tick / SPINNER_TICKS_PER_FRAME) % spinnerRef.current.length];
|
|
4026
|
-
const sponsorLine = busy && sponsor ? sponsorRow(sponsor.text, cols, sponsor.origin, sponsor.linkText) : null;
|
|
4101
|
+
const sponsorLine = busy && sponsor ? sponsorRow(sponsor.text, cols, sponsor.origin, sponsor.linkText, sponsor.linkRequired === true) : null;
|
|
4027
4102
|
const adColor = adColorEnabled({ isTTY: stdout.isTTY, env: process.env });
|
|
4028
4103
|
const linkable = hyperlinksEnabled({ isTTY: stdout.isTTY, env: process.env });
|
|
4029
4104
|
const modalOpen = Boolean(picker || ask || plan || buy);
|
|
4030
4105
|
modalOpenRef.current = modalOpen;
|
|
4031
4106
|
const card = busy && !modalOpen && adSlots.sidebar_card ? sidebarCard(adSlots.sidebar_card.text, cols, adSlots.sidebar_card.linkText) : null;
|
|
4032
|
-
const statusBarLine = busy && !modalOpen && adSlots.status_bar ? sponsorRow(adSlots.status_bar.text, cols, "network", adSlots.status_bar.linkText) : null;
|
|
4107
|
+
const statusBarLine = busy && !modalOpen && adSlots.status_bar ? sponsorRow(adSlots.status_bar.text, cols, "network", adSlots.status_bar.linkText, adSlots.status_bar.linkRequired === true) : null;
|
|
4033
4108
|
const viewport = Math.max(1, rows - 1);
|
|
4034
4109
|
const inputRows = Math.max(1, Math.min(MAX_INPUT_ROWS, editor.lines.length));
|
|
4035
4110
|
const inputFrom = windowStart(editor.row, editor.lines.length, inputRows);
|
|
@@ -4060,9 +4135,24 @@ ${dropped.map((l) => ` \xB7 ${l}`).join("\n")}`
|
|
|
4060
4135
|
showCard ? adSlots.sidebar_card?.impressionId : void 0,
|
|
4061
4136
|
showStatusBar ? adSlots.status_bar?.impressionId : void 0
|
|
4062
4137
|
].filter(Boolean).join(" ");
|
|
4138
|
+
const placesKey = [
|
|
4139
|
+
showSponsor && sponsorLine ? placeKey("top_bar") : void 0,
|
|
4140
|
+
showCard ? placeKey("sidebar_card") : void 0,
|
|
4141
|
+
showStatusBar ? placeKey("status_bar") : void 0
|
|
4142
|
+
].filter(Boolean).join(" ");
|
|
4143
|
+
if (showSponsor && sponsorLine && sponsor?.impressionId?.startsWith("direct:")) {
|
|
4144
|
+
linkModeRef.current.set(sponsor.impressionId, linkable ? "link" : sponsorLine.link ? "address" : "none");
|
|
4145
|
+
}
|
|
4146
|
+
if (showCard && card && adSlots.sidebar_card?.impressionId.startsWith("direct:")) {
|
|
4147
|
+
linkModeRef.current.set(adSlots.sidebar_card.impressionId, linkable ? "link" : card.link ? "address" : "none");
|
|
4148
|
+
}
|
|
4149
|
+
if (showStatusBar && statusBarLine && adSlots.status_bar?.impressionId.startsWith("direct:")) {
|
|
4150
|
+
linkModeRef.current.set(adSlots.status_bar.impressionId, linkable ? "link" : statusBarLine.link ? "address" : "none");
|
|
4151
|
+
}
|
|
4063
4152
|
useEffect(() => {
|
|
4064
4153
|
for (const id of drawnKey.split(" ")) if (id) drawnRef.current.add(id);
|
|
4065
|
-
|
|
4154
|
+
visibilityRef.current.observe([...drawnKey.split(" "), ...placesKey.split(" ")].filter(Boolean), Date.now());
|
|
4155
|
+
}, [drawnKey, placesKey]);
|
|
4066
4156
|
let budget = Math.max(0, viewport - chromeHeight - menu.length - busyHeight);
|
|
4067
4157
|
const pickerCompact = Boolean(picker) && budget < PICKER_CHROME + 1;
|
|
4068
4158
|
const pickerChrome = pickerCompact ? PICKER_CHROME_COMPACT : PICKER_CHROME;
|