aads-cli 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. package/LICENSE +21 -0
  2. package/README.ja.md +159 -0
  3. package/README.md +159 -0
  4. package/data/campaign-layer-policy.json +68 -0
  5. package/dist/analysis/anomaly-detection.d.ts +16 -0
  6. package/dist/analysis/anomaly-detection.d.ts.map +1 -0
  7. package/dist/analysis/anomaly-detection.js +55 -0
  8. package/dist/analysis/anomaly-detection.js.map +1 -0
  9. package/dist/analysis/auto-to-manual.d.ts +11 -0
  10. package/dist/analysis/auto-to-manual.d.ts.map +1 -0
  11. package/dist/analysis/auto-to-manual.js +57 -0
  12. package/dist/analysis/auto-to-manual.js.map +1 -0
  13. package/dist/analysis/campaign-layer-classifier.d.ts +10 -0
  14. package/dist/analysis/campaign-layer-classifier.d.ts.map +1 -0
  15. package/dist/analysis/campaign-layer-classifier.js +50 -0
  16. package/dist/analysis/campaign-layer-classifier.js.map +1 -0
  17. package/dist/analysis/campaign-structure.d.ts +3 -0
  18. package/dist/analysis/campaign-structure.d.ts.map +1 -0
  19. package/dist/analysis/campaign-structure.js +51 -0
  20. package/dist/analysis/campaign-structure.js.map +1 -0
  21. package/dist/analysis/cpc-optimizer.d.ts +11 -0
  22. package/dist/analysis/cpc-optimizer.d.ts.map +1 -0
  23. package/dist/analysis/cpc-optimizer.js +46 -0
  24. package/dist/analysis/cpc-optimizer.js.map +1 -0
  25. package/dist/analysis/performance-analyzer.d.ts +3 -0
  26. package/dist/analysis/performance-analyzer.d.ts.map +1 -0
  27. package/dist/analysis/performance-analyzer.js +58 -0
  28. package/dist/analysis/performance-analyzer.js.map +1 -0
  29. package/dist/analysis/sku-classifier.d.ts +3 -0
  30. package/dist/analysis/sku-classifier.d.ts.map +1 -0
  31. package/dist/analysis/sku-classifier.js +64 -0
  32. package/dist/analysis/sku-classifier.js.map +1 -0
  33. package/dist/cli.d.ts +3 -0
  34. package/dist/cli.d.ts.map +1 -0
  35. package/dist/cli.js +351 -0
  36. package/dist/cli.js.map +1 -0
  37. package/dist/config/campaign-layer-policy.d.ts +28 -0
  38. package/dist/config/campaign-layer-policy.d.ts.map +1 -0
  39. package/dist/config/campaign-layer-policy.js +56 -0
  40. package/dist/config/campaign-layer-policy.js.map +1 -0
  41. package/dist/config/constants.d.ts +74 -0
  42. package/dist/config/constants.d.ts.map +1 -0
  43. package/dist/config/constants.js +61 -0
  44. package/dist/config/constants.js.map +1 -0
  45. package/dist/config/optimisation-config.d.ts +24 -0
  46. package/dist/config/optimisation-config.d.ts.map +1 -0
  47. package/dist/config/optimisation-config.js +41 -0
  48. package/dist/config/optimisation-config.js.map +1 -0
  49. package/dist/core/header-mapper.d.ts +6 -0
  50. package/dist/core/header-mapper.d.ts.map +1 -0
  51. package/dist/core/header-mapper.js +34 -0
  52. package/dist/core/header-mapper.js.map +1 -0
  53. package/dist/core/normalizer.d.ts +9 -0
  54. package/dist/core/normalizer.d.ts.map +1 -0
  55. package/dist/core/normalizer.js +76 -0
  56. package/dist/core/normalizer.js.map +1 -0
  57. package/dist/io/csv-reader.d.ts +3 -0
  58. package/dist/io/csv-reader.d.ts.map +1 -0
  59. package/dist/io/csv-reader.js +52 -0
  60. package/dist/io/csv-reader.js.map +1 -0
  61. package/dist/io/excel-reader.d.ts +4 -0
  62. package/dist/io/excel-reader.d.ts.map +1 -0
  63. package/dist/io/excel-reader.js +83 -0
  64. package/dist/io/excel-reader.js.map +1 -0
  65. package/dist/io/excel-writer.d.ts +7 -0
  66. package/dist/io/excel-writer.d.ts.map +1 -0
  67. package/dist/io/excel-writer.js +42 -0
  68. package/dist/io/excel-writer.js.map +1 -0
  69. package/dist/pipeline/analyze-pipeline.d.ts +8 -0
  70. package/dist/pipeline/analyze-pipeline.d.ts.map +1 -0
  71. package/dist/pipeline/analyze-pipeline.js +145 -0
  72. package/dist/pipeline/analyze-pipeline.js.map +1 -0
  73. package/dist/pipeline/types.d.ts +142 -0
  74. package/dist/pipeline/types.d.ts.map +1 -0
  75. package/dist/pipeline/types.js +2 -0
  76. package/dist/pipeline/types.js.map +1 -0
  77. package/dist/ranking/keyword-matcher.d.ts +10 -0
  78. package/dist/ranking/keyword-matcher.d.ts.map +1 -0
  79. package/dist/ranking/keyword-matcher.js +62 -0
  80. package/dist/ranking/keyword-matcher.js.map +1 -0
  81. package/dist/ranking/ranking-db.d.ts +14 -0
  82. package/dist/ranking/ranking-db.d.ts.map +1 -0
  83. package/dist/ranking/ranking-db.js +97 -0
  84. package/dist/ranking/ranking-db.js.map +1 -0
  85. package/dist/ranking/seo-factor.d.ts +5 -0
  86. package/dist/ranking/seo-factor.d.ts.map +1 -0
  87. package/dist/ranking/seo-factor.js +57 -0
  88. package/dist/ranking/seo-factor.js.map +1 -0
  89. package/dist/ranking/types.d.ts +25 -0
  90. package/dist/ranking/types.d.ts.map +1 -0
  91. package/dist/ranking/types.js +2 -0
  92. package/dist/ranking/types.js.map +1 -0
  93. package/dist/schemas/types.d.ts +32 -0
  94. package/dist/schemas/types.d.ts.map +1 -0
  95. package/dist/schemas/types.js +2 -0
  96. package/dist/schemas/types.js.map +1 -0
  97. package/dist/utils/date-utils.d.ts +17 -0
  98. package/dist/utils/date-utils.d.ts.map +1 -0
  99. package/dist/utils/date-utils.js +56 -0
  100. package/dist/utils/date-utils.js.map +1 -0
  101. package/dist/utils/logger.d.ts +12 -0
  102. package/dist/utils/logger.d.ts.map +1 -0
  103. package/dist/utils/logger.js +45 -0
  104. package/dist/utils/logger.js.map +1 -0
  105. package/package.json +65 -0
@@ -0,0 +1,83 @@
1
+ import ExcelJS from "exceljs";
2
+ import fs from "node:fs";
3
+ import path from "node:path";
4
+ const wildcardToRegExp = (pattern) => {
5
+ const escaped = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&");
6
+ const regex = escaped.replace(/\*/g, ".*").replace(/\?/g, ".");
7
+ return new RegExp(`^${regex}$`, "i");
8
+ };
9
+ export const resolveInputFiles = (inputPattern) => {
10
+ const normalized = inputPattern.replace(/\\/g, "/");
11
+ const hasWildcard = /[*?]/.test(normalized);
12
+ if (!hasWildcard) {
13
+ return [inputPattern];
14
+ }
15
+ const parsed = path.parse(normalized);
16
+ const dir = parsed.dir || ".";
17
+ const filePattern = parsed.base;
18
+ const regex = wildcardToRegExp(filePattern);
19
+ if (!fs.existsSync(dir)) {
20
+ throw new Error(`Input directory not found: ${dir}`);
21
+ }
22
+ return fs
23
+ .readdirSync(dir)
24
+ .filter((name) => regex.test(name))
25
+ .map((name) => path.join(dir, name))
26
+ .sort((a, b) => a.localeCompare(b));
27
+ };
28
+ const normalizeCell = (value) => {
29
+ if (value === null || value === undefined)
30
+ return "";
31
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean")
32
+ return value;
33
+ if (value instanceof Date)
34
+ return value;
35
+ if (typeof value === "object" && "text" in value && typeof value.text === "string")
36
+ return value.text;
37
+ if (typeof value === "object" && "result" in value)
38
+ return value.result ?? "";
39
+ return String(value);
40
+ };
41
+ const readWorksheetAsRows = (worksheet) => {
42
+ const rows = [];
43
+ worksheet.eachRow((row) => {
44
+ const values = row.values;
45
+ rows.push(values.slice(1).map((value) => (value === undefined ? "" : value)));
46
+ });
47
+ if (rows.length === 0) {
48
+ return { headers: [], rows: [] };
49
+ }
50
+ const headers = rows[0].map((h) => String(h ?? "").trim());
51
+ const dataRows = rows.slice(1).map((cells) => {
52
+ const item = {};
53
+ for (let i = 0; i < headers.length; i += 1) {
54
+ item[headers[i]] = normalizeCell(cells[i]);
55
+ }
56
+ return item;
57
+ });
58
+ return { headers, rows: dataRows };
59
+ };
60
+ export const readBulkExcelFiles = async (inputPattern) => {
61
+ const files = resolveInputFiles(inputPattern);
62
+ if (files.length === 0) {
63
+ throw new Error(`No input files matched: ${inputPattern}`);
64
+ }
65
+ const results = [];
66
+ for (const file of files) {
67
+ const workbook = new ExcelJS.Workbook();
68
+ await workbook.xlsx.readFile(file);
69
+ for (const worksheet of workbook.worksheets) {
70
+ const parsed = readWorksheetAsRows(worksheet);
71
+ if (parsed.headers.length === 0 || parsed.rows.length === 0) {
72
+ continue;
73
+ }
74
+ results.push({
75
+ sourceFile: `${file}#${worksheet.name}`,
76
+ headers: parsed.headers,
77
+ rows: parsed.rows,
78
+ });
79
+ }
80
+ }
81
+ return results;
82
+ };
83
+ //# sourceMappingURL=excel-reader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"excel-reader.js","sourceRoot":"","sources":["../../src/io/excel-reader.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ export interface WriteSheetInput {
2
+ name: string;
3
+ header: string[];
4
+ rows: Array<Array<string | number | Date>>;
5
+ }
6
+ export declare const writeXlsx: (outputPath: string, sheets: WriteSheetInput[]) => Promise<void>;
7
+ //# sourceMappingURL=excel-writer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"excel-writer.d.ts","sourceRoot":"","sources":["../../src/io/excel-writer.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,IAAI,EAAE,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC;CAC5C;AAmBD,eAAO,MAAM,SAAS,GAAU,YAAY,MAAM,EAAE,QAAQ,eAAe,EAAE,KAAG,OAAO,CAAC,IAAI,CAwB3F,CAAC"}
@@ -0,0 +1,42 @@
1
+ import ExcelJS from "exceljs";
2
+ import fs from "node:fs";
3
+ import path from "node:path";
4
+ const autoFitColumns = (worksheet) => {
5
+ worksheet.columns?.forEach((column) => {
6
+ let maxLength = 10;
7
+ if (!column.eachCell) {
8
+ return;
9
+ }
10
+ column.eachCell({ includeEmpty: true }, (cell) => {
11
+ const value = cell.value;
12
+ const cellText = value === null || value === undefined ? "" : String(value);
13
+ if (cellText.length > maxLength) {
14
+ maxLength = Math.min(cellText.length + 2, 80);
15
+ }
16
+ });
17
+ column.width = maxLength;
18
+ });
19
+ };
20
+ export const writeXlsx = async (outputPath, sheets) => {
21
+ if (sheets.length === 0) {
22
+ throw new Error("No sheets to write.");
23
+ }
24
+ const workbook = new ExcelJS.Workbook();
25
+ workbook.creator = "aads";
26
+ workbook.created = new Date();
27
+ for (const sheet of sheets) {
28
+ const ws = workbook.addWorksheet(sheet.name);
29
+ ws.addRow(sheet.header);
30
+ for (const row of sheet.rows) {
31
+ ws.addRow(row);
32
+ }
33
+ const headerRow = ws.getRow(1);
34
+ headerRow.font = { bold: true };
35
+ headerRow.alignment = { vertical: "middle", horizontal: "left" };
36
+ ws.views = [{ state: "frozen", ySplit: 1 }];
37
+ autoFitColumns(ws);
38
+ }
39
+ fs.mkdirSync(path.dirname(outputPath), { recursive: true });
40
+ await workbook.xlsx.writeFile(outputPath);
41
+ };
42
+ //# sourceMappingURL=excel-writer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"excel-writer.js","sourceRoot":"","sources":["../../src/io/excel-writer.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,SAAS,CAAC;AAC9B,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAQ7B,MAAM,cAAc,GAAG,CAAC,SAA4B,EAAQ,EAAE;IAC5D,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,MAAM,EAAE,EAAE;QACpC,IAAI,SAAS,GAAG,EAAE,CAAC;QACnB,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC;YACrB,OAAO;QACT,CAAC;QACD,MAAM,CAAC,QAAQ,CAAC,EAAE,YAAY,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,EAAE;YAC/C,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;YACzB,MAAM,QAAQ,GAAG,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAC5E,IAAI,QAAQ,CAAC,MAAM,GAAG,SAAS,EAAE,CAAC;gBAChC,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC;YAChD,CAAC;QACH,CAAC,CAAC,CAAC;QACH,MAAM,CAAC,KAAK,GAAG,SAAS,CAAC;IAC3B,CAAC,CAAC,CAAC;AACL,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,SAAS,GAAG,KAAK,EAAE,UAAkB,EAAE,MAAyB,EAAiB,EAAE;IAC9F,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CAAC,qBAAqB,CAAC,CAAC;IACzC,CAAC;IAED,MAAM,QAAQ,GAAG,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;IACxC,QAAQ,CAAC,OAAO,GAAG,MAAM,CAAC;IAC1B,QAAQ,CAAC,OAAO,GAAG,IAAI,IAAI,EAAE,CAAC;IAE9B,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,EAAE,GAAG,QAAQ,CAAC,YAAY,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC7C,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QACxB,KAAK,MAAM,GAAG,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC;YAC7B,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACjB,CAAC;QACD,MAAM,SAAS,GAAG,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QAC/B,SAAS,CAAC,IAAI,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;QAChC,SAAS,CAAC,SAAS,GAAG,EAAE,QAAQ,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,EAAE,CAAC;QACjE,EAAE,CAAC,KAAK,GAAG,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC;QAC5C,cAAc,CAAC,EAAE,CAAC,CAAC;IACrB,CAAC;IAED,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC5D,MAAM,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;AAC5C,CAAC,CAAC"}
@@ -0,0 +1,8 @@
1
+ import type { AnalyzePipelineResult } from "./types.js";
2
+ import type { OptimisationConfig } from "../config/optimisation-config.js";
3
+ export interface AnalyzePipelineOptions {
4
+ layerPolicyPath?: string;
5
+ rankingDbPath?: string;
6
+ }
7
+ export declare const runAnalyzePipeline: (inputPattern: string, config: OptimisationConfig, options?: AnalyzePipelineOptions) => Promise<AnalyzePipelineResult>;
8
+ //# sourceMappingURL=analyze-pipeline.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analyze-pipeline.d.ts","sourceRoot":"","sources":["../../src/pipeline/analyze-pipeline.ts"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EAAE,qBAAqB,EAA4C,MAAM,YAAY,CAAC;AAClG,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,kCAAkC,CAAC;AAqE3E,MAAM,WAAW,sBAAsB;IACrC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,eAAO,MAAM,kBAAkB,GAC7B,cAAc,MAAM,EACpB,QAAQ,kBAAkB,EAC1B,UAAU,sBAAsB,KAC/B,OAAO,CAAC,qBAAqB,CAwE/B,CAAC"}
@@ -0,0 +1,145 @@
1
+ import path from "node:path";
2
+ import { existsSync } from "node:fs";
3
+ import { createHeaderMap } from "../core/header-mapper.js";
4
+ import { asNumber, normalizeMatchType, normalizeState, normalizeText, safeDivide, toNumber, } from "../core/normalizer.js";
5
+ import { readBulkExcelFiles } from "../io/excel-reader.js";
6
+ import { readCsvFiles } from "../io/csv-reader.js";
7
+ import { analyzePerformance } from "../analysis/performance-analyzer.js";
8
+ import { buildCampaignStructure } from "../analysis/campaign-structure.js";
9
+ import { classifySkus } from "../analysis/sku-classifier.js";
10
+ import { generateCpcRecommendations } from "../analysis/cpc-optimizer.js";
11
+ import { analyzeAutoToManual } from "../analysis/auto-to-manual.js";
12
+ import { classifyCampaignLayers } from "../analysis/campaign-layer-classifier.js";
13
+ import { loadCampaignLayerPolicy } from "../config/campaign-layer-policy.js";
14
+ import { extractDateRangeFromFiles } from "../utils/date-utils.js";
15
+ import { RankingDb } from "../ranking/ranking-db.js";
16
+ const readInputs = async (inputPattern) => {
17
+ const ext = path.extname(inputPattern).toLowerCase();
18
+ if (ext === ".csv") {
19
+ return readCsvFiles(inputPattern);
20
+ }
21
+ return readBulkExcelFiles(inputPattern);
22
+ };
23
+ const normalizeRecord = (row, source) => {
24
+ const map = createHeaderMap(source.headers);
25
+ const pick = (index) => (index >= 0 ? row[source.headers[index]] : "");
26
+ const asText = (index) => normalizeText(pick(index));
27
+ const asNum = (index) => asNumber(pick(index), 0);
28
+ const asNumOrEmpty = (index) => toNumber(pick(index));
29
+ const clicks = asNum(map.clicks);
30
+ const impressions = asNum(map.impressions);
31
+ const spend = asNum(map.spend);
32
+ const sales = asNum(map.sales);
33
+ const orders = asNum(map.orders);
34
+ const keywordText = asText(map.keywordText);
35
+ const customerSearchTerm = asText(map.customerSearchTerm);
36
+ // Infer targetingType as "auto" from product targeting expression auto subtypes
37
+ const productTargetingExpr = asText(map.productTargetingExpression);
38
+ const AUTO_SUBTYPES = ["close-match", "loose-match", "substitutes", "complements"];
39
+ let targetingType = asText(map.targetingType);
40
+ if (!targetingType && AUTO_SUBTYPES.includes(productTargetingExpr)) {
41
+ targetingType = "auto";
42
+ }
43
+ return {
44
+ campaignId: asText(map.campaignId),
45
+ campaignName: asText(map.campaignName),
46
+ adGroupId: asText(map.adGroupId),
47
+ adGroupName: asText(map.adGroupName),
48
+ keywordId: asText(map.keywordId),
49
+ keywordText,
50
+ customerSearchTerm,
51
+ productTargetingExpression: productTargetingExpr,
52
+ matchType: normalizeMatchType(asText(map.matchType)),
53
+ targetingType,
54
+ sku: asText(map.sku),
55
+ asin: asText(map.asin),
56
+ portfolioId: asText(map.portfolioId),
57
+ state: normalizeState(asText(map.state)),
58
+ campaignStatus: normalizeState(asText(map.state)),
59
+ dailyBudget: asNumOrEmpty(map.dailyBudget),
60
+ bid: asNumOrEmpty(map.bid),
61
+ adGroupDefaultBid: asNumOrEmpty(map.adGroupDefaultBid),
62
+ clicks,
63
+ impressions,
64
+ spend,
65
+ sales,
66
+ orders,
67
+ ctr: safeDivide(clicks, impressions),
68
+ cvr: safeDivide(orders, clicks),
69
+ acos: safeDivide(spend, sales),
70
+ roas: safeDivide(sales, spend),
71
+ startDate: "",
72
+ endDate: "",
73
+ biddingStrategy: "",
74
+ sourceFile: source.sourceFile,
75
+ };
76
+ };
77
+ export const runAnalyzePipeline = async (inputPattern, config, options) => {
78
+ const input = await readInputs(inputPattern);
79
+ const dateRange = extractDateRangeFromFiles(input.map((i) => i.sourceFile));
80
+ const records = input
81
+ .flatMap((file) => file.rows.map((row) => normalizeRecord(row, file)))
82
+ .filter((row) => row.campaignId !== "" ||
83
+ row.campaignName !== "" ||
84
+ row.keywordText !== "" ||
85
+ row.customerSearchTerm !== "" ||
86
+ row.productTargetingExpression !== "" ||
87
+ row.clicks > 0 ||
88
+ row.impressions > 0 ||
89
+ row.spend > 0 ||
90
+ row.sales > 0);
91
+ // Build SEO ranking data if ranking DB is available
92
+ let seoRankingData;
93
+ const rankingDbPath = options?.rankingDbPath ?? process.env.RANKING_DB_PATH;
94
+ if (rankingDbPath && config.seo.enabled && existsSync(rankingDbPath)) {
95
+ let rankingDb;
96
+ try {
97
+ rankingDb = new RankingDb(rankingDbPath);
98
+ const adKeywords = [...new Set(records.map((r) => r.keywordText).filter((k) => k !== ""))];
99
+ const asins = [...new Set(records.map((r) => r.asin).filter((a) => a !== ""))];
100
+ seoRankingData = rankingDb.buildSeoRankingData(adKeywords, asins, rankingDbPath);
101
+ }
102
+ finally {
103
+ rankingDb?.close();
104
+ }
105
+ }
106
+ const campaignMetrics = analyzePerformance(records);
107
+ const structure = buildCampaignStructure(records);
108
+ const skuClassification = classifySkus(records);
109
+ const cpcRecommendations = generateCpcRecommendations(records, skuClassification, {
110
+ minClicks: config.minClicksForCpc,
111
+ targetAcos: config.targetAcos,
112
+ seoRankingData,
113
+ seoConfig: config.seo,
114
+ });
115
+ const { promotionCandidates, negativeCandidates } = analyzeAutoToManual(records, {
116
+ minClicks: config.minClicksForPromotion,
117
+ minCvr: config.minCvrForPromotion,
118
+ negativeAcosThreshold: config.negativeAcosThreshold,
119
+ });
120
+ // Layer classification (optional, skipped if policy not found)
121
+ let layerClassification;
122
+ try {
123
+ const policy = await loadCampaignLayerPolicy(options?.layerPolicyPath);
124
+ if (policy) {
125
+ layerClassification = classifyCampaignLayers(campaignMetrics, policy);
126
+ }
127
+ }
128
+ catch {
129
+ // Policy file invalid or unreadable — skip layer classification silently
130
+ }
131
+ return {
132
+ input,
133
+ records,
134
+ dateRange,
135
+ campaignMetrics,
136
+ structure,
137
+ skuClassification,
138
+ cpcRecommendations,
139
+ promotionCandidates,
140
+ negativeCandidates,
141
+ layerClassification,
142
+ seoRankingData,
143
+ };
144
+ };
145
+ //# sourceMappingURL=analyze-pipeline.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analyze-pipeline.js","sourceRoot":"","sources":["../../src/pipeline/analyze-pipeline.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,142 @@
1
+ import type { CampaignLayerClassification } from "../analysis/campaign-layer-classifier.js";
2
+ import type { SeoRankingData } from "../ranking/types.js";
3
+ export type RowValue = string | number | boolean | Date | null | undefined;
4
+ export type DataRow = Record<string, RowValue>;
5
+ export type OutputFormat = "console" | "json" | "markdown" | "xlsx";
6
+ export interface BulkInputData {
7
+ sourceFile: string;
8
+ headers: string[];
9
+ rows: DataRow[];
10
+ }
11
+ export interface NormalizedRecord {
12
+ campaignId: string;
13
+ campaignName: string;
14
+ adGroupId: string;
15
+ adGroupName: string;
16
+ keywordId: string;
17
+ keywordText: string;
18
+ customerSearchTerm: string;
19
+ productTargetingExpression: string;
20
+ matchType: string;
21
+ targetingType: string;
22
+ sku: string;
23
+ asin: string;
24
+ portfolioId: string;
25
+ state: string;
26
+ campaignStatus: string;
27
+ dailyBudget: number | "";
28
+ bid: number | "";
29
+ adGroupDefaultBid: number | "";
30
+ clicks: number;
31
+ impressions: number;
32
+ spend: number;
33
+ sales: number;
34
+ orders: number;
35
+ ctr: number;
36
+ cvr: number;
37
+ acos: number;
38
+ roas: number;
39
+ startDate: string;
40
+ endDate: string;
41
+ biddingStrategy: string;
42
+ sourceFile: string;
43
+ }
44
+ export interface CampaignMetrics {
45
+ campaignId: string;
46
+ campaignName: string;
47
+ targetingType: string;
48
+ state: string;
49
+ clicks: number;
50
+ impressions: number;
51
+ spend: number;
52
+ sales: number;
53
+ orders: number;
54
+ ctr: number;
55
+ cvr: number;
56
+ acos: number;
57
+ roas: number;
58
+ dailyBudget: number | "";
59
+ }
60
+ export interface CampaignStructureNode {
61
+ campaignId: string;
62
+ campaignName: string;
63
+ adGroups: Array<{
64
+ adGroupId: string;
65
+ adGroupName: string;
66
+ keywordCount: number;
67
+ productTargetCount: number;
68
+ spend: number;
69
+ sales: number;
70
+ acos: number;
71
+ }>;
72
+ }
73
+ export type SkuLabel = "focus" | "nurture" | "improve" | "prune";
74
+ export interface SkuClassification {
75
+ sku: string;
76
+ label: SkuLabel;
77
+ bidAdjust: number;
78
+ budgetAdjust: number;
79
+ reason: string;
80
+ }
81
+ export interface CpcRecommendation {
82
+ campaignId: string;
83
+ campaignName: string;
84
+ adGroupId: string;
85
+ adGroupName: string;
86
+ keywordId: string;
87
+ keywordText: string;
88
+ matchType: string;
89
+ sku: string;
90
+ clicks: number;
91
+ avgCpc: number;
92
+ currentBid: number;
93
+ recommendedBid: number;
94
+ bidAdjust: number;
95
+ reason: string;
96
+ seoFactor?: number;
97
+ organicPosition?: number | null;
98
+ seoReason?: string;
99
+ }
100
+ export interface PromotionCandidate {
101
+ campaignId: string;
102
+ campaignName: string;
103
+ adGroupId: string;
104
+ adGroupName: string;
105
+ keywordText: string;
106
+ matchType: string;
107
+ sku: string;
108
+ clicks: number;
109
+ spend: number;
110
+ orders: number;
111
+ cvr: number;
112
+ avgCpc: number;
113
+ recommendedBid: number;
114
+ recommendedAdGroupName: string;
115
+ }
116
+ export interface NegativeCandidate {
117
+ campaignId: string;
118
+ campaignName: string;
119
+ adGroupId: string;
120
+ adGroupName: string;
121
+ keywordText: string;
122
+ matchType: string;
123
+ reason: string;
124
+ }
125
+ export interface AnalyzePipelineResult {
126
+ input: BulkInputData[];
127
+ records: NormalizedRecord[];
128
+ dateRange: {
129
+ startDate: string;
130
+ endDate: string;
131
+ days: number;
132
+ } | null;
133
+ campaignMetrics: CampaignMetrics[];
134
+ structure: CampaignStructureNode[];
135
+ skuClassification: SkuClassification[];
136
+ cpcRecommendations: CpcRecommendation[];
137
+ promotionCandidates: PromotionCandidate[];
138
+ negativeCandidates: NegativeCandidate[];
139
+ layerClassification?: CampaignLayerClassification[];
140
+ seoRankingData?: SeoRankingData;
141
+ }
142
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/pipeline/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/pipeline/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,10 @@
1
+ import type { KeywordMapping } from "./types.js";
2
+ export declare const normalizeKeyword: (text: string) => string;
3
+ export interface KeywordMatchResult {
4
+ adKeyword: string;
5
+ rankingKeyword: string;
6
+ normalizedKey: string;
7
+ source: "exact" | "normalized" | "mapping";
8
+ }
9
+ export declare const matchKeywords: (adKeywords: string[], rankingKeywords: string[], mappings?: KeywordMapping[]) => KeywordMatchResult[];
10
+ //# sourceMappingURL=keyword-matcher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keyword-matcher.d.ts","sourceRoot":"","sources":["../../src/ranking/keyword-matcher.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAqBjD,eAAO,MAAM,gBAAgB,GAAI,MAAM,MAAM,KAAG,MAE/C,CAAC;AAEF,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,OAAO,GAAG,YAAY,GAAG,SAAS,CAAC;CAC5C;AAED,eAAO,MAAM,aAAa,GACxB,YAAY,MAAM,EAAE,EACpB,iBAAiB,MAAM,EAAE,EACzB,WAAW,cAAc,EAAE,KAC1B,kBAAkB,EA2CpB,CAAC"}
@@ -0,0 +1,62 @@
1
+ // Full-width to half-width conversion table for ASCII range (U+FF01..U+FF5E -> U+0021..U+007E)
2
+ const FULLWIDTH_OFFSET = 0xff01 - 0x0021;
3
+ const toHalfWidth = (text) => {
4
+ let result = "";
5
+ for (const ch of text) {
6
+ const code = ch.codePointAt(0);
7
+ if (code >= 0xff01 && code <= 0xff5e) {
8
+ result += String.fromCodePoint(code - FULLWIDTH_OFFSET);
9
+ }
10
+ else if (code === 0x3000) {
11
+ // Ideographic space -> ASCII space
12
+ result += " ";
13
+ }
14
+ else {
15
+ result += ch;
16
+ }
17
+ }
18
+ return result;
19
+ };
20
+ export const normalizeKeyword = (text) => {
21
+ return toHalfWidth(text).toLowerCase().replace(/\s+/g, " ").trim();
22
+ };
23
+ export const matchKeywords = (adKeywords, rankingKeywords, mappings) => {
24
+ const results = [];
25
+ const rankingNormMap = new Map();
26
+ for (const rk of rankingKeywords) {
27
+ rankingNormMap.set(normalizeKeyword(rk), rk);
28
+ }
29
+ // Build manual mapping lookup (adKeyword normalized -> rankingKeyword)
30
+ const manualMap = new Map();
31
+ if (mappings) {
32
+ for (const m of mappings) {
33
+ manualMap.set(normalizeKeyword(m.adKeyword), m.rankingKeyword);
34
+ }
35
+ }
36
+ for (const adKw of adKeywords) {
37
+ const normAd = normalizeKeyword(adKw);
38
+ // 1. Manual mapping takes priority
39
+ const mappedRanking = manualMap.get(normAd);
40
+ if (mappedRanking) {
41
+ results.push({
42
+ adKeyword: adKw,
43
+ rankingKeyword: mappedRanking,
44
+ normalizedKey: normalizeKeyword(mappedRanking),
45
+ source: "mapping",
46
+ });
47
+ continue;
48
+ }
49
+ // 2. Normalized match
50
+ const exactRanking = rankingNormMap.get(normAd);
51
+ if (exactRanking) {
52
+ results.push({
53
+ adKeyword: adKw,
54
+ rankingKeyword: exactRanking,
55
+ normalizedKey: normAd,
56
+ source: "normalized",
57
+ });
58
+ }
59
+ }
60
+ return results;
61
+ };
62
+ //# sourceMappingURL=keyword-matcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keyword-matcher.js","sourceRoot":"","sources":["../../src/ranking/keyword-matcher.ts"],"names":[],"mappings":"AAEA,+FAA+F;AAC/F,MAAM,gBAAgB,GAAG,MAAM,GAAG,MAAM,CAAC;AAEzC,MAAM,WAAW,GAAG,CAAC,IAAY,EAAU,EAAE;IAC3C,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,KAAK,MAAM,EAAE,IAAI,IAAI,EAAE,CAAC;QACtB,MAAM,IAAI,GAAG,EAAE,CAAC,WAAW,CAAC,CAAC,CAAE,CAAC;QAChC,IAAI,IAAI,IAAI,MAAM,IAAI,IAAI,IAAI,MAAM,EAAE,CAAC;YACrC,MAAM,IAAI,MAAM,CAAC,aAAa,CAAC,IAAI,GAAG,gBAAgB,CAAC,CAAC;QAC1D,CAAC;aAAM,IAAI,IAAI,KAAK,MAAM,EAAE,CAAC;YAC3B,mCAAmC;YACnC,MAAM,IAAI,GAAG,CAAC;QAChB,CAAC;aAAM,CAAC;YACN,MAAM,IAAI,EAAE,CAAC;QACf,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,IAAY,EAAU,EAAE;IACvD,OAAO,WAAW,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;AACrE,CAAC,CAAC;AASF,MAAM,CAAC,MAAM,aAAa,GAAG,CAC3B,UAAoB,EACpB,eAAyB,EACzB,QAA2B,EACL,EAAE;IACxB,MAAM,OAAO,GAAyB,EAAE,CAAC;IACzC,MAAM,cAAc,GAAG,IAAI,GAAG,EAAkB,CAAC;IACjD,KAAK,MAAM,EAAE,IAAI,eAAe,EAAE,CAAC;QACjC,cAAc,CAAC,GAAG,CAAC,gBAAgB,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;IAC/C,CAAC;IAED,uEAAuE;IACvE,MAAM,SAAS,GAAG,IAAI,GAAG,EAAkB,CAAC;IAC5C,IAAI,QAAQ,EAAE,CAAC;QACb,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;YACzB,SAAS,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,cAAc,CAAC,CAAC;QACjE,CAAC;IACH,CAAC;IAED,KAAK,MAAM,IAAI,IAAI,UAAU,EAAE,CAAC;QAC9B,MAAM,MAAM,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC;QAEtC,mCAAmC;QACnC,MAAM,aAAa,GAAG,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAC5C,IAAI,aAAa,EAAE,CAAC;YAClB,OAAO,CAAC,IAAI,CAAC;gBACX,SAAS,EAAE,IAAI;gBACf,cAAc,EAAE,aAAa;gBAC7B,aAAa,EAAE,gBAAgB,CAAC,aAAa,CAAC;gBAC9C,MAAM,EAAE,SAAS;aAClB,CAAC,CAAC;YACH,SAAS;QACX,CAAC;QAED,sBAAsB;QACtB,MAAM,YAAY,GAAG,cAAc,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAChD,IAAI,YAAY,EAAE,CAAC;YACjB,OAAO,CAAC,IAAI,CAAC;gBACX,SAAS,EAAE,IAAI;gBACf,cAAc,EAAE,YAAY;gBAC5B,aAAa,EAAE,MAAM;gBACrB,MAAM,EAAE,YAAY;aACrB,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC,CAAC"}
@@ -0,0 +1,14 @@
1
+ import type { KeywordRankingInfo, SeoRankingData } from "./types.js";
2
+ export declare class RankingDb {
3
+ private db;
4
+ constructor(dbPath: string);
5
+ getOrganicPosition(keyword: string, asin: string): number | null;
6
+ getSponsoredPosition(keyword: string, asin: string): number | null;
7
+ getLatestRanking(keyword: string, asin: string): KeywordRankingInfo;
8
+ getTrackedKeywords(): string[];
9
+ getTrackedAsins(): string[];
10
+ getLatestSnapshotDate(): string;
11
+ buildSeoRankingData(adKeywords: string[], asins: string[], dbPath: string): SeoRankingData;
12
+ close(): void;
13
+ }
14
+ //# sourceMappingURL=ranking-db.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ranking-db.d.ts","sourceRoot":"","sources":["../../src/ranking/ranking-db.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAgBrE,qBAAa,SAAS;IACpB,OAAO,CAAC,EAAE,CAAoB;gBAElB,MAAM,EAAE,MAAM;IAK1B,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAahE,oBAAoB,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAalE,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,kBAAkB;IAgCnE,kBAAkB,IAAI,MAAM,EAAE;IAM9B,eAAe,IAAI,MAAM,EAAE;IAM3B,qBAAqB,IAAI,MAAM;IAQ/B,mBAAmB,CAAC,UAAU,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,MAAM,GAAG,cAAc;IAiC1F,KAAK,IAAI,IAAI;CAGd"}