siluzan-tso-cli 1.1.38 → 1.1.39-beta.2
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 +2 -1
- package/dist/index.js +881 -768
- package/dist/skill/_meta.json +2 -2
- package/dist/skill/references/accounts/accounts-balance-stats.md +1 -3
- package/dist/skill/references/accounts/accounts-list.md +1 -1
- package/dist/skill/references/accounts/accounts-permissions.md +2 -2
- package/dist/skill/references/accounts/finance.md +1 -1
- package/dist/skill/references/accounts/open-account-by-media.md +1 -1
- package/dist/skill/references/accounts/open-account-google-ui.md +1 -1
- package/dist/skill/references/analytics/account-analytics.md +2 -1
- package/dist/skill/references/analytics/rag.md +1 -1
- package/dist/skill/references/analytics/reporting.md +5 -5
- package/dist/skill/references/core/setup.md +5 -5
- package/dist/skill/references/misc/tso-home.md +2 -2
- package/dist/skill/scripts/install.ps1 +3 -3
- package/dist/skill/scripts/install.sh +3 -3
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -258,9 +258,9 @@ var require_semver = __commonJS({
|
|
|
258
258
|
} else {
|
|
259
259
|
this.prerelease = m[4].split(".").map((id) => {
|
|
260
260
|
if (/^[0-9]+$/.test(id)) {
|
|
261
|
-
const
|
|
262
|
-
if (
|
|
263
|
-
return
|
|
261
|
+
const num11 = +id;
|
|
262
|
+
if (num11 >= 0 && num11 < MAX_SAFE_INTEGER) {
|
|
263
|
+
return num11;
|
|
264
264
|
}
|
|
265
265
|
}
|
|
266
266
|
return id;
|
|
@@ -3218,6 +3218,16 @@ function getResolvedWriteAuditCommit() {
|
|
|
3218
3218
|
const env = process.env.SILUZAN_AUDIT_NOTE?.trim() ?? "";
|
|
3219
3219
|
return env !== "" ? truncateCommit(env) : "";
|
|
3220
3220
|
}
|
|
3221
|
+
function isWriteAuditCommitRequiredSatisfied() {
|
|
3222
|
+
if (isSiluzanAgentEnv()) return true;
|
|
3223
|
+
return getResolvedWriteAuditCommit() !== "";
|
|
3224
|
+
}
|
|
3225
|
+
function resolveWriteAuditCommitForRecord() {
|
|
3226
|
+
const c = getResolvedWriteAuditCommit();
|
|
3227
|
+
if (c !== "") return c;
|
|
3228
|
+
if (isSiluzanAgentEnv()) return WRITE_AUDIT_AGENT_AUTO_COMMIT;
|
|
3229
|
+
return "";
|
|
3230
|
+
}
|
|
3221
3231
|
function getWriteAuditRunId() {
|
|
3222
3232
|
const r = process.env.SILUZAN_AUDIT_RUN_ID?.trim();
|
|
3223
3233
|
return r !== void 0 && r !== "" ? r : void 0;
|
|
@@ -3805,7 +3815,7 @@ async function issueApiKeyWithPhoneCode(opts) {
|
|
|
3805
3815
|
});
|
|
3806
3816
|
return apiKey;
|
|
3807
3817
|
}
|
|
3808
|
-
var import_semver, SILUZAN_DIR, CONFIG_FILE, inProcessLockChain, ALLOWED_HOSTNAME_SUFFIXES, EXACT_ID_FIELD_NAMES, DEFAULT_TIMEOUT_MS, MAX_RESPONSE_BYTES, httpsAgent, httpAgent, PERF_PREFIX, DEFAULT_DETAIL_MAX, VERBOSE_DETAIL_MAX, ASCII_TABLE_CHARS, CLI_SNAPSHOT_MANIFEST_FILE, SCHEMA_VERSION, FALLBACK_FIELD_GUIDE_REFS, _cliPackage, _resolveCliVersion, _fieldGuideRefs, OUTLINE_AGENT_HINT, TS_LIKE_ARRAY_SAMPLE_MAX, MAX_INVOCATION_CHARS, currentInvocation, MAX_COMMIT_CHARS, cliCommitOverride, WRITE_AUDIT_SCHEMA_VERSION, MUTATING, BEIJING_TZ, AUDIT_LOG_FILENAME_RE, DEFAULT_MAX_FILE_MB, MIN_SEGMENT_BYTES, MAX_SEGMENT_BYTES, DEFAULT_RETENTION_DAYS, MIN_RETENTION_DAYS, MAX_RETENTION_DAYS, PRUNE_THROTTLE_MS, lastPruneAtMs, MAX_BODY_CHARS, MAX_ERROR_CHARS, DEFAULT_FIND_AUDIT_MAX_DAYS, MAX_SNAPSHOT_FILE_BYTES, API_KEY_SERVICE_VALUES;
|
|
3818
|
+
var import_semver, SILUZAN_DIR, CONFIG_FILE, inProcessLockChain, ALLOWED_HOSTNAME_SUFFIXES, EXACT_ID_FIELD_NAMES, DEFAULT_TIMEOUT_MS, MAX_RESPONSE_BYTES, httpsAgent, httpAgent, PERF_PREFIX, DEFAULT_DETAIL_MAX, VERBOSE_DETAIL_MAX, ASCII_TABLE_CHARS, CLI_SNAPSHOT_MANIFEST_FILE, SCHEMA_VERSION, FALLBACK_FIELD_GUIDE_REFS, _cliPackage, _resolveCliVersion, _fieldGuideRefs, OUTLINE_AGENT_HINT, TS_LIKE_ARRAY_SAMPLE_MAX, MAX_INVOCATION_CHARS, currentInvocation, MAX_COMMIT_CHARS, WRITE_AUDIT_AGENT_AUTO_COMMIT, cliCommitOverride, WRITE_AUDIT_SCHEMA_VERSION, MUTATING, BEIJING_TZ, AUDIT_LOG_FILENAME_RE, DEFAULT_MAX_FILE_MB, MIN_SEGMENT_BYTES, MAX_SEGMENT_BYTES, DEFAULT_RETENTION_DAYS, MIN_RETENTION_DAYS, MAX_RETENTION_DAYS, PRUNE_THROTTLE_MS, lastPruneAtMs, MAX_BODY_CHARS, MAX_ERROR_CHARS, DEFAULT_FIND_AUDIT_MAX_DAYS, MAX_SNAPSHOT_FILE_BYTES, API_KEY_SERVICE_VALUES;
|
|
3809
3819
|
var init_dist = __esm({
|
|
3810
3820
|
"../common/dist/index.js"() {
|
|
3811
3821
|
"use strict";
|
|
@@ -3897,6 +3907,7 @@ var init_dist = __esm({
|
|
|
3897
3907
|
TS_LIKE_ARRAY_SAMPLE_MAX = 8;
|
|
3898
3908
|
MAX_INVOCATION_CHARS = 4e3;
|
|
3899
3909
|
MAX_COMMIT_CHARS = 2e3;
|
|
3910
|
+
WRITE_AUDIT_AGENT_AUTO_COMMIT = "agent:auto";
|
|
3900
3911
|
WRITE_AUDIT_SCHEMA_VERSION = 2;
|
|
3901
3912
|
MUTATING = /* @__PURE__ */ new Set(["POST", "PUT", "PATCH", "DELETE"]);
|
|
3902
3913
|
BEIJING_TZ = "Asia/Shanghai";
|
|
@@ -3926,7 +3937,7 @@ var DEFAULT_API_BASE;
|
|
|
3926
3937
|
var init_defaults = __esm({
|
|
3927
3938
|
"src/config/defaults.ts"() {
|
|
3928
3939
|
"use strict";
|
|
3929
|
-
DEFAULT_API_BASE = "https://tso-api.siluzan.com";
|
|
3940
|
+
DEFAULT_API_BASE = "https://tso-api-ci.siluzan.com";
|
|
3930
3941
|
}
|
|
3931
3942
|
});
|
|
3932
3943
|
|
|
@@ -4159,15 +4170,14 @@ function isTsoArgvExemptFromWriteCommit(argv) {
|
|
|
4159
4170
|
}
|
|
4160
4171
|
function ensureWriteCommitForMutatingHttp() {
|
|
4161
4172
|
if (isTsoArgvExemptFromWriteCommit(process.argv.slice(2))) return;
|
|
4162
|
-
|
|
4163
|
-
if (c !== "") return;
|
|
4173
|
+
if (isWriteAuditCommitRequiredSatisfied()) return;
|
|
4164
4174
|
console.error('\n\u274C \u5199\u64CD\u4F5C\u5FC5\u987B\u63D0\u4F9B\u8BF4\u660E\uFF08commit\uFF09\uFF1A\u8BF7\u4F7F\u7528 --commit "\u2026"');
|
|
4165
4175
|
process.exit(1);
|
|
4166
4176
|
}
|
|
4167
4177
|
async function withWriteAudit(params, execute) {
|
|
4168
4178
|
ensureWriteCommitForMutatingHttp();
|
|
4169
4179
|
const auditId = randomUUID();
|
|
4170
|
-
const commit =
|
|
4180
|
+
const commit = resolveWriteAuditCommitForRecord();
|
|
4171
4181
|
const runId = getWriteAuditRunId();
|
|
4172
4182
|
const snap = await tryWritePreSnapshot({
|
|
4173
4183
|
namespace: TSO_WRITE_AUDIT_NS,
|
|
@@ -5407,335 +5417,6 @@ var init_accounts_digest2 = __esm({
|
|
|
5407
5417
|
}
|
|
5408
5418
|
});
|
|
5409
5419
|
|
|
5410
|
-
// src/commands/google-analysis/wrap-snapshot-envelope.ts
|
|
5411
|
-
function coerceToRowArray(value) {
|
|
5412
|
-
if (Array.isArray(value)) return value;
|
|
5413
|
-
if (value === null || typeof value !== "object") return [];
|
|
5414
|
-
const o = value;
|
|
5415
|
-
const keys = Object.keys(o);
|
|
5416
|
-
if (keys.length === 0) return [];
|
|
5417
|
-
if (keys.every((k) => /^\d+$/.test(k))) {
|
|
5418
|
-
return keys.sort((a, b) => Number(a) - Number(b)).map((k) => o[k]);
|
|
5419
|
-
}
|
|
5420
|
-
return [];
|
|
5421
|
-
}
|
|
5422
|
-
function asRecord(value) {
|
|
5423
|
-
if (value === null || typeof value !== "object" || Array.isArray(value)) return null;
|
|
5424
|
-
return value;
|
|
5425
|
-
}
|
|
5426
|
-
function readGatewayList(bag) {
|
|
5427
|
-
const items2 = coerceToRowArray(bag.data);
|
|
5428
|
-
const meta = {};
|
|
5429
|
-
if (typeof bag.code === "number") meta.code = bag.code;
|
|
5430
|
-
if (typeof bag.message === "string") meta.message = bag.message;
|
|
5431
|
-
return { items: items2, ...Object.keys(meta).length > 0 ? { meta } : {} };
|
|
5432
|
-
}
|
|
5433
|
-
function flattenMaterials(payload) {
|
|
5434
|
-
const bag = asRecord(payload);
|
|
5435
|
-
if (!bag) return [];
|
|
5436
|
-
const images = coerceToRowArray(bag.images).map(
|
|
5437
|
-
(row) => asRecord(row) ? { ...row, assetType: "image" } : row
|
|
5438
|
-
);
|
|
5439
|
-
const videos = coerceToRowArray(bag.videos).map(
|
|
5440
|
-
(row) => asRecord(row) ? { ...row, assetType: "video" } : row
|
|
5441
|
-
);
|
|
5442
|
-
return [...images, ...videos];
|
|
5443
|
-
}
|
|
5444
|
-
function wrapGoogleAnalysisSnapshotPayload(section, payload) {
|
|
5445
|
-
let items2 = [];
|
|
5446
|
-
let record2 = null;
|
|
5447
|
-
let meta;
|
|
5448
|
-
if (COMPOSITE_SECTIONS.has(section)) {
|
|
5449
|
-
items2 = flattenMaterials(payload);
|
|
5450
|
-
} else if (RECORD_ONLY_SECTIONS.has(section)) {
|
|
5451
|
-
record2 = asRecord(payload);
|
|
5452
|
-
} else if (GATEWAY_LIST_SECTIONS.has(section)) {
|
|
5453
|
-
const bag = asRecord(payload);
|
|
5454
|
-
if (bag) {
|
|
5455
|
-
const r = readGatewayList(bag);
|
|
5456
|
-
items2 = r.items;
|
|
5457
|
-
meta = r.meta;
|
|
5458
|
-
}
|
|
5459
|
-
} else if (ROOT_ARRAY_SECTIONS.has(section)) {
|
|
5460
|
-
items2 = coerceToRowArray(payload);
|
|
5461
|
-
} else {
|
|
5462
|
-
const rowKey = ROW_KEY_BY_SECTION[section];
|
|
5463
|
-
const bag = asRecord(payload);
|
|
5464
|
-
if (rowKey && bag) {
|
|
5465
|
-
items2 = coerceToRowArray(bag[rowKey]);
|
|
5466
|
-
} else {
|
|
5467
|
-
const arr = coerceToRowArray(payload);
|
|
5468
|
-
if (arr.length > 0) items2 = arr;
|
|
5469
|
-
else record2 = asRecord(payload);
|
|
5470
|
-
}
|
|
5471
|
-
}
|
|
5472
|
-
return {
|
|
5473
|
-
schemaVersion: GOOGLE_ANALYSIS_FILE_SCHEMA_VERSION,
|
|
5474
|
-
section,
|
|
5475
|
-
itemCount: items2.length,
|
|
5476
|
-
items: items2,
|
|
5477
|
-
record: record2,
|
|
5478
|
-
...meta !== void 0 ? { meta } : {}
|
|
5479
|
-
};
|
|
5480
|
-
}
|
|
5481
|
-
var GOOGLE_ANALYSIS_FILE_SCHEMA_VERSION, ROW_KEY_BY_SECTION, RECORD_ONLY_SECTIONS, COMPOSITE_SECTIONS, ROOT_ARRAY_SECTIONS, GATEWAY_LIST_SECTIONS;
|
|
5482
|
-
var init_wrap_snapshot_envelope = __esm({
|
|
5483
|
-
"src/commands/google-analysis/wrap-snapshot-envelope.ts"() {
|
|
5484
|
-
"use strict";
|
|
5485
|
-
GOOGLE_ANALYSIS_FILE_SCHEMA_VERSION = 3;
|
|
5486
|
-
ROW_KEY_BY_SECTION = {
|
|
5487
|
-
keywords: "keywords",
|
|
5488
|
-
campaigns: "campaigns",
|
|
5489
|
-
devices: "devices",
|
|
5490
|
-
geographic: "countries",
|
|
5491
|
-
"geo-matched": "countries",
|
|
5492
|
-
"campaign-geo": "countries",
|
|
5493
|
-
"campaign-geo-matched": "countries",
|
|
5494
|
-
"campaign-device": "devices",
|
|
5495
|
-
audience: "audience"
|
|
5496
|
-
};
|
|
5497
|
-
RECORD_ONLY_SECTIONS = /* @__PURE__ */ new Set([
|
|
5498
|
-
"overview",
|
|
5499
|
-
"resource-counts",
|
|
5500
|
-
"dimension-summary",
|
|
5501
|
-
"gold-account",
|
|
5502
|
-
"final-urls",
|
|
5503
|
-
"campaign-types",
|
|
5504
|
-
"ads-index"
|
|
5505
|
-
]);
|
|
5506
|
-
COMPOSITE_SECTIONS = /* @__PURE__ */ new Set(["materials"]);
|
|
5507
|
-
ROOT_ARRAY_SECTIONS = /* @__PURE__ */ new Set([
|
|
5508
|
-
"campaign-hour",
|
|
5509
|
-
"extensions",
|
|
5510
|
-
"asset-images",
|
|
5511
|
-
"videos",
|
|
5512
|
-
"daily-metrics",
|
|
5513
|
-
"conversion-actions"
|
|
5514
|
-
]);
|
|
5515
|
-
GATEWAY_LIST_SECTIONS = /* @__PURE__ */ new Set([
|
|
5516
|
-
"search-terms",
|
|
5517
|
-
"ads"
|
|
5518
|
-
]);
|
|
5519
|
-
}
|
|
5520
|
-
});
|
|
5521
|
-
|
|
5522
|
-
// src/utils/snapshot/dir.ts
|
|
5523
|
-
var init_dir = __esm({
|
|
5524
|
-
"src/utils/snapshot/dir.ts"() {
|
|
5525
|
-
"use strict";
|
|
5526
|
-
init_dist();
|
|
5527
|
-
}
|
|
5528
|
-
});
|
|
5529
|
-
|
|
5530
|
-
// src/utils/snapshot/google-analysis.ts
|
|
5531
|
-
import * as fs7 from "fs/promises";
|
|
5532
|
-
import * as path11 from "path";
|
|
5533
|
-
function googleAnalysisManifestFile(accountId) {
|
|
5534
|
-
return `${applyIdSuffix("manifest", accountId)}.json`;
|
|
5535
|
-
}
|
|
5536
|
-
function buildOutlineHints(section) {
|
|
5537
|
-
const hints = [...GOOGLE_ANALYSIS_ENVELOPE_OUTLINE_HINTS];
|
|
5538
|
-
if (RATE_BEARING_SECTIONS.has(section)) {
|
|
5539
|
-
hints.push(...GOOGLE_ANALYSIS_RATE_NORMALIZED_OUTLINE_HINTS);
|
|
5540
|
-
}
|
|
5541
|
-
if (section === "campaigns") {
|
|
5542
|
-
hints.push(
|
|
5543
|
-
...GOOGLE_ANALYSIS_CAMPAIGNS_OUTLINE_BUDGET_HINTS,
|
|
5544
|
-
...GOOGLE_ANALYSIS_CAMPAIGNS_COMPETITIVE_METRICS_HINTS
|
|
5545
|
-
);
|
|
5546
|
-
}
|
|
5547
|
-
if (section === "ads") {
|
|
5548
|
-
hints.push(...GOOGLE_ANALYSIS_ADS_OUTLINE_BUDGET_HINTS);
|
|
5549
|
-
}
|
|
5550
|
-
const zhHints = GOOGLE_ANALYSIS_ZH_FIELD_HINTS_BY_SECTION[section];
|
|
5551
|
-
if (zhHints) hints.push(...zhHints);
|
|
5552
|
-
return hints.length > 0 ? hints : void 0;
|
|
5553
|
-
}
|
|
5554
|
-
function googleAnalysisSectionFilename(section, accountId, dateRange) {
|
|
5555
|
-
if (!/^[a-z0-9-]+$/.test(section)) {
|
|
5556
|
-
throw new Error(`\u975E\u6CD5\u5B50\u547D\u4EE4\u540D\uFF0C\u65E0\u6CD5\u751F\u6210\u6587\u4EF6\u540D\uFF1A${section}`);
|
|
5557
|
-
}
|
|
5558
|
-
let stem = applyIdSuffix(section, accountId);
|
|
5559
|
-
if (dateRange?.mode === "range") {
|
|
5560
|
-
const start = dateRange.start.replace(/-/g, "");
|
|
5561
|
-
const end = dateRange.end.replace(/-/g, "");
|
|
5562
|
-
stem = `${stem}_${start}-${end}`;
|
|
5563
|
-
}
|
|
5564
|
-
return `${stem}.json`;
|
|
5565
|
-
}
|
|
5566
|
-
async function readManifestIfExists(absDir, accountId) {
|
|
5567
|
-
const candidates = [];
|
|
5568
|
-
const suffixed = googleAnalysisManifestFile(accountId);
|
|
5569
|
-
candidates.push(suffixed);
|
|
5570
|
-
if (suffixed !== LEGACY_MANIFEST_FILE) {
|
|
5571
|
-
candidates.push(LEGACY_MANIFEST_FILE);
|
|
5572
|
-
}
|
|
5573
|
-
for (const name2 of candidates) {
|
|
5574
|
-
const manifestPath = path11.join(absDir, name2);
|
|
5575
|
-
try {
|
|
5576
|
-
const raw = await fs7.readFile(manifestPath, "utf8");
|
|
5577
|
-
const parsed = JSON.parse(raw);
|
|
5578
|
-
const sv = parsed?.schemaVersion;
|
|
5579
|
-
if (sv !== 2 && sv !== SCHEMA_VERSION2 || !Array.isArray(parsed.artifacts)) {
|
|
5580
|
-
continue;
|
|
5581
|
-
}
|
|
5582
|
-
return parsed;
|
|
5583
|
-
} catch {
|
|
5584
|
-
continue;
|
|
5585
|
-
}
|
|
5586
|
-
}
|
|
5587
|
-
return null;
|
|
5588
|
-
}
|
|
5589
|
-
function mergeGoogleAnalysisManifest(existing, params) {
|
|
5590
|
-
const prevArts = existing?.artifacts ?? [];
|
|
5591
|
-
const without = prevArts.filter((a) => a.file !== params.newArtifact.file);
|
|
5592
|
-
const artifacts = [...without, params.newArtifact];
|
|
5593
|
-
const fieldGuide = existing?.fieldGuide ?? DEFAULT_FIELD_GUIDE;
|
|
5594
|
-
return {
|
|
5595
|
-
schemaVersion: SCHEMA_VERSION2,
|
|
5596
|
-
cliPackage: CLI_PACKAGE,
|
|
5597
|
-
cliVersion: params.cliVersion,
|
|
5598
|
-
googleAnalysis: {
|
|
5599
|
-
accountId: params.accountId,
|
|
5600
|
-
dateRange: params.dateRange
|
|
5601
|
-
},
|
|
5602
|
-
fieldGuide: {
|
|
5603
|
-
markdownRefs: [...fieldGuide.markdownRefs],
|
|
5604
|
-
tsTypesModule: fieldGuide.tsTypesModule
|
|
5605
|
-
},
|
|
5606
|
-
artifacts
|
|
5607
|
-
};
|
|
5608
|
-
}
|
|
5609
|
-
async function writeGoogleAnalysisSnapshot(params) {
|
|
5610
|
-
const absDir = await ensureSnapshotDir(params.snapshotDir);
|
|
5611
|
-
const accountSlug = slugifyIdSuffix(params.accountId);
|
|
5612
|
-
const fileName = googleAnalysisSectionFilename(
|
|
5613
|
-
params.section,
|
|
5614
|
-
accountSlug || void 0,
|
|
5615
|
-
params.dateRange
|
|
5616
|
-
);
|
|
5617
|
-
const relativeFile = fileName;
|
|
5618
|
-
const writtenAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
5619
|
-
const wrapped = wrapGoogleAnalysisSnapshotPayload(
|
|
5620
|
-
params.section,
|
|
5621
|
-
params.payload
|
|
5622
|
-
);
|
|
5623
|
-
const normalizedWrapped = stringifyIdsDeep(wrapped);
|
|
5624
|
-
const body = JSON.stringify(normalizedWrapped, null, 2);
|
|
5625
|
-
await fs7.writeFile(path11.join(absDir, fileName), `${body}
|
|
5626
|
-
`, "utf8");
|
|
5627
|
-
const outlineFileName = snapshotOutlineFileName(fileName);
|
|
5628
|
-
const outlineExtra = buildOutlineHints(params.section);
|
|
5629
|
-
const outlineBody = formatOutlineFileBody(fileName, normalizedWrapped, outlineExtra);
|
|
5630
|
-
await fs7.writeFile(path11.join(absDir, outlineFileName), `${outlineBody}
|
|
5631
|
-
`, "utf8");
|
|
5632
|
-
const existing = await readManifestIfExists(absDir, accountSlug || void 0);
|
|
5633
|
-
const newArtifact = {
|
|
5634
|
-
section: params.section,
|
|
5635
|
-
file: relativeFile,
|
|
5636
|
-
writtenAt,
|
|
5637
|
-
...params.endpointHint !== void 0 ? { endpointHint: params.endpointHint } : {}
|
|
5638
|
-
};
|
|
5639
|
-
const merged = mergeGoogleAnalysisManifest(existing, {
|
|
5640
|
-
accountId: params.accountId,
|
|
5641
|
-
dateRange: params.dateRange,
|
|
5642
|
-
cliVersion: params.cliVersion,
|
|
5643
|
-
newArtifact
|
|
5644
|
-
});
|
|
5645
|
-
const manifestFile = googleAnalysisManifestFile(accountSlug || void 0);
|
|
5646
|
-
await fs7.writeFile(
|
|
5647
|
-
path11.join(absDir, manifestFile),
|
|
5648
|
-
`${JSON.stringify(stringifyIdsDeep(merged), null, 2)}
|
|
5649
|
-
`,
|
|
5650
|
-
"utf8"
|
|
5651
|
-
);
|
|
5652
|
-
return {
|
|
5653
|
-
kind: "siluzan-tso-google-analysis-snapshot",
|
|
5654
|
-
schemaVersion: SCHEMA_VERSION2,
|
|
5655
|
-
absoluteSnapshotDir: absDir,
|
|
5656
|
-
manifestFile,
|
|
5657
|
-
writtenFiles: [fileName, outlineFileName],
|
|
5658
|
-
section: params.section,
|
|
5659
|
-
outlineFile: outlineFileName,
|
|
5660
|
-
agentHint: OUTLINE_AGENT_HINT
|
|
5661
|
-
};
|
|
5662
|
-
}
|
|
5663
|
-
var LEGACY_MANIFEST_FILE, CLI_PACKAGE, SCHEMA_VERSION2, DEFAULT_FIELD_GUIDE, GOOGLE_ANALYSIS_CAMPAIGNS_OUTLINE_BUDGET_HINTS, GOOGLE_ANALYSIS_ADS_OUTLINE_BUDGET_HINTS, GOOGLE_ANALYSIS_CAMPAIGNS_COMPETITIVE_METRICS_HINTS, RATE_BEARING_SECTIONS, GOOGLE_ANALYSIS_RATE_NORMALIZED_OUTLINE_HINTS, GOOGLE_ANALYSIS_ENVELOPE_OUTLINE_HINTS, GOOGLE_ANALYSIS_ZH_FIELD_HINTS_BY_SECTION;
|
|
5664
|
-
var init_google_analysis = __esm({
|
|
5665
|
-
"src/utils/snapshot/google-analysis.ts"() {
|
|
5666
|
-
"use strict";
|
|
5667
|
-
init_cli_json();
|
|
5668
|
-
init_wrap_snapshot_envelope();
|
|
5669
|
-
init_dir();
|
|
5670
|
-
LEGACY_MANIFEST_FILE = "manifest.json";
|
|
5671
|
-
CLI_PACKAGE = "siluzan-tso-cli";
|
|
5672
|
-
SCHEMA_VERSION2 = 3;
|
|
5673
|
-
DEFAULT_FIELD_GUIDE = {
|
|
5674
|
-
markdownRefs: ["references/accounts/currency.md", "references/analytics/account-analytics.md"],
|
|
5675
|
-
tsTypesModule: "tso-cli/src/types/google-analysis-api.ts"
|
|
5676
|
-
};
|
|
5677
|
-
GOOGLE_ANALYSIS_CAMPAIGNS_OUTLINE_BUDGET_HINTS = [
|
|
5678
|
-
"// \u91D1\u989D\uFF1A`campaigns[].budgetAmountYuan` / `campaignTargetCpaYuan` / `maximizeConversionsTargetCpaYuan` \u5747\u4E3A**\u5143**\uFF08CLI \u51FA\u53E3\u7EDF\u4E00\uFF09\uFF1B\u540C\u884C `spend` / `averageCpc` / `costPerConversion` \u4E5F\u662F\u5143\u3002",
|
|
5679
|
-
"// \u65E7\u5B57\u6BB5 `budgetAmount`\uFF08\u5206\uFF09/ `*Micros`\uFF08\u5FAE\u5143\uFF09\u5DF2\u4E0D\u518D\u843D\u76D8\uFF0C**\u7981\u6B62**\u518D\u505A \xF7100 / \xF71_000_000 \u6362\u7B97\u3002",
|
|
5680
|
-
"// \u72B6\u6001\uFF1A\u6BCF\u884C\u542B `campaignStatusDisplay`\uFF08\u6295\u653E\u4E2D/\u5DF2\u6682\u505C/\u5DF2\u79FB\u9664\uFF09\uFF1B\u62A5\u544A\u72B6\u6001\u5217**\u76F4\u63A5\u8BFB\u6B64\u5B57\u6BB5**\uFF0C\u7981\u6B62\u5BF9 `campaignStatus` \u5199 `MAP[s]||'\u5DF2\u79FB\u9664'`\u3002"
|
|
5681
|
-
];
|
|
5682
|
-
GOOGLE_ANALYSIS_ADS_OUTLINE_BUDGET_HINTS = [
|
|
5683
|
-
"// \u91D1\u989D\uFF1A`ads[].spend` / `averageCpc` / `costPerConversion` \u843D\u76D8\u524D\u5DF2\u7EDF\u4E00\u4E3A**\u5143**\uFF08`costPerConversion` \u7531\u7F51\u5173\u5FAE\u5143 \xF71e6\uFF09\uFF1B**\u7981\u6B62**\u518D\u5BF9 `costPerConversion` \u505A \xF71_000_000\u3002"
|
|
5684
|
-
];
|
|
5685
|
-
GOOGLE_ANALYSIS_CAMPAIGNS_COMPETITIVE_METRICS_HINTS = [
|
|
5686
|
-
"// \u7ADE\u4E89\u6307\u6807\uFF1A`campaigns[].competitiveMetrics` \u4E3A **0~1 \u5C0F\u6570**\uFF08\u5982 `0.0999` = 9.99%\uFF09\uFF0C\u542B Top/AbsoluteTop/Content/ClickShare \u7B49\uFF1B\u65E0\u6570\u636E\u65F6\u4E3A `null`\u3002",
|
|
5687
|
-
"// \u884C\u9876 `searchImpressionShare` / `searchBudgetLostImpressionShare` / `searchRankLostImpressionShare` \u843D\u76D8\u524D\u5DF2\u5F52\u4E00\u4E3A **0~1 \u5C0F\u6570**\uFF08\u4E0E `competitiveMetrics` \u540C\u540D\u9879\u4E00\u81F4\uFF09\uFF1B\u5C55\u793A\u4E3A % \u65F6 \xD7100\u3002",
|
|
5688
|
-
"// `keywords[]` \u884C\u9876 3 \u9879\u4EFD\u989D\u540C\u6837\u4E3A 0~1 \u5C0F\u6570\uFF08\u65E0 `competitiveMetrics` \u65F6\u7531\u767E\u5206\u6570 \xF7100\uFF09\u3002"
|
|
5689
|
-
];
|
|
5690
|
-
RATE_BEARING_SECTIONS = /* @__PURE__ */ new Set([
|
|
5691
|
-
"overview",
|
|
5692
|
-
"keywords",
|
|
5693
|
-
"search-terms",
|
|
5694
|
-
"campaigns",
|
|
5695
|
-
"ads",
|
|
5696
|
-
"extensions",
|
|
5697
|
-
"devices",
|
|
5698
|
-
"geographic",
|
|
5699
|
-
"geo-matched",
|
|
5700
|
-
"campaign-geo",
|
|
5701
|
-
"campaign-geo-matched",
|
|
5702
|
-
"campaign-device",
|
|
5703
|
-
"audience",
|
|
5704
|
-
"asset-images",
|
|
5705
|
-
"videos",
|
|
5706
|
-
"materials",
|
|
5707
|
-
"daily-metrics",
|
|
5708
|
-
"dimension-summary",
|
|
5709
|
-
"ads-index"
|
|
5710
|
-
]);
|
|
5711
|
-
GOOGLE_ANALYSIS_RATE_NORMALIZED_OUTLINE_HINTS = [
|
|
5712
|
-
"// \u6982\u7387\u5B57\u6BB5\uFF1A`ctr` / `conversionRate` \u81EA manifest schemaVersion 2\uFF082026-05\uFF09\u8D77\u5DF2\u7531 CLI \u7EDF\u4E00\u5F52\u4E00\u4E3A **0~1 \u5C0F\u6570**\uFF08\u5982 `0.0964` = 9.64%\uFF09\u3002",
|
|
5713
|
-
"// \u5199 Excel 0~1 \u5C0F\u6570\u5217\uFF1A\u76F4\u63A5\u5199\u5165\uFF1B\u5199\u300Cx%\u300D\u6587\u6848\uFF1A`(v * 100).toFixed(2) + '%'`\uFF1B**\u7981\u6B62**\u518D \xF7100\u3002`interactionRate` \u4ECD\u662F\u5B57\u7B26\u4E32 0~1 \u5C0F\u6570\uFF0C`parseFloat` \u540E\u4F7F\u7528\u3002"
|
|
5714
|
-
];
|
|
5715
|
-
GOOGLE_ANALYSIS_ENVELOPE_OUTLINE_HINTS = [
|
|
5716
|
-
"// \u7EDF\u4E00\u8BBF\u95EE\u5C42\uFF08manifest / \u6587\u4EF6\u5185\u5747\u4E3A `schemaVersion: 3`\uFF09\uFF1A\u5224\u522B\u53EA\u6709\u4E00\u6761\u2014\u2014`record` \u975E null \u5373**\u6C47\u603B\u7EF4\u5EA6**\uFF08overview/resource-counts/gold-account/ads-index/dimension-summary/final-urls/campaign-types\uFF09\uFF0C\u8BFB `record`\uFF1B\u5426\u5219\u8BFB `items[]`\uFF08\u6240\u6709\u5217\u8868\u7EF4\u5EA6\uFF0C\u542B materials\uFF0C\u884C\u5DF2\u7EDF\u4E00\u642C\u5165\uFF0C`itemCount` = `items.length`\uFF09\u3002",
|
|
5717
|
-
"// \u7EF4\u5EA6\u4E13\u5C5E\u539F\u952E\u540D\uFF08keywords/campaigns/countries/data \u7B49\uFF09\u5DF2**\u79FB\u9664**\uFF0C\u4E0D\u8981\u518D\u6309\u7EF4\u5EA6\u731C\u952E\u540D\uFF1B`search-terms`/`ads` \u7684\u7F51\u5173 `code`/`message` \u5728 `meta`\uFF08\u4E0E\u6570\u636E\u65E0\u5173\uFF09\uFF1Bmaterials \u884C\u5E26 `assetType: 'image'|'video'`\u3002"
|
|
5718
|
-
];
|
|
5719
|
-
GOOGLE_ANALYSIS_ZH_FIELD_HINTS_BY_SECTION = {
|
|
5720
|
-
keywords: [
|
|
5721
|
-
"// \u4E2D\u6587\u8BD1\u540D\uFF1A`keywordMatchTypeZh`\uFF08\u7531 `keywordMatchType` \u7ECF match-type-en2zh.json \u7FFB\u8BD1\uFF0C\u8986\u76D6 BROAD/PHRASE/EXACT \u4E0E Broad/Phrase/Exact \u5927\u5C0F\u5199\uFF1B\u672A\u547D\u4E2D\u65F6\u8BE5\u5B57\u6BB5\u7F3A\u7701\uFF09\u3002"
|
|
5722
|
-
],
|
|
5723
|
-
"search-terms": [
|
|
5724
|
-
"// \u4E2D\u6587\u8BD1\u540D\uFF1A`matchTypeZh`\uFF08\u7531 `matchType` \u7ECF match-type-en2zh.json \u7FFB\u8BD1\uFF1B\u672A\u547D\u4E2D\u65F6\u8BE5\u5B57\u6BB5\u7F3A\u7701\uFF09\u3002"
|
|
5725
|
-
],
|
|
5726
|
-
"campaign-geo": [
|
|
5727
|
-
"// \u4E2D\u6587\u8BD1\u540D\uFF1A`countryOrRegionZh`\uFF08\u7531 `countryOrRegion` \u7ECF geo-en2zh.json \u7FFB\u8BD1\uFF0C\u76EE\u524D\u8986\u76D6 105 \u4E2A\u56FD\u5BB6/\u5730\u533A\uFF1B\u672A\u547D\u4E2D\u65F6\u8BE5\u5B57\u6BB5\u7F3A\u7701\uFF09\u3002"
|
|
5728
|
-
],
|
|
5729
|
-
"campaign-geo-matched": [
|
|
5730
|
-
"// \u4E2D\u6587\u8BD1\u540D\uFF1A`countryOrRegionZh`\uFF08\u7531 `countryOrRegion` \u7ECF geo-en2zh.json \u7FFB\u8BD1\uFF0C\u76EE\u524D\u8986\u76D6 105 \u4E2A\u56FD\u5BB6/\u5730\u533A\uFF1B\u672A\u547D\u4E2D\u65F6\u8BE5\u5B57\u6BB5\u7F3A\u7701\uFF09\u3002"
|
|
5731
|
-
],
|
|
5732
|
-
"geo-matched": [
|
|
5733
|
-
"// \u4E2D\u6587\u8BD1\u540D\uFF1A`countryOrRegionZh`\uFF08\u7531 `countryOrRegion` \u7ECF geo-en2zh.json \u7FFB\u8BD1\uFF0C\u76EE\u524D\u8986\u76D6 105 \u4E2A\u56FD\u5BB6/\u5730\u533A\uFF1B\u672A\u547D\u4E2D\u65F6\u8BE5\u5B57\u6BB5\u7F3A\u7701\uFF09\u3002"
|
|
5734
|
-
]
|
|
5735
|
-
};
|
|
5736
|
-
}
|
|
5737
|
-
});
|
|
5738
|
-
|
|
5739
5420
|
// src/utils/strip-legacy-google-fields.ts
|
|
5740
5421
|
function stripLegacyGoogleFieldsIfV2Present(value) {
|
|
5741
5422
|
return walk(value);
|
|
@@ -5773,11 +5454,147 @@ var init_strip_legacy_google_fields = __esm({
|
|
|
5773
5454
|
}
|
|
5774
5455
|
});
|
|
5775
5456
|
|
|
5776
|
-
// src/utils/
|
|
5777
|
-
|
|
5778
|
-
|
|
5457
|
+
// src/utils/http-retry.ts
|
|
5458
|
+
function classifyError(err) {
|
|
5459
|
+
const status = parseHttpStatusFromError(err);
|
|
5460
|
+
if (status === 401) return { class: "abort", status };
|
|
5461
|
+
if (status === void 0) {
|
|
5462
|
+
return { class: "retryable" };
|
|
5463
|
+
}
|
|
5464
|
+
if (status === 408 || status === 429) return { class: "retryable", status };
|
|
5465
|
+
if (status >= 500 && status <= 599) return { class: "retryable", status };
|
|
5466
|
+
if (status >= 400 && status <= 499) return { class: "permanent", status };
|
|
5467
|
+
return { class: "permanent", status };
|
|
5468
|
+
}
|
|
5469
|
+
function computeBackoffMs(attempt, policy) {
|
|
5470
|
+
const exp = policy.baseMs * 2 ** Math.max(0, attempt - 1);
|
|
5471
|
+
const capped = Math.min(exp, policy.maxBackoffMs);
|
|
5472
|
+
const jitter = Math.floor(Math.random() * policy.baseMs);
|
|
5473
|
+
return capped + jitter;
|
|
5474
|
+
}
|
|
5475
|
+
function sleep2(ms, signal) {
|
|
5476
|
+
return new Promise((resolve21, reject) => {
|
|
5477
|
+
if (signal?.aborted) {
|
|
5478
|
+
reject(new Error("retry sleep aborted"));
|
|
5479
|
+
return;
|
|
5480
|
+
}
|
|
5481
|
+
const timer = setTimeout(() => {
|
|
5482
|
+
signal?.removeEventListener("abort", onAbort);
|
|
5483
|
+
resolve21();
|
|
5484
|
+
}, ms);
|
|
5485
|
+
const onAbort = () => {
|
|
5486
|
+
clearTimeout(timer);
|
|
5487
|
+
reject(new Error("retry sleep aborted"));
|
|
5488
|
+
};
|
|
5489
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
5490
|
+
});
|
|
5491
|
+
}
|
|
5492
|
+
async function withTaskTimeout(factory, timeoutMs, label) {
|
|
5493
|
+
if (!timeoutMs || timeoutMs <= 0) return factory();
|
|
5494
|
+
let timer;
|
|
5495
|
+
try {
|
|
5496
|
+
return await Promise.race([
|
|
5497
|
+
factory(),
|
|
5498
|
+
new Promise((_, reject) => {
|
|
5499
|
+
timer = setTimeout(() => {
|
|
5500
|
+
reject(new Error(`\u8BF7\u6C42\u8D85\u65F6\uFF08${(timeoutMs / 1e3).toFixed(0)} \u79D2\uFF09\uFF1A${label}`));
|
|
5501
|
+
}, timeoutMs);
|
|
5502
|
+
})
|
|
5503
|
+
]);
|
|
5504
|
+
} finally {
|
|
5505
|
+
if (timer) clearTimeout(timer);
|
|
5506
|
+
}
|
|
5507
|
+
}
|
|
5508
|
+
async function fetchWithRetry(factory, options) {
|
|
5509
|
+
const policy = { ...DEFAULT_RETRY_POLICY, ...options.policy ?? {} };
|
|
5510
|
+
let lastErr;
|
|
5511
|
+
let lastStatus;
|
|
5512
|
+
for (let attempt = 1; attempt <= policy.maxAttempts; attempt++) {
|
|
5513
|
+
if (options.signal?.aborted) {
|
|
5514
|
+
throw new AbortRunError({
|
|
5515
|
+
message: `\u4EFB\u52A1\u88AB\u5916\u90E8\u4FE1\u53F7\u4E2D\u6B62\uFF1A${options.label}`
|
|
5516
|
+
});
|
|
5517
|
+
}
|
|
5518
|
+
try {
|
|
5519
|
+
return await withTaskTimeout(factory, policy.taskTimeoutMs, options.label);
|
|
5520
|
+
} catch (raw) {
|
|
5521
|
+
const err = raw instanceof Error ? raw : new Error(String(raw));
|
|
5522
|
+
const cls = classifyError(err);
|
|
5523
|
+
lastErr = err;
|
|
5524
|
+
lastStatus = cls.status;
|
|
5525
|
+
if (cls.class === "abort") {
|
|
5526
|
+
throw new AbortRunError({
|
|
5527
|
+
message: `Token \u5931\u6548\u6216\u81F4\u547D\u9519\u8BEF\uFF08${options.label}\uFF09\uFF1A${err.message}`,
|
|
5528
|
+
status: cls.status,
|
|
5529
|
+
cause: err
|
|
5530
|
+
});
|
|
5531
|
+
}
|
|
5532
|
+
if (cls.class === "permanent" || attempt >= policy.maxAttempts) {
|
|
5533
|
+
throw new HttpRetryError({
|
|
5534
|
+
message: cls.class === "permanent" ? `\u6C38\u4E45\u5931\u8D25\uFF08${options.label}\uFF09\uFF1A${err.message}` : `\u91CD\u8BD5 ${attempt} \u6B21\u4ECD\u5931\u8D25\uFF08${options.label}\uFF09\uFF1A${err.message}`,
|
|
5535
|
+
class: cls.class === "permanent" ? "permanent" : "retryable",
|
|
5536
|
+
status: cls.status,
|
|
5537
|
+
attempts: attempt,
|
|
5538
|
+
cause: err
|
|
5539
|
+
});
|
|
5540
|
+
}
|
|
5541
|
+
const backoffMs = computeBackoffMs(attempt, policy);
|
|
5542
|
+
options.onRetry?.({ attempt, backoffMs, status: cls.status, error: err });
|
|
5543
|
+
try {
|
|
5544
|
+
await sleep2(backoffMs, options.signal);
|
|
5545
|
+
} catch {
|
|
5546
|
+
throw new AbortRunError({
|
|
5547
|
+
message: `\u91CD\u8BD5\u7B49\u5F85\u88AB\u4E2D\u6B62\uFF1A${options.label}`,
|
|
5548
|
+
cause: err
|
|
5549
|
+
});
|
|
5550
|
+
}
|
|
5551
|
+
}
|
|
5552
|
+
}
|
|
5553
|
+
throw new HttpRetryError({
|
|
5554
|
+
message: `\u672A\u77E5\u91CD\u8BD5\u5931\u8D25\uFF08${options.label}\uFF09\uFF1A${lastErr?.message ?? "no error"}`,
|
|
5555
|
+
class: "retryable",
|
|
5556
|
+
status: lastStatus,
|
|
5557
|
+
attempts: policy.maxAttempts,
|
|
5558
|
+
cause: lastErr
|
|
5559
|
+
});
|
|
5560
|
+
}
|
|
5561
|
+
var HttpRetryError, AbortRunError, DEFAULT_RETRY_POLICY;
|
|
5562
|
+
var init_http_retry = __esm({
|
|
5563
|
+
"src/utils/http-retry.ts"() {
|
|
5779
5564
|
"use strict";
|
|
5780
|
-
|
|
5565
|
+
init_dist();
|
|
5566
|
+
HttpRetryError = class extends Error {
|
|
5567
|
+
class;
|
|
5568
|
+
status;
|
|
5569
|
+
attempts;
|
|
5570
|
+
cause;
|
|
5571
|
+
constructor(opts) {
|
|
5572
|
+
super(opts.message);
|
|
5573
|
+
this.name = "HttpRetryError";
|
|
5574
|
+
this.class = opts.class;
|
|
5575
|
+
this.status = opts.status;
|
|
5576
|
+
this.attempts = opts.attempts;
|
|
5577
|
+
this.cause = opts.cause;
|
|
5578
|
+
}
|
|
5579
|
+
};
|
|
5580
|
+
AbortRunError = class extends HttpRetryError {
|
|
5581
|
+
constructor(opts) {
|
|
5582
|
+
super({
|
|
5583
|
+
message: opts.message,
|
|
5584
|
+
class: "abort",
|
|
5585
|
+
status: opts.status,
|
|
5586
|
+
attempts: 1,
|
|
5587
|
+
cause: opts.cause
|
|
5588
|
+
});
|
|
5589
|
+
this.name = "AbortRunError";
|
|
5590
|
+
}
|
|
5591
|
+
};
|
|
5592
|
+
DEFAULT_RETRY_POLICY = {
|
|
5593
|
+
maxAttempts: 3,
|
|
5594
|
+
baseMs: 1e3,
|
|
5595
|
+
maxBackoffMs: 3e4,
|
|
5596
|
+
taskTimeoutMs: 6e4
|
|
5597
|
+
};
|
|
5781
5598
|
}
|
|
5782
5599
|
});
|
|
5783
5600
|
|
|
@@ -5952,150 +5769,6 @@ var init_sections = __esm({
|
|
|
5952
5769
|
}
|
|
5953
5770
|
});
|
|
5954
5771
|
|
|
5955
|
-
// src/utils/http-retry.ts
|
|
5956
|
-
function classifyError(err) {
|
|
5957
|
-
const status = parseHttpStatusFromError(err);
|
|
5958
|
-
if (status === 401) return { class: "abort", status };
|
|
5959
|
-
if (status === void 0) {
|
|
5960
|
-
return { class: "retryable" };
|
|
5961
|
-
}
|
|
5962
|
-
if (status === 408 || status === 429) return { class: "retryable", status };
|
|
5963
|
-
if (status >= 500 && status <= 599) return { class: "retryable", status };
|
|
5964
|
-
if (status >= 400 && status <= 499) return { class: "permanent", status };
|
|
5965
|
-
return { class: "permanent", status };
|
|
5966
|
-
}
|
|
5967
|
-
function computeBackoffMs(attempt, policy) {
|
|
5968
|
-
const exp = policy.baseMs * 2 ** Math.max(0, attempt - 1);
|
|
5969
|
-
const capped = Math.min(exp, policy.maxBackoffMs);
|
|
5970
|
-
const jitter = Math.floor(Math.random() * policy.baseMs);
|
|
5971
|
-
return capped + jitter;
|
|
5972
|
-
}
|
|
5973
|
-
function sleep3(ms, signal) {
|
|
5974
|
-
return new Promise((resolve21, reject) => {
|
|
5975
|
-
if (signal?.aborted) {
|
|
5976
|
-
reject(new Error("retry sleep aborted"));
|
|
5977
|
-
return;
|
|
5978
|
-
}
|
|
5979
|
-
const timer = setTimeout(() => {
|
|
5980
|
-
signal?.removeEventListener("abort", onAbort);
|
|
5981
|
-
resolve21();
|
|
5982
|
-
}, ms);
|
|
5983
|
-
const onAbort = () => {
|
|
5984
|
-
clearTimeout(timer);
|
|
5985
|
-
reject(new Error("retry sleep aborted"));
|
|
5986
|
-
};
|
|
5987
|
-
signal?.addEventListener("abort", onAbort, { once: true });
|
|
5988
|
-
});
|
|
5989
|
-
}
|
|
5990
|
-
async function withTaskTimeout(factory, timeoutMs, label) {
|
|
5991
|
-
if (!timeoutMs || timeoutMs <= 0) return factory();
|
|
5992
|
-
let timer;
|
|
5993
|
-
try {
|
|
5994
|
-
return await Promise.race([
|
|
5995
|
-
factory(),
|
|
5996
|
-
new Promise((_, reject) => {
|
|
5997
|
-
timer = setTimeout(() => {
|
|
5998
|
-
reject(new Error(`\u8BF7\u6C42\u8D85\u65F6\uFF08${(timeoutMs / 1e3).toFixed(0)} \u79D2\uFF09\uFF1A${label}`));
|
|
5999
|
-
}, timeoutMs);
|
|
6000
|
-
})
|
|
6001
|
-
]);
|
|
6002
|
-
} finally {
|
|
6003
|
-
if (timer) clearTimeout(timer);
|
|
6004
|
-
}
|
|
6005
|
-
}
|
|
6006
|
-
async function fetchWithRetry(factory, options) {
|
|
6007
|
-
const policy = { ...DEFAULT_RETRY_POLICY, ...options.policy ?? {} };
|
|
6008
|
-
let lastErr;
|
|
6009
|
-
let lastStatus;
|
|
6010
|
-
for (let attempt = 1; attempt <= policy.maxAttempts; attempt++) {
|
|
6011
|
-
if (options.signal?.aborted) {
|
|
6012
|
-
throw new AbortRunError({
|
|
6013
|
-
message: `\u4EFB\u52A1\u88AB\u5916\u90E8\u4FE1\u53F7\u4E2D\u6B62\uFF1A${options.label}`
|
|
6014
|
-
});
|
|
6015
|
-
}
|
|
6016
|
-
try {
|
|
6017
|
-
return await withTaskTimeout(factory, policy.taskTimeoutMs, options.label);
|
|
6018
|
-
} catch (raw) {
|
|
6019
|
-
const err = raw instanceof Error ? raw : new Error(String(raw));
|
|
6020
|
-
const cls = classifyError(err);
|
|
6021
|
-
lastErr = err;
|
|
6022
|
-
lastStatus = cls.status;
|
|
6023
|
-
if (cls.class === "abort") {
|
|
6024
|
-
throw new AbortRunError({
|
|
6025
|
-
message: `Token \u5931\u6548\u6216\u81F4\u547D\u9519\u8BEF\uFF08${options.label}\uFF09\uFF1A${err.message}`,
|
|
6026
|
-
status: cls.status,
|
|
6027
|
-
cause: err
|
|
6028
|
-
});
|
|
6029
|
-
}
|
|
6030
|
-
if (cls.class === "permanent" || attempt >= policy.maxAttempts) {
|
|
6031
|
-
throw new HttpRetryError({
|
|
6032
|
-
message: cls.class === "permanent" ? `\u6C38\u4E45\u5931\u8D25\uFF08${options.label}\uFF09\uFF1A${err.message}` : `\u91CD\u8BD5 ${attempt} \u6B21\u4ECD\u5931\u8D25\uFF08${options.label}\uFF09\uFF1A${err.message}`,
|
|
6033
|
-
class: cls.class === "permanent" ? "permanent" : "retryable",
|
|
6034
|
-
status: cls.status,
|
|
6035
|
-
attempts: attempt,
|
|
6036
|
-
cause: err
|
|
6037
|
-
});
|
|
6038
|
-
}
|
|
6039
|
-
const backoffMs = computeBackoffMs(attempt, policy);
|
|
6040
|
-
options.onRetry?.({ attempt, backoffMs, status: cls.status, error: err });
|
|
6041
|
-
try {
|
|
6042
|
-
await sleep3(backoffMs, options.signal);
|
|
6043
|
-
} catch {
|
|
6044
|
-
throw new AbortRunError({
|
|
6045
|
-
message: `\u91CD\u8BD5\u7B49\u5F85\u88AB\u4E2D\u6B62\uFF1A${options.label}`,
|
|
6046
|
-
cause: err
|
|
6047
|
-
});
|
|
6048
|
-
}
|
|
6049
|
-
}
|
|
6050
|
-
}
|
|
6051
|
-
throw new HttpRetryError({
|
|
6052
|
-
message: `\u672A\u77E5\u91CD\u8BD5\u5931\u8D25\uFF08${options.label}\uFF09\uFF1A${lastErr?.message ?? "no error"}`,
|
|
6053
|
-
class: "retryable",
|
|
6054
|
-
status: lastStatus,
|
|
6055
|
-
attempts: policy.maxAttempts,
|
|
6056
|
-
cause: lastErr
|
|
6057
|
-
});
|
|
6058
|
-
}
|
|
6059
|
-
var HttpRetryError, AbortRunError, DEFAULT_RETRY_POLICY;
|
|
6060
|
-
var init_http_retry = __esm({
|
|
6061
|
-
"src/utils/http-retry.ts"() {
|
|
6062
|
-
"use strict";
|
|
6063
|
-
init_dist();
|
|
6064
|
-
HttpRetryError = class extends Error {
|
|
6065
|
-
class;
|
|
6066
|
-
status;
|
|
6067
|
-
attempts;
|
|
6068
|
-
cause;
|
|
6069
|
-
constructor(opts) {
|
|
6070
|
-
super(opts.message);
|
|
6071
|
-
this.name = "HttpRetryError";
|
|
6072
|
-
this.class = opts.class;
|
|
6073
|
-
this.status = opts.status;
|
|
6074
|
-
this.attempts = opts.attempts;
|
|
6075
|
-
this.cause = opts.cause;
|
|
6076
|
-
}
|
|
6077
|
-
};
|
|
6078
|
-
AbortRunError = class extends HttpRetryError {
|
|
6079
|
-
constructor(opts) {
|
|
6080
|
-
super({
|
|
6081
|
-
message: opts.message,
|
|
6082
|
-
class: "abort",
|
|
6083
|
-
status: opts.status,
|
|
6084
|
-
attempts: 1,
|
|
6085
|
-
cause: opts.cause
|
|
6086
|
-
});
|
|
6087
|
-
this.name = "AbortRunError";
|
|
6088
|
-
}
|
|
6089
|
-
};
|
|
6090
|
-
DEFAULT_RETRY_POLICY = {
|
|
6091
|
-
maxAttempts: 3,
|
|
6092
|
-
baseMs: 1e3,
|
|
6093
|
-
maxBackoffMs: 3e4,
|
|
6094
|
-
taskTimeoutMs: 6e4
|
|
6095
|
-
};
|
|
6096
|
-
}
|
|
6097
|
-
});
|
|
6098
|
-
|
|
6099
5772
|
// src/commands/google-analysis/normalize-impression-shares.ts
|
|
6100
5773
|
function normalizeShareValue(value, competitiveMetrics, field) {
|
|
6101
5774
|
const cmVal = competitiveMetrics?.[field];
|
|
@@ -101811,7 +101484,7 @@ var init_daily_metrics_range = __esm({
|
|
|
101811
101484
|
});
|
|
101812
101485
|
|
|
101813
101486
|
// src/commands/google-analysis/fetch.ts
|
|
101814
|
-
function
|
|
101487
|
+
function defaultDateRange2() {
|
|
101815
101488
|
const end = /* @__PURE__ */ new Date();
|
|
101816
101489
|
end.setDate(end.getDate() - 1);
|
|
101817
101490
|
const start = new Date(end);
|
|
@@ -101821,7 +101494,7 @@ function defaultDateRange3() {
|
|
|
101821
101494
|
}
|
|
101822
101495
|
function resolveDateRange(start, end) {
|
|
101823
101496
|
if (start && end) return { startDate: start, endDate: end };
|
|
101824
|
-
if (!start && !end) return
|
|
101497
|
+
if (!start && !end) return defaultDateRange2();
|
|
101825
101498
|
console.error("\n\u274C --start \u4E0E --end \u987B\u540C\u65F6\u4F20\u5165\uFF0C\u6216\u540C\u65F6\u7701\u7565\u4EE5\u4F7F\u7528\u9ED8\u8BA4\u8FD1 7 \u5929\uFF08\u622A\u81F3\u6628\u5929\uFF09\u3002\n");
|
|
101826
101499
|
process.exit(1);
|
|
101827
101500
|
}
|
|
@@ -102132,6 +101805,343 @@ var init_fetch = __esm({
|
|
|
102132
101805
|
}
|
|
102133
101806
|
});
|
|
102134
101807
|
|
|
101808
|
+
// src/commands/google-analysis/wrap-snapshot-envelope.ts
|
|
101809
|
+
function coerceToRowArray(value) {
|
|
101810
|
+
if (Array.isArray(value)) return value;
|
|
101811
|
+
if (value === null || typeof value !== "object") return [];
|
|
101812
|
+
const o = value;
|
|
101813
|
+
const keys = Object.keys(o);
|
|
101814
|
+
if (keys.length === 0) return [];
|
|
101815
|
+
if (keys.every((k) => /^\d+$/.test(k))) {
|
|
101816
|
+
return keys.sort((a, b) => Number(a) - Number(b)).map((k) => o[k]);
|
|
101817
|
+
}
|
|
101818
|
+
return [];
|
|
101819
|
+
}
|
|
101820
|
+
function asRecord(value) {
|
|
101821
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) return null;
|
|
101822
|
+
return value;
|
|
101823
|
+
}
|
|
101824
|
+
function readGatewayList(bag) {
|
|
101825
|
+
const items2 = coerceToRowArray(bag.data);
|
|
101826
|
+
const meta = {};
|
|
101827
|
+
if (typeof bag.code === "number") meta.code = bag.code;
|
|
101828
|
+
if (typeof bag.message === "string") meta.message = bag.message;
|
|
101829
|
+
return { items: items2, ...Object.keys(meta).length > 0 ? { meta } : {} };
|
|
101830
|
+
}
|
|
101831
|
+
function flattenMaterials(payload) {
|
|
101832
|
+
const bag = asRecord(payload);
|
|
101833
|
+
if (!bag) return [];
|
|
101834
|
+
const images = coerceToRowArray(bag.images).map(
|
|
101835
|
+
(row) => asRecord(row) ? { ...row, assetType: "image" } : row
|
|
101836
|
+
);
|
|
101837
|
+
const videos = coerceToRowArray(bag.videos).map(
|
|
101838
|
+
(row) => asRecord(row) ? { ...row, assetType: "video" } : row
|
|
101839
|
+
);
|
|
101840
|
+
return [...images, ...videos];
|
|
101841
|
+
}
|
|
101842
|
+
function wrapGoogleAnalysisSnapshotPayload(section, payload) {
|
|
101843
|
+
let items2 = [];
|
|
101844
|
+
let record2 = null;
|
|
101845
|
+
let meta;
|
|
101846
|
+
if (COMPOSITE_SECTIONS.has(section)) {
|
|
101847
|
+
items2 = flattenMaterials(payload);
|
|
101848
|
+
} else if (RECORD_ONLY_SECTIONS.has(section)) {
|
|
101849
|
+
record2 = asRecord(payload);
|
|
101850
|
+
} else if (GATEWAY_LIST_SECTIONS.has(section)) {
|
|
101851
|
+
const bag = asRecord(payload);
|
|
101852
|
+
if (bag) {
|
|
101853
|
+
const r = readGatewayList(bag);
|
|
101854
|
+
items2 = r.items;
|
|
101855
|
+
meta = r.meta;
|
|
101856
|
+
}
|
|
101857
|
+
} else if (ROOT_ARRAY_SECTIONS.has(section)) {
|
|
101858
|
+
items2 = coerceToRowArray(payload);
|
|
101859
|
+
} else {
|
|
101860
|
+
const rowKey = ROW_KEY_BY_SECTION[section];
|
|
101861
|
+
const bag = asRecord(payload);
|
|
101862
|
+
if (rowKey && bag) {
|
|
101863
|
+
items2 = coerceToRowArray(bag[rowKey]);
|
|
101864
|
+
} else {
|
|
101865
|
+
const arr = coerceToRowArray(payload);
|
|
101866
|
+
if (arr.length > 0) items2 = arr;
|
|
101867
|
+
else record2 = asRecord(payload);
|
|
101868
|
+
}
|
|
101869
|
+
}
|
|
101870
|
+
return {
|
|
101871
|
+
schemaVersion: GOOGLE_ANALYSIS_FILE_SCHEMA_VERSION,
|
|
101872
|
+
section,
|
|
101873
|
+
itemCount: items2.length,
|
|
101874
|
+
items: items2,
|
|
101875
|
+
record: record2,
|
|
101876
|
+
...meta !== void 0 ? { meta } : {}
|
|
101877
|
+
};
|
|
101878
|
+
}
|
|
101879
|
+
var GOOGLE_ANALYSIS_FILE_SCHEMA_VERSION, ROW_KEY_BY_SECTION, RECORD_ONLY_SECTIONS, COMPOSITE_SECTIONS, ROOT_ARRAY_SECTIONS, GATEWAY_LIST_SECTIONS;
|
|
101880
|
+
var init_wrap_snapshot_envelope = __esm({
|
|
101881
|
+
"src/commands/google-analysis/wrap-snapshot-envelope.ts"() {
|
|
101882
|
+
"use strict";
|
|
101883
|
+
GOOGLE_ANALYSIS_FILE_SCHEMA_VERSION = 3;
|
|
101884
|
+
ROW_KEY_BY_SECTION = {
|
|
101885
|
+
keywords: "keywords",
|
|
101886
|
+
campaigns: "campaigns",
|
|
101887
|
+
devices: "devices",
|
|
101888
|
+
geographic: "countries",
|
|
101889
|
+
"geo-matched": "countries",
|
|
101890
|
+
"campaign-geo": "countries",
|
|
101891
|
+
"campaign-geo-matched": "countries",
|
|
101892
|
+
"campaign-device": "devices",
|
|
101893
|
+
audience: "audience"
|
|
101894
|
+
};
|
|
101895
|
+
RECORD_ONLY_SECTIONS = /* @__PURE__ */ new Set([
|
|
101896
|
+
"overview",
|
|
101897
|
+
"resource-counts",
|
|
101898
|
+
"dimension-summary",
|
|
101899
|
+
"gold-account",
|
|
101900
|
+
"final-urls",
|
|
101901
|
+
"campaign-types",
|
|
101902
|
+
"ads-index"
|
|
101903
|
+
]);
|
|
101904
|
+
COMPOSITE_SECTIONS = /* @__PURE__ */ new Set(["materials"]);
|
|
101905
|
+
ROOT_ARRAY_SECTIONS = /* @__PURE__ */ new Set([
|
|
101906
|
+
"campaign-hour",
|
|
101907
|
+
"extensions",
|
|
101908
|
+
"asset-images",
|
|
101909
|
+
"videos",
|
|
101910
|
+
"daily-metrics",
|
|
101911
|
+
"conversion-actions"
|
|
101912
|
+
]);
|
|
101913
|
+
GATEWAY_LIST_SECTIONS = /* @__PURE__ */ new Set([
|
|
101914
|
+
"search-terms",
|
|
101915
|
+
"ads"
|
|
101916
|
+
]);
|
|
101917
|
+
}
|
|
101918
|
+
});
|
|
101919
|
+
|
|
101920
|
+
// src/utils/snapshot/dir.ts
|
|
101921
|
+
var init_dir = __esm({
|
|
101922
|
+
"src/utils/snapshot/dir.ts"() {
|
|
101923
|
+
"use strict";
|
|
101924
|
+
init_dist();
|
|
101925
|
+
}
|
|
101926
|
+
});
|
|
101927
|
+
|
|
101928
|
+
// src/utils/snapshot/google-analysis.ts
|
|
101929
|
+
import * as fs7 from "fs/promises";
|
|
101930
|
+
import * as path11 from "path";
|
|
101931
|
+
function googleAnalysisManifestFile(accountId) {
|
|
101932
|
+
return `${applyIdSuffix("manifest", accountId)}.json`;
|
|
101933
|
+
}
|
|
101934
|
+
function buildOutlineHints(section) {
|
|
101935
|
+
const hints = [...GOOGLE_ANALYSIS_ENVELOPE_OUTLINE_HINTS];
|
|
101936
|
+
if (RATE_BEARING_SECTIONS.has(section)) {
|
|
101937
|
+
hints.push(...GOOGLE_ANALYSIS_RATE_NORMALIZED_OUTLINE_HINTS);
|
|
101938
|
+
}
|
|
101939
|
+
if (section === "campaigns") {
|
|
101940
|
+
hints.push(
|
|
101941
|
+
...GOOGLE_ANALYSIS_CAMPAIGNS_OUTLINE_BUDGET_HINTS,
|
|
101942
|
+
...GOOGLE_ANALYSIS_CAMPAIGNS_COMPETITIVE_METRICS_HINTS
|
|
101943
|
+
);
|
|
101944
|
+
}
|
|
101945
|
+
if (section === "ads") {
|
|
101946
|
+
hints.push(...GOOGLE_ANALYSIS_ADS_OUTLINE_BUDGET_HINTS);
|
|
101947
|
+
}
|
|
101948
|
+
const zhHints = GOOGLE_ANALYSIS_ZH_FIELD_HINTS_BY_SECTION[section];
|
|
101949
|
+
if (zhHints) hints.push(...zhHints);
|
|
101950
|
+
return hints.length > 0 ? hints : void 0;
|
|
101951
|
+
}
|
|
101952
|
+
function googleAnalysisSectionFilename(section, accountId, dateRange) {
|
|
101953
|
+
if (!/^[a-z0-9-]+$/.test(section)) {
|
|
101954
|
+
throw new Error(`\u975E\u6CD5\u5B50\u547D\u4EE4\u540D\uFF0C\u65E0\u6CD5\u751F\u6210\u6587\u4EF6\u540D\uFF1A${section}`);
|
|
101955
|
+
}
|
|
101956
|
+
let stem = applyIdSuffix(section, accountId);
|
|
101957
|
+
if (dateRange?.mode === "range") {
|
|
101958
|
+
const start = dateRange.start.replace(/-/g, "");
|
|
101959
|
+
const end = dateRange.end.replace(/-/g, "");
|
|
101960
|
+
stem = `${stem}_${start}-${end}`;
|
|
101961
|
+
}
|
|
101962
|
+
return `${stem}.json`;
|
|
101963
|
+
}
|
|
101964
|
+
async function readManifestIfExists(absDir, accountId) {
|
|
101965
|
+
const candidates = [];
|
|
101966
|
+
const suffixed = googleAnalysisManifestFile(accountId);
|
|
101967
|
+
candidates.push(suffixed);
|
|
101968
|
+
if (suffixed !== LEGACY_MANIFEST_FILE) {
|
|
101969
|
+
candidates.push(LEGACY_MANIFEST_FILE);
|
|
101970
|
+
}
|
|
101971
|
+
for (const name2 of candidates) {
|
|
101972
|
+
const manifestPath = path11.join(absDir, name2);
|
|
101973
|
+
try {
|
|
101974
|
+
const raw = await fs7.readFile(manifestPath, "utf8");
|
|
101975
|
+
const parsed = JSON.parse(raw);
|
|
101976
|
+
const sv = parsed?.schemaVersion;
|
|
101977
|
+
if (sv !== 2 && sv !== SCHEMA_VERSION2 || !Array.isArray(parsed.artifacts)) {
|
|
101978
|
+
continue;
|
|
101979
|
+
}
|
|
101980
|
+
return parsed;
|
|
101981
|
+
} catch {
|
|
101982
|
+
continue;
|
|
101983
|
+
}
|
|
101984
|
+
}
|
|
101985
|
+
return null;
|
|
101986
|
+
}
|
|
101987
|
+
function mergeGoogleAnalysisManifest(existing, params) {
|
|
101988
|
+
const prevArts = existing?.artifacts ?? [];
|
|
101989
|
+
const without = prevArts.filter((a) => a.file !== params.newArtifact.file);
|
|
101990
|
+
const artifacts = [...without, params.newArtifact];
|
|
101991
|
+
const fieldGuide = existing?.fieldGuide ?? DEFAULT_FIELD_GUIDE;
|
|
101992
|
+
return {
|
|
101993
|
+
schemaVersion: SCHEMA_VERSION2,
|
|
101994
|
+
cliPackage: CLI_PACKAGE,
|
|
101995
|
+
cliVersion: params.cliVersion,
|
|
101996
|
+
googleAnalysis: {
|
|
101997
|
+
accountId: params.accountId,
|
|
101998
|
+
dateRange: params.dateRange
|
|
101999
|
+
},
|
|
102000
|
+
fieldGuide: {
|
|
102001
|
+
markdownRefs: [...fieldGuide.markdownRefs],
|
|
102002
|
+
tsTypesModule: fieldGuide.tsTypesModule
|
|
102003
|
+
},
|
|
102004
|
+
artifacts
|
|
102005
|
+
};
|
|
102006
|
+
}
|
|
102007
|
+
async function writeGoogleAnalysisSnapshot(params) {
|
|
102008
|
+
const absDir = await ensureSnapshotDir(params.snapshotDir);
|
|
102009
|
+
const accountSlug = slugifyIdSuffix(params.accountId);
|
|
102010
|
+
const fileName = googleAnalysisSectionFilename(
|
|
102011
|
+
params.section,
|
|
102012
|
+
accountSlug || void 0,
|
|
102013
|
+
params.dateRange
|
|
102014
|
+
);
|
|
102015
|
+
const relativeFile = fileName;
|
|
102016
|
+
const writtenAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
102017
|
+
const wrapped = wrapGoogleAnalysisSnapshotPayload(
|
|
102018
|
+
params.section,
|
|
102019
|
+
params.payload
|
|
102020
|
+
);
|
|
102021
|
+
const normalizedWrapped = stringifyIdsDeep(wrapped);
|
|
102022
|
+
const body = JSON.stringify(normalizedWrapped, null, 2);
|
|
102023
|
+
await fs7.writeFile(path11.join(absDir, fileName), `${body}
|
|
102024
|
+
`, "utf8");
|
|
102025
|
+
const outlineFileName = snapshotOutlineFileName(fileName);
|
|
102026
|
+
const outlineExtra = buildOutlineHints(params.section);
|
|
102027
|
+
const outlineBody = formatOutlineFileBody(fileName, normalizedWrapped, outlineExtra);
|
|
102028
|
+
await fs7.writeFile(path11.join(absDir, outlineFileName), `${outlineBody}
|
|
102029
|
+
`, "utf8");
|
|
102030
|
+
const existing = await readManifestIfExists(absDir, accountSlug || void 0);
|
|
102031
|
+
const newArtifact = {
|
|
102032
|
+
section: params.section,
|
|
102033
|
+
file: relativeFile,
|
|
102034
|
+
writtenAt,
|
|
102035
|
+
...params.endpointHint !== void 0 ? { endpointHint: params.endpointHint } : {}
|
|
102036
|
+
};
|
|
102037
|
+
const merged = mergeGoogleAnalysisManifest(existing, {
|
|
102038
|
+
accountId: params.accountId,
|
|
102039
|
+
dateRange: params.dateRange,
|
|
102040
|
+
cliVersion: params.cliVersion,
|
|
102041
|
+
newArtifact
|
|
102042
|
+
});
|
|
102043
|
+
const manifestFile = googleAnalysisManifestFile(accountSlug || void 0);
|
|
102044
|
+
await fs7.writeFile(
|
|
102045
|
+
path11.join(absDir, manifestFile),
|
|
102046
|
+
`${JSON.stringify(stringifyIdsDeep(merged), null, 2)}
|
|
102047
|
+
`,
|
|
102048
|
+
"utf8"
|
|
102049
|
+
);
|
|
102050
|
+
return {
|
|
102051
|
+
kind: "siluzan-tso-google-analysis-snapshot",
|
|
102052
|
+
schemaVersion: SCHEMA_VERSION2,
|
|
102053
|
+
absoluteSnapshotDir: absDir,
|
|
102054
|
+
manifestFile,
|
|
102055
|
+
writtenFiles: [fileName, outlineFileName],
|
|
102056
|
+
section: params.section,
|
|
102057
|
+
outlineFile: outlineFileName,
|
|
102058
|
+
agentHint: OUTLINE_AGENT_HINT
|
|
102059
|
+
};
|
|
102060
|
+
}
|
|
102061
|
+
var LEGACY_MANIFEST_FILE, CLI_PACKAGE, SCHEMA_VERSION2, DEFAULT_FIELD_GUIDE, GOOGLE_ANALYSIS_CAMPAIGNS_OUTLINE_BUDGET_HINTS, GOOGLE_ANALYSIS_ADS_OUTLINE_BUDGET_HINTS, GOOGLE_ANALYSIS_CAMPAIGNS_COMPETITIVE_METRICS_HINTS, RATE_BEARING_SECTIONS, GOOGLE_ANALYSIS_RATE_NORMALIZED_OUTLINE_HINTS, GOOGLE_ANALYSIS_ENVELOPE_OUTLINE_HINTS, GOOGLE_ANALYSIS_ZH_FIELD_HINTS_BY_SECTION;
|
|
102062
|
+
var init_google_analysis = __esm({
|
|
102063
|
+
"src/utils/snapshot/google-analysis.ts"() {
|
|
102064
|
+
"use strict";
|
|
102065
|
+
init_cli_json();
|
|
102066
|
+
init_wrap_snapshot_envelope();
|
|
102067
|
+
init_dir();
|
|
102068
|
+
LEGACY_MANIFEST_FILE = "manifest.json";
|
|
102069
|
+
CLI_PACKAGE = "siluzan-tso-cli";
|
|
102070
|
+
SCHEMA_VERSION2 = 3;
|
|
102071
|
+
DEFAULT_FIELD_GUIDE = {
|
|
102072
|
+
markdownRefs: ["references/accounts/currency.md", "references/analytics/account-analytics.md"],
|
|
102073
|
+
tsTypesModule: "tso-cli/src/types/google-analysis-api.ts"
|
|
102074
|
+
};
|
|
102075
|
+
GOOGLE_ANALYSIS_CAMPAIGNS_OUTLINE_BUDGET_HINTS = [
|
|
102076
|
+
"// \u91D1\u989D\uFF1A`campaigns[].budgetAmountYuan` / `campaignTargetCpaYuan` / `maximizeConversionsTargetCpaYuan` \u5747\u4E3A**\u5143**\uFF08CLI \u51FA\u53E3\u7EDF\u4E00\uFF09\uFF1B\u540C\u884C `spend` / `averageCpc` / `costPerConversion` \u4E5F\u662F\u5143\u3002",
|
|
102077
|
+
"// \u65E7\u5B57\u6BB5 `budgetAmount`\uFF08\u5206\uFF09/ `*Micros`\uFF08\u5FAE\u5143\uFF09\u5DF2\u4E0D\u518D\u843D\u76D8\uFF0C**\u7981\u6B62**\u518D\u505A \xF7100 / \xF71_000_000 \u6362\u7B97\u3002",
|
|
102078
|
+
"// \u72B6\u6001\uFF1A\u6BCF\u884C\u542B `campaignStatusDisplay`\uFF08\u6295\u653E\u4E2D/\u5DF2\u6682\u505C/\u5DF2\u79FB\u9664\uFF09\uFF1B\u62A5\u544A\u72B6\u6001\u5217**\u76F4\u63A5\u8BFB\u6B64\u5B57\u6BB5**\uFF0C\u7981\u6B62\u5BF9 `campaignStatus` \u5199 `MAP[s]||'\u5DF2\u79FB\u9664'`\u3002"
|
|
102079
|
+
];
|
|
102080
|
+
GOOGLE_ANALYSIS_ADS_OUTLINE_BUDGET_HINTS = [
|
|
102081
|
+
"// \u91D1\u989D\uFF1A`ads[].spend` / `averageCpc` / `costPerConversion` \u843D\u76D8\u524D\u5DF2\u7EDF\u4E00\u4E3A**\u5143**\uFF08`costPerConversion` \u7531\u7F51\u5173\u5FAE\u5143 \xF71e6\uFF09\uFF1B**\u7981\u6B62**\u518D\u5BF9 `costPerConversion` \u505A \xF71_000_000\u3002"
|
|
102082
|
+
];
|
|
102083
|
+
GOOGLE_ANALYSIS_CAMPAIGNS_COMPETITIVE_METRICS_HINTS = [
|
|
102084
|
+
"// \u7ADE\u4E89\u6307\u6807\uFF1A`campaigns[].competitiveMetrics` \u4E3A **0~1 \u5C0F\u6570**\uFF08\u5982 `0.0999` = 9.99%\uFF09\uFF0C\u542B Top/AbsoluteTop/Content/ClickShare \u7B49\uFF1B\u65E0\u6570\u636E\u65F6\u4E3A `null`\u3002",
|
|
102085
|
+
"// \u884C\u9876 `searchImpressionShare` / `searchBudgetLostImpressionShare` / `searchRankLostImpressionShare` \u843D\u76D8\u524D\u5DF2\u5F52\u4E00\u4E3A **0~1 \u5C0F\u6570**\uFF08\u4E0E `competitiveMetrics` \u540C\u540D\u9879\u4E00\u81F4\uFF09\uFF1B\u5C55\u793A\u4E3A % \u65F6 \xD7100\u3002",
|
|
102086
|
+
"// `keywords[]` \u884C\u9876 3 \u9879\u4EFD\u989D\u540C\u6837\u4E3A 0~1 \u5C0F\u6570\uFF08\u65E0 `competitiveMetrics` \u65F6\u7531\u767E\u5206\u6570 \xF7100\uFF09\u3002"
|
|
102087
|
+
];
|
|
102088
|
+
RATE_BEARING_SECTIONS = /* @__PURE__ */ new Set([
|
|
102089
|
+
"overview",
|
|
102090
|
+
"keywords",
|
|
102091
|
+
"search-terms",
|
|
102092
|
+
"campaigns",
|
|
102093
|
+
"ads",
|
|
102094
|
+
"extensions",
|
|
102095
|
+
"devices",
|
|
102096
|
+
"geographic",
|
|
102097
|
+
"geo-matched",
|
|
102098
|
+
"campaign-geo",
|
|
102099
|
+
"campaign-geo-matched",
|
|
102100
|
+
"campaign-device",
|
|
102101
|
+
"audience",
|
|
102102
|
+
"asset-images",
|
|
102103
|
+
"videos",
|
|
102104
|
+
"materials",
|
|
102105
|
+
"daily-metrics",
|
|
102106
|
+
"dimension-summary",
|
|
102107
|
+
"ads-index"
|
|
102108
|
+
]);
|
|
102109
|
+
GOOGLE_ANALYSIS_RATE_NORMALIZED_OUTLINE_HINTS = [
|
|
102110
|
+
"// \u6982\u7387\u5B57\u6BB5\uFF1A`ctr` / `conversionRate` \u81EA manifest schemaVersion 2\uFF082026-05\uFF09\u8D77\u5DF2\u7531 CLI \u7EDF\u4E00\u5F52\u4E00\u4E3A **0~1 \u5C0F\u6570**\uFF08\u5982 `0.0964` = 9.64%\uFF09\u3002",
|
|
102111
|
+
"// \u5199 Excel 0~1 \u5C0F\u6570\u5217\uFF1A\u76F4\u63A5\u5199\u5165\uFF1B\u5199\u300Cx%\u300D\u6587\u6848\uFF1A`(v * 100).toFixed(2) + '%'`\uFF1B**\u7981\u6B62**\u518D \xF7100\u3002`interactionRate` \u4ECD\u662F\u5B57\u7B26\u4E32 0~1 \u5C0F\u6570\uFF0C`parseFloat` \u540E\u4F7F\u7528\u3002"
|
|
102112
|
+
];
|
|
102113
|
+
GOOGLE_ANALYSIS_ENVELOPE_OUTLINE_HINTS = [
|
|
102114
|
+
"// \u7EDF\u4E00\u8BBF\u95EE\u5C42\uFF08manifest / \u6587\u4EF6\u5185\u5747\u4E3A `schemaVersion: 3`\uFF09\uFF1A\u5224\u522B\u53EA\u6709\u4E00\u6761\u2014\u2014`record` \u975E null \u5373**\u6C47\u603B\u7EF4\u5EA6**\uFF08overview/resource-counts/gold-account/ads-index/dimension-summary/final-urls/campaign-types\uFF09\uFF0C\u8BFB `record`\uFF1B\u5426\u5219\u8BFB `items[]`\uFF08\u6240\u6709\u5217\u8868\u7EF4\u5EA6\uFF0C\u542B materials\uFF0C\u884C\u5DF2\u7EDF\u4E00\u642C\u5165\uFF0C`itemCount` = `items.length`\uFF09\u3002",
|
|
102115
|
+
"// \u7EF4\u5EA6\u4E13\u5C5E\u539F\u952E\u540D\uFF08keywords/campaigns/countries/data \u7B49\uFF09\u5DF2**\u79FB\u9664**\uFF0C\u4E0D\u8981\u518D\u6309\u7EF4\u5EA6\u731C\u952E\u540D\uFF1B`search-terms`/`ads` \u7684\u7F51\u5173 `code`/`message` \u5728 `meta`\uFF08\u4E0E\u6570\u636E\u65E0\u5173\uFF09\uFF1Bmaterials \u884C\u5E26 `assetType: 'image'|'video'`\u3002"
|
|
102116
|
+
];
|
|
102117
|
+
GOOGLE_ANALYSIS_ZH_FIELD_HINTS_BY_SECTION = {
|
|
102118
|
+
keywords: [
|
|
102119
|
+
"// \u4E2D\u6587\u8BD1\u540D\uFF1A`keywordMatchTypeZh`\uFF08\u7531 `keywordMatchType` \u7ECF match-type-en2zh.json \u7FFB\u8BD1\uFF0C\u8986\u76D6 BROAD/PHRASE/EXACT \u4E0E Broad/Phrase/Exact \u5927\u5C0F\u5199\uFF1B\u672A\u547D\u4E2D\u65F6\u8BE5\u5B57\u6BB5\u7F3A\u7701\uFF09\u3002"
|
|
102120
|
+
],
|
|
102121
|
+
"search-terms": [
|
|
102122
|
+
"// \u4E2D\u6587\u8BD1\u540D\uFF1A`matchTypeZh`\uFF08\u7531 `matchType` \u7ECF match-type-en2zh.json \u7FFB\u8BD1\uFF1B\u672A\u547D\u4E2D\u65F6\u8BE5\u5B57\u6BB5\u7F3A\u7701\uFF09\u3002"
|
|
102123
|
+
],
|
|
102124
|
+
"campaign-geo": [
|
|
102125
|
+
"// \u4E2D\u6587\u8BD1\u540D\uFF1A`countryOrRegionZh`\uFF08\u7531 `countryOrRegion` \u7ECF geo-en2zh.json \u7FFB\u8BD1\uFF0C\u76EE\u524D\u8986\u76D6 105 \u4E2A\u56FD\u5BB6/\u5730\u533A\uFF1B\u672A\u547D\u4E2D\u65F6\u8BE5\u5B57\u6BB5\u7F3A\u7701\uFF09\u3002"
|
|
102126
|
+
],
|
|
102127
|
+
"campaign-geo-matched": [
|
|
102128
|
+
"// \u4E2D\u6587\u8BD1\u540D\uFF1A`countryOrRegionZh`\uFF08\u7531 `countryOrRegion` \u7ECF geo-en2zh.json \u7FFB\u8BD1\uFF0C\u76EE\u524D\u8986\u76D6 105 \u4E2A\u56FD\u5BB6/\u5730\u533A\uFF1B\u672A\u547D\u4E2D\u65F6\u8BE5\u5B57\u6BB5\u7F3A\u7701\uFF09\u3002"
|
|
102129
|
+
],
|
|
102130
|
+
"geo-matched": [
|
|
102131
|
+
"// \u4E2D\u6587\u8BD1\u540D\uFF1A`countryOrRegionZh`\uFF08\u7531 `countryOrRegion` \u7ECF geo-en2zh.json \u7FFB\u8BD1\uFF0C\u76EE\u524D\u8986\u76D6 105 \u4E2A\u56FD\u5BB6/\u5730\u533A\uFF1B\u672A\u547D\u4E2D\u65F6\u8BE5\u5B57\u6BB5\u7F3A\u7701\uFF09\u3002"
|
|
102132
|
+
]
|
|
102133
|
+
};
|
|
102134
|
+
}
|
|
102135
|
+
});
|
|
102136
|
+
|
|
102137
|
+
// src/utils/google-analysis-snapshot.ts
|
|
102138
|
+
var init_google_analysis_snapshot = __esm({
|
|
102139
|
+
"src/utils/google-analysis-snapshot.ts"() {
|
|
102140
|
+
"use strict";
|
|
102141
|
+
init_google_analysis();
|
|
102142
|
+
}
|
|
102143
|
+
});
|
|
102144
|
+
|
|
102135
102145
|
// src/commands/google-analysis/merge-snapshot.ts
|
|
102136
102146
|
import * as fs20 from "fs/promises";
|
|
102137
102147
|
import * as path25 from "path";
|
|
@@ -102141,11 +102151,11 @@ function asRecord11(value) {
|
|
|
102141
102151
|
}
|
|
102142
102152
|
return null;
|
|
102143
102153
|
}
|
|
102144
|
-
function
|
|
102154
|
+
function num3(value) {
|
|
102145
102155
|
const n = Number(value);
|
|
102146
102156
|
return Number.isFinite(n) ? n : void 0;
|
|
102147
102157
|
}
|
|
102148
|
-
function
|
|
102158
|
+
function round23(value) {
|
|
102149
102159
|
return value == null ? void 0 : Math.round(value * 100) / 100;
|
|
102150
102160
|
}
|
|
102151
102161
|
async function readManifest(snapshotDir, accountId) {
|
|
@@ -102188,13 +102198,13 @@ function record(envelope) {
|
|
|
102188
102198
|
}
|
|
102189
102199
|
function pickMetricRow(row, extraFields) {
|
|
102190
102200
|
const base = {
|
|
102191
|
-
spend:
|
|
102192
|
-
impressions:
|
|
102193
|
-
clicks:
|
|
102194
|
-
ctr:
|
|
102195
|
-
averageCpc:
|
|
102196
|
-
conversions:
|
|
102197
|
-
costPerConversion:
|
|
102201
|
+
spend: num3(row.spend) ?? 0,
|
|
102202
|
+
impressions: num3(row.impressions) ?? 0,
|
|
102203
|
+
clicks: num3(row.clicks) ?? 0,
|
|
102204
|
+
ctr: num3(row.ctr),
|
|
102205
|
+
averageCpc: num3(row.averageCpc),
|
|
102206
|
+
conversions: num3(row.conversions) ?? 0,
|
|
102207
|
+
costPerConversion: num3(row.costPerConversion)
|
|
102198
102208
|
};
|
|
102199
102209
|
for (const f of extraFields) {
|
|
102200
102210
|
if (row[f] !== void 0) base[f] = row[f];
|
|
@@ -102208,22 +102218,22 @@ function sumCampaignRowsToPeriodKpis(rows) {
|
|
|
102208
102218
|
let clicks = 0;
|
|
102209
102219
|
let conversions = 0;
|
|
102210
102220
|
for (const row of rows) {
|
|
102211
|
-
cost +=
|
|
102212
|
-
impressions +=
|
|
102213
|
-
clicks +=
|
|
102214
|
-
conversions +=
|
|
102221
|
+
cost += num3(row.spend) ?? 0;
|
|
102222
|
+
impressions += num3(row.impressions) ?? 0;
|
|
102223
|
+
clicks += num3(row.clicks) ?? 0;
|
|
102224
|
+
conversions += num3(row.conversions) ?? 0;
|
|
102215
102225
|
}
|
|
102216
102226
|
const ctr = impressions > 0 ? clicks / impressions : void 0;
|
|
102217
102227
|
const averageCpc = clicks > 0 ? cost / clicks : void 0;
|
|
102218
102228
|
const costPerConversion = conversions > 0 ? cost / conversions : void 0;
|
|
102219
102229
|
return {
|
|
102220
|
-
cost:
|
|
102230
|
+
cost: round23(cost),
|
|
102221
102231
|
impressions: Math.round(impressions),
|
|
102222
102232
|
clicks: Math.round(clicks),
|
|
102223
|
-
conversions:
|
|
102233
|
+
conversions: round23(conversions),
|
|
102224
102234
|
ctr,
|
|
102225
|
-
averageCpc:
|
|
102226
|
-
costPerConversion:
|
|
102235
|
+
averageCpc: round23(averageCpc),
|
|
102236
|
+
costPerConversion: round23(costPerConversion)
|
|
102227
102237
|
};
|
|
102228
102238
|
}
|
|
102229
102239
|
async function mergeGoogleAnalysisSnapshotIntoReport(payload, snapshotDir) {
|
|
@@ -102256,13 +102266,13 @@ async function mergeGoogleAnalysisSnapshotIntoReport(payload, snapshotDir) {
|
|
|
102256
102266
|
const campaignKpis = sumCampaignRowsToPeriodKpis(campaignRows2);
|
|
102257
102267
|
const kpis = { ...payload.kpis ?? {} };
|
|
102258
102268
|
const currentKpiSource = campaignKpis ?? (currentPeriod ? {
|
|
102259
|
-
cost:
|
|
102260
|
-
impressions:
|
|
102261
|
-
clicks:
|
|
102262
|
-
conversions:
|
|
102263
|
-
ctr:
|
|
102264
|
-
averageCpc:
|
|
102265
|
-
costPerConversion:
|
|
102269
|
+
cost: num3(currentPeriod.spend),
|
|
102270
|
+
impressions: num3(currentPeriod.impressions),
|
|
102271
|
+
clicks: num3(currentPeriod.clicks),
|
|
102272
|
+
conversions: num3(currentPeriod.conversions),
|
|
102273
|
+
ctr: num3(currentPeriod.ctr),
|
|
102274
|
+
averageCpc: num3(currentPeriod.averageCpc),
|
|
102275
|
+
costPerConversion: num3(currentPeriod.costPerConversion)
|
|
102266
102276
|
} : null);
|
|
102267
102277
|
if (currentKpiSource) {
|
|
102268
102278
|
if (kpis.cost == null) kpis.cost = currentKpiSource.cost;
|
|
@@ -102275,13 +102285,13 @@ async function mergeGoogleAnalysisSnapshotIntoReport(payload, snapshotDir) {
|
|
|
102275
102285
|
}
|
|
102276
102286
|
if (!kpis.previousPeriod && previousPeriod) {
|
|
102277
102287
|
kpis.previousPeriod = {
|
|
102278
|
-
cost:
|
|
102279
|
-
impressions:
|
|
102280
|
-
clicks:
|
|
102281
|
-
conversions:
|
|
102282
|
-
ctr:
|
|
102283
|
-
averageCpc:
|
|
102284
|
-
costPerConversion:
|
|
102288
|
+
cost: num3(previousPeriod.spend),
|
|
102289
|
+
impressions: num3(previousPeriod.impressions),
|
|
102290
|
+
clicks: num3(previousPeriod.clicks),
|
|
102291
|
+
conversions: num3(previousPeriod.conversions),
|
|
102292
|
+
ctr: num3(previousPeriod.ctr),
|
|
102293
|
+
averageCpc: num3(previousPeriod.averageCpc),
|
|
102294
|
+
costPerConversion: num3(previousPeriod.costPerConversion)
|
|
102285
102295
|
};
|
|
102286
102296
|
}
|
|
102287
102297
|
const charts = { ...payload.charts ?? {} };
|
|
@@ -102293,9 +102303,9 @@ async function mergeGoogleAnalysisSnapshotIntoReport(payload, snapshotDir) {
|
|
|
102293
102303
|
);
|
|
102294
102304
|
charts.dailyTrend = {
|
|
102295
102305
|
dates: sorted.map((r) => String(r.date ?? "\u2014")),
|
|
102296
|
-
cost: sorted.map((r) =>
|
|
102297
|
-
conversions: sorted.map((r) => Math.round(
|
|
102298
|
-
cpa: sorted.map((r) =>
|
|
102306
|
+
cost: sorted.map((r) => round23(num3(r.spend)) ?? 0),
|
|
102307
|
+
conversions: sorted.map((r) => Math.round(num3(r.conversions) ?? 0)),
|
|
102308
|
+
cpa: sorted.map((r) => round23(num3(r.costPerConversion)) ?? 0)
|
|
102299
102309
|
};
|
|
102300
102310
|
}
|
|
102301
102311
|
}
|
|
@@ -102304,16 +102314,16 @@ async function mergeGoogleAnalysisSnapshotIntoReport(payload, snapshotDir) {
|
|
|
102304
102314
|
const summary = record(sectionMap.get("dimension-summary"));
|
|
102305
102315
|
if (summary) {
|
|
102306
102316
|
tables.dimensionSummary = {
|
|
102307
|
-
cost:
|
|
102308
|
-
impressions:
|
|
102309
|
-
clicks:
|
|
102310
|
-
conversions:
|
|
102311
|
-
ctr:
|
|
102312
|
-
averageCpc:
|
|
102313
|
-
costPerConversion:
|
|
102314
|
-
searchImpressionShare:
|
|
102315
|
-
searchBudgetLostImpressionShare:
|
|
102316
|
-
searchRankLostImpressionShare:
|
|
102317
|
+
cost: num3(summary.spend),
|
|
102318
|
+
impressions: num3(summary.impressions),
|
|
102319
|
+
clicks: num3(summary.clicks),
|
|
102320
|
+
conversions: num3(summary.conversions),
|
|
102321
|
+
ctr: num3(summary.ctr),
|
|
102322
|
+
averageCpc: num3(summary.averageCpc),
|
|
102323
|
+
costPerConversion: num3(summary.costPerConversion),
|
|
102324
|
+
searchImpressionShare: num3(summary.searchImpressionShare),
|
|
102325
|
+
searchBudgetLostImpressionShare: num3(summary.searchBudgetLostImpressionShare),
|
|
102326
|
+
searchRankLostImpressionShare: num3(summary.searchRankLostImpressionShare)
|
|
102317
102327
|
};
|
|
102318
102328
|
}
|
|
102319
102329
|
}
|
|
@@ -107039,12 +107049,116 @@ init_auth();
|
|
|
107039
107049
|
init_cli_json_snapshot();
|
|
107040
107050
|
init_cli_table();
|
|
107041
107051
|
init_balance();
|
|
107052
|
+
|
|
107053
|
+
// src/utils/google-campaign-spend.ts
|
|
107054
|
+
init_fetch();
|
|
107055
|
+
var GOOGLE_CAMPAIGN_SPEND_CONCURRENCY = 5;
|
|
107056
|
+
function round22(n) {
|
|
107057
|
+
if (n == null || !Number.isFinite(n)) return n;
|
|
107058
|
+
return Math.round(n * 100) / 100;
|
|
107059
|
+
}
|
|
107060
|
+
function num(v) {
|
|
107061
|
+
if (typeof v === "number" && Number.isFinite(v)) return v;
|
|
107062
|
+
if (typeof v === "string" && v.trim() !== "") {
|
|
107063
|
+
const n = Number(v);
|
|
107064
|
+
if (Number.isFinite(n)) return n;
|
|
107065
|
+
}
|
|
107066
|
+
return void 0;
|
|
107067
|
+
}
|
|
107068
|
+
function sumCampaignRowsToSpendTotals(rows) {
|
|
107069
|
+
let spend = 0;
|
|
107070
|
+
let impressions = 0;
|
|
107071
|
+
let clicks = 0;
|
|
107072
|
+
let conversions = 0;
|
|
107073
|
+
for (const row of rows) {
|
|
107074
|
+
spend += num(row.spend) ?? 0;
|
|
107075
|
+
impressions += num(row.impressions) ?? 0;
|
|
107076
|
+
clicks += num(row.clicks) ?? 0;
|
|
107077
|
+
conversions += num(row.conversions) ?? 0;
|
|
107078
|
+
}
|
|
107079
|
+
return {
|
|
107080
|
+
spend: round22(spend) ?? 0,
|
|
107081
|
+
impressions: Math.round(impressions),
|
|
107082
|
+
clicks: Math.round(clicks),
|
|
107083
|
+
conversions: round22(conversions) ?? 0,
|
|
107084
|
+
costPerClick: clicks > 0 ? round22(spend / clicks) ?? 0 : 0
|
|
107085
|
+
};
|
|
107086
|
+
}
|
|
107087
|
+
function overviewFromCampaignSectionPayload(mediaAccountId, payload) {
|
|
107088
|
+
const bag = payload ?? {};
|
|
107089
|
+
const rows = Array.isArray(bag.campaigns) ? bag.campaigns.map((r) => r) : [];
|
|
107090
|
+
const totals = sumCampaignRowsToSpendTotals(rows);
|
|
107091
|
+
return {
|
|
107092
|
+
mediaAccountId: String(mediaAccountId),
|
|
107093
|
+
spend: totals.spend,
|
|
107094
|
+
impressions: totals.impressions,
|
|
107095
|
+
clicks: totals.clicks,
|
|
107096
|
+
conversions: totals.conversions,
|
|
107097
|
+
costPerClick: totals.costPerClick,
|
|
107098
|
+
currencyCode: typeof bag.currencyCode === "string" ? bag.currencyCode : void 0
|
|
107099
|
+
};
|
|
107100
|
+
}
|
|
107101
|
+
async function mapPool(items2, concurrency, fn) {
|
|
107102
|
+
const results = new Array(items2.length);
|
|
107103
|
+
let next = 0;
|
|
107104
|
+
const workers = Array.from(
|
|
107105
|
+
{ length: Math.max(1, Math.min(concurrency, items2.length || 1)) },
|
|
107106
|
+
async () => {
|
|
107107
|
+
while (true) {
|
|
107108
|
+
const i = next++;
|
|
107109
|
+
if (i >= items2.length) return;
|
|
107110
|
+
results[i] = await fn(items2[i]);
|
|
107111
|
+
}
|
|
107112
|
+
}
|
|
107113
|
+
);
|
|
107114
|
+
await Promise.all(workers);
|
|
107115
|
+
return results;
|
|
107116
|
+
}
|
|
107117
|
+
async function fetchGoogleOverviewMapFromCampaigns(opts) {
|
|
107118
|
+
const {
|
|
107119
|
+
accountIds,
|
|
107120
|
+
config,
|
|
107121
|
+
startDate,
|
|
107122
|
+
endDate,
|
|
107123
|
+
verbose,
|
|
107124
|
+
concurrency = GOOGLE_CAMPAIGN_SPEND_CONCURRENCY
|
|
107125
|
+
} = opts;
|
|
107126
|
+
const result = /* @__PURE__ */ new Map();
|
|
107127
|
+
if (accountIds.length === 0) return result;
|
|
107128
|
+
if (accountIds.length > 1) {
|
|
107129
|
+
process.stderr.write(
|
|
107130
|
+
`\u23F3 [stats Google\u2190campaigns] ${accountIds.length} \u6237\uFF08\u5E76\u53D1 ${concurrency}\uFF0C${startDate} ~ ${endDate}\uFF09\u2026
|
|
107131
|
+
`
|
|
107132
|
+
);
|
|
107133
|
+
}
|
|
107134
|
+
const outcomes = await mapPool(accountIds, concurrency, async (id) => {
|
|
107135
|
+
const { payload } = await fetchOneGoogleSection({
|
|
107136
|
+
config,
|
|
107137
|
+
accountId: id,
|
|
107138
|
+
section: "campaigns",
|
|
107139
|
+
start: startDate,
|
|
107140
|
+
end: endDate,
|
|
107141
|
+
verbose
|
|
107142
|
+
});
|
|
107143
|
+
return { id, row: overviewFromCampaignSectionPayload(id, payload) };
|
|
107144
|
+
});
|
|
107145
|
+
for (const o of outcomes) {
|
|
107146
|
+
result.set(o.id, o.row);
|
|
107147
|
+
}
|
|
107148
|
+
if (accountIds.length > 1) {
|
|
107149
|
+
process.stderr.write(` \u2713 campaigns \u7D2F\u52A0\u5B8C\u6210\uFF1A${result.size} \u6237
|
|
107150
|
+
`);
|
|
107151
|
+
}
|
|
107152
|
+
return result;
|
|
107153
|
+
}
|
|
107154
|
+
|
|
107155
|
+
// src/commands/stats.ts
|
|
107042
107156
|
init_media_account_lookup();
|
|
107043
107157
|
init_media_customer_id();
|
|
107044
107158
|
var VALID_MEDIA_TYPES3 = ["Google", "TikTok", "Yandex", "MetaAd", "BingV2", "Kwai"];
|
|
107045
107159
|
var MAX_BY_DAY_SPAN = 366;
|
|
107046
107160
|
var DATE_RE = /^\d{4}-\d{2}-\d{2}$/;
|
|
107047
|
-
function
|
|
107161
|
+
function defaultDateRange3() {
|
|
107048
107162
|
const end = /* @__PURE__ */ new Date();
|
|
107049
107163
|
end.setDate(end.getDate() - 1);
|
|
107050
107164
|
const start = new Date(end);
|
|
@@ -107082,21 +107196,20 @@ async function fetchStatsWindow(media, ids, config, startDate, endDate, verbose)
|
|
|
107082
107196
|
const isGoogle = media === "Google";
|
|
107083
107197
|
const isMetaAd = media === "MetaAd";
|
|
107084
107198
|
if (isGoogle) {
|
|
107085
|
-
const
|
|
107086
|
-
|
|
107087
|
-
|
|
107088
|
-
|
|
107089
|
-
|
|
107090
|
-
|
|
107091
|
-
|
|
107092
|
-
|
|
107093
|
-
|
|
107094
|
-
|
|
107095
|
-
|
|
107096
|
-
|
|
107097
|
-
|
|
107098
|
-
|
|
107099
|
-
}));
|
|
107199
|
+
const map2 = await fetchGoogleOverviewMapFromCampaigns({
|
|
107200
|
+
accountIds: ids,
|
|
107201
|
+
config,
|
|
107202
|
+
startDate,
|
|
107203
|
+
endDate,
|
|
107204
|
+
verbose
|
|
107205
|
+
});
|
|
107206
|
+
return ids.map((id) => {
|
|
107207
|
+
const row = map2.get(id);
|
|
107208
|
+
if (!row) {
|
|
107209
|
+
throw new Error(`\u672A\u4ECE CampaignSectionData \u5F97\u5230\u8D26\u6237 ${id} \u7684\u6D88\u8017\u6C47\u603B`);
|
|
107210
|
+
}
|
|
107211
|
+
return row;
|
|
107212
|
+
});
|
|
107100
107213
|
}
|
|
107101
107214
|
if (isMetaAd) {
|
|
107102
107215
|
const accountMediaTypes = await lookupMetaMediaAccountTypes(config, ids, verbose);
|
|
@@ -107135,7 +107248,7 @@ async function runStats(opts) {
|
|
|
107135
107248
|
process.exit(1);
|
|
107136
107249
|
}
|
|
107137
107250
|
const { startDate, endDate } = {
|
|
107138
|
-
...
|
|
107251
|
+
...defaultDateRange3(),
|
|
107139
107252
|
...opts.startDate ? { startDate: opts.startDate } : {},
|
|
107140
107253
|
...opts.endDate ? { endDate: opts.endDate } : {}
|
|
107141
107254
|
};
|
|
@@ -107287,7 +107400,7 @@ ${opts.media} \u6295\u653E\u6570\u636E\uFF08${rangeLabel}\uFF09\uFF08\u7B2C 1 \u
|
|
|
107287
107400
|
}
|
|
107288
107401
|
function register11(program2) {
|
|
107289
107402
|
program2.command("stats").description(
|
|
107290
|
-
"\u67E5\u8BE2\u5E7F\u544A\u6D88\u8017\u3001\u70B9\u51FB\u3001\u8F6C\u5316\u7B49\u6295\u653E\u6570\u636E\uFF08\u9ED8\u8BA4\u8FD1 7 \u5929\u533A\u95F4\u5408\u8BA1\uFF0C\u4E0D\u542B\u4ECA\u5929\uFF1B\u8981\u6309\u65E5\u660E\u7EC6\u52A0 --by-day\uFF09"
|
|
107403
|
+
"\u67E5\u8BE2\u5E7F\u544A\u6D88\u8017\u3001\u70B9\u51FB\u3001\u8F6C\u5316\u7B49\u6295\u653E\u6570\u636E\uFF08\u9ED8\u8BA4\u8FD1 7 \u5929\u533A\u95F4\u5408\u8BA1\uFF0C\u4E0D\u542B\u4ECA\u5929\uFF1B\u8981\u6309\u65E5\u660E\u7EC6\u52A0 --by-day\uFF09\u3002Google\uFF1A\u8D26\u6237 KPI \u7531 CampaignSectionData \u7CFB\u5217\u7D2F\u52A0"
|
|
107291
107404
|
).requiredOption(
|
|
107292
107405
|
"-m, --media <type>",
|
|
107293
107406
|
"\u5A92\u4F53\u7C7B\u578B\uFF1AGoogle | TikTok | Yandex | MetaAd | BingV2 | Kwai"
|
|
@@ -117752,7 +117865,7 @@ async function fetchVideoUploadStatus(config, googleApiUrl, mediaAccountId, reso
|
|
|
117752
117865
|
throw new Error("\u67E5\u8BE2\u89C6\u9891\u5904\u7406\u72B6\u6001\u54CD\u5E94\u975E JSON");
|
|
117753
117866
|
}
|
|
117754
117867
|
}
|
|
117755
|
-
function
|
|
117868
|
+
function sleep3(ms) {
|
|
117756
117869
|
return new Promise((r) => setTimeout(r, ms));
|
|
117757
117870
|
}
|
|
117758
117871
|
async function pollVideoUntilProcessed(config, googleApiUrl, mediaAccountId, resourceName, verbose, onProgress) {
|
|
@@ -117779,7 +117892,7 @@ async function pollVideoUntilProcessed(config, googleApiUrl, mediaAccountId, res
|
|
|
117779
117892
|
throw new Error(`\u89C6\u9891\u5904\u7406\u7ED3\u675F\u4F46\u65E0 video_id\uFF08state=${state}\uFF09`);
|
|
117780
117893
|
}
|
|
117781
117894
|
if (attempt < PMAX_VIDEO_POLL_MAX_ATTEMPTS) {
|
|
117782
|
-
await
|
|
117895
|
+
await sleep3(PMAX_VIDEO_POLL_INTERVAL_MS);
|
|
117783
117896
|
}
|
|
117784
117897
|
}
|
|
117785
117898
|
throw new Error(
|
|
@@ -127102,16 +127215,16 @@ function sectionRecord(env) {
|
|
|
127102
127215
|
}
|
|
127103
127216
|
|
|
127104
127217
|
// src/commands/google-ads-diagnosis/build-report-data.ts
|
|
127105
|
-
function
|
|
127218
|
+
function num2(value) {
|
|
127106
127219
|
const n = Number(value);
|
|
127107
127220
|
return Number.isFinite(n) ? n : 0;
|
|
127108
127221
|
}
|
|
127109
127222
|
function rowCost(row) {
|
|
127110
|
-
return
|
|
127223
|
+
return num2(row.cost ?? row.spend);
|
|
127111
127224
|
}
|
|
127112
127225
|
function cvrOf(row, clicks) {
|
|
127113
|
-
if (clicks > 0) return
|
|
127114
|
-
return
|
|
127226
|
+
if (clicks > 0) return num2(row.conversions) / clicks;
|
|
127227
|
+
return num2(row.conversionRate ?? row.cvr);
|
|
127115
127228
|
}
|
|
127116
127229
|
function pct(value) {
|
|
127117
127230
|
return `${(value * 100).toFixed(2)}%`;
|
|
@@ -127142,11 +127255,11 @@ function asPeriodRecord(value) {
|
|
|
127142
127255
|
}
|
|
127143
127256
|
function toKeyMetricRow(title, current, previous) {
|
|
127144
127257
|
const currentCost = rowCost(current);
|
|
127145
|
-
const currentClicks =
|
|
127258
|
+
const currentClicks = num2(current.clicks);
|
|
127146
127259
|
const currentCvr = cvrOf(current, currentClicks);
|
|
127147
127260
|
const previousCost = previous ? rowCost(previous) : null;
|
|
127148
|
-
const previousClicks = previous ?
|
|
127149
|
-
const previousCvr = previous ? cvrOf(previous,
|
|
127261
|
+
const previousClicks = previous ? num2(previous.clicks) : null;
|
|
127262
|
+
const previousCvr = previous ? cvrOf(previous, num2(previous.clicks)) : null;
|
|
127150
127263
|
return {
|
|
127151
127264
|
title,
|
|
127152
127265
|
currentCost,
|
|
@@ -127176,13 +127289,13 @@ function buildComparisonItems(currentRows, previousRows, titleFn, keyFn) {
|
|
|
127176
127289
|
}
|
|
127177
127290
|
function toTargetingItem(row, labelKey, label) {
|
|
127178
127291
|
const cost = rowCost(row);
|
|
127179
|
-
const clicks =
|
|
127180
|
-
const impressions =
|
|
127181
|
-
const conversions =
|
|
127182
|
-
const ctr =
|
|
127292
|
+
const clicks = num2(row.clicks);
|
|
127293
|
+
const impressions = num2(row.impressions);
|
|
127294
|
+
const conversions = num2(row.conversions);
|
|
127295
|
+
const ctr = num2(row.ctr);
|
|
127183
127296
|
const cvr = cvrOf(row, clicks);
|
|
127184
|
-
const cpc =
|
|
127185
|
-
const cpa = conversions > 0 ? cost / conversions :
|
|
127297
|
+
const cpc = num2(row.averageCpc ?? row.cpc);
|
|
127298
|
+
const cpa = conversions > 0 ? cost / conversions : num2(row.costPerConversion ?? row.cpa);
|
|
127186
127299
|
return {
|
|
127187
127300
|
[labelKey]: label,
|
|
127188
127301
|
cost,
|
|
@@ -127197,11 +127310,11 @@ function toTargetingItem(row, labelKey, label) {
|
|
|
127197
127310
|
}
|
|
127198
127311
|
function toDailyConversionItem(row) {
|
|
127199
127312
|
const cost = rowCost(row);
|
|
127200
|
-
const conversions =
|
|
127313
|
+
const conversions = num2(row.conversions);
|
|
127201
127314
|
const rawDate = String(row.date ?? "");
|
|
127202
127315
|
const date = rawDate.includes("T") ? rawDate.slice(0, 10) : rawDate.slice(0, 10);
|
|
127203
|
-
const cpa = conversions > 0 ? cost / conversions :
|
|
127204
|
-
return { date, cost, conversions, cpa, clicks:
|
|
127316
|
+
const cpa = conversions > 0 ? cost / conversions : num2(row.costPerConversion ?? row.cpa);
|
|
127317
|
+
return { date, cost, conversions, cpa, clicks: num2(row.clicks), impressions: num2(row.impressions) };
|
|
127205
127318
|
}
|
|
127206
127319
|
function loadCompanyNameFromSnap(snapDir) {
|
|
127207
127320
|
const file = path22.join(snapDir, "list-accounts-google.json");
|
|
@@ -127238,8 +127351,8 @@ function inferBusinessProfile(campaignRows2, adRows, website) {
|
|
|
127238
127351
|
};
|
|
127239
127352
|
}
|
|
127240
127353
|
function primaryConversionLabel(rows) {
|
|
127241
|
-
const sorted = [...rows].sort((a, b) =>
|
|
127242
|
-
const top = sorted.find((r) =>
|
|
127354
|
+
const sorted = [...rows].sort((a, b) => num2(b.allConversions) - num2(a.allConversions));
|
|
127355
|
+
const top = sorted.find((r) => num2(r.allConversions) > 0 && String(r.status) === "Enabled");
|
|
127243
127356
|
if (top) return String(top.name ?? "\u8BE2\u76D8/\u8F6C\u5316");
|
|
127244
127357
|
const enabled = rows.find((r) => String(r.status) === "Enabled");
|
|
127245
127358
|
return enabled ? String(enabled.name ?? "\u8BE2\u76D8/\u8F6C\u5316") : "\u8BE2\u76D8/\u8F6C\u5316";
|
|
@@ -127258,7 +127371,7 @@ function buildBiddingStrategyItems(campaignRows2, endDate, gold) {
|
|
|
127258
127371
|
const strategy = String(row.biddingStrategyTypeV2 ?? row.biddingStrategyType ?? "UNKNOWN");
|
|
127259
127372
|
const status = String(row.campaignStatus ?? row.campaignStatusV2 ?? "");
|
|
127260
127373
|
const isPaused = /paused/i.test(status);
|
|
127261
|
-
const recommended =
|
|
127374
|
+
const recommended = num2(row.conversions) > 0 ? "MAXIMIZE_CONVERSIONS" : "TARGET_SPEND";
|
|
127262
127375
|
const isCorrect = policyOk && !isPaused && strategy === recommended;
|
|
127263
127376
|
return {
|
|
127264
127377
|
campaignName: String(row.campaignName ?? "\u672A\u547D\u540D\u7CFB\u5217"),
|
|
@@ -127271,16 +127384,16 @@ function buildBiddingStrategyItems(campaignRows2, endDate, gold) {
|
|
|
127271
127384
|
});
|
|
127272
127385
|
}
|
|
127273
127386
|
function buildStructureCounts(resourceRecord, campaignRows2, keywordRows, searchRows) {
|
|
127274
|
-
const campaignCount = Math.max(
|
|
127275
|
-
const keywordCount = Math.max(
|
|
127387
|
+
const campaignCount = Math.max(num2(resourceRecord?.campaignCount), campaignRows2.length);
|
|
127388
|
+
const keywordCount = Math.max(num2(resourceRecord?.keywordCount), keywordRows.length);
|
|
127276
127389
|
return {
|
|
127277
127390
|
campaignCount,
|
|
127278
|
-
adGroupCount:
|
|
127391
|
+
adGroupCount: num2(resourceRecord?.adGroupCount),
|
|
127279
127392
|
keywordCount,
|
|
127280
|
-
adCount:
|
|
127281
|
-
extensionCount:
|
|
127282
|
-
negativeKeywordCount:
|
|
127283
|
-
countriesWithConversionsCount:
|
|
127393
|
+
adCount: num2(resourceRecord?.adCount),
|
|
127394
|
+
extensionCount: num2(resourceRecord?.extensionCount),
|
|
127395
|
+
negativeKeywordCount: num2(resourceRecord?.negativeKeywordCount),
|
|
127396
|
+
countriesWithConversionsCount: num2(resourceRecord?.countriesWithConversionsCount),
|
|
127284
127397
|
searchTermCount: searchRows.length
|
|
127285
127398
|
};
|
|
127286
127399
|
}
|
|
@@ -127294,26 +127407,26 @@ function loadWebsiteFromAds(snapDir, accountId, start, end) {
|
|
|
127294
127407
|
}
|
|
127295
127408
|
function buildKeywordShareItems(rows) {
|
|
127296
127409
|
const totalCost = rows.reduce((sum, row) => sum + rowCost(row), 0);
|
|
127297
|
-
const totalConversions = rows.reduce((sum, row) => sum +
|
|
127410
|
+
const totalConversions = rows.reduce((sum, row) => sum + num2(row.conversions), 0);
|
|
127298
127411
|
return rows.map((row) => {
|
|
127299
127412
|
const cost = rowCost(row);
|
|
127300
|
-
const conversions =
|
|
127413
|
+
const conversions = num2(row.conversions);
|
|
127301
127414
|
const keywordText = String(row.keywordText ?? row.keyword ?? "").trim();
|
|
127302
127415
|
return {
|
|
127303
127416
|
keyword: keywordText || "\u672A\u547D\u540D",
|
|
127304
|
-
cpc:
|
|
127417
|
+
cpc: num2(row.averageCpc ?? row.cpc),
|
|
127305
127418
|
matchType: String(
|
|
127306
127419
|
row.keywordMatchTypeZh ?? row.keywordMatchType ?? row.matchType ?? ""
|
|
127307
127420
|
),
|
|
127308
|
-
impressions:
|
|
127309
|
-
clicks:
|
|
127421
|
+
impressions: num2(row.impressions),
|
|
127422
|
+
clicks: num2(row.clicks),
|
|
127310
127423
|
cost,
|
|
127311
127424
|
conversions,
|
|
127312
127425
|
costShare: totalCost > 0 ? cost / totalCost * 100 : 0,
|
|
127313
127426
|
conversionsShare: totalConversions > 0 ? conversions / totalConversions * 100 : 0,
|
|
127314
127427
|
cpa: conversions > 0 ? cost / conversions : 0,
|
|
127315
|
-
ctr:
|
|
127316
|
-
cvr: cvrOf(row,
|
|
127428
|
+
ctr: num2(row.ctr),
|
|
127429
|
+
cvr: cvrOf(row, num2(row.clicks))
|
|
127317
127430
|
};
|
|
127318
127431
|
});
|
|
127319
127432
|
}
|
|
@@ -127321,17 +127434,17 @@ function buildSearchTermItems(rows) {
|
|
|
127321
127434
|
const sorted = [...rows].sort((a, b) => rowCost(b) - rowCost(a));
|
|
127322
127435
|
return sorted.slice(0, 50).map((row) => {
|
|
127323
127436
|
const cost = rowCost(row);
|
|
127324
|
-
const conversions =
|
|
127325
|
-
const cpa = conversions > 0 ?
|
|
127437
|
+
const conversions = num2(row.conversions);
|
|
127438
|
+
const cpa = conversions > 0 ? num2(row.costPerConversion) || cost / conversions : void 0;
|
|
127326
127439
|
return {
|
|
127327
127440
|
searchTerm: String(row.searchTermText ?? row.searchTerm ?? "\u672A\u547D\u540D"),
|
|
127328
127441
|
keyword: String(row.keywordText ?? row.keyword ?? ""),
|
|
127329
127442
|
cost,
|
|
127330
127443
|
conversions,
|
|
127331
|
-
clicks:
|
|
127332
|
-
impressions:
|
|
127333
|
-
ctr:
|
|
127334
|
-
cvr: cvrOf(row,
|
|
127444
|
+
clicks: num2(row.clicks),
|
|
127445
|
+
impressions: num2(row.impressions),
|
|
127446
|
+
ctr: num2(row.ctr),
|
|
127447
|
+
cvr: cvrOf(row, num2(row.clicks)),
|
|
127335
127448
|
cpa
|
|
127336
127449
|
};
|
|
127337
127450
|
});
|
|
@@ -127373,18 +127486,18 @@ function buildAdCreativeItems(rows) {
|
|
|
127373
127486
|
}
|
|
127374
127487
|
function buildBudgetCompetitiveness(overviewRecord, dimensionRecord) {
|
|
127375
127488
|
const current = asPeriodRecord(overviewRecord?.currentPeriod);
|
|
127376
|
-
const totalCost =
|
|
127377
|
-
const activeDays =
|
|
127378
|
-
const avgDaily =
|
|
127379
|
-
const remainingBudget =
|
|
127489
|
+
const totalCost = num2(overviewRecord?.totalCost ?? current?.spend);
|
|
127490
|
+
const activeDays = num2(overviewRecord?.activeDays);
|
|
127491
|
+
const avgDaily = num2(overviewRecord?.averageDailyCost ?? (activeDays > 0 ? totalCost / activeDays : 0));
|
|
127492
|
+
const remainingBudget = num2(overviewRecord?.remainingAccountBudget);
|
|
127380
127493
|
const utilization = remainingBudget > 0 && avgDaily > 0 ? Math.min(100, avgDaily / (avgDaily + remainingBudget / Math.max(activeDays, 1)) * 100) : avgDaily > 0 ? 85 : 0;
|
|
127381
|
-
const sis =
|
|
127494
|
+
const sis = num2(
|
|
127382
127495
|
dimensionRecord?.searchImpressionShare ?? current?.searchImpressionShare
|
|
127383
127496
|
);
|
|
127384
|
-
const budgetLost =
|
|
127497
|
+
const budgetLost = num2(
|
|
127385
127498
|
dimensionRecord?.searchBudgetLostImpressionShare ?? current?.searchBudgetLostImpressionShare
|
|
127386
127499
|
);
|
|
127387
|
-
const rankLost =
|
|
127500
|
+
const rankLost = num2(
|
|
127388
127501
|
dimensionRecord?.searchRankLostImpressionShare ?? current?.searchRankLostImpressionShare
|
|
127389
127502
|
);
|
|
127390
127503
|
return [
|
|
@@ -127470,17 +127583,17 @@ function buildGoogleAdsDiagnosisCollectPayload(opts) {
|
|
|
127470
127583
|
};
|
|
127471
127584
|
data.reportDate = end;
|
|
127472
127585
|
const cost = rowCost(currentPeriod ?? overviewRecord ?? {});
|
|
127473
|
-
const impressions =
|
|
127474
|
-
const clicks =
|
|
127475
|
-
const conversions =
|
|
127476
|
-
const ctr =
|
|
127586
|
+
const impressions = num2(currentPeriod?.impressions);
|
|
127587
|
+
const clicks = num2(currentPeriod?.clicks);
|
|
127588
|
+
const conversions = num2(currentPeriod?.conversions);
|
|
127589
|
+
const ctr = num2(currentPeriod?.ctr);
|
|
127477
127590
|
const cvr = cvrOf(currentPeriod ?? {}, clicks);
|
|
127478
|
-
const cpa = conversions > 0 ? cost / conversions :
|
|
127591
|
+
const cpa = conversions > 0 ? cost / conversions : num2(currentPeriod?.costPerConversion);
|
|
127479
127592
|
const prevCost = previousPeriod ? rowCost(previousPeriod) : 0;
|
|
127480
|
-
const prevConversions = previousPeriod ?
|
|
127481
|
-
const prevCtr = previousPeriod ?
|
|
127482
|
-
const prevCvr = previousPeriod ? cvrOf(previousPeriod,
|
|
127483
|
-
const prevCpa = prevConversions > 0 ? rowCost(previousPeriod) / prevConversions :
|
|
127593
|
+
const prevConversions = previousPeriod ? num2(previousPeriod.conversions) : 0;
|
|
127594
|
+
const prevCtr = previousPeriod ? num2(previousPeriod.ctr) : 0;
|
|
127595
|
+
const prevCvr = previousPeriod ? cvrOf(previousPeriod, num2(previousPeriod.clicks)) : 0;
|
|
127596
|
+
const prevCpa = prevConversions > 0 ? rowCost(previousPeriod) / prevConversions : num2(previousPeriod?.costPerConversion);
|
|
127484
127597
|
data.metrics = {
|
|
127485
127598
|
cost,
|
|
127486
127599
|
impressions,
|
|
@@ -127516,8 +127629,8 @@ function buildGoogleAdsDiagnosisCollectPayload(opts) {
|
|
|
127516
127629
|
items: conversionRows.map((row) => ({
|
|
127517
127630
|
name: String(row.name ?? row.eventName ?? "\u672A\u77E5\u4E8B\u4EF6"),
|
|
127518
127631
|
status: String(row.status ?? ""),
|
|
127519
|
-
allConversions:
|
|
127520
|
-
allConversionsValue:
|
|
127632
|
+
allConversions: num2(row.allConversions),
|
|
127633
|
+
allConversionsValue: num2(row.allConversionsValue)
|
|
127521
127634
|
}))
|
|
127522
127635
|
};
|
|
127523
127636
|
const campaignPrevious = sectionItems(
|
|
@@ -127634,7 +127747,7 @@ function buildGoogleAdsDiagnosisCollectPayload(opts) {
|
|
|
127634
127747
|
data.newFeatures = {
|
|
127635
127748
|
items: nfItems.map((item) => {
|
|
127636
127749
|
const strategy = String(item.strategy ?? "");
|
|
127637
|
-
const enabled = strategy === "PerformanceMax" ?
|
|
127750
|
+
const enabled = strategy === "PerformanceMax" ? num2(campaignTypes?.PerformanceMax) > 0 : strategy === "KwMatch" ? num2(campaignTypes?.Search) > 0 : strategy === "DemandGen" ? num2(campaignTypes?.DemandGen) > 0 : strategy === "Youtube" ? num2(campaignTypes?.Video) > 0 || num2(campaignTypes?.Youtube) > 0 : false;
|
|
127638
127751
|
return {
|
|
127639
127752
|
...item,
|
|
127640
127753
|
accountStatus: enabled,
|
|
@@ -127644,7 +127757,7 @@ function buildGoogleAdsDiagnosisCollectPayload(opts) {
|
|
|
127644
127757
|
...emptyModuleNarrative()
|
|
127645
127758
|
};
|
|
127646
127759
|
data.summary = emptySummary();
|
|
127647
|
-
const zeroConvKw = kwCurrent.filter((r) => rowCost(r) > 50 &&
|
|
127760
|
+
const zeroConvKw = kwCurrent.filter((r) => rowCost(r) > 50 && num2(r.conversions) === 0);
|
|
127648
127761
|
const agentBrief = buildGoogleAdsDiagnosisAgentBrief({
|
|
127649
127762
|
accountId,
|
|
127650
127763
|
period: formatPeriod(start, end),
|
|
@@ -127668,9 +127781,9 @@ function buildGoogleAdsDiagnosisCollectPayload(opts) {
|
|
|
127668
127781
|
prevCpa
|
|
127669
127782
|
},
|
|
127670
127783
|
dimension: {
|
|
127671
|
-
searchImpressionShare:
|
|
127672
|
-
searchBudgetLostImpressionShare:
|
|
127673
|
-
searchRankLostImpressionShare:
|
|
127784
|
+
searchImpressionShare: num2(dimensionRecord?.searchImpressionShare),
|
|
127785
|
+
searchBudgetLostImpressionShare: num2(dimensionRecord?.searchBudgetLostImpressionShare),
|
|
127786
|
+
searchRankLostImpressionShare: num2(dimensionRecord?.searchRankLostImpressionShare)
|
|
127674
127787
|
},
|
|
127675
127788
|
structure: structureCounts,
|
|
127676
127789
|
goldAccount: goldRecord,
|
|
@@ -128584,7 +128697,7 @@ var PHASE_LABEL = {
|
|
|
128584
128697
|
"find-winner": "\u627E\u8D62\u5BB6",
|
|
128585
128698
|
scale: "\u653E\u91CF"
|
|
128586
128699
|
};
|
|
128587
|
-
function
|
|
128700
|
+
function num4(value) {
|
|
128588
128701
|
const n = Number(value);
|
|
128589
128702
|
return Number.isFinite(n) ? n : void 0;
|
|
128590
128703
|
}
|
|
@@ -128595,35 +128708,35 @@ function money(value, currency = "USD") {
|
|
|
128595
128708
|
}
|
|
128596
128709
|
function adSetsWithSpend(tables) {
|
|
128597
128710
|
const rows = Array.isArray(tables?.adSets) ? tables.adSets : [];
|
|
128598
|
-
return rows.filter((r) => (
|
|
128711
|
+
return rows.filter((r) => (num4(r.spend) ?? 0) > 0);
|
|
128599
128712
|
}
|
|
128600
128713
|
function topAdSetConcentration(adSets) {
|
|
128601
128714
|
if (!adSets.length) return null;
|
|
128602
|
-
const totalSpend = adSets.reduce((s, r) => s + (
|
|
128603
|
-
const totalResults = adSets.reduce((s, r) => s + (
|
|
128715
|
+
const totalSpend = adSets.reduce((s, r) => s + (num4(r.spend) ?? 0), 0);
|
|
128716
|
+
const totalResults = adSets.reduce((s, r) => s + (num4(r.results) ?? 0), 0);
|
|
128604
128717
|
let best = adSets[0];
|
|
128605
|
-
let bestSpend =
|
|
128718
|
+
let bestSpend = num4(best.spend) ?? 0;
|
|
128606
128719
|
for (const r of adSets) {
|
|
128607
|
-
const sp =
|
|
128720
|
+
const sp = num4(r.spend) ?? 0;
|
|
128608
128721
|
if (sp > bestSpend) {
|
|
128609
128722
|
best = r;
|
|
128610
128723
|
bestSpend = sp;
|
|
128611
128724
|
}
|
|
128612
128725
|
}
|
|
128613
|
-
const results =
|
|
128726
|
+
const results = num4(best.results) ?? 0;
|
|
128614
128727
|
return {
|
|
128615
128728
|
name: String(best.adGroupName ?? best.name ?? "\u2014"),
|
|
128616
128729
|
spendShare: totalSpend > 0 ? bestSpend / totalSpend : 0,
|
|
128617
128730
|
resultsShare: totalResults > 0 ? results / totalResults : 0,
|
|
128618
|
-
cpl:
|
|
128731
|
+
cpl: num4(best.costPerResult)
|
|
128619
128732
|
};
|
|
128620
128733
|
}
|
|
128621
128734
|
function winnerSpendShare(adSets, avgCpl, totalSpend) {
|
|
128622
128735
|
if (totalSpend <= 0 || avgCpl <= 0) return 0;
|
|
128623
128736
|
const winnerSpend = adSets.filter((r) => {
|
|
128624
|
-
const cpl =
|
|
128737
|
+
const cpl = num4(r.costPerResult);
|
|
128625
128738
|
return cpl != null && cpl <= avgCpl * 0.9;
|
|
128626
|
-
}).reduce((s, r) => s + (
|
|
128739
|
+
}).reduce((s, r) => s + (num4(r.spend) ?? 0), 0);
|
|
128627
128740
|
return winnerSpend / totalSpend;
|
|
128628
128741
|
}
|
|
128629
128742
|
function countActiveDimensions(charts, tables) {
|
|
@@ -128640,7 +128753,7 @@ function asArray2(value) {
|
|
|
128640
128753
|
}
|
|
128641
128754
|
function inferLifecyclePhase(input) {
|
|
128642
128755
|
const { avgCpl, currency = "USD" } = input;
|
|
128643
|
-
const spend =
|
|
128756
|
+
const spend = num4(input.spend) ?? 0;
|
|
128644
128757
|
const adSets = adSetsWithSpend(input.tables);
|
|
128645
128758
|
const activeDims = countActiveDimensions(input.charts, input.tables);
|
|
128646
128759
|
const winShare = winnerSpendShare(adSets, avgCpl, spend);
|
|
@@ -128699,7 +128812,7 @@ function ensureLifecycleFromSnapshot(healthDiagnosis, merged) {
|
|
|
128699
128812
|
}
|
|
128700
128813
|
|
|
128701
128814
|
// src/commands/facebook-analysis/scorecard-autofill.ts
|
|
128702
|
-
function
|
|
128815
|
+
function num5(value) {
|
|
128703
128816
|
const n = Number(value);
|
|
128704
128817
|
return Number.isFinite(n) ? n : void 0;
|
|
128705
128818
|
}
|
|
@@ -128739,8 +128852,8 @@ function buildScorecardFromMergedData(input) {
|
|
|
128739
128852
|
if (pLabels.length) {
|
|
128740
128853
|
const indexed = pLabels.map((label, i) => ({
|
|
128741
128854
|
label: String(label),
|
|
128742
|
-
cpl:
|
|
128743
|
-
spend:
|
|
128855
|
+
cpl: num5(pCpl[i]),
|
|
128856
|
+
spend: num5(pSpend[i]) ?? 0
|
|
128744
128857
|
})).filter((x) => x.spend > 0 || x.cpl != null && x.cpl > 0);
|
|
128745
128858
|
const sorted = [...indexed].sort((a, b) => (a.cpl ?? Infinity) - (b.cpl ?? Infinity));
|
|
128746
128859
|
if (sorted[0]) {
|
|
@@ -128765,7 +128878,7 @@ function buildScorecardFromMergedData(input) {
|
|
|
128765
128878
|
const cLabels = Array.isArray(country?.labels) ? country.labels : [];
|
|
128766
128879
|
const cCpl = Array.isArray(country?.cpl) ? country.cpl : [];
|
|
128767
128880
|
if (cLabels.length) {
|
|
128768
|
-
const indexed = cLabels.map((label, i) => ({ label: String(label), cpl:
|
|
128881
|
+
const indexed = cLabels.map((label, i) => ({ label: String(label), cpl: num5(cCpl[i]) })).filter((x) => x.cpl != null && x.cpl > 0);
|
|
128769
128882
|
const sorted = [...indexed].sort((a, b) => (a.cpl ?? 0) - (b.cpl ?? 0));
|
|
128770
128883
|
if (sorted[0]) {
|
|
128771
128884
|
const s = cplSignal(sorted[0].cpl, avgCpl);
|
|
@@ -128786,24 +128899,24 @@ function buildScorecardFromMergedData(input) {
|
|
|
128786
128899
|
}
|
|
128787
128900
|
}
|
|
128788
128901
|
const adSets = Array.isArray(tables.adSets) ? tables.adSets : [];
|
|
128789
|
-
const adWithSpend = adSets.filter((g) => (
|
|
128902
|
+
const adWithSpend = adSets.filter((g) => (num5(g.spend) ?? 0) > 0);
|
|
128790
128903
|
if (adWithSpend.length) {
|
|
128791
128904
|
const sorted = [...adWithSpend].sort(
|
|
128792
|
-
(a, b) => (
|
|
128905
|
+
(a, b) => (num5(a.costPerResult) ?? Infinity) - (num5(b.costPerResult) ?? Infinity)
|
|
128793
128906
|
);
|
|
128794
128907
|
const best = sorted[0];
|
|
128795
|
-
const sBest = cplSignal(
|
|
128908
|
+
const sBest = cplSignal(num5(best.costPerResult), avgCpl);
|
|
128796
128909
|
pushRow(rows, seen, {
|
|
128797
128910
|
item: String(best.name ?? "\u5E7F\u544A\u7EC4"),
|
|
128798
|
-
data: `CPL ${money2(
|
|
128911
|
+
data: `CPL ${money2(num5(best.costPerResult), currency)}`,
|
|
128799
128912
|
...sBest
|
|
128800
128913
|
});
|
|
128801
128914
|
if (sorted.length > 1) {
|
|
128802
128915
|
const worst = sorted[sorted.length - 1];
|
|
128803
|
-
const sWorst = cplSignal(
|
|
128916
|
+
const sWorst = cplSignal(num5(worst.costPerResult), avgCpl);
|
|
128804
128917
|
pushRow(rows, seen, {
|
|
128805
128918
|
item: String(worst.name ?? "\u5E7F\u544A\u7EC4"),
|
|
128806
|
-
data: `CPL ${money2(
|
|
128919
|
+
data: `CPL ${money2(num5(worst.costPerResult), currency)}`,
|
|
128807
128920
|
...sWorst
|
|
128808
128921
|
});
|
|
128809
128922
|
}
|
|
@@ -128811,18 +128924,18 @@ function buildScorecardFromMergedData(input) {
|
|
|
128811
128924
|
const topAud = Array.isArray(tables.audienceTop) ? tables.audienceTop : [];
|
|
128812
128925
|
const bottomAud = Array.isArray(tables.audienceBottom) ? tables.audienceBottom : [];
|
|
128813
128926
|
if (topAud[0]) {
|
|
128814
|
-
const s = cplSignal(
|
|
128927
|
+
const s = cplSignal(num5(topAud[0].costPerResult), avgCpl);
|
|
128815
128928
|
pushRow(rows, seen, {
|
|
128816
128929
|
item: `\u53D7\u4F17\xB7${String(topAud[0].label ?? "Top")}`,
|
|
128817
|
-
data: `CPL ${money2(
|
|
128930
|
+
data: `CPL ${money2(num5(topAud[0].costPerResult), currency)}`,
|
|
128818
128931
|
...s
|
|
128819
128932
|
});
|
|
128820
128933
|
}
|
|
128821
128934
|
if (bottomAud[0]) {
|
|
128822
|
-
const s = cplSignal(
|
|
128935
|
+
const s = cplSignal(num5(bottomAud[0].costPerResult), avgCpl);
|
|
128823
128936
|
pushRow(rows, seen, {
|
|
128824
128937
|
item: `\u53D7\u4F17\xB7${String(bottomAud[0].label ?? "Bottom")}`,
|
|
128825
|
-
data: `CPL ${money2(
|
|
128938
|
+
data: `CPL ${money2(num5(bottomAud[0].costPerResult), currency)}`,
|
|
128826
128939
|
...s
|
|
128827
128940
|
});
|
|
128828
128941
|
}
|
|
@@ -128866,7 +128979,7 @@ function asRecord14(value) {
|
|
|
128866
128979
|
}
|
|
128867
128980
|
return null;
|
|
128868
128981
|
}
|
|
128869
|
-
function
|
|
128982
|
+
function num6(value) {
|
|
128870
128983
|
const n = Number(value);
|
|
128871
128984
|
return Number.isFinite(n) ? n : void 0;
|
|
128872
128985
|
}
|
|
@@ -128920,8 +129033,8 @@ function aggregatePlatform(networks) {
|
|
|
128920
129033
|
const platform = String(row.publisherPlatform ?? row.network ?? "unknown");
|
|
128921
129034
|
const prev = map.get(platform) ?? { spend: 0, results: 0 };
|
|
128922
129035
|
map.set(platform, {
|
|
128923
|
-
spend: prev.spend + (
|
|
128924
|
-
results: prev.results + (
|
|
129036
|
+
spend: prev.spend + (num6(row.spend) ?? 0),
|
|
129037
|
+
results: prev.results + (num6(row.results) ?? 0)
|
|
128925
129038
|
});
|
|
128926
129039
|
}
|
|
128927
129040
|
const labels = [];
|
|
@@ -128937,10 +129050,10 @@ function aggregatePlatform(networks) {
|
|
|
128937
129050
|
function buildAudienceRows(audiences) {
|
|
128938
129051
|
return audiences.map((a) => ({
|
|
128939
129052
|
label: audienceLabel(a.age, a.gender),
|
|
128940
|
-
spend:
|
|
128941
|
-
results:
|
|
128942
|
-
costPerResult:
|
|
128943
|
-
frequency:
|
|
129053
|
+
spend: num6(a.spend) ?? 0,
|
|
129054
|
+
results: num6(a.results) ?? 0,
|
|
129055
|
+
costPerResult: num6(a.costPerResult) ?? (num6(a.results) ? (num6(a.spend) ?? 0) / (num6(a.results) ?? 1) : 0),
|
|
129056
|
+
frequency: num6(a.frequency)
|
|
128944
129057
|
})).filter((r) => r.spend > 0 || r.results > 0);
|
|
128945
129058
|
}
|
|
128946
129059
|
async function mergeFacebookSnapshotIntoReport(payload, snapshotDir) {
|
|
@@ -128979,7 +129092,7 @@ async function mergeFacebookSnapshotIntoReport(payload, snapshotDir) {
|
|
|
128979
129092
|
}
|
|
128980
129093
|
if (!meta.resultType && current?.resultType) meta.resultType = String(current.resultType);
|
|
128981
129094
|
const charts = { ...payload.charts ?? {} };
|
|
128982
|
-
const avgCpl =
|
|
129095
|
+
const avgCpl = num6(kpis.costPerResult) ?? 0;
|
|
128983
129096
|
if (!charts.platform) {
|
|
128984
129097
|
const platform = sectionMap.get("platform");
|
|
128985
129098
|
const networks = Array.isArray(platform?.networks) ? platform.networks : [];
|
|
@@ -128989,10 +129102,10 @@ async function mergeFacebookSnapshotIntoReport(payload, snapshotDir) {
|
|
|
128989
129102
|
const country = sectionMap.get("country");
|
|
128990
129103
|
const countries = Array.isArray(country?.countries) ? country.countries : [];
|
|
128991
129104
|
if (countries.length) {
|
|
128992
|
-
const sorted = [...countries].sort((a, b) => (
|
|
129105
|
+
const sorted = [...countries].sort((a, b) => (num6(b.spend) ?? 0) - (num6(a.spend) ?? 0));
|
|
128993
129106
|
charts.country = {
|
|
128994
129107
|
labels: sorted.map((c) => String(c.countryOrRegion ?? "\u2014")),
|
|
128995
|
-
cpl: sorted.map((c) =>
|
|
129108
|
+
cpl: sorted.map((c) => num6(c.costPerResult) ?? 0)
|
|
128996
129109
|
};
|
|
128997
129110
|
}
|
|
128998
129111
|
}
|
|
@@ -129008,7 +129121,7 @@ async function mergeFacebookSnapshotIntoReport(payload, snapshotDir) {
|
|
|
129008
129121
|
};
|
|
129009
129122
|
}
|
|
129010
129123
|
}
|
|
129011
|
-
if (!charts.funnel &&
|
|
129124
|
+
if (!charts.funnel && num6(kpis.reach) != null) {
|
|
129012
129125
|
charts.funnel = { reach: kpis.reach, results: kpis.results ?? 0 };
|
|
129013
129126
|
}
|
|
129014
129127
|
const tables = { ...payload.tables ?? {} };
|
|
@@ -129017,14 +129130,14 @@ async function mergeFacebookSnapshotIntoReport(payload, snapshotDir) {
|
|
|
129017
129130
|
const groups = Array.isArray(adSets?.adGroups) ? adSets.adGroups : [];
|
|
129018
129131
|
if (groups.length) {
|
|
129019
129132
|
tables.adSets = groups.map((g) => {
|
|
129020
|
-
const cpl =
|
|
129021
|
-
const freq =
|
|
129133
|
+
const cpl = num6(g.costPerResult);
|
|
129134
|
+
const freq = num6(g.frequency);
|
|
129022
129135
|
const fatigue = fatigueFromFrequency(freq);
|
|
129023
129136
|
const status = statusFromCpl(cpl, avgCpl);
|
|
129024
129137
|
return {
|
|
129025
129138
|
name: String(g.adGroupName ?? g.campaignName ?? "\u2014"),
|
|
129026
|
-
spend:
|
|
129027
|
-
results:
|
|
129139
|
+
spend: num6(g.spend) ?? 0,
|
|
129140
|
+
results: num6(g.results) ?? 0,
|
|
129028
129141
|
costPerResult: cpl ?? 0,
|
|
129029
129142
|
frequency: freq,
|
|
129030
129143
|
fatigueLevel: fatigue.level,
|
|
@@ -129048,7 +129161,7 @@ async function mergeFacebookSnapshotIntoReport(payload, snapshotDir) {
|
|
|
129048
129161
|
}
|
|
129049
129162
|
const currency = typeof meta.currency === "string" ? meta.currency : "USD";
|
|
129050
129163
|
const mergeCtx = {
|
|
129051
|
-
spend:
|
|
129164
|
+
spend: num6(kpis.spend),
|
|
129052
129165
|
avgCpl,
|
|
129053
129166
|
currency,
|
|
129054
129167
|
charts,
|
|
@@ -129671,7 +129784,7 @@ function asRecord17(value) {
|
|
|
129671
129784
|
}
|
|
129672
129785
|
return null;
|
|
129673
129786
|
}
|
|
129674
|
-
function
|
|
129787
|
+
function num7(value) {
|
|
129675
129788
|
const n = Number(value);
|
|
129676
129789
|
return Number.isFinite(n) ? n : void 0;
|
|
129677
129790
|
}
|
|
@@ -129680,16 +129793,16 @@ function asRows(value) {
|
|
|
129680
129793
|
}
|
|
129681
129794
|
function pickMetricExtras(row, extras) {
|
|
129682
129795
|
const out = {
|
|
129683
|
-
spend:
|
|
129684
|
-
impressions:
|
|
129685
|
-
clicks:
|
|
129686
|
-
results:
|
|
129687
|
-
costPerResult:
|
|
129688
|
-
reach:
|
|
129689
|
-
frequency:
|
|
129690
|
-
ctr:
|
|
129691
|
-
conversions:
|
|
129692
|
-
costPerConversion:
|
|
129796
|
+
spend: num7(row.spend) ?? 0,
|
|
129797
|
+
impressions: num7(row.impressions) ?? 0,
|
|
129798
|
+
clicks: num7(row.clicks) ?? 0,
|
|
129799
|
+
results: num7(row.results),
|
|
129800
|
+
costPerResult: num7(row.costPerResult),
|
|
129801
|
+
reach: num7(row.reach),
|
|
129802
|
+
frequency: num7(row.frequency),
|
|
129803
|
+
ctr: num7(row.ctr),
|
|
129804
|
+
conversions: num7(row.conversions),
|
|
129805
|
+
costPerConversion: num7(row.costPerConversion)
|
|
129693
129806
|
};
|
|
129694
129807
|
for (const f of extras) {
|
|
129695
129808
|
if (row[f] !== void 0 && row[f] !== null) out[f] = row[f];
|
|
@@ -129758,27 +129871,27 @@ async function mergeMetaDiagnosisSnapshotIntoReport(payload, snapshotDir) {
|
|
|
129758
129871
|
if (!meta.generatedAt) meta.generatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
129759
129872
|
const kpis = { ...payload.kpis ?? {} };
|
|
129760
129873
|
if (currentPeriod) {
|
|
129761
|
-
if (kpis.spend == null) kpis.spend =
|
|
129762
|
-
if (kpis.impressions == null) kpis.impressions =
|
|
129763
|
-
if (kpis.clicks == null) kpis.clicks =
|
|
129764
|
-
if (kpis.results == null) kpis.results =
|
|
129765
|
-
if (kpis.costPerResult == null) kpis.costPerResult =
|
|
129766
|
-
if (kpis.ctr == null) kpis.ctr =
|
|
129767
|
-
if (kpis.cpc == null) kpis.cpc =
|
|
129768
|
-
if (kpis.reach == null) kpis.reach =
|
|
129769
|
-
if (kpis.frequency == null) kpis.frequency =
|
|
129874
|
+
if (kpis.spend == null) kpis.spend = num7(currentPeriod.spend);
|
|
129875
|
+
if (kpis.impressions == null) kpis.impressions = num7(currentPeriod.impressions);
|
|
129876
|
+
if (kpis.clicks == null) kpis.clicks = num7(currentPeriod.clicks);
|
|
129877
|
+
if (kpis.results == null) kpis.results = num7(currentPeriod.results);
|
|
129878
|
+
if (kpis.costPerResult == null) kpis.costPerResult = num7(currentPeriod.costPerResult);
|
|
129879
|
+
if (kpis.ctr == null) kpis.ctr = num7(currentPeriod.ctr);
|
|
129880
|
+
if (kpis.cpc == null) kpis.cpc = num7(currentPeriod.cpc ?? currentPeriod.averageCpc);
|
|
129881
|
+
if (kpis.reach == null) kpis.reach = num7(currentPeriod.reach);
|
|
129882
|
+
if (kpis.frequency == null) kpis.frequency = num7(currentPeriod.frequency);
|
|
129770
129883
|
}
|
|
129771
129884
|
if (!kpis.previousPeriod && previousPeriod) {
|
|
129772
129885
|
kpis.previousPeriod = {
|
|
129773
|
-
spend:
|
|
129774
|
-
impressions:
|
|
129775
|
-
clicks:
|
|
129776
|
-
results:
|
|
129777
|
-
costPerResult:
|
|
129778
|
-
ctr:
|
|
129779
|
-
cpc:
|
|
129780
|
-
reach:
|
|
129781
|
-
frequency:
|
|
129886
|
+
spend: num7(previousPeriod.spend),
|
|
129887
|
+
impressions: num7(previousPeriod.impressions),
|
|
129888
|
+
clicks: num7(previousPeriod.clicks),
|
|
129889
|
+
results: num7(previousPeriod.results),
|
|
129890
|
+
costPerResult: num7(previousPeriod.costPerResult),
|
|
129891
|
+
ctr: num7(previousPeriod.ctr),
|
|
129892
|
+
cpc: num7(previousPeriod.cpc ?? previousPeriod.averageCpc),
|
|
129893
|
+
reach: num7(previousPeriod.reach),
|
|
129894
|
+
frequency: num7(previousPeriod.frequency)
|
|
129782
129895
|
};
|
|
129783
129896
|
}
|
|
129784
129897
|
const tables = { ...payload.tables ?? {} };
|
|
@@ -130363,7 +130476,7 @@ init_auth();
|
|
|
130363
130476
|
init_balance();
|
|
130364
130477
|
|
|
130365
130478
|
// src/commands/bing-analysis/normalize-bing-overview.ts
|
|
130366
|
-
function
|
|
130479
|
+
function num8(v) {
|
|
130367
130480
|
return typeof v === "number" && Number.isFinite(v) ? v : void 0;
|
|
130368
130481
|
}
|
|
130369
130482
|
function roundMoney(v) {
|
|
@@ -130384,19 +130497,19 @@ function countInclusiveCalendarDays(startDate, endDate) {
|
|
|
130384
130497
|
}
|
|
130385
130498
|
function periodSpend(period) {
|
|
130386
130499
|
if (!period || typeof period !== "object") return void 0;
|
|
130387
|
-
return
|
|
130500
|
+
return num8(period.spend);
|
|
130388
130501
|
}
|
|
130389
130502
|
function enrichBingOverviewDerivedMetrics(record2, startDate, endDate) {
|
|
130390
130503
|
const out = { ...record2 };
|
|
130391
130504
|
const currentSpend = periodSpend(out.currentPeriod);
|
|
130392
|
-
let totalCost =
|
|
130505
|
+
let totalCost = num8(out.totalCost);
|
|
130393
130506
|
if (totalCost == null || totalCost <= 0) {
|
|
130394
130507
|
if (currentSpend != null && currentSpend > 0) {
|
|
130395
130508
|
out.totalCost = currentSpend;
|
|
130396
130509
|
totalCost = currentSpend;
|
|
130397
130510
|
}
|
|
130398
130511
|
}
|
|
130399
|
-
let activeDays =
|
|
130512
|
+
let activeDays = num8(out.activeDays);
|
|
130400
130513
|
if (activeDays == null || activeDays <= 0) {
|
|
130401
130514
|
const calendarDays = countInclusiveCalendarDays(startDate, endDate);
|
|
130402
130515
|
if (calendarDays > 0) {
|
|
@@ -130404,7 +130517,7 @@ function enrichBingOverviewDerivedMetrics(record2, startDate, endDate) {
|
|
|
130404
130517
|
activeDays = calendarDays;
|
|
130405
130518
|
}
|
|
130406
130519
|
}
|
|
130407
|
-
const averageDailyCost =
|
|
130520
|
+
const averageDailyCost = num8(out.averageDailyCost);
|
|
130408
130521
|
if ((averageDailyCost == null || averageDailyCost <= 0) && totalCost != null && totalCost > 0 && activeDays != null && activeDays > 0) {
|
|
130409
130522
|
out.averageDailyCost = roundMoney(totalCost / activeDays);
|
|
130410
130523
|
}
|
|
@@ -130436,16 +130549,16 @@ function calcBingPreviousPeriodRange(startDate, endDate) {
|
|
|
130436
130549
|
function isBingPeriodBlockEmpty(period) {
|
|
130437
130550
|
if (!period || typeof period !== "object") return true;
|
|
130438
130551
|
const p = period;
|
|
130439
|
-
const spend =
|
|
130440
|
-
const impressions =
|
|
130441
|
-
const clicks =
|
|
130552
|
+
const spend = num8(p.spend) ?? 0;
|
|
130553
|
+
const impressions = num8(p.impressions) ?? 0;
|
|
130554
|
+
const clicks = num8(p.clicks) ?? 0;
|
|
130442
130555
|
return spend <= 0 && impressions <= 0 && clicks <= 0;
|
|
130443
130556
|
}
|
|
130444
130557
|
function syncOverviewBalanceFields(record2) {
|
|
130445
130558
|
const out = { ...record2 };
|
|
130446
|
-
const budget =
|
|
130559
|
+
const budget = num8(out.remainingAccountBudget);
|
|
130447
130560
|
if (budget != null && budget >= 0) {
|
|
130448
|
-
const balanceField =
|
|
130561
|
+
const balanceField = num8(out.balance);
|
|
130449
130562
|
if (balanceField == null || balanceField <= 0 && budget > 0) {
|
|
130450
130563
|
out.balance = budget;
|
|
130451
130564
|
}
|
|
@@ -130809,11 +130922,11 @@ function asRecord20(value) {
|
|
|
130809
130922
|
}
|
|
130810
130923
|
return null;
|
|
130811
130924
|
}
|
|
130812
|
-
function
|
|
130925
|
+
function num9(value) {
|
|
130813
130926
|
const n = Number(value);
|
|
130814
130927
|
return Number.isFinite(n) ? n : void 0;
|
|
130815
130928
|
}
|
|
130816
|
-
function
|
|
130929
|
+
function round24(value) {
|
|
130817
130930
|
return value == null ? void 0 : Math.round(value * 100) / 100;
|
|
130818
130931
|
}
|
|
130819
130932
|
function asRows2(value) {
|
|
@@ -130855,14 +130968,14 @@ async function readManifest4(snapshotDir, accountId) {
|
|
|
130855
130968
|
}
|
|
130856
130969
|
function pickMetrics(row, extras = []) {
|
|
130857
130970
|
const out = {
|
|
130858
|
-
spend:
|
|
130859
|
-
impressions:
|
|
130860
|
-
clicks:
|
|
130861
|
-
ctr:
|
|
130862
|
-
averageCpc:
|
|
130863
|
-
conversions:
|
|
130864
|
-
conversionRate:
|
|
130865
|
-
costPerConversion:
|
|
130971
|
+
spend: num9(row.spend) ?? 0,
|
|
130972
|
+
impressions: num9(row.impressions) ?? 0,
|
|
130973
|
+
clicks: num9(row.clicks) ?? 0,
|
|
130974
|
+
ctr: num9(row.ctr),
|
|
130975
|
+
averageCpc: num9(row.averageCpc),
|
|
130976
|
+
conversions: num9(row.conversions) ?? 0,
|
|
130977
|
+
conversionRate: num9(row.conversionRate),
|
|
130978
|
+
costPerConversion: num9(row.costPerConversion)
|
|
130866
130979
|
};
|
|
130867
130980
|
for (const f of extras) {
|
|
130868
130981
|
if (row[f] !== void 0 && row[f] !== null) out[f] = row[f];
|
|
@@ -130876,19 +130989,19 @@ function sumBingCampaignRowsToPeriodKpis(rows) {
|
|
|
130876
130989
|
let clicks = 0;
|
|
130877
130990
|
let conversions = 0;
|
|
130878
130991
|
for (const row of rows) {
|
|
130879
|
-
spend +=
|
|
130880
|
-
impressions +=
|
|
130881
|
-
clicks +=
|
|
130882
|
-
conversions +=
|
|
130992
|
+
spend += num9(row.spend) ?? 0;
|
|
130993
|
+
impressions += num9(row.impressions) ?? 0;
|
|
130994
|
+
clicks += num9(row.clicks) ?? 0;
|
|
130995
|
+
conversions += num9(row.conversions) ?? 0;
|
|
130883
130996
|
}
|
|
130884
130997
|
return {
|
|
130885
|
-
spend:
|
|
130998
|
+
spend: round24(spend),
|
|
130886
130999
|
impressions: Math.round(impressions),
|
|
130887
131000
|
clicks: Math.round(clicks),
|
|
130888
|
-
conversions:
|
|
131001
|
+
conversions: round24(conversions),
|
|
130889
131002
|
ctr: impressions > 0 ? clicks / impressions : void 0,
|
|
130890
|
-
averageCpc: clicks > 0 ?
|
|
130891
|
-
costPerConversion: conversions > 0 ?
|
|
131003
|
+
averageCpc: clicks > 0 ? round24(spend / clicks) : void 0,
|
|
131004
|
+
costPerConversion: conversions > 0 ? round24(spend / conversions) : void 0
|
|
130892
131005
|
};
|
|
130893
131006
|
}
|
|
130894
131007
|
function campaignStatusDisplay(status) {
|
|
@@ -131026,13 +131139,13 @@ async function mergeBingAnalysisSnapshotIntoReport(payload, snapshotDir) {
|
|
|
131026
131139
|
if (!meta.generatedAt) meta.generatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
131027
131140
|
const kpis = { ...payload.kpis ?? {} };
|
|
131028
131141
|
const currentKpiSource = campaignKpis ?? (currentPeriod ? {
|
|
131029
|
-
spend:
|
|
131030
|
-
impressions:
|
|
131031
|
-
clicks:
|
|
131032
|
-
conversions:
|
|
131033
|
-
ctr:
|
|
131034
|
-
averageCpc:
|
|
131035
|
-
costPerConversion:
|
|
131142
|
+
spend: num9(currentPeriod.spend),
|
|
131143
|
+
impressions: num9(currentPeriod.impressions),
|
|
131144
|
+
clicks: num9(currentPeriod.clicks),
|
|
131145
|
+
conversions: num9(currentPeriod.conversions),
|
|
131146
|
+
ctr: num9(currentPeriod.ctr),
|
|
131147
|
+
averageCpc: num9(currentPeriod.averageCpc),
|
|
131148
|
+
costPerConversion: num9(currentPeriod.costPerConversion)
|
|
131036
131149
|
} : null);
|
|
131037
131150
|
if (currentKpiSource) {
|
|
131038
131151
|
if (kpis.spend == null) kpis.spend = currentKpiSource.spend;
|
|
@@ -131044,24 +131157,24 @@ async function mergeBingAnalysisSnapshotIntoReport(payload, snapshotDir) {
|
|
|
131044
131157
|
if (kpis.costPerConversion == null) kpis.costPerConversion = currentKpiSource.costPerConversion;
|
|
131045
131158
|
}
|
|
131046
131159
|
if (kpis.averageDailyCost == null && overview) {
|
|
131047
|
-
kpis.averageDailyCost =
|
|
131160
|
+
kpis.averageDailyCost = num9(overview.averageDailyCost);
|
|
131048
131161
|
}
|
|
131049
|
-
if (kpis.balance == null && overview) kpis.balance =
|
|
131162
|
+
if (kpis.balance == null && overview) kpis.balance = num9(overview.balance);
|
|
131050
131163
|
if (kpis.remainingAccountBudget == null && overview) {
|
|
131051
|
-
kpis.remainingAccountBudget =
|
|
131164
|
+
kpis.remainingAccountBudget = num9(overview.remainingAccountBudget);
|
|
131052
131165
|
}
|
|
131053
131166
|
if (kpis.optimizationScore == null && overview) {
|
|
131054
|
-
kpis.optimizationScore =
|
|
131167
|
+
kpis.optimizationScore = num9(overview.optimizationScore);
|
|
131055
131168
|
}
|
|
131056
131169
|
if (!kpis.previousPeriod && previousPeriod) {
|
|
131057
131170
|
kpis.previousPeriod = {
|
|
131058
|
-
spend:
|
|
131059
|
-
impressions:
|
|
131060
|
-
clicks:
|
|
131061
|
-
conversions:
|
|
131062
|
-
ctr:
|
|
131063
|
-
averageCpc:
|
|
131064
|
-
costPerConversion:
|
|
131171
|
+
spend: num9(previousPeriod.spend),
|
|
131172
|
+
impressions: num9(previousPeriod.impressions),
|
|
131173
|
+
clicks: num9(previousPeriod.clicks),
|
|
131174
|
+
conversions: num9(previousPeriod.conversions),
|
|
131175
|
+
ctr: num9(previousPeriod.ctr),
|
|
131176
|
+
averageCpc: num9(previousPeriod.averageCpc),
|
|
131177
|
+
costPerConversion: num9(previousPeriod.costPerConversion)
|
|
131065
131178
|
};
|
|
131066
131179
|
}
|
|
131067
131180
|
const tables = { ...payload.tables ?? {} };
|
|
@@ -131682,11 +131795,11 @@ function asRecord23(value) {
|
|
|
131682
131795
|
}
|
|
131683
131796
|
return null;
|
|
131684
131797
|
}
|
|
131685
|
-
function
|
|
131798
|
+
function num10(value) {
|
|
131686
131799
|
const n = Number(value);
|
|
131687
131800
|
return Number.isFinite(n) ? n : void 0;
|
|
131688
131801
|
}
|
|
131689
|
-
function
|
|
131802
|
+
function round25(value) {
|
|
131690
131803
|
return value == null ? void 0 : Math.round(value * 100) / 100;
|
|
131691
131804
|
}
|
|
131692
131805
|
async function loadSectionPayload2(snapshotDir, file) {
|
|
@@ -131722,19 +131835,19 @@ async function readManifest5(snapshotDir, accountId) {
|
|
|
131722
131835
|
}
|
|
131723
131836
|
function normalizeTikTokMetrics(metrics) {
|
|
131724
131837
|
const m = metrics ?? {};
|
|
131725
|
-
const spend =
|
|
131726
|
-
const impressions =
|
|
131727
|
-
const clicks =
|
|
131728
|
-
const conversions =
|
|
131838
|
+
const spend = num10(m.spend);
|
|
131839
|
+
const impressions = num10(m.impressions);
|
|
131840
|
+
const clicks = num10(m.clicks);
|
|
131841
|
+
const conversions = num10(m.conversion);
|
|
131729
131842
|
return {
|
|
131730
131843
|
spend: spend ?? 0,
|
|
131731
131844
|
impressions: impressions ?? 0,
|
|
131732
131845
|
clicks: clicks ?? 0,
|
|
131733
131846
|
conversions: conversions == null ? 0 : Math.round(conversions),
|
|
131734
|
-
ctr:
|
|
131735
|
-
averageCpc:
|
|
131736
|
-
costPerConversion:
|
|
131737
|
-
conversionRate:
|
|
131847
|
+
ctr: num10(m.ctr),
|
|
131848
|
+
averageCpc: num10(m.cpc),
|
|
131849
|
+
costPerConversion: num10(m.cost_per_conversion),
|
|
131850
|
+
conversionRate: num10(m.conversion_rate)
|
|
131738
131851
|
};
|
|
131739
131852
|
}
|
|
131740
131853
|
function listFromEnvelope(payload) {
|
|
@@ -131753,19 +131866,19 @@ function sumTikTokCampaignRowsToPeriodKpis(rows) {
|
|
|
131753
131866
|
let clicks = 0;
|
|
131754
131867
|
let conversions = 0;
|
|
131755
131868
|
for (const row of rows) {
|
|
131756
|
-
spend +=
|
|
131757
|
-
impressions +=
|
|
131758
|
-
clicks +=
|
|
131759
|
-
conversions +=
|
|
131869
|
+
spend += num10(row.spend) ?? 0;
|
|
131870
|
+
impressions += num10(row.impressions) ?? 0;
|
|
131871
|
+
clicks += num10(row.clicks) ?? 0;
|
|
131872
|
+
conversions += num10(row.conversions) ?? 0;
|
|
131760
131873
|
}
|
|
131761
131874
|
return {
|
|
131762
|
-
spend:
|
|
131875
|
+
spend: round25(spend),
|
|
131763
131876
|
impressions: Math.round(impressions),
|
|
131764
131877
|
clicks: Math.round(clicks),
|
|
131765
|
-
conversions:
|
|
131878
|
+
conversions: round25(conversions),
|
|
131766
131879
|
ctr: impressions > 0 ? clicks / impressions : void 0,
|
|
131767
|
-
averageCpc: clicks > 0 ?
|
|
131768
|
-
costPerConversion: conversions > 0 ?
|
|
131880
|
+
averageCpc: clicks > 0 ? round25(spend / clicks) : void 0,
|
|
131881
|
+
costPerConversion: conversions > 0 ? round25(spend / conversions) : void 0
|
|
131769
131882
|
};
|
|
131770
131883
|
}
|
|
131771
131884
|
function mapCampaignTable(rows) {
|
|
@@ -131773,13 +131886,13 @@ function mapCampaignTable(rows) {
|
|
|
131773
131886
|
campaignId: r.campaignId,
|
|
131774
131887
|
campaignName: r.campaignName,
|
|
131775
131888
|
status: r.campaignStatus,
|
|
131776
|
-
spend:
|
|
131777
|
-
impressions:
|
|
131778
|
-
clicks:
|
|
131779
|
-
conversions:
|
|
131780
|
-
ctr:
|
|
131781
|
-
averageCpc:
|
|
131782
|
-
costPerConversion:
|
|
131889
|
+
spend: num10(r.spend) ?? 0,
|
|
131890
|
+
impressions: num10(r.impressions) ?? 0,
|
|
131891
|
+
clicks: num10(r.clicks) ?? 0,
|
|
131892
|
+
conversions: num10(r.conversions) ?? 0,
|
|
131893
|
+
ctr: num10(r.ctr),
|
|
131894
|
+
averageCpc: num10(r.averageCpc),
|
|
131895
|
+
costPerConversion: num10(r.costPerConversion)
|
|
131783
131896
|
}));
|
|
131784
131897
|
}
|
|
131785
131898
|
function mapAdGroupTable(payload) {
|
|
@@ -131861,13 +131974,13 @@ async function mergeTikTokAnalysisSnapshotIntoReport(payload, snapshotDir) {
|
|
|
131861
131974
|
if (!meta.generatedAt) meta.generatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
131862
131975
|
const kpis = { ...payload.kpis ?? {} };
|
|
131863
131976
|
const currentKpiSource = campaignKpis ?? (currentPeriod ? {
|
|
131864
|
-
spend:
|
|
131865
|
-
impressions:
|
|
131866
|
-
clicks:
|
|
131867
|
-
conversions:
|
|
131868
|
-
ctr:
|
|
131869
|
-
averageCpc:
|
|
131870
|
-
costPerConversion:
|
|
131977
|
+
spend: num10(currentPeriod.spend),
|
|
131978
|
+
impressions: num10(currentPeriod.impressions),
|
|
131979
|
+
clicks: num10(currentPeriod.clicks),
|
|
131980
|
+
conversions: num10(currentPeriod.conversions),
|
|
131981
|
+
ctr: num10(currentPeriod.ctr),
|
|
131982
|
+
averageCpc: num10(currentPeriod.averageCpc),
|
|
131983
|
+
costPerConversion: num10(currentPeriod.costPerConversion)
|
|
131871
131984
|
} : null);
|
|
131872
131985
|
if (currentKpiSource) {
|
|
131873
131986
|
if (kpis.spend == null) kpis.spend = currentKpiSource.spend;
|
|
@@ -131880,13 +131993,13 @@ async function mergeTikTokAnalysisSnapshotIntoReport(payload, snapshotDir) {
|
|
|
131880
131993
|
}
|
|
131881
131994
|
if (!kpis.previousPeriod && previousPeriod) {
|
|
131882
131995
|
kpis.previousPeriod = {
|
|
131883
|
-
spend:
|
|
131884
|
-
impressions:
|
|
131885
|
-
clicks:
|
|
131886
|
-
conversions:
|
|
131887
|
-
ctr:
|
|
131888
|
-
averageCpc:
|
|
131889
|
-
costPerConversion:
|
|
131996
|
+
spend: num10(previousPeriod.spend),
|
|
131997
|
+
impressions: num10(previousPeriod.impressions),
|
|
131998
|
+
clicks: num10(previousPeriod.clicks),
|
|
131999
|
+
conversions: num10(previousPeriod.conversions),
|
|
132000
|
+
ctr: num10(previousPeriod.ctr),
|
|
132001
|
+
averageCpc: num10(previousPeriod.averageCpc),
|
|
132002
|
+
costPerConversion: num10(previousPeriod.costPerConversion)
|
|
131890
132003
|
};
|
|
131891
132004
|
}
|
|
131892
132005
|
const tables = { ...payload.tables ?? {} };
|