scaledthought 0.3.2 → 0.3.4
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/README.md +16 -5
- package/dist/index.js +861 -82
- package/package.json +13 -9
package/dist/index.js
CHANGED
|
@@ -1,4 +1,32 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __returnValue = (v) => v;
|
|
4
|
+
function __exportSetter(name, newValue) {
|
|
5
|
+
this[name] = __returnValue.bind(null, newValue);
|
|
6
|
+
}
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, {
|
|
10
|
+
get: all[name],
|
|
11
|
+
enumerable: true,
|
|
12
|
+
configurable: true,
|
|
13
|
+
set: __exportSetter.bind(all, name)
|
|
14
|
+
});
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
// ../../node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/classic/iso.js
|
|
18
|
+
var exports_iso = {};
|
|
19
|
+
__export(exports_iso, {
|
|
20
|
+
ZodISODate: () => ZodISODate,
|
|
21
|
+
ZodISODateTime: () => ZodISODateTime,
|
|
22
|
+
ZodISODuration: () => ZodISODuration,
|
|
23
|
+
ZodISOTime: () => ZodISOTime,
|
|
24
|
+
date: () => date2,
|
|
25
|
+
datetime: () => datetime2,
|
|
26
|
+
duration: () => duration2,
|
|
27
|
+
time: () => time2
|
|
28
|
+
});
|
|
29
|
+
|
|
2
30
|
// ../../node_modules/.pnpm/citty@0.2.2/node_modules/citty/dist/_chunks/libs/scule.mjs
|
|
3
31
|
var NUMBER_CHAR_RE = /\d/;
|
|
4
32
|
var STR_SPLITTERS = [
|
|
@@ -553,8 +581,8 @@ import { join } from "node:path";
|
|
|
553
581
|
// package.json
|
|
554
582
|
var package_default = {
|
|
555
583
|
name: "scaledthought",
|
|
556
|
-
version: "0.3.
|
|
557
|
-
description: "
|
|
584
|
+
version: "0.3.4",
|
|
585
|
+
description: "OpenAI-compatible inference for open-weight models, set up by your coding agent. Prepaid, pay per token, no subscription. US live; Canada coming soon.",
|
|
558
586
|
license: "MIT",
|
|
559
587
|
keywords: [
|
|
560
588
|
"llm",
|
|
@@ -563,18 +591,22 @@ var package_default = {
|
|
|
563
591
|
"openai-compatible",
|
|
564
592
|
"mcp",
|
|
565
593
|
"agents",
|
|
566
|
-
"
|
|
567
|
-
"
|
|
568
|
-
"
|
|
594
|
+
"coding-agents",
|
|
595
|
+
"claude-code",
|
|
596
|
+
"llm-api",
|
|
597
|
+
"inference-api",
|
|
598
|
+
"open-models",
|
|
599
|
+
"mcp-server",
|
|
600
|
+
"model-context-protocol",
|
|
601
|
+
"cli"
|
|
569
602
|
],
|
|
570
|
-
homepage: "https://scaledthought.com",
|
|
603
|
+
homepage: "https://scaledthought.com/go/org-npm",
|
|
571
604
|
bugs: {
|
|
572
|
-
url: "https://github.com/Scaled-Thought/scaledthought/issues"
|
|
605
|
+
url: "https://github.com/Scaled-Thought/scaledthought-mcp/issues"
|
|
573
606
|
},
|
|
574
607
|
repository: {
|
|
575
608
|
type: "git",
|
|
576
|
-
url: "git+https://github.com/Scaled-Thought/scaledthought.git"
|
|
577
|
-
directory: "apps/cli"
|
|
609
|
+
url: "git+https://github.com/Scaled-Thought/scaledthought-mcp.git"
|
|
578
610
|
},
|
|
579
611
|
type: "module",
|
|
580
612
|
bin: {
|
|
@@ -666,6 +698,7 @@ var HINTS = {
|
|
|
666
698
|
gone: "This endpoint was removed. For credits use `billing topup --amount-usd 20`.",
|
|
667
699
|
fine_tuning_requires_self_hosted: "This base model can't be fine-tuned in your region (it isn't served on our own GPUs). Choose another base model.",
|
|
668
700
|
rate_limit_exceeded: "Wait the number of seconds in retry_after, then retry.",
|
|
701
|
+
http_429: "Too many requests from this address for now. Wait about 5 minutes, then run the same command again. A top-up link you already gave your human still works until its expires_at: don't create a new one unless it expired.",
|
|
669
702
|
session_limit_exceeded: "Too many realtime sessions are open on this key. Close one, then retry.",
|
|
670
703
|
audio_window_exceeded: "Send shorter turns: commit the audio and ask for a response at least every 5 minutes.",
|
|
671
704
|
invalid_client_secret: "Client secrets are single use and expire in about a minute. Mint a new one and connect at once.",
|
|
@@ -6513,6 +6546,14 @@ function object(shape, params) {
|
|
|
6513
6546
|
};
|
|
6514
6547
|
return new ZodObject(def);
|
|
6515
6548
|
}
|
|
6549
|
+
function strictObject(shape, params) {
|
|
6550
|
+
return new ZodObject({
|
|
6551
|
+
type: "object",
|
|
6552
|
+
shape,
|
|
6553
|
+
catchall: never(),
|
|
6554
|
+
...normalizeParams(params)
|
|
6555
|
+
});
|
|
6556
|
+
}
|
|
6516
6557
|
var ZodUnion = /* @__PURE__ */ $constructor("ZodUnion", (inst, def) => {
|
|
6517
6558
|
$ZodUnion.init(inst, def);
|
|
6518
6559
|
ZodType.init(inst, def);
|
|
@@ -6812,6 +6853,19 @@ function refine(fn, _params = {}) {
|
|
|
6812
6853
|
function superRefine(fn, params) {
|
|
6813
6854
|
return _superRefine(fn, params);
|
|
6814
6855
|
}
|
|
6856
|
+
// ../../node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/classic/iso.js
|
|
6857
|
+
function datetime2(params) {
|
|
6858
|
+
return _isoDateTime(ZodISODateTime, params);
|
|
6859
|
+
}
|
|
6860
|
+
function date2(params) {
|
|
6861
|
+
return _isoDate(ZodISODate, params);
|
|
6862
|
+
}
|
|
6863
|
+
function time2(params) {
|
|
6864
|
+
return _isoTime(ZodISOTime, params);
|
|
6865
|
+
}
|
|
6866
|
+
function duration2(params) {
|
|
6867
|
+
return _isoDuration(ZodISODuration, params);
|
|
6868
|
+
}
|
|
6815
6869
|
// ../../packages/growth/src/codes.ts
|
|
6816
6870
|
var CODE_RE = /^[a-z0-9]{1,3}(-[a-z0-9]{1,12}){1,2}$/;
|
|
6817
6871
|
function normalizeCode(raw) {
|
|
@@ -6834,6 +6888,7 @@ var CHANNELS = [
|
|
|
6834
6888
|
"organic"
|
|
6835
6889
|
];
|
|
6836
6890
|
var Channel = _enum(CHANNELS);
|
|
6891
|
+
var SITE_ORIGIN = "https://scaledthought.com";
|
|
6837
6892
|
|
|
6838
6893
|
// ../../packages/growth/src/ad-click.ts
|
|
6839
6894
|
var AD_CLICK_PLATFORMS = ["google", "reddit", "x", "microsoft"];
|
|
@@ -7150,6 +7205,11 @@ function parseWith(def, text, opts) {
|
|
|
7150
7205
|
skipped++;
|
|
7151
7206
|
return;
|
|
7152
7207
|
}
|
|
7208
|
+
const second = (r.filter((c) => c.trim() !== "")[1] ?? "").trim().toLowerCase();
|
|
7209
|
+
if (def.totalPrefix && parseReportDay(first) && second.startsWith(def.totalPrefix.toLowerCase())) {
|
|
7210
|
+
skipped++;
|
|
7211
|
+
return;
|
|
7212
|
+
}
|
|
7153
7213
|
const rawDay = cell(r, "day") ?? "";
|
|
7154
7214
|
const day = parseReportDay(rawDay);
|
|
7155
7215
|
if (!day) {
|
|
@@ -7401,10 +7461,62 @@ var GoogleCredentials = object({
|
|
|
7401
7461
|
refresh_token: string2().min(1).optional(),
|
|
7402
7462
|
service_account: object({ client_email: string2().email(), private_key: string2().min(1) }).optional()
|
|
7403
7463
|
}).refine((c) => c.service_account || c.client_id && c.client_secret && c.refresh_token);
|
|
7404
|
-
var
|
|
7464
|
+
var Secret = string2().min(1);
|
|
7465
|
+
var GoogleSpendAccount = strictObject({
|
|
7466
|
+
customer_id: CustomerId,
|
|
7467
|
+
login_customer_id: CustomerId.optional(),
|
|
7468
|
+
developer_token: Secret.optional(),
|
|
7469
|
+
auth: union([
|
|
7470
|
+
strictObject({ oauth: strictObject({ client_id: Secret, client_secret: Secret, refresh_token: Secret }) }),
|
|
7471
|
+
strictObject({
|
|
7472
|
+
service_account: strictObject({ client_email: string2().email(), private_key: Secret })
|
|
7473
|
+
})
|
|
7474
|
+
])
|
|
7475
|
+
});
|
|
7476
|
+
var GoogleSpendAccounts = array(GoogleSpendAccount).min(1).max(20).superRefine((list, ctx) => {
|
|
7477
|
+
const seen = new Set;
|
|
7478
|
+
list.forEach((a, i) => {
|
|
7479
|
+
if (seen.has(a.customer_id))
|
|
7480
|
+
ctx.addIssue({ code: "custom", path: [i, "customer_id"], message: "duplicate" });
|
|
7481
|
+
seen.add(a.customer_id);
|
|
7482
|
+
});
|
|
7483
|
+
});
|
|
7484
|
+
var flatten = (a) => ({
|
|
7485
|
+
customer_id: a.customer_id,
|
|
7486
|
+
...a.login_customer_id ? { login_customer_id: a.login_customer_id } : {},
|
|
7487
|
+
...a.developer_token ? { developer_token: a.developer_token } : {},
|
|
7488
|
+
..."oauth" in a.auth ? a.auth.oauth : { service_account: a.auth.service_account }
|
|
7489
|
+
});
|
|
7490
|
+
var parseJson2 = (raw) => {
|
|
7491
|
+
if (!raw)
|
|
7492
|
+
return { ok: false };
|
|
7493
|
+
try {
|
|
7494
|
+
return { ok: true, json: JSON.parse(raw) };
|
|
7495
|
+
} catch {
|
|
7496
|
+
return { ok: false };
|
|
7497
|
+
}
|
|
7498
|
+
};
|
|
7499
|
+
function googleSpendAccounts(raw) {
|
|
7500
|
+
const p = parseJson2(raw);
|
|
7501
|
+
if (!p.ok)
|
|
7502
|
+
throw new SpendApiError("credentials_invalid");
|
|
7503
|
+
if (Array.isArray(p.json)) {
|
|
7504
|
+
const list = GoogleSpendAccounts.safeParse(p.json);
|
|
7505
|
+
if (!list.success)
|
|
7506
|
+
throw new SpendApiError("credentials_invalid");
|
|
7507
|
+
return list.data.map(flatten);
|
|
7508
|
+
}
|
|
7509
|
+
const single = GoogleCredentials.safeParse(p.json);
|
|
7510
|
+
if (!single.success)
|
|
7511
|
+
throw new SpendApiError("credentials_invalid");
|
|
7512
|
+
return [single.data];
|
|
7513
|
+
}
|
|
7405
7514
|
var hyphenCustomerId = (id) => `${id.slice(0, 3)}-${id.slice(3, 6)}-${id.slice(6)}`;
|
|
7515
|
+
function googleApiAccounts(creds) {
|
|
7516
|
+
return googleSpendAccounts(creds[ENV]).map((c) => hyphenCustomerId(c.customer_id));
|
|
7517
|
+
}
|
|
7406
7518
|
function googleApiAccount(creds) {
|
|
7407
|
-
return
|
|
7519
|
+
return googleApiAccounts(creds)[0];
|
|
7408
7520
|
}
|
|
7409
7521
|
var Token = object({ access_token: string2().min(1) });
|
|
7410
7522
|
async function googleAccessToken(c, f) {
|
|
@@ -7474,7 +7586,10 @@ async function search(c, token, query, f) {
|
|
|
7474
7586
|
var FIELDS = "segments.date, customer.currency_code, campaign.id, campaign.name, metrics.impressions, metrics.clicks, " + "metrics.cost_micros, metrics.conversions";
|
|
7475
7587
|
async function pullGoogleAds(range, ctx) {
|
|
7476
7588
|
checkRange(range);
|
|
7477
|
-
const
|
|
7589
|
+
const all = googleSpendAccounts(ctx.credentials[ENV]);
|
|
7590
|
+
const c = ctx.adAccountId ? all.find((a) => hyphenCustomerId(a.customer_id) === ctx.adAccountId) : all[0];
|
|
7591
|
+
if (!c)
|
|
7592
|
+
throw new SpendApiError("credentials_invalid");
|
|
7478
7593
|
const token = await googleAccessToken(c, ctx.fetch);
|
|
7479
7594
|
const where = `WHERE segments.date BETWEEN '${range.from}' AND '${range.to}'`;
|
|
7480
7595
|
const adGroups = await search(c, token, `SELECT ${FIELDS}, ad_group.id, ad_group.name FROM ad_group ${where}`, ctx.fetch);
|
|
@@ -7750,8 +7865,8 @@ var MicrosoftCredentials = object({
|
|
|
7750
7865
|
tenant: string2().regex(/^[A-Za-z0-9.-]{1,100}$/).default("common"),
|
|
7751
7866
|
report_time_zone: string2().regex(/^[A-Za-z]{2,80}$/).optional()
|
|
7752
7867
|
});
|
|
7753
|
-
var
|
|
7754
|
-
var microsoftApiAccount = (creds) =>
|
|
7868
|
+
var credentials = (creds) => parseCredentialsJson(creds[ENV2], MicrosoftCredentials);
|
|
7869
|
+
var microsoftApiAccount = (creds) => credentials(creds).account_id;
|
|
7755
7870
|
var Token2 = object({ access_token: string2().min(1) });
|
|
7756
7871
|
async function microsoftAccessToken(c, f) {
|
|
7757
7872
|
const form = new URLSearchParams({
|
|
@@ -7820,7 +7935,7 @@ var Polled = object({
|
|
|
7820
7935
|
});
|
|
7821
7936
|
async function pullMicrosoftAds(range, ctx) {
|
|
7822
7937
|
checkRange(range);
|
|
7823
|
-
const c =
|
|
7938
|
+
const c = credentials(ctx.credentials);
|
|
7824
7939
|
const token = await microsoftAccessToken(c, ctx.fetch);
|
|
7825
7940
|
const headers = {
|
|
7826
7941
|
authorization: `Bearer ${token}`,
|
|
@@ -7899,10 +8014,175 @@ var AD_WRITE_CREDENTIAL_ENV = {
|
|
|
7899
8014
|
microsoft: "AD_WRITE_MICROSOFT_CREDENTIALS"
|
|
7900
8015
|
};
|
|
7901
8016
|
var AD_WRITE_CREDENTIAL_ENV_NAMES = Object.values(AD_WRITE_CREDENTIAL_ENV);
|
|
8017
|
+
// ../../packages/growth/src/campaign-google.ts
|
|
8018
|
+
var CAMPAIGN_CHANNELS = ["search", "display"];
|
|
8019
|
+
var GOOGLE_ASSET_LIMITS = {
|
|
8020
|
+
callout: 25,
|
|
8021
|
+
callouts: 20,
|
|
8022
|
+
sitelinkText: 25,
|
|
8023
|
+
sitelinkLine: 35,
|
|
8024
|
+
sitelinks: 20,
|
|
8025
|
+
snippetValue: 25,
|
|
8026
|
+
snippetValuesMin: 3,
|
|
8027
|
+
snippetValuesMax: 10,
|
|
8028
|
+
snippets: 10,
|
|
8029
|
+
businessName: 25,
|
|
8030
|
+
images: 20,
|
|
8031
|
+
customAudiences: 10,
|
|
8032
|
+
audienceMembers: 200,
|
|
8033
|
+
audienceKeyword: 80,
|
|
8034
|
+
exclusions: 5000
|
|
8035
|
+
};
|
|
8036
|
+
var CENT_MICROS = 1e4;
|
|
8037
|
+
var MAX_BID_MICROS = 1e8;
|
|
8038
|
+
var Line = (max, what) => string2().trim().min(1).refine((s) => [...s].length <= max, `${what}: at most ${max} characters`);
|
|
8039
|
+
var BidMicros = number2().int().positive().max(MAX_BID_MICROS).refine((n) => n % CENT_MICROS === 0, "whole cents (a multiple of 10,000 micros)");
|
|
8040
|
+
var CampaignBidding = discriminatedUnion("strategy", [
|
|
8041
|
+
object({ strategy: literal("maximize_clicks"), max_cpc_micros: BidMicros.nullable().default(null) }).strict(),
|
|
8042
|
+
object({ strategy: literal("maximize_conversions"), target_cpa_micros: BidMicros.nullable().default(null) }).strict(),
|
|
8043
|
+
object({ strategy: literal("manual_cpc"), default_cpc_micros: BidMicros }).strict()
|
|
8044
|
+
]);
|
|
8045
|
+
var DeviceAdjustment = number2().int().refine((n) => n === -100 || n >= -90 && n <= 900, "−100 (excluded) or −90 … +900 percent");
|
|
8046
|
+
var CampaignDevices = object({
|
|
8047
|
+
desktop: DeviceAdjustment.default(0),
|
|
8048
|
+
mobile: DeviceAdjustment.default(0),
|
|
8049
|
+
tablet: DeviceAdjustment.default(0),
|
|
8050
|
+
tv: DeviceAdjustment.default(0)
|
|
8051
|
+
}).strict();
|
|
8052
|
+
var noDeviceAdjustments = () => ({ desktop: 0, mobile: 0, tablet: 0, tv: 0 });
|
|
8053
|
+
var SiteUrl = string2().trim().max(200).refine((s) => {
|
|
8054
|
+
if (!s.startsWith(`${SITE_ORIGIN}/`) && s !== SITE_ORIGIN)
|
|
8055
|
+
return false;
|
|
8056
|
+
try {
|
|
8057
|
+
const u = new URL(s);
|
|
8058
|
+
return u.origin === SITE_ORIGIN && !u.search && !u.hash && !u.username && !u.password;
|
|
8059
|
+
} catch {
|
|
8060
|
+
return false;
|
|
8061
|
+
}
|
|
8062
|
+
}, `a page on ${SITE_ORIGIN} (https, no query string or fragment)`);
|
|
8063
|
+
var Sitelink = object({
|
|
8064
|
+
text: Line(GOOGLE_ASSET_LIMITS.sitelinkText, "sitelink text"),
|
|
8065
|
+
line1: Line(GOOGLE_ASSET_LIMITS.sitelinkLine, "sitelink line").nullable().default(null),
|
|
8066
|
+
line2: Line(GOOGLE_ASSET_LIMITS.sitelinkLine, "sitelink line").nullable().default(null),
|
|
8067
|
+
final_url: SiteUrl
|
|
8068
|
+
}).strict().refine((s) => s.line1 == null === (s.line2 == null), "sitelink lines: both or neither");
|
|
8069
|
+
var SNIPPET_HEADERS = [
|
|
8070
|
+
"Amenities",
|
|
8071
|
+
"Brands",
|
|
8072
|
+
"Courses",
|
|
8073
|
+
"Degree programs",
|
|
8074
|
+
"Destinations",
|
|
8075
|
+
"Featured hotels",
|
|
8076
|
+
"Insurance coverage",
|
|
8077
|
+
"Models",
|
|
8078
|
+
"Neighborhoods",
|
|
8079
|
+
"Service catalog",
|
|
8080
|
+
"Shows",
|
|
8081
|
+
"Styles",
|
|
8082
|
+
"Types"
|
|
8083
|
+
];
|
|
8084
|
+
var StructuredSnippet = object({
|
|
8085
|
+
header: _enum(SNIPPET_HEADERS),
|
|
8086
|
+
values: array(Line(GOOGLE_ASSET_LIMITS.snippetValue, "snippet value")).min(GOOGLE_ASSET_LIMITS.snippetValuesMin).max(GOOGLE_ASSET_LIMITS.snippetValuesMax)
|
|
8087
|
+
}).strict();
|
|
8088
|
+
var AssetId = string2().regex(/^\d{1,20}$/, "a Google Ads asset id");
|
|
8089
|
+
var emptyAssets = () => ({
|
|
8090
|
+
callouts: [],
|
|
8091
|
+
sitelinks: [],
|
|
8092
|
+
structured_snippets: [],
|
|
8093
|
+
business_name: null,
|
|
8094
|
+
logo_asset_id: null,
|
|
8095
|
+
image_asset_ids: []
|
|
8096
|
+
});
|
|
8097
|
+
var CampaignAssets = object({
|
|
8098
|
+
callouts: array(Line(GOOGLE_ASSET_LIMITS.callout, "callout")).max(GOOGLE_ASSET_LIMITS.callouts).default([]),
|
|
8099
|
+
sitelinks: array(Sitelink).max(GOOGLE_ASSET_LIMITS.sitelinks).default([]),
|
|
8100
|
+
structured_snippets: array(StructuredSnippet).max(GOOGLE_ASSET_LIMITS.snippets).default([]),
|
|
8101
|
+
business_name: Line(GOOGLE_ASSET_LIMITS.businessName, "business name").nullable().default(null),
|
|
8102
|
+
logo_asset_id: AssetId.nullable().default(null),
|
|
8103
|
+
image_asset_ids: array(AssetId).max(GOOGLE_ASSET_LIMITS.images).default([])
|
|
8104
|
+
}).strict();
|
|
8105
|
+
var CONTENT_LABELS = [
|
|
8106
|
+
"BELOW_THE_FOLD",
|
|
8107
|
+
"BRAND_SUITABILITY_CONTENT_FOR_FAMILIES",
|
|
8108
|
+
"BRAND_SUITABILITY_GAMES_FIGHTING",
|
|
8109
|
+
"BRAND_SUITABILITY_GAMES_MATURE",
|
|
8110
|
+
"BRAND_SUITABILITY_HEALTH_SENSITIVE",
|
|
8111
|
+
"BRAND_SUITABILITY_HEALTH_SOURCE_UNDETERMINED",
|
|
8112
|
+
"BRAND_SUITABILITY_NEWS_RECENT",
|
|
8113
|
+
"BRAND_SUITABILITY_NEWS_SENSITIVE",
|
|
8114
|
+
"BRAND_SUITABILITY_NEWS_SOURCE_NOT_FEATURED",
|
|
8115
|
+
"BRAND_SUITABILITY_POLITICS",
|
|
8116
|
+
"BRAND_SUITABILITY_RELIGION",
|
|
8117
|
+
"EMBEDDED_VIDEO",
|
|
8118
|
+
"JUVENILE",
|
|
8119
|
+
"LIVE_STREAMING_VIDEO",
|
|
8120
|
+
"PARKED_DOMAIN",
|
|
8121
|
+
"PROFANITY",
|
|
8122
|
+
"SEXUALLY_SUGGESTIVE",
|
|
8123
|
+
"SOCIAL_ISSUES",
|
|
8124
|
+
"TRAGEDY",
|
|
8125
|
+
"VIDEO",
|
|
8126
|
+
"VIDEO_NOT_YET_RATED",
|
|
8127
|
+
"VIDEO_RATING_DV_G",
|
|
8128
|
+
"VIDEO_RATING_DV_MA",
|
|
8129
|
+
"VIDEO_RATING_DV_PG",
|
|
8130
|
+
"VIDEO_RATING_DV_T"
|
|
8131
|
+
];
|
|
8132
|
+
var Placement = string2().trim().min(1).max(2048);
|
|
8133
|
+
var AppCategory = string2().regex(/^\d{1,12}$/, "a mobile app category id, e.g. 60008");
|
|
8134
|
+
var uniq = (xs) => new Set(xs).size === xs.length;
|
|
8135
|
+
var CampaignExclusions = object({
|
|
8136
|
+
placements: array(Placement).max(GOOGLE_ASSET_LIMITS.exclusions).default([]),
|
|
8137
|
+
mobile_app_categories: array(AppCategory).max(GOOGLE_ASSET_LIMITS.exclusions).default([]),
|
|
8138
|
+
content_labels: array(_enum(CONTENT_LABELS)).max(CONTENT_LABELS.length).default([])
|
|
8139
|
+
}).strict().refine((e) => uniq(e.placements) && uniq(e.mobile_app_categories) && uniq(e.content_labels), "exclusions are listed once");
|
|
8140
|
+
var noExclusions = () => ({
|
|
8141
|
+
placements: [],
|
|
8142
|
+
mobile_app_categories: [],
|
|
8143
|
+
content_labels: []
|
|
8144
|
+
});
|
|
8145
|
+
var CUSTOM_AUDIENCE_TYPES = ["search", "auto"];
|
|
8146
|
+
var CustomAudience = object({
|
|
8147
|
+
name: string2().trim().min(1).max(255),
|
|
8148
|
+
type: _enum(CUSTOM_AUDIENCE_TYPES),
|
|
8149
|
+
keywords: array(Line(GOOGLE_ASSET_LIMITS.audienceKeyword, "audience keyword").refine((s) => s.split(/\s+/).length <= 10, "audience keyword: at most 10 words")).max(GOOGLE_ASSET_LIMITS.audienceMembers).default([]),
|
|
8150
|
+
urls: array(string2().trim().url().max(2048)).max(GOOGLE_ASSET_LIMITS.audienceMembers).default([])
|
|
8151
|
+
}).strict().refine((a) => a.keywords.length + a.urls.length > 0, "an audience has at least one keyword or URL").refine((a) => a.type === "auto" || a.urls.length === 0, "a search audience has keywords only").refine((a) => a.keywords.length + a.urls.length <= GOOGLE_ASSET_LIMITS.audienceMembers, "at most 200 members");
|
|
8152
|
+
var emptyDisplay = () => ({
|
|
8153
|
+
optimized_targeting: false,
|
|
8154
|
+
custom_audiences: [],
|
|
8155
|
+
exclusions: noExclusions()
|
|
8156
|
+
});
|
|
8157
|
+
var CampaignDisplay = object({
|
|
8158
|
+
optimized_targeting: boolean2().default(false),
|
|
8159
|
+
custom_audiences: array(CustomAudience).max(GOOGLE_ASSET_LIMITS.customAudiences).default([]),
|
|
8160
|
+
exclusions: CampaignExclusions.default(() => noExclusions())
|
|
8161
|
+
}).strict();
|
|
8162
|
+
var AdAccountExclusions = object({
|
|
8163
|
+
placements: array(Placement).max(GOOGLE_ASSET_LIMITS.exclusions).default([]),
|
|
8164
|
+
mobile_app_categories: array(AppCategory).max(GOOGLE_ASSET_LIMITS.exclusions).default([]),
|
|
8165
|
+
content_labels: array(_enum(CONTENT_LABELS)).max(CONTENT_LABELS.length).default([]),
|
|
8166
|
+
mobile_applications: array(string2().trim().min(1).max(255)).max(GOOGLE_ASSET_LIMITS.exclusions).default([]),
|
|
8167
|
+
youtube_channels: array(string2().trim().min(1).max(128)).max(GOOGLE_ASSET_LIMITS.exclusions).default([]),
|
|
8168
|
+
youtube_videos: array(string2().trim().min(1).max(64)).max(GOOGLE_ASSET_LIMITS.exclusions).default([])
|
|
8169
|
+
}).strict().refine((e) => uniq(e.placements) && uniq(e.mobile_app_categories) && uniq(e.content_labels) && uniq(e.mobile_applications) && uniq(e.youtube_channels) && uniq(e.youtube_videos), "exclusions are listed once");
|
|
8170
|
+
var GOOGLE_AD_ACCOUNT_RE = /^\d{3}-\d{3}-\d{4}$/;
|
|
8171
|
+
var GoogleAdAccountId = string2().regex(GOOGLE_AD_ACCOUNT_RE, "a Google Ads account id, 123-456-7890");
|
|
8172
|
+
var AdAccountSettings = object({
|
|
8173
|
+
exclusions: AdAccountExclusions.default(() => ({
|
|
8174
|
+
placements: [],
|
|
8175
|
+
mobile_app_categories: [],
|
|
8176
|
+
content_labels: [],
|
|
8177
|
+
mobile_applications: [],
|
|
8178
|
+
youtube_channels: [],
|
|
8179
|
+
youtube_videos: []
|
|
8180
|
+
}))
|
|
8181
|
+
}).strict();
|
|
7902
8182
|
// ../../packages/growth/src/portfolio.ts
|
|
7903
8183
|
var PORTFOLIO_LIMITS = {
|
|
7904
|
-
weeklyBudgetMicros:
|
|
7905
|
-
founders: ["alexey-scaled-throught", "josh-scaledthought"],
|
|
8184
|
+
weeklyBudgetMicros: 1500000000,
|
|
8185
|
+
founders: ["alexey-scaled", "alexey-scaled-throught", "josh-scaledthought"],
|
|
7906
8186
|
effortDayMicros: 50000000
|
|
7907
8187
|
};
|
|
7908
8188
|
var FUNNEL_STAGES = ["click", "fetch", "signup", "activated", "paid"];
|
|
@@ -7928,6 +8208,7 @@ var EXPERIMENT_METRICS = [
|
|
|
7928
8208
|
"agent_fetches",
|
|
7929
8209
|
"human_visits",
|
|
7930
8210
|
"signups",
|
|
8211
|
+
"landing_signup_rate",
|
|
7931
8212
|
"activation_rate",
|
|
7932
8213
|
"paid_rate",
|
|
7933
8214
|
"topup_request_rate",
|
|
@@ -8019,22 +8300,23 @@ var GOOGLE_AD_LIMITS = {
|
|
|
8019
8300
|
negativeKeywords: 500
|
|
8020
8301
|
};
|
|
8021
8302
|
var CampaignId = string2().regex(CAMPAIGN_ID_RE, "a campaign id, gcm_<ulid>");
|
|
8022
|
-
var
|
|
8303
|
+
var Line2 = (max, what) => string2().trim().min(1).refine((s) => [...s].length <= max, `${what}: at most ${max} characters`);
|
|
8023
8304
|
var Keyword = object({
|
|
8024
|
-
text:
|
|
8305
|
+
text: Line2(GOOGLE_AD_LIMITS.keyword, "keyword").refine((s) => s.split(/\s+/).length <= GOOGLE_AD_LIMITS.keywordWords, `keyword: at most ${GOOGLE_AD_LIMITS.keywordWords} words`),
|
|
8025
8306
|
match: _enum(KEYWORD_MATCH_TYPES)
|
|
8026
8307
|
}).strict();
|
|
8027
8308
|
var SearchAd = object({
|
|
8028
|
-
headlines: array(
|
|
8029
|
-
descriptions: array(
|
|
8030
|
-
path1:
|
|
8031
|
-
path2:
|
|
8309
|
+
headlines: array(Line2(GOOGLE_AD_LIMITS.headline, "headline")).min(GOOGLE_AD_LIMITS.headlinesMin).max(GOOGLE_AD_LIMITS.headlinesMax),
|
|
8310
|
+
descriptions: array(Line2(GOOGLE_AD_LIMITS.description, "description")).min(GOOGLE_AD_LIMITS.descriptionsMin).max(GOOGLE_AD_LIMITS.descriptionsMax),
|
|
8311
|
+
path1: Line2(GOOGLE_AD_LIMITS.path, "path").optional(),
|
|
8312
|
+
path2: Line2(GOOGLE_AD_LIMITS.path, "path").optional()
|
|
8032
8313
|
}).strict().refine((a) => !a.path2 || a.path1, "path2 needs path1");
|
|
8033
8314
|
var AdGroup2 = object({
|
|
8034
8315
|
name: string2().trim().min(1).max(255),
|
|
8035
|
-
keywords: array(Keyword).
|
|
8036
|
-
ads: array(SearchAd).
|
|
8037
|
-
negative_keywords: array(Keyword).max(GOOGLE_AD_LIMITS.negativeKeywords).default([])
|
|
8316
|
+
keywords: array(Keyword).max(GOOGLE_AD_LIMITS.keywordsPerAdGroup),
|
|
8317
|
+
ads: array(SearchAd).max(GOOGLE_AD_LIMITS.adsPerAdGroup),
|
|
8318
|
+
negative_keywords: array(Keyword).max(GOOGLE_AD_LIMITS.negativeKeywords).default([]),
|
|
8319
|
+
audiences: array(string2().trim().min(1).max(255)).max(10).default([])
|
|
8038
8320
|
}).strict();
|
|
8039
8321
|
var CampaignContent = object({
|
|
8040
8322
|
ad_groups: array(AdGroup2).min(1).max(GOOGLE_AD_LIMITS.adGroups),
|
|
@@ -8061,7 +8343,12 @@ var CAMPAIGN_FIELD_SHAPE = {
|
|
|
8061
8343
|
run_to: Day2,
|
|
8062
8344
|
targeting: CampaignTargeting,
|
|
8063
8345
|
content: CampaignContent,
|
|
8064
|
-
notes: string2().trim().max(4000).nullable()
|
|
8346
|
+
notes: string2().trim().max(4000).nullable(),
|
|
8347
|
+
channel: _enum(CAMPAIGN_CHANNELS),
|
|
8348
|
+
bidding: CampaignBidding.nullable(),
|
|
8349
|
+
devices: CampaignDevices,
|
|
8350
|
+
assets: CampaignAssets,
|
|
8351
|
+
display: CampaignDisplay
|
|
8065
8352
|
};
|
|
8066
8353
|
var CampaignFields = object({
|
|
8067
8354
|
...CAMPAIGN_FIELD_SHAPE,
|
|
@@ -8069,7 +8356,12 @@ var CampaignFields = object({
|
|
|
8069
8356
|
ad_account_id: CAMPAIGN_FIELD_SHAPE.ad_account_id.default(null),
|
|
8070
8357
|
daily_budget_micros: CAMPAIGN_FIELD_SHAPE.daily_budget_micros.default(null),
|
|
8071
8358
|
weekly_budget_micros: CAMPAIGN_FIELD_SHAPE.weekly_budget_micros.default(null),
|
|
8072
|
-
notes: CAMPAIGN_FIELD_SHAPE.notes.default(null)
|
|
8359
|
+
notes: CAMPAIGN_FIELD_SHAPE.notes.default(null),
|
|
8360
|
+
channel: CAMPAIGN_FIELD_SHAPE.channel.default("search"),
|
|
8361
|
+
bidding: CAMPAIGN_FIELD_SHAPE.bidding.default(null),
|
|
8362
|
+
devices: CAMPAIGN_FIELD_SHAPE.devices.default(noDeviceAdjustments),
|
|
8363
|
+
assets: CAMPAIGN_FIELD_SHAPE.assets.default(emptyAssets),
|
|
8364
|
+
display: CAMPAIGN_FIELD_SHAPE.display.default(emptyDisplay)
|
|
8073
8365
|
}).strict();
|
|
8074
8366
|
var CampaignFieldsPatch = object(CAMPAIGN_FIELD_SHAPE).partial().strict();
|
|
8075
8367
|
// ../../packages/growth/src/sinks/google.ts
|
|
@@ -8083,18 +8375,94 @@ var ENV3 = {
|
|
|
8083
8375
|
signupAction: "GOOGLE_ADS_SIGNUP_CONVERSION_ACTION_ID",
|
|
8084
8376
|
purchaseAction: "GOOGLE_ADS_PURCHASE_CONVERSION_ACTION_ID",
|
|
8085
8377
|
loginCustomerId: "GOOGLE_ADS_LOGIN_CUSTOMER_ID",
|
|
8086
|
-
validateOnly: "GOOGLE_ADS_CONVERSIONS_VALIDATE_ONLY"
|
|
8378
|
+
validateOnly: "GOOGLE_ADS_CONVERSIONS_VALIDATE_ONLY",
|
|
8379
|
+
routes: "GOOGLE_ADS_CONVERSION_ROUTES",
|
|
8380
|
+
refreshToken2: "GOOGLE_DATA_MANAGER_REFRESH_TOKEN_2",
|
|
8381
|
+
refreshToken3: "GOOGLE_DATA_MANAGER_REFRESH_TOKEN_3"
|
|
8087
8382
|
};
|
|
8383
|
+
var GOOGLE_ROUTE_REFRESH_TOKEN_ENV = [ENV3.refreshToken2, ENV3.refreshToken3];
|
|
8384
|
+
var GOOGLE_ROUTING_ENV = [ENV3.routes, ...GOOGLE_ROUTE_REFRESH_TOKEN_ENV];
|
|
8385
|
+
var CustomerId2 = string2().regex(/^\d{3}-?\d{3}-?\d{4}$/, "a 10-digit Google Ads customer id (dashes allowed)");
|
|
8386
|
+
var ActionId = string2().regex(/^\d{1,20}$/, "a numeric conversion action id");
|
|
8387
|
+
var GoogleConversionRoute = strictObject({
|
|
8388
|
+
codes: array(string2().regex(CODE_RE, "a campaign code")).min(1).max(50),
|
|
8389
|
+
customer_id: CustomerId2,
|
|
8390
|
+
signup_action_id: ActionId,
|
|
8391
|
+
purchase_action_id: ActionId,
|
|
8392
|
+
login_customer_id: CustomerId2.optional(),
|
|
8393
|
+
refresh_token_ref: _enum(GOOGLE_ROUTE_REFRESH_TOKEN_ENV).optional()
|
|
8394
|
+
});
|
|
8395
|
+
var GoogleConversionRoutes = array(GoogleConversionRoute).max(20);
|
|
8088
8396
|
var digits = (s) => (s ?? "").replace(/-/g, "");
|
|
8089
|
-
function
|
|
8090
|
-
const
|
|
8091
|
-
|
|
8092
|
-
|
|
8397
|
+
function parseGoogleConversionRoutes(c) {
|
|
8398
|
+
const raw = c[ENV3.routes]?.trim();
|
|
8399
|
+
if (!raw)
|
|
8400
|
+
return [];
|
|
8401
|
+
let json;
|
|
8402
|
+
try {
|
|
8403
|
+
json = JSON.parse(raw);
|
|
8404
|
+
} catch {
|
|
8405
|
+
throw new Error(`${ENV3.routes} is not valid JSON`);
|
|
8406
|
+
}
|
|
8407
|
+
const parsed = GoogleConversionRoutes.safeParse(json);
|
|
8408
|
+
if (!parsed.success) {
|
|
8409
|
+
const i = parsed.error.issues[0];
|
|
8410
|
+
throw new Error(`${ENV3.routes} is invalid at ${i?.path.join(".") || "(root)"}: ${i?.message ?? "invalid"}`);
|
|
8411
|
+
}
|
|
8412
|
+
const seen = new Set;
|
|
8413
|
+
for (const [i, r] of parsed.data.entries()) {
|
|
8414
|
+
for (const code of r.codes) {
|
|
8415
|
+
if (seen.has(code))
|
|
8416
|
+
throw new Error(`${ENV3.routes}[${i}].codes repeats a code already listed`);
|
|
8417
|
+
seen.add(code);
|
|
8418
|
+
}
|
|
8419
|
+
if (r.refresh_token_ref && !c[r.refresh_token_ref]?.trim())
|
|
8420
|
+
throw new Error(`${ENV3.routes}[${i}].refresh_token_ref names ${r.refresh_token_ref}, which is not set`);
|
|
8421
|
+
}
|
|
8422
|
+
return parsed.data;
|
|
8423
|
+
}
|
|
8424
|
+
function validateGoogleConversionConfig(c) {
|
|
8425
|
+
const check = (name, schema) => {
|
|
8426
|
+
const v = c[name]?.trim();
|
|
8427
|
+
if (v && !schema.safeParse(v).success)
|
|
8428
|
+
throw new Error(`${name} must be digits`);
|
|
8429
|
+
};
|
|
8430
|
+
check(ENV3.customerId, CustomerId2);
|
|
8431
|
+
check(ENV3.loginCustomerId, CustomerId2);
|
|
8432
|
+
check(ENV3.signupAction, ActionId);
|
|
8433
|
+
check(ENV3.purchaseAction, ActionId);
|
|
8434
|
+
parseGoogleConversionRoutes(c);
|
|
8435
|
+
}
|
|
8436
|
+
var defaultDestination = (c) => ({
|
|
8437
|
+
key: "default",
|
|
8438
|
+
customerId: digits(c[ENV3.customerId]),
|
|
8439
|
+
loginCustomerId: digits(c[ENV3.loginCustomerId]),
|
|
8440
|
+
signupActionId: c[ENV3.signupAction] ?? "",
|
|
8441
|
+
purchaseActionId: c[ENV3.purchaseAction] ?? "",
|
|
8442
|
+
refreshTokenEnv: ENV3.refreshToken
|
|
8443
|
+
});
|
|
8444
|
+
function googleDestinationFor(code, routes, c) {
|
|
8445
|
+
const i = code ? routes.findIndex((r) => r.codes.includes(code)) : -1;
|
|
8446
|
+
const r = routes[i];
|
|
8447
|
+
if (!r)
|
|
8448
|
+
return defaultDestination(c);
|
|
8449
|
+
return {
|
|
8450
|
+
key: `route:${i}`,
|
|
8451
|
+
customerId: digits(r.customer_id),
|
|
8452
|
+
loginCustomerId: digits(r.login_customer_id),
|
|
8453
|
+
signupActionId: r.signup_action_id,
|
|
8454
|
+
purchaseActionId: r.purchase_action_id,
|
|
8455
|
+
refreshTokenEnv: r.refresh_token_ref ?? ENV3.refreshToken
|
|
8456
|
+
};
|
|
8457
|
+
}
|
|
8458
|
+
function googleIngestBody(e, c, dest) {
|
|
8459
|
+
const d = dest ?? googleDestinationFor(e.code, parseGoogleConversionRoutes(c), c);
|
|
8460
|
+
const action = e.kind === "signup" ? d.signupActionId : d.purchaseActionId;
|
|
8093
8461
|
return {
|
|
8094
8462
|
destinations: [
|
|
8095
8463
|
{
|
|
8096
|
-
operatingAccount: { accountType: "GOOGLE_ADS", accountId: customerId },
|
|
8097
|
-
...
|
|
8464
|
+
operatingAccount: { accountType: "GOOGLE_ADS", accountId: d.customerId },
|
|
8465
|
+
...d.loginCustomerId ? { loginAccount: { accountType: "GOOGLE_ADS", accountId: d.loginCustomerId } } : {},
|
|
8098
8466
|
productDestinationId: action
|
|
8099
8467
|
}
|
|
8100
8468
|
],
|
|
@@ -8121,22 +8489,40 @@ var googleSink = {
|
|
|
8121
8489
|
ENV3.signupAction,
|
|
8122
8490
|
ENV3.purchaseAction
|
|
8123
8491
|
],
|
|
8124
|
-
optionalCredentialEnv: [ENV3.loginCustomerId, ENV3.validateOnly],
|
|
8492
|
+
optionalCredentialEnv: [ENV3.loginCustomerId, ENV3.validateOnly, ...GOOGLE_ROUTING_ENV],
|
|
8125
8493
|
maxEventAgeDays: 90,
|
|
8126
8494
|
clickWindowDays: 90,
|
|
8495
|
+
validate: validateGoogleConversionConfig,
|
|
8127
8496
|
async send(events, { credentials: c, fetch: f }) {
|
|
8128
|
-
|
|
8129
|
-
|
|
8130
|
-
|
|
8131
|
-
|
|
8132
|
-
|
|
8133
|
-
|
|
8134
|
-
|
|
8497
|
+
let routes;
|
|
8498
|
+
try {
|
|
8499
|
+
routes = parseGoogleConversionRoutes(c);
|
|
8500
|
+
} catch {
|
|
8501
|
+
return events.map(() => ({ status: "retry", errorCode: "google_routes_invalid" }));
|
|
8502
|
+
}
|
|
8503
|
+
const tokens = new Map;
|
|
8504
|
+
const tokenFor = (env) => {
|
|
8505
|
+
let t = tokens.get(env);
|
|
8506
|
+
if (!t) {
|
|
8507
|
+
const refresh = c[env];
|
|
8508
|
+
t = refresh ? refreshAccessToken(f, "google", GOOGLE_TOKEN_URL, {
|
|
8509
|
+
client_id: c[ENV3.clientId],
|
|
8510
|
+
client_secret: c[ENV3.clientSecret],
|
|
8511
|
+
refresh_token: refresh
|
|
8512
|
+
}) : Promise.resolve({ ok: false, result: { status: "retry", errorCode: "google_route_token_missing" } });
|
|
8513
|
+
tokens.set(env, t);
|
|
8514
|
+
}
|
|
8515
|
+
return t;
|
|
8516
|
+
};
|
|
8135
8517
|
return eachEvent(events, async (e) => {
|
|
8518
|
+
const dest = googleDestinationFor(e.code, routes, c);
|
|
8519
|
+
const auth = await tokenFor(dest.refreshTokenEnv);
|
|
8520
|
+
if (!auth.ok)
|
|
8521
|
+
return auth.result;
|
|
8136
8522
|
const r = await request(f, GOOGLE_DATA_MANAGER_URL, {
|
|
8137
8523
|
method: "POST",
|
|
8138
8524
|
headers: { authorization: `Bearer ${auth.token}`, "content-type": "application/json" },
|
|
8139
|
-
body: JSON.stringify(googleIngestBody(e, c))
|
|
8525
|
+
body: JSON.stringify(googleIngestBody(e, c, dest))
|
|
8140
8526
|
});
|
|
8141
8527
|
if (!r.ok)
|
|
8142
8528
|
return { status: "retry", errorCode: `google_${r.error}` };
|
|
@@ -8374,6 +8760,7 @@ var CONVERSION_SINKS = {
|
|
|
8374
8760
|
var CONVERSION_CREDENTIAL_ENV = [
|
|
8375
8761
|
...new Set(Object.values(CONVERSION_SINKS).flatMap((s) => [...s.credentialEnv, ...s.optionalCredentialEnv ?? []]))
|
|
8376
8762
|
].sort();
|
|
8763
|
+
var CONVERSION_ROUTING_ENV = [...GOOGLE_ROUTING_ENV];
|
|
8377
8764
|
var CONVERSION_CLAIM_MS = 30 * 60000;
|
|
8378
8765
|
var PERMANENT_FIRST_PURCHASE_SKIPS = new Set([
|
|
8379
8766
|
"outside_click_window",
|
|
@@ -8386,6 +8773,19 @@ var EXPERIMENTS = {};
|
|
|
8386
8773
|
var EXPERIMENT_KEYS = Object.keys(EXPERIMENTS);
|
|
8387
8774
|
var DEFAULT_EXPERIMENT_KEY = EXPERIMENT_KEYS[0] ?? null;
|
|
8388
8775
|
var EXPERIMENT_PHASES = ["before", "spending", "reading_payment", "payment_read", "tail_read"];
|
|
8776
|
+
// ../../packages/growth/src/funnel.ts
|
|
8777
|
+
var PIPELINE_STAGES = [
|
|
8778
|
+
"site_visits",
|
|
8779
|
+
"go_visits",
|
|
8780
|
+
"signups",
|
|
8781
|
+
"payment_link",
|
|
8782
|
+
"page_opened",
|
|
8783
|
+
"checkout_started",
|
|
8784
|
+
"paid",
|
|
8785
|
+
"first_call",
|
|
8786
|
+
"dashboard_opened"
|
|
8787
|
+
];
|
|
8788
|
+
var PIPELINE_ACCOUNT_STAGES = PIPELINE_STAGES.filter((s) => s !== "site_visits" && s !== "go_visits");
|
|
8389
8789
|
// ../../packages/growth/src/go-hits.ts
|
|
8390
8790
|
var GO_HIT_KINDS = ["human", "agent"];
|
|
8391
8791
|
var GoHit = object({
|
|
@@ -8395,6 +8795,278 @@ var GoHit = object({
|
|
|
8395
8795
|
}).strict();
|
|
8396
8796
|
// ../../packages/growth/src/go-pages.ts
|
|
8397
8797
|
var AD_CLICK_TOKEN_RE = /^[A-Za-z0-9_-]{16,2000}\.[A-Za-z0-9_-]{43}$/;
|
|
8798
|
+
// ../../packages/growth/src/google-ads/reconcile.ts
|
|
8799
|
+
var MANAGED_ASSET_TYPES = new Set(["CALLOUT", "SITELINK", "STRUCTURED_SNIPPET"]);
|
|
8800
|
+
|
|
8801
|
+
// ../../packages/growth/src/google-ads/client.ts
|
|
8802
|
+
var MutateResponse2 = object({
|
|
8803
|
+
mutateOperationResponses: array(record(string2(), object({ resourceName: string2().optional() }).passthrough())).optional()
|
|
8804
|
+
});
|
|
8805
|
+
var AudienceResponse = object({ results: array(object({ resourceName: string2().optional() })).optional() });
|
|
8806
|
+
var Id4 = union([string2(), number2()]).transform(String);
|
|
8807
|
+
var Int = union([string2(), number2()]).optional().nullable().transform((v) => v == null || v === "" ? null : Number(v));
|
|
8808
|
+
var Str = string2().optional().nullable();
|
|
8809
|
+
var Bool = boolean2().optional().nullable();
|
|
8810
|
+
var loose = (shape) => object(shape).passthrough();
|
|
8811
|
+
var CampaignRow2 = loose({
|
|
8812
|
+
customer: loose({ currencyCode: Str, timeZone: Str }).optional(),
|
|
8813
|
+
campaign: loose({
|
|
8814
|
+
resourceName: string2(),
|
|
8815
|
+
id: Id4,
|
|
8816
|
+
name: string2().default(""),
|
|
8817
|
+
status: string2().default("UNKNOWN"),
|
|
8818
|
+
advertisingChannelType: string2().default("UNKNOWN"),
|
|
8819
|
+
biddingStrategyType: string2().default("UNKNOWN"),
|
|
8820
|
+
campaignBudget: Str,
|
|
8821
|
+
startDateTime: Str,
|
|
8822
|
+
endDateTime: Str,
|
|
8823
|
+
targetSpend: loose({ cpcBidCeilingMicros: Int }).optional(),
|
|
8824
|
+
maximizeConversions: loose({ targetCpaMicros: Int }).optional(),
|
|
8825
|
+
networkSettings: loose({
|
|
8826
|
+
targetGoogleSearch: Bool,
|
|
8827
|
+
targetSearchNetwork: Bool,
|
|
8828
|
+
targetContentNetwork: Bool
|
|
8829
|
+
}).optional(),
|
|
8830
|
+
geoTargetTypeSetting: loose({ positiveGeoTargetType: Str }).optional()
|
|
8831
|
+
}),
|
|
8832
|
+
campaignBudget: loose({
|
|
8833
|
+
resourceName: Str,
|
|
8834
|
+
amountMicros: Int,
|
|
8835
|
+
explicitlyShared: Bool,
|
|
8836
|
+
period: Str
|
|
8837
|
+
}).optional()
|
|
8838
|
+
});
|
|
8839
|
+
var Keyword2 = loose({ text: string2(), matchType: string2() }).optional();
|
|
8840
|
+
var CampaignCriterionRow = loose({
|
|
8841
|
+
campaignCriterion: loose({
|
|
8842
|
+
resourceName: string2(),
|
|
8843
|
+
type: string2().default("UNKNOWN"),
|
|
8844
|
+
status: Str,
|
|
8845
|
+
negative: Bool,
|
|
8846
|
+
bidModifier: number2().optional().nullable(),
|
|
8847
|
+
location: loose({ geoTargetConstant: string2() }).optional(),
|
|
8848
|
+
language: loose({ languageConstant: string2() }).optional(),
|
|
8849
|
+
device: loose({ type: string2() }).optional(),
|
|
8850
|
+
keyword: Keyword2,
|
|
8851
|
+
placement: loose({ url: string2() }).optional(),
|
|
8852
|
+
mobileAppCategory: loose({ mobileAppCategoryConstant: string2() }).optional(),
|
|
8853
|
+
contentLabel: loose({ type: string2() }).optional(),
|
|
8854
|
+
customAudience: loose({ customAudience: string2() }).optional()
|
|
8855
|
+
})
|
|
8856
|
+
});
|
|
8857
|
+
var AdGroupRow2 = loose({
|
|
8858
|
+
adGroup: loose({
|
|
8859
|
+
resourceName: string2(),
|
|
8860
|
+
id: Id4,
|
|
8861
|
+
name: string2().default(""),
|
|
8862
|
+
status: string2().default("UNKNOWN"),
|
|
8863
|
+
type: string2().default("UNKNOWN"),
|
|
8864
|
+
cpcBidMicros: Int,
|
|
8865
|
+
optimizedTargetingEnabled: Bool
|
|
8866
|
+
})
|
|
8867
|
+
});
|
|
8868
|
+
var AdGroupCriterionRow = loose({
|
|
8869
|
+
adGroup: loose({ resourceName: string2() }),
|
|
8870
|
+
adGroupCriterion: loose({
|
|
8871
|
+
resourceName: string2(),
|
|
8872
|
+
type: string2().default("UNKNOWN"),
|
|
8873
|
+
status: Str,
|
|
8874
|
+
negative: Bool,
|
|
8875
|
+
keyword: Keyword2,
|
|
8876
|
+
customAudience: loose({ customAudience: string2() }).optional()
|
|
8877
|
+
})
|
|
8878
|
+
});
|
|
8879
|
+
var AdText = array(loose({ text: string2().default("") })).optional();
|
|
8880
|
+
var AdRow = loose({
|
|
8881
|
+
adGroup: loose({ resourceName: string2() }),
|
|
8882
|
+
adGroupAd: loose({
|
|
8883
|
+
resourceName: string2(),
|
|
8884
|
+
status: string2().default("UNKNOWN"),
|
|
8885
|
+
ad: loose({
|
|
8886
|
+
type: string2().default("UNKNOWN"),
|
|
8887
|
+
finalUrls: array(string2()).optional(),
|
|
8888
|
+
responsiveSearchAd: loose({ headlines: AdText, descriptions: AdText, path1: Str, path2: Str }).optional()
|
|
8889
|
+
})
|
|
8890
|
+
})
|
|
8891
|
+
});
|
|
8892
|
+
var CampaignAssetRow = loose({
|
|
8893
|
+
campaignAsset: loose({ resourceName: string2(), status: string2().default("UNKNOWN"), fieldType: string2() }),
|
|
8894
|
+
asset: loose({
|
|
8895
|
+
resourceName: string2(),
|
|
8896
|
+
finalUrls: array(string2()).optional(),
|
|
8897
|
+
calloutAsset: loose({ calloutText: string2() }).optional(),
|
|
8898
|
+
sitelinkAsset: loose({ linkText: string2(), description1: Str, description2: Str }).optional(),
|
|
8899
|
+
structuredSnippetAsset: loose({ header: string2(), values: array(string2()).default([]) }).optional()
|
|
8900
|
+
})
|
|
8901
|
+
});
|
|
8902
|
+
var AudienceRow = loose({
|
|
8903
|
+
customAudience: loose({
|
|
8904
|
+
resourceName: string2(),
|
|
8905
|
+
name: string2().default(""),
|
|
8906
|
+
type: string2().default("UNKNOWN"),
|
|
8907
|
+
status: Str,
|
|
8908
|
+
members: array(loose({
|
|
8909
|
+
memberType: string2().default("UNKNOWN"),
|
|
8910
|
+
keyword: Str,
|
|
8911
|
+
url: Str,
|
|
8912
|
+
app: Str,
|
|
8913
|
+
placeCategory: union([string2(), number2()]).optional().nullable()
|
|
8914
|
+
})).optional()
|
|
8915
|
+
})
|
|
8916
|
+
});
|
|
8917
|
+
var NegativeRow = loose({
|
|
8918
|
+
customerNegativeCriterion: loose({
|
|
8919
|
+
resourceName: string2(),
|
|
8920
|
+
type: string2().default("UNKNOWN"),
|
|
8921
|
+
placement: loose({ url: string2() }).optional(),
|
|
8922
|
+
mobileAppCategory: loose({ mobileAppCategoryConstant: string2() }).optional(),
|
|
8923
|
+
contentLabel: loose({ type: string2() }).optional(),
|
|
8924
|
+
mobileApplication: loose({ appId: string2() }).optional(),
|
|
8925
|
+
youtubeChannel: loose({ channelId: string2() }).optional(),
|
|
8926
|
+
youtubeVideo: loose({ videoId: string2() }).optional()
|
|
8927
|
+
})
|
|
8928
|
+
});
|
|
8929
|
+
var CurrencyRow = loose({ customer: loose({ currencyCode: Str, timeZone: Str }).optional() });
|
|
8930
|
+
var NEG_TYPES = new Set([
|
|
8931
|
+
"PLACEMENT",
|
|
8932
|
+
"MOBILE_APP_CATEGORY",
|
|
8933
|
+
"CONTENT_LABEL",
|
|
8934
|
+
"MOBILE_APPLICATION",
|
|
8935
|
+
"YOUTUBE_CHANNEL",
|
|
8936
|
+
"YOUTUBE_VIDEO"
|
|
8937
|
+
]);
|
|
8938
|
+
// ../../packages/growth/src/insights-core.ts
|
|
8939
|
+
var VISITOR_COOKIE_MAX_AGE_S = 395 * 24 * 3600;
|
|
8940
|
+
var SESSION_IDLE_S = 30 * 60;
|
|
8941
|
+
var INSIGHTS_ID_RE = /^[A-Za-z0-9_-]{22}$/;
|
|
8942
|
+
var INSIGHTS_MAX_EVENTS_PER_BATCH = 50;
|
|
8943
|
+
var REPLAY_CHUNK_MAX_BYTES = 400000;
|
|
8944
|
+
var REPLAY_MAX_CHUNKS_PER_SEGMENT = 360;
|
|
8945
|
+
|
|
8946
|
+
// ../../packages/growth/src/insights.ts
|
|
8947
|
+
var TRACKED_COUNTRIES = ["US", "CA"];
|
|
8948
|
+
var Ms = number2().int().nonnegative();
|
|
8949
|
+
var Path = string2().regex(/^\/[^\s?#]{0,199}$/);
|
|
8950
|
+
var Selector = string2().min(1).max(200);
|
|
8951
|
+
var Px = number2().int().min(0).max(1e5);
|
|
8952
|
+
var Tag = string2().regex(/^[A-Za-z0-9._-]{1,60}$/).optional();
|
|
8953
|
+
var Variant = string2().regex(/^[a-z0-9][a-z0-9-]{0,39}$/).optional();
|
|
8954
|
+
var Base = { t: Ms, p: Path };
|
|
8955
|
+
var Pointer = {
|
|
8956
|
+
...Base,
|
|
8957
|
+
s: Selector,
|
|
8958
|
+
x: number2().int().min(0).max(1e4),
|
|
8959
|
+
y: Px,
|
|
8960
|
+
vw: Px,
|
|
8961
|
+
vh: Px,
|
|
8962
|
+
dh: Px
|
|
8963
|
+
};
|
|
8964
|
+
var BrowserEvent = discriminatedUnion("k", [
|
|
8965
|
+
object({
|
|
8966
|
+
k: literal("pageview"),
|
|
8967
|
+
...Base,
|
|
8968
|
+
r: string2().regex(/^[a-z0-9.-]{1,100}$/).optional(),
|
|
8969
|
+
q: object({ source: Tag, utm_source: Tag, utm_medium: Tag, utm_campaign: Tag }).strict().optional(),
|
|
8970
|
+
vw: Px,
|
|
8971
|
+
vh: Px,
|
|
8972
|
+
v: Variant
|
|
8973
|
+
}).strict(),
|
|
8974
|
+
object({ k: literal("click"), ...Pointer }).strict(),
|
|
8975
|
+
object({ k: literal("rage_click"), ...Pointer }).strict(),
|
|
8976
|
+
object({ k: literal("dead_click"), ...Pointer }).strict(),
|
|
8977
|
+
object({ k: literal("scroll"), ...Base, d: number2().int().min(0).max(100), dh: Px }).strict(),
|
|
8978
|
+
object({ k: literal("leave"), ...Base, ms: number2().int().min(0).max(86400000) }).strict()
|
|
8979
|
+
]);
|
|
8980
|
+
var INSIGHTS_EVENT_KINDS = ["pageview", "click", "rage_click", "dead_click", "scroll", "leave"];
|
|
8981
|
+
var BrowserBatch = object({
|
|
8982
|
+
v: literal(1),
|
|
8983
|
+
h: _enum(["site", "dashboard"]),
|
|
8984
|
+
e: array(BrowserEvent).min(1).max(INSIGHTS_MAX_EVENTS_PER_BATCH)
|
|
8985
|
+
}).strict();
|
|
8986
|
+
var DEVICE_CLASSES = ["desktop", "mobile", "tablet"];
|
|
8987
|
+
var BROWSER_FAMILIES = ["chrome", "safari", "firefox", "edge", "opera", "samsung", "other"];
|
|
8988
|
+
var InsightsEvent = object({
|
|
8989
|
+
kind: _enum(INSIGHTS_EVENT_KINDS),
|
|
8990
|
+
at: exports_iso.datetime(),
|
|
8991
|
+
path: Path,
|
|
8992
|
+
selector: Selector.optional(),
|
|
8993
|
+
x: number2().int().min(0).max(1e4).optional(),
|
|
8994
|
+
y: Px.optional(),
|
|
8995
|
+
vw: Px.optional(),
|
|
8996
|
+
vh: Px.optional(),
|
|
8997
|
+
doc_h: Px.optional(),
|
|
8998
|
+
scroll_pct: number2().int().min(0).max(100).optional(),
|
|
8999
|
+
duration_ms: number2().int().min(0).max(86400000).optional(),
|
|
9000
|
+
source: string2().max(110).optional(),
|
|
9001
|
+
code: string2().regex(CODE_RE).optional(),
|
|
9002
|
+
variant: Variant
|
|
9003
|
+
}).strict();
|
|
9004
|
+
var InsightsHit = object({
|
|
9005
|
+
insights: object({
|
|
9006
|
+
visitor: string2().regex(INSIGHTS_ID_RE),
|
|
9007
|
+
session: string2().regex(INSIGHTS_ID_RE),
|
|
9008
|
+
surface: _enum(["site", "dashboard"]),
|
|
9009
|
+
country: _enum(TRACKED_COUNTRIES),
|
|
9010
|
+
device: _enum(DEVICE_CLASSES),
|
|
9011
|
+
browser: _enum(BROWSER_FAMILIES),
|
|
9012
|
+
ip: string2().regex(/^[0-9a-fA-F:.]{2,45}$/).optional(),
|
|
9013
|
+
events: array(InsightsEvent).min(1).max(INSIGHTS_MAX_EVENTS_PER_BATCH)
|
|
9014
|
+
}).strict()
|
|
9015
|
+
}).strict();
|
|
9016
|
+
var InsightsForgetHit = object({ insights_forget: object({ visitor: string2().regex(INSIGHTS_ID_RE) }).strict() }).strict();
|
|
9017
|
+
var ReplayHit = object({
|
|
9018
|
+
replay: object({
|
|
9019
|
+
visitor: string2().regex(INSIGHTS_ID_RE),
|
|
9020
|
+
session: string2().regex(INSIGHTS_ID_RE),
|
|
9021
|
+
segment: string2().regex(INSIGHTS_ID_RE),
|
|
9022
|
+
seq: number2().int().min(0).max(REPLAY_MAX_CHUNKS_PER_SEGMENT - 1),
|
|
9023
|
+
surface: _enum(["site", "dashboard"]),
|
|
9024
|
+
country: _enum(TRACKED_COUNTRIES),
|
|
9025
|
+
device: _enum(DEVICE_CLASSES),
|
|
9026
|
+
browser: _enum(BROWSER_FAMILIES),
|
|
9027
|
+
path: Path,
|
|
9028
|
+
data: string2().regex(/^[A-Za-z0-9+/]+={0,2}$/).max(Math.ceil(REPLAY_CHUNK_MAX_BYTES / 3) * 4)
|
|
9029
|
+
}).strict()
|
|
9030
|
+
}).strict();
|
|
9031
|
+
// ../../packages/growth/src/landing.ts
|
|
9032
|
+
var LANDING_VARIANT_ID_RE = /^glv_[0-9A-HJKMNP-TV-Z]{26}$/;
|
|
9033
|
+
var LandingVariantId = string2().regex(LANDING_VARIANT_ID_RE, "a landing variant id, glv_<ulid>");
|
|
9034
|
+
var LANDING_CTAS = ["agent_prompt", "cli_command", "browser_signup"];
|
|
9035
|
+
var LANDING_SNIPPETS = ["curl", "openai_sdk"];
|
|
9036
|
+
var LANDING_MOBILE_ORDERS = ["browser_signup_first", "same_as_desktop"];
|
|
9037
|
+
var LANDING_LIMITS = { name: 80, headline: 90, subhead: 240, bullet: 120, bullets: 4, trust: 240 };
|
|
9038
|
+
var LANDING_WEIGHT_MAX = 1000;
|
|
9039
|
+
var UNSAFE_TEXT = /[<>`*_[\]{}|\\#~^]|:\/\/|www\.|[\u0000-\u001f\u007f-\u009f---]/i;
|
|
9040
|
+
var plain = (min, max) => string2().trim().min(min).max(max).refine((s) => !UNSAFE_TEXT.test(s), "plain text only: no markup, links, templates or control characters");
|
|
9041
|
+
var LANDING_MODEL_ID_RE = /^[a-z0-9]+(-[a-z0-9]+){0,8}$/;
|
|
9042
|
+
var LandingContent = object({
|
|
9043
|
+
headline: plain(8, LANDING_LIMITS.headline),
|
|
9044
|
+
subhead: plain(1, LANDING_LIMITS.subhead).nullable().default(null),
|
|
9045
|
+
bullets: array(plain(3, LANDING_LIMITS.bullet)).max(LANDING_LIMITS.bullets).default([]),
|
|
9046
|
+
primary_cta: _enum(LANDING_CTAS).default("agent_prompt"),
|
|
9047
|
+
mobile_cta_order: _enum(LANDING_MOBILE_ORDERS).default("browser_signup_first"),
|
|
9048
|
+
snippet: _enum(LANDING_SNIPPETS).nullable().default(null),
|
|
9049
|
+
price_model_id: string2().regex(LANDING_MODEL_ID_RE).max(64).nullable().default(null),
|
|
9050
|
+
trust_line: plain(1, LANDING_LIMITS.trust).nullable().default(null)
|
|
9051
|
+
}).strict();
|
|
9052
|
+
var NOT_USAGE = String.raw`(?![\s-]+(?:for|credits?|tokens?|tiers?|trials?|usage|plans?|access|calls?|requests?|inference|api|models?|allowance|minutes?|hours?|days?|weeks?|months?)\b)`;
|
|
9053
|
+
var SIGN_UP = "(?:sign(?:ing)?[- ]?up)";
|
|
9054
|
+
var SIGNUP_FREE_RE = new RegExp([
|
|
9055
|
+
String.raw`\b${SIGN_UP}\s+(?:for\s+)?free\b${NOT_USAGE}`,
|
|
9056
|
+
String.raw`\bfree\s+to\s+(?:${SIGN_UP}|create\s+an\s+account)\b`,
|
|
9057
|
+
String.raw`\b(?:${SIGN_UP}|creating\s+an\s+account)\s+is\s+free\b${NOT_USAGE}`
|
|
9058
|
+
].join("|"), "gi");
|
|
9059
|
+
var LandingServeVariant = object({
|
|
9060
|
+
code: string2().regex(CODE_RE),
|
|
9061
|
+
weight: number2().int().min(1).max(LANDING_WEIGHT_MAX),
|
|
9062
|
+
sha256: string2().regex(/^[0-9a-f]{64}$/),
|
|
9063
|
+
content: LandingContent
|
|
9064
|
+
}).strict();
|
|
9065
|
+
var LandingServe = object({
|
|
9066
|
+
code: string2().regex(CODE_RE),
|
|
9067
|
+
parent: string2().regex(CODE_RE).nullable(),
|
|
9068
|
+
variants: array(LandingServeVariant).max(20)
|
|
9069
|
+
}).strict();
|
|
8398
9070
|
// ../../packages/growth/src/platforms/carbon.ts
|
|
8399
9071
|
var carbonAds = defineCsvSource({
|
|
8400
9072
|
platform: "carbon",
|
|
@@ -8442,8 +9114,8 @@ var EthicalAdsCredentials = object({
|
|
|
8442
9114
|
api_key: string2().min(1),
|
|
8443
9115
|
advertiser: string2().trim().regex(/^[a-z0-9_-]{1,100}$/i)
|
|
8444
9116
|
});
|
|
8445
|
-
var
|
|
8446
|
-
var ethicalAdsApiAccount = (creds) =>
|
|
9117
|
+
var credentials2 = (creds) => parseCredentialsJson(creds[ENV7], EthicalAdsCredentials);
|
|
9118
|
+
var ethicalAdsApiAccount = (creds) => credentials2(creds).advertiser;
|
|
8447
9119
|
var Num3 = union([number2(), string2()]).nullable().optional();
|
|
8448
9120
|
var Day3 = object({ date: string2().optional(), index: string2().optional(), views: Num3, clicks: Num3, cost: Num3 });
|
|
8449
9121
|
var Report = object({
|
|
@@ -8457,7 +9129,7 @@ var Report = object({
|
|
|
8457
9129
|
var dayOf2 = (d) => (d.date ?? d.index ?? "").slice(0, 10);
|
|
8458
9130
|
async function pullEthicalAds(range, ctx) {
|
|
8459
9131
|
checkRange(range);
|
|
8460
|
-
const c =
|
|
9132
|
+
const c = credentials2(ctx.credentials);
|
|
8461
9133
|
const q = new URLSearchParams({ start_date: range.from, end_date: range.to });
|
|
8462
9134
|
const report = await httpJson(ctx.fetch, `${API3}/advertisers/${encodeURIComponent(c.advertiser)}/report/?${q}`, Report, { headers: { authorization: `Token ${c.api_key}` } });
|
|
8463
9135
|
const rows = [];
|
|
@@ -8520,7 +9192,7 @@ var googleAds = defineCsvSource({
|
|
|
8520
9192
|
normalizeAccountId: googleAccountId,
|
|
8521
9193
|
totalPrefix: "total",
|
|
8522
9194
|
accountTotalLabel: "total: account",
|
|
8523
|
-
exportHint: "In Google Ads, open Campaigns > Ad groups,
|
|
9195
|
+
exportHint: "In Google Ads, open Campaigns > Ad groups, choose the dates, Segment > Time > Day, add the Campaign ID and Ad " + "group ID columns (Attributes), remove filters, then Download > .csv. Give the ad account id (123-456-7890, top " + "right) on import: the table has no Customer ID column."
|
|
8524
9196
|
});
|
|
8525
9197
|
|
|
8526
9198
|
// ../../packages/growth/src/platforms/linkedin.ts
|
|
@@ -8563,8 +9235,8 @@ var LinkedInCredentials = object({
|
|
|
8563
9235
|
client_secret: string2().min(1).optional(),
|
|
8564
9236
|
refresh_token: string2().min(1).optional()
|
|
8565
9237
|
}).refine((c) => c.access_token || c.client_id && c.client_secret && c.refresh_token);
|
|
8566
|
-
var
|
|
8567
|
-
var linkedInApiAccount = (creds) =>
|
|
9238
|
+
var credentials3 = (creds) => parseCredentialsJson(creds[ENV8], LinkedInCredentials);
|
|
9239
|
+
var linkedInApiAccount = (creds) => credentials3(creds).account_id;
|
|
8568
9240
|
var Token3 = object({ access_token: string2().min(1) });
|
|
8569
9241
|
async function accessToken(c, f) {
|
|
8570
9242
|
if (!c.refresh_token)
|
|
@@ -8615,7 +9287,7 @@ var Element = object({
|
|
|
8615
9287
|
var Analytics = object({ elements: array(Element) });
|
|
8616
9288
|
async function pullLinkedInAds(range, ctx) {
|
|
8617
9289
|
checkRange(range);
|
|
8618
|
-
const c =
|
|
9290
|
+
const c = credentials3(ctx.credentials);
|
|
8619
9291
|
const token = await accessToken(c, ctx.fetch);
|
|
8620
9292
|
const headers = {
|
|
8621
9293
|
authorization: `Bearer ${token}`,
|
|
@@ -8696,8 +9368,8 @@ var MetaCredentials = object({
|
|
|
8696
9368
|
access_token: string2().min(1),
|
|
8697
9369
|
ad_account_id: string2().trim().regex(/^(act_)?\d{1,30}$/).transform((s) => s.replace(/^act_/, ""))
|
|
8698
9370
|
});
|
|
8699
|
-
var
|
|
8700
|
-
var metaApiAccount = (creds) =>
|
|
9371
|
+
var credentials4 = (creds) => parseCredentialsJson(creds[ENV9], MetaCredentials);
|
|
9372
|
+
var metaApiAccount = (creds) => credentials4(creds).ad_account_id;
|
|
8701
9373
|
var Account3 = object({ currency: string2() });
|
|
8702
9374
|
var Insight = object({
|
|
8703
9375
|
date_start: string2(),
|
|
@@ -8747,7 +9419,7 @@ function nextUrl(next) {
|
|
|
8747
9419
|
}
|
|
8748
9420
|
async function pullMetaAds(range, ctx) {
|
|
8749
9421
|
checkRange(range);
|
|
8750
|
-
const c =
|
|
9422
|
+
const c = credentials4(ctx.credentials);
|
|
8751
9423
|
const account = await metaJson(ctx.fetch, `${API5}/act_${c.ad_account_id}?fields=currency`, c.access_token, Account3);
|
|
8752
9424
|
assertUsd(account.currency);
|
|
8753
9425
|
const q = new URLSearchParams({
|
|
@@ -8819,8 +9491,8 @@ var RedditCredentials = object({
|
|
|
8819
9491
|
ad_account_id: string2().trim().regex(/^[A-Za-z0-9_-]{1,64}$/),
|
|
8820
9492
|
user_agent: string2().min(1).max(200).optional()
|
|
8821
9493
|
});
|
|
8822
|
-
var
|
|
8823
|
-
var redditApiAccount = (creds) =>
|
|
9494
|
+
var credentials5 = (creds) => parseCredentialsJson(creds[ENV10], RedditCredentials);
|
|
9495
|
+
var redditApiAccount = (creds) => credentials5(creds).ad_account_id;
|
|
8824
9496
|
var Token4 = object({ access_token: string2().min(1) });
|
|
8825
9497
|
async function accessToken2(c, f) {
|
|
8826
9498
|
try {
|
|
@@ -8874,7 +9546,7 @@ function nextUrl2(next) {
|
|
|
8874
9546
|
}
|
|
8875
9547
|
async function pullRedditAds(range, ctx) {
|
|
8876
9548
|
checkRange(range);
|
|
8877
|
-
const c =
|
|
9549
|
+
const c = credentials5(ctx.credentials);
|
|
8878
9550
|
const token = await accessToken2(c, ctx.fetch);
|
|
8879
9551
|
const headers = { authorization: `Bearer ${token}`, "user-agent": c.user_agent ?? DEFAULT_USER_AGENT };
|
|
8880
9552
|
const acct = encodeURIComponent(c.ad_account_id);
|
|
@@ -8967,8 +9639,8 @@ var XCredentials = object({
|
|
|
8967
9639
|
access_token_secret: string2().min(1),
|
|
8968
9640
|
account_id: string2().trim().regex(/^[A-Za-z0-9]{1,32}$/)
|
|
8969
9641
|
});
|
|
8970
|
-
var
|
|
8971
|
-
var xApiAccount = (creds) =>
|
|
9642
|
+
var credentials6 = (creds) => parseCredentialsJson(creds[ENV11], XCredentials);
|
|
9643
|
+
var xApiAccount = (creds) => credentials6(creds).account_id;
|
|
8972
9644
|
function zonedMidnightUtc(day, tz) {
|
|
8973
9645
|
const fmt = new Intl.DateTimeFormat("en-US", {
|
|
8974
9646
|
timeZone: tz,
|
|
@@ -9001,13 +9673,18 @@ var Stats = object({
|
|
|
9001
9673
|
data: array(object({
|
|
9002
9674
|
id: string2(),
|
|
9003
9675
|
id_data: array(object({
|
|
9004
|
-
metrics: object({
|
|
9676
|
+
metrics: object({
|
|
9677
|
+
impressions: Series,
|
|
9678
|
+
link_clicks: Series,
|
|
9679
|
+
url_clicks: Series,
|
|
9680
|
+
billed_charge_local_micro: Series
|
|
9681
|
+
})
|
|
9005
9682
|
}))
|
|
9006
9683
|
}))
|
|
9007
9684
|
});
|
|
9008
9685
|
async function pullXAds(range, ctx) {
|
|
9009
9686
|
checkRange(range);
|
|
9010
|
-
const c =
|
|
9687
|
+
const c = credentials6(ctx.credentials);
|
|
9011
9688
|
const oauth = {
|
|
9012
9689
|
consumerKey: c.consumer_key,
|
|
9013
9690
|
consumerSecret: c.consumer_secret,
|
|
@@ -9066,6 +9743,7 @@ async function pullXAds(range, ctx) {
|
|
|
9066
9743
|
const campaignId = li?.campaign_id ?? d.id;
|
|
9067
9744
|
for (const s of d.id_data) {
|
|
9068
9745
|
const m = s.metrics;
|
|
9746
|
+
const linkClicks = m.link_clicks ?? m.url_clicks;
|
|
9069
9747
|
for (let k = 0;k < days; k++) {
|
|
9070
9748
|
rows.push(row("x", {
|
|
9071
9749
|
day: addDays(start, k),
|
|
@@ -9074,7 +9752,7 @@ async function pullXAds(range, ctx) {
|
|
|
9074
9752
|
adGroupId: d.id,
|
|
9075
9753
|
names: { campaign: campaigns.get(campaignId)?.name ?? null, adGroup: li?.name ?? null, ad: null },
|
|
9076
9754
|
impressions: count(m.impressions?.[k]),
|
|
9077
|
-
clicks: count(
|
|
9755
|
+
clicks: count(linkClicks?.[k]),
|
|
9078
9756
|
spendMicros: m.billed_charge_local_micro?.[k] == null ? 0 : intMicros(m.billed_charge_local_micro[k])
|
|
9079
9757
|
}));
|
|
9080
9758
|
}
|
|
@@ -9090,7 +9768,10 @@ async function pullXAds(range, ctx) {
|
|
|
9090
9768
|
function withApi(source, platform, pull, apiAccount) {
|
|
9091
9769
|
return { ...source, pull, apiAccount, credentialEnv: [SPEND_CREDENTIAL_ENV[platform]] };
|
|
9092
9770
|
}
|
|
9093
|
-
var googleAds2 =
|
|
9771
|
+
var googleAds2 = {
|
|
9772
|
+
...withApi(googleAds, "google", pullGoogleAds, googleApiAccount),
|
|
9773
|
+
apiAccounts: googleApiAccounts
|
|
9774
|
+
};
|
|
9094
9775
|
var redditAds2 = withApi(redditAds, "reddit", pullRedditAds, redditApiAccount);
|
|
9095
9776
|
var xAds2 = withApi(xAds, "x", pullXAds, xApiAccount);
|
|
9096
9777
|
var ethicalAds2 = withApi(ethicalAds, "ethicalads", pullEthicalAds, ethicalAdsApiAccount);
|
|
@@ -9289,8 +9970,34 @@ var GrowthResults = object({
|
|
|
9289
9970
|
summary: string2(),
|
|
9290
9971
|
decisions: array(GrowthDecision)
|
|
9291
9972
|
});
|
|
9973
|
+
// ../../packages/growth/src/site-visits.ts
|
|
9974
|
+
var SITE_PATH_RE = /^\/[a-z0-9._~/-]{0,99}$/;
|
|
9975
|
+
var OTHER_PATH = "(other)";
|
|
9976
|
+
var SECTION_OTHER_RE = /^\/[a-z0-9._~-]{1,80}\/\(other\)$/;
|
|
9977
|
+
var SOURCE_RE = /^(?=.{1,100}$)[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)+$/;
|
|
9978
|
+
var TAG_SOURCE_RE = /^tag:[a-z0-9][a-z0-9._-]{0,39}$/;
|
|
9979
|
+
var COUNTRY_RE = /^[A-Z]{2}$/;
|
|
9980
|
+
var SiteVisit = object({
|
|
9981
|
+
path: union([string2().regex(SITE_PATH_RE), string2().regex(SECTION_OTHER_RE), literal(OTHER_PATH)]),
|
|
9982
|
+
source: union([
|
|
9983
|
+
string2().regex(SOURCE_RE),
|
|
9984
|
+
string2().regex(TAG_SOURCE_RE),
|
|
9985
|
+
literal("direct"),
|
|
9986
|
+
literal("internal")
|
|
9987
|
+
]),
|
|
9988
|
+
country: string2().regex(COUNTRY_RE),
|
|
9989
|
+
kind: _enum(["human", "agent"])
|
|
9990
|
+
}).strict();
|
|
9991
|
+
var SiteVisitHit = object({ visit: SiteVisit }).strict();
|
|
9992
|
+
var IP_RE = /^[0-9a-fA-F:.]{2,45}$/;
|
|
9993
|
+
var SiteTouch = object({
|
|
9994
|
+
ip: string2().regex(IP_RE),
|
|
9995
|
+
path: SiteVisit.shape.path,
|
|
9996
|
+
source: SiteVisit.shape.source
|
|
9997
|
+
}).strict();
|
|
9998
|
+
var SiteTouchHit = object({ touch: SiteTouch }).strict();
|
|
9292
9999
|
// ../../packages/schemas/src/legal.ts
|
|
9293
|
-
var TERMS_VERSION = "2026-10-
|
|
10000
|
+
var TERMS_VERSION = "2026-10-13";
|
|
9294
10001
|
var LEGAL_SITE = "https://scaledthought.com";
|
|
9295
10002
|
var LEGAL_PATHS = {
|
|
9296
10003
|
index: "/legal",
|
|
@@ -9806,6 +10513,18 @@ var CREDIT_STEPS = [
|
|
|
9806
10513
|
`3. If opened_in_browser is false (or it's still unpaid after ${WAIT_PATIENCE_MIN} minutes), end your turn with message_for_human: it holds the approval_url exactly as printed. When they're back, run ${WAIT_COMMAND}. Either way, don't retry the call and don't create another account.`,
|
|
9807
10514
|
"4. Then make the call below."
|
|
9808
10515
|
];
|
|
10516
|
+
var OWNER_EMAIL_QUESTION = "What email should own this account? You'll use it to sign in to the ScaledThought dashboard (billing, credits, keys). We only send it account email, such as this confirmation, sign-in links and security notices, never marketing.";
|
|
10517
|
+
var OWNER_EMAIL_COMMAND = `${NPX} account email set <their email>`;
|
|
10518
|
+
var OWNER_EMAIL_STEP = `This account has no owner email yet. Ask your human one question: "${OWNER_EMAIL_QUESTION}" Then run: ${OWNER_EMAIL_COMMAND} (we email them one confirmation link; relay message_for_human). If they'd rather not, carry on without it.`;
|
|
10519
|
+
function ownerEmailFields(given, r) {
|
|
10520
|
+
const owner = r.owner_email ?? (r.email_confirmation === "sent" ? "pending" : given ? undefined : "none");
|
|
10521
|
+
return {
|
|
10522
|
+
...owner ? { owner_email: owner } : {},
|
|
10523
|
+
...r.email_confirmation ? { email_confirmation: r.email_confirmation } : {},
|
|
10524
|
+
...r.message_for_human ? { message_for_human: r.message_for_human } : {},
|
|
10525
|
+
...owner === "none" ? { missing: ["owner_email"], owner_email_hint: OWNER_EMAIL_STEP } : {}
|
|
10526
|
+
};
|
|
10527
|
+
}
|
|
9809
10528
|
function nextSteps(model, needsCredits) {
|
|
9810
10529
|
return [
|
|
9811
10530
|
...needsCredits ? CREDIT_STEPS : [],
|
|
@@ -9869,16 +10588,29 @@ async function init(ctx, opts) {
|
|
|
9869
10588
|
const where = envKey ? "ST_API_KEY environment variable" : ".env (ST_API_KEY, ST_BASE_URL)";
|
|
9870
10589
|
if (opts.region && opts.region !== region)
|
|
9871
10590
|
throw new CliError("region_mismatch", `A ${region} key already exists (${where}) but --region ${opts.region} was requested. Nothing was created.`, `Accounts are pinned to one region. Use the existing ${region} account, or run init in a directory with no ST_API_KEY (and no ST_API_KEY in the environment) to create a separate ${opts.region} account.`, { existing_region: region, requested_region: opts.region });
|
|
9872
|
-
const status = await
|
|
10591
|
+
const status = await account2(ctx);
|
|
9873
10592
|
const ignored = [opts.source !== undefined && "--source", opts.adClick !== undefined && "--ad-click"].filter(Boolean);
|
|
9874
10593
|
const shown = withoutFreeFields(status);
|
|
10594
|
+
const summary = await liveSummary(ctx, region, balanceOf(status));
|
|
10595
|
+
const noOwner = status.owner_email === "none";
|
|
10596
|
+
const warnings = [
|
|
10597
|
+
...ignored.length ? [`${ignored.join(" and ")} apply only to a new account and were not sent.`] : [],
|
|
10598
|
+
...opts.email !== undefined ? [
|
|
10599
|
+
`--email applies only to a new account and was not sent. To name this account's owner, run: ${OWNER_EMAIL_COMMAND}`
|
|
10600
|
+
] : []
|
|
10601
|
+
];
|
|
9875
10602
|
return {
|
|
9876
10603
|
already_initialized: true,
|
|
9877
10604
|
...shown,
|
|
9878
10605
|
key_saved_to: where,
|
|
9879
10606
|
terms: termsOf(),
|
|
9880
|
-
...
|
|
9881
|
-
...
|
|
10607
|
+
...summary,
|
|
10608
|
+
...noOwner ? {
|
|
10609
|
+
missing: ["owner_email"],
|
|
10610
|
+
owner_email_hint: OWNER_EMAIL_STEP,
|
|
10611
|
+
next_steps: [OWNER_EMAIL_STEP, ...summary.next_steps]
|
|
10612
|
+
} : {},
|
|
10613
|
+
...warnings.length ? { warnings } : {}
|
|
9882
10614
|
};
|
|
9883
10615
|
}
|
|
9884
10616
|
if (opts.account && opts.newAccount)
|
|
@@ -9906,6 +10638,8 @@ async function init(ctx, opts) {
|
|
|
9906
10638
|
const { saved, existingCode } = await afterNewAccount(ctx, { ...acct, name: opts.name }, { noSave: opts.noSave });
|
|
9907
10639
|
const keyed = { ...ctx, env: { ...ctx.env, ST_API_KEY: acct.api_key } };
|
|
9908
10640
|
const billing = await api(keyed, "GET", "/v1/billing").catch(() => null);
|
|
10641
|
+
const owner = ownerEmailFields(opts.email !== undefined, acct);
|
|
10642
|
+
const summary = await liveSummary(keyed, acct.region, balanceOf(billing));
|
|
9909
10643
|
return {
|
|
9910
10644
|
already_initialized: false,
|
|
9911
10645
|
account_id: acct.account_id,
|
|
@@ -9919,7 +10653,9 @@ async function init(ctx, opts) {
|
|
|
9919
10653
|
...existingCode ? { existing_account_code: existingCode, existing_account_hint: existingAccountHint(existingCode) } : {},
|
|
9920
10654
|
terms: termsOf(acct),
|
|
9921
10655
|
...attribution.source ? { source: acct.source ?? attribution.source } : {},
|
|
9922
|
-
...
|
|
10656
|
+
...owner,
|
|
10657
|
+
...summary,
|
|
10658
|
+
...owner.missing ? { next_steps: [OWNER_EMAIL_STEP, ...summary.next_steps] } : {},
|
|
9923
10659
|
...attribution.warnings.length ? { warnings: attribution.warnings } : {}
|
|
9924
10660
|
};
|
|
9925
10661
|
}
|
|
@@ -10001,7 +10737,7 @@ function withoutFreeFields(o) {
|
|
|
10001
10737
|
}
|
|
10002
10738
|
return out;
|
|
10003
10739
|
}
|
|
10004
|
-
async function
|
|
10740
|
+
async function account2(ctx) {
|
|
10005
10741
|
const a = withoutFreeFields(await api(ctx, "GET", "/v1/account"));
|
|
10006
10742
|
const fields = ["balance_usd", "auto_reload"];
|
|
10007
10743
|
if (fields.every((f) => (f in a)))
|
|
@@ -10020,6 +10756,16 @@ async function accountDelete(ctx, o) {
|
|
|
10020
10756
|
throw new CliError("bad_argument", "--confirm must be your account id (acct_...).", "Find it with `account`.");
|
|
10021
10757
|
return api(ctx, "DELETE", "/v1/account", { body: { confirm: o.confirm } });
|
|
10022
10758
|
}
|
|
10759
|
+
async function accountEmailSet(ctx, address) {
|
|
10760
|
+
const email = address.trim();
|
|
10761
|
+
if (!email.includes("@"))
|
|
10762
|
+
throw new CliError("bad_argument", `"${address}" isn't an email address.`, `Ask your human for their email, then run: ${OWNER_EMAIL_COMMAND}`);
|
|
10763
|
+
return api(ctx, "PUT", "/v1/account/email", { body: { email } });
|
|
10764
|
+
}
|
|
10765
|
+
async function accountRename(ctx, name) {
|
|
10766
|
+
const v = name.trim();
|
|
10767
|
+
return api(ctx, "PATCH", "/v1/account", { body: { name: v || null } });
|
|
10768
|
+
}
|
|
10023
10769
|
async function accountAdMeasurement(ctx, state) {
|
|
10024
10770
|
const v = state.trim().toLowerCase();
|
|
10025
10771
|
if (v !== "on" && v !== "off")
|
|
@@ -10028,7 +10774,7 @@ async function accountAdMeasurement(ctx, state) {
|
|
|
10028
10774
|
}
|
|
10029
10775
|
var keysList = (ctx) => api(ctx, "GET", "/v1/keys");
|
|
10030
10776
|
var DURATION_RE = /^(0|[1-9]\d{0,5}[smhd])$/;
|
|
10031
|
-
function
|
|
10777
|
+
function duration3(flag, v, allowZero = false) {
|
|
10032
10778
|
if (v === undefined)
|
|
10033
10779
|
return;
|
|
10034
10780
|
if (!DURATION_RE.test(v) || !allowZero && v === "0")
|
|
@@ -10039,14 +10785,14 @@ var keysCreate = async (ctx, o) => api(ctx, "POST", "/v1/keys", {
|
|
|
10039
10785
|
body: {
|
|
10040
10786
|
name: o.name,
|
|
10041
10787
|
daily_budget_usd: o.budgetUsd,
|
|
10042
|
-
expires_in:
|
|
10788
|
+
expires_in: duration3("expires-in", o.expiresIn),
|
|
10043
10789
|
scopes: o.scopes,
|
|
10044
10790
|
child: o.child || undefined
|
|
10045
10791
|
}
|
|
10046
10792
|
});
|
|
10047
10793
|
var keysRevoke = (ctx, id) => api(ctx, "DELETE", `/v1/keys/${encodeURIComponent(id)}`);
|
|
10048
10794
|
var keysRotate = async (ctx, id, o = {}) => api(ctx, "POST", `/v1/keys/${encodeURIComponent(id)}/rotate`, {
|
|
10049
|
-
body: { grace:
|
|
10795
|
+
body: { grace: duration3("grace", o.grace, true), expires_in: duration3("expires-in", o.expiresIn) }
|
|
10050
10796
|
});
|
|
10051
10797
|
var keysRevokeSelf = (ctx) => api(ctx, "DELETE", "/v1/keys/self");
|
|
10052
10798
|
var usage = (ctx, o) => api(ctx, "GET", `/v1/usage?days=${o.days}&group_by=${encodeURIComponent(o.by)}`);
|
|
@@ -10107,7 +10853,7 @@ async function chat(ctx, o) {
|
|
|
10107
10853
|
};
|
|
10108
10854
|
}
|
|
10109
10855
|
var billingStatus = async (ctx) => withoutFreeFields(await api(ctx, "GET", "/v1/billing"));
|
|
10110
|
-
var TOPUP_LIMITS = { min_usd:
|
|
10856
|
+
var TOPUP_LIMITS = { min_usd: 10, max_usd: 2000, daily_max_usd: 2000 };
|
|
10111
10857
|
function checkTopupLimits(amountUsd, autoReload) {
|
|
10112
10858
|
const { min_usd, max_usd, daily_max_usd } = TOPUP_LIMITS;
|
|
10113
10859
|
const range = (flag, v, lo, hi) => {
|
|
@@ -11669,7 +12415,10 @@ var init2 = defineCommand({
|
|
|
11669
12415
|
...jsonFlag,
|
|
11670
12416
|
region: { type: "string", description: "Home region for your data: us (default) or ca. Permanent." },
|
|
11671
12417
|
name: { type: "string", description: "Account name (optional)" },
|
|
11672
|
-
email: {
|
|
12418
|
+
email: {
|
|
12419
|
+
type: "string",
|
|
12420
|
+
description: "Your human's email, to own the account: ask them first. We email it one confirmation link; once they click it they sign in to the dashboard. Account email only, never marketing (optional; later: account email set)"
|
|
12421
|
+
},
|
|
11673
12422
|
source: {
|
|
11674
12423
|
type: "string",
|
|
11675
12424
|
description: "Campaign code from the scaledthought.com/go/<code> link that brought you here, e.g. a-rd (optional; stored on the new account)"
|
|
@@ -11790,14 +12539,14 @@ var models = defineCommand({
|
|
|
11790
12539
|
});
|
|
11791
12540
|
}, args)
|
|
11792
12541
|
});
|
|
11793
|
-
var ACCOUNT_SUBCOMMANDS = new Set(["delete", "ad-measurement"]);
|
|
11794
|
-
var
|
|
11795
|
-
meta: { name: "account", description: "Region, spend, credit balance
|
|
12542
|
+
var ACCOUNT_SUBCOMMANDS = new Set(["delete", "rename", "ad-measurement", "email"]);
|
|
12543
|
+
var account3 = defineCommand({
|
|
12544
|
+
meta: { name: "account", description: "Region, spend, credit balance, auto-reload and owner_email" },
|
|
11796
12545
|
args: jsonFlag,
|
|
11797
12546
|
run: ({ args, rawArgs }) => {
|
|
11798
12547
|
if (rawArgs.some((a) => ACCOUNT_SUBCOMMANDS.has(a)))
|
|
11799
12548
|
return;
|
|
11800
|
-
return run2(() =>
|
|
12549
|
+
return run2(() => account2(makeCtx()), args);
|
|
11801
12550
|
},
|
|
11802
12551
|
subCommands: {
|
|
11803
12552
|
delete: defineCommand({
|
|
@@ -11811,6 +12560,17 @@ var account2 = defineCommand({
|
|
|
11811
12560
|
},
|
|
11812
12561
|
run: ({ args }) => run2(() => accountDelete(makeCtx(), { confirm: args.confirm }), args)
|
|
11813
12562
|
}),
|
|
12563
|
+
rename: defineCommand({
|
|
12564
|
+
meta: {
|
|
12565
|
+
name: "rename",
|
|
12566
|
+
description: 'Rename the account (shown on the dashboard and in its emails); "" goes back to the default'
|
|
12567
|
+
},
|
|
12568
|
+
args: {
|
|
12569
|
+
...jsonFlag,
|
|
12570
|
+
name: { type: "positional", required: true, description: "The new name" }
|
|
12571
|
+
},
|
|
12572
|
+
run: ({ args }) => run2(() => accountRename(makeCtx(), args.name), args)
|
|
12573
|
+
}),
|
|
11814
12574
|
"ad-measurement": defineCommand({
|
|
11815
12575
|
meta: {
|
|
11816
12576
|
name: "ad-measurement",
|
|
@@ -11821,6 +12581,22 @@ var account2 = defineCommand({
|
|
|
11821
12581
|
state: { type: "positional", required: true, description: "off or on" }
|
|
11822
12582
|
},
|
|
11823
12583
|
run: ({ args }) => run2(() => accountAdMeasurement(makeCtx(), args.state), args)
|
|
12584
|
+
}),
|
|
12585
|
+
email: defineCommand({
|
|
12586
|
+
meta: { name: "email", description: "The email that owns this account (confirmed by a link we email them)" },
|
|
12587
|
+
subCommands: {
|
|
12588
|
+
set: defineCommand({
|
|
12589
|
+
meta: {
|
|
12590
|
+
name: "set",
|
|
12591
|
+
description: "Name your human as the account's owner: we email them one confirmation link and they own it once they click. Ask them first; account email only, never marketing. Before anyone has signed in or paid"
|
|
12592
|
+
},
|
|
12593
|
+
args: {
|
|
12594
|
+
...jsonFlag,
|
|
12595
|
+
address: { type: "positional", required: true, description: "Their email address" }
|
|
12596
|
+
},
|
|
12597
|
+
run: ({ args }) => run2(() => accountEmailSet(makeCtx(), args.address), args)
|
|
12598
|
+
})
|
|
12599
|
+
}
|
|
11824
12600
|
})
|
|
11825
12601
|
}
|
|
11826
12602
|
});
|
|
@@ -12128,7 +12904,7 @@ var billing = defineCommand({
|
|
|
12128
12904
|
...jsonFlag,
|
|
12129
12905
|
"amount-usd": {
|
|
12130
12906
|
type: "string",
|
|
12131
|
-
description: "Credits to buy in USD (default 20; $
|
|
12907
|
+
description: "Credits to buy in USD (default 20; $10 to $2,000, at most $2,000 per 24 h). Your human can change it"
|
|
12132
12908
|
},
|
|
12133
12909
|
"auto-reload-below": {
|
|
12134
12910
|
type: "string",
|
|
@@ -12227,7 +13003,10 @@ var billing = defineCommand({
|
|
|
12227
13003
|
}
|
|
12228
13004
|
});
|
|
12229
13005
|
var batches = defineCommand({
|
|
12230
|
-
meta: {
|
|
13006
|
+
meta: {
|
|
13007
|
+
name: "batches",
|
|
13008
|
+
description: "Batch inference at the normal per-token price (OpenAI-compatible). Paid from prepaid credits"
|
|
13009
|
+
},
|
|
12231
13010
|
subCommands: {
|
|
12232
13011
|
create: defineCommand({
|
|
12233
13012
|
meta: { name: "create", description: "Upload a JSONL file and start a batch" },
|
|
@@ -12451,7 +13230,7 @@ var mcp = defineCommand({
|
|
|
12451
13230
|
var dashboard = defineCommand({
|
|
12452
13231
|
meta: {
|
|
12453
13232
|
name: "dashboard",
|
|
12454
|
-
description: "Open your human's ScaledThought dashboard (billing, keys, members, connect an agent) in their browser. No typing: if they're not signed in, one click emails them a link"
|
|
13233
|
+
description: "Open your human's ScaledThought dashboard (billing, keys, members, connect an agent) in their browser. No typing: if they're not signed in, one click emails them a link (after they've confirmed their email)"
|
|
12455
13234
|
},
|
|
12456
13235
|
args: {
|
|
12457
13236
|
...jsonFlag,
|
|
@@ -12486,7 +13265,7 @@ var root = defineCommand({
|
|
|
12486
13265
|
models,
|
|
12487
13266
|
benchmarks: benchmarks2,
|
|
12488
13267
|
status: status2,
|
|
12489
|
-
account:
|
|
13268
|
+
account: account3,
|
|
12490
13269
|
keys,
|
|
12491
13270
|
usage: usage3,
|
|
12492
13271
|
chat: chat2,
|