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.
- package/LICENSE +21 -0
- package/README.ja.md +159 -0
- package/README.md +159 -0
- package/data/campaign-layer-policy.json +68 -0
- package/dist/analysis/anomaly-detection.d.ts +16 -0
- package/dist/analysis/anomaly-detection.d.ts.map +1 -0
- package/dist/analysis/anomaly-detection.js +55 -0
- package/dist/analysis/anomaly-detection.js.map +1 -0
- package/dist/analysis/auto-to-manual.d.ts +11 -0
- package/dist/analysis/auto-to-manual.d.ts.map +1 -0
- package/dist/analysis/auto-to-manual.js +57 -0
- package/dist/analysis/auto-to-manual.js.map +1 -0
- package/dist/analysis/campaign-layer-classifier.d.ts +10 -0
- package/dist/analysis/campaign-layer-classifier.d.ts.map +1 -0
- package/dist/analysis/campaign-layer-classifier.js +50 -0
- package/dist/analysis/campaign-layer-classifier.js.map +1 -0
- package/dist/analysis/campaign-structure.d.ts +3 -0
- package/dist/analysis/campaign-structure.d.ts.map +1 -0
- package/dist/analysis/campaign-structure.js +51 -0
- package/dist/analysis/campaign-structure.js.map +1 -0
- package/dist/analysis/cpc-optimizer.d.ts +11 -0
- package/dist/analysis/cpc-optimizer.d.ts.map +1 -0
- package/dist/analysis/cpc-optimizer.js +46 -0
- package/dist/analysis/cpc-optimizer.js.map +1 -0
- package/dist/analysis/performance-analyzer.d.ts +3 -0
- package/dist/analysis/performance-analyzer.d.ts.map +1 -0
- package/dist/analysis/performance-analyzer.js +58 -0
- package/dist/analysis/performance-analyzer.js.map +1 -0
- package/dist/analysis/sku-classifier.d.ts +3 -0
- package/dist/analysis/sku-classifier.d.ts.map +1 -0
- package/dist/analysis/sku-classifier.js +64 -0
- package/dist/analysis/sku-classifier.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +351 -0
- package/dist/cli.js.map +1 -0
- package/dist/config/campaign-layer-policy.d.ts +28 -0
- package/dist/config/campaign-layer-policy.d.ts.map +1 -0
- package/dist/config/campaign-layer-policy.js +56 -0
- package/dist/config/campaign-layer-policy.js.map +1 -0
- package/dist/config/constants.d.ts +74 -0
- package/dist/config/constants.d.ts.map +1 -0
- package/dist/config/constants.js +61 -0
- package/dist/config/constants.js.map +1 -0
- package/dist/config/optimisation-config.d.ts +24 -0
- package/dist/config/optimisation-config.d.ts.map +1 -0
- package/dist/config/optimisation-config.js +41 -0
- package/dist/config/optimisation-config.js.map +1 -0
- package/dist/core/header-mapper.d.ts +6 -0
- package/dist/core/header-mapper.d.ts.map +1 -0
- package/dist/core/header-mapper.js +34 -0
- package/dist/core/header-mapper.js.map +1 -0
- package/dist/core/normalizer.d.ts +9 -0
- package/dist/core/normalizer.d.ts.map +1 -0
- package/dist/core/normalizer.js +76 -0
- package/dist/core/normalizer.js.map +1 -0
- package/dist/io/csv-reader.d.ts +3 -0
- package/dist/io/csv-reader.d.ts.map +1 -0
- package/dist/io/csv-reader.js +52 -0
- package/dist/io/csv-reader.js.map +1 -0
- package/dist/io/excel-reader.d.ts +4 -0
- package/dist/io/excel-reader.d.ts.map +1 -0
- package/dist/io/excel-reader.js +83 -0
- package/dist/io/excel-reader.js.map +1 -0
- package/dist/io/excel-writer.d.ts +7 -0
- package/dist/io/excel-writer.d.ts.map +1 -0
- package/dist/io/excel-writer.js +42 -0
- package/dist/io/excel-writer.js.map +1 -0
- package/dist/pipeline/analyze-pipeline.d.ts +8 -0
- package/dist/pipeline/analyze-pipeline.d.ts.map +1 -0
- package/dist/pipeline/analyze-pipeline.js +145 -0
- package/dist/pipeline/analyze-pipeline.js.map +1 -0
- package/dist/pipeline/types.d.ts +142 -0
- package/dist/pipeline/types.d.ts.map +1 -0
- package/dist/pipeline/types.js +2 -0
- package/dist/pipeline/types.js.map +1 -0
- package/dist/ranking/keyword-matcher.d.ts +10 -0
- package/dist/ranking/keyword-matcher.d.ts.map +1 -0
- package/dist/ranking/keyword-matcher.js +62 -0
- package/dist/ranking/keyword-matcher.js.map +1 -0
- package/dist/ranking/ranking-db.d.ts +14 -0
- package/dist/ranking/ranking-db.d.ts.map +1 -0
- package/dist/ranking/ranking-db.js +97 -0
- package/dist/ranking/ranking-db.js.map +1 -0
- package/dist/ranking/seo-factor.d.ts +5 -0
- package/dist/ranking/seo-factor.d.ts.map +1 -0
- package/dist/ranking/seo-factor.js +57 -0
- package/dist/ranking/seo-factor.js.map +1 -0
- package/dist/ranking/types.d.ts +25 -0
- package/dist/ranking/types.d.ts.map +1 -0
- package/dist/ranking/types.js +2 -0
- package/dist/ranking/types.js.map +1 -0
- package/dist/schemas/types.d.ts +32 -0
- package/dist/schemas/types.d.ts.map +1 -0
- package/dist/schemas/types.js +2 -0
- package/dist/schemas/types.js.map +1 -0
- package/dist/utils/date-utils.d.ts +17 -0
- package/dist/utils/date-utils.d.ts.map +1 -0
- package/dist/utils/date-utils.js +56 -0
- package/dist/utils/date-utils.js.map +1 -0
- package/dist/utils/logger.d.ts +12 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +45 -0
- package/dist/utils/logger.js.map +1 -0
- package/package.json +65 -0
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import Database from "better-sqlite3";
|
|
2
|
+
import { normalizeKeyword } from "./keyword-matcher.js";
|
|
3
|
+
export class RankingDb {
|
|
4
|
+
db;
|
|
5
|
+
constructor(dbPath) {
|
|
6
|
+
this.db = new Database(dbPath, { readonly: true });
|
|
7
|
+
this.db.pragma("journal_mode = WAL");
|
|
8
|
+
}
|
|
9
|
+
getOrganicPosition(keyword, asin) {
|
|
10
|
+
const row = this.db
|
|
11
|
+
.prepare(`SELECT position FROM ranking_history
|
|
12
|
+
WHERE keyword = ? AND asin = ? AND is_sponsored = 0
|
|
13
|
+
ORDER BY timestamp DESC
|
|
14
|
+
LIMIT 1`)
|
|
15
|
+
.get(keyword, asin);
|
|
16
|
+
return row?.position ?? null;
|
|
17
|
+
}
|
|
18
|
+
getSponsoredPosition(keyword, asin) {
|
|
19
|
+
const row = this.db
|
|
20
|
+
.prepare(`SELECT position FROM ranking_history
|
|
21
|
+
WHERE keyword = ? AND asin = ? AND is_sponsored = 1
|
|
22
|
+
ORDER BY timestamp DESC
|
|
23
|
+
LIMIT 1`)
|
|
24
|
+
.get(keyword, asin);
|
|
25
|
+
return row?.position ?? null;
|
|
26
|
+
}
|
|
27
|
+
getLatestRanking(keyword, asin) {
|
|
28
|
+
const latest = this.db
|
|
29
|
+
.prepare(`SELECT asin, keyword, timestamp, position, is_sponsored
|
|
30
|
+
FROM ranking_history
|
|
31
|
+
WHERE keyword = ? AND asin = ?
|
|
32
|
+
ORDER BY timestamp DESC
|
|
33
|
+
LIMIT 1`)
|
|
34
|
+
.get(keyword, asin);
|
|
35
|
+
if (!latest) {
|
|
36
|
+
return {
|
|
37
|
+
keyword,
|
|
38
|
+
asin,
|
|
39
|
+
organicPosition: null,
|
|
40
|
+
sponsoredPosition: null,
|
|
41
|
+
snapshotTimestamp: "",
|
|
42
|
+
found: false,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
return {
|
|
46
|
+
keyword,
|
|
47
|
+
asin,
|
|
48
|
+
organicPosition: this.getOrganicPosition(keyword, asin),
|
|
49
|
+
sponsoredPosition: this.getSponsoredPosition(keyword, asin),
|
|
50
|
+
snapshotTimestamp: latest.timestamp,
|
|
51
|
+
found: true,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
getTrackedKeywords() {
|
|
55
|
+
const rows = this.db.prepare("SELECT keyword FROM keywords WHERE is_active = 1").all();
|
|
56
|
+
return rows.map((r) => r.keyword);
|
|
57
|
+
}
|
|
58
|
+
getTrackedAsins() {
|
|
59
|
+
const rows = this.db.prepare("SELECT DISTINCT asin FROM products ORDER BY asin").all();
|
|
60
|
+
return rows.map((r) => r.asin);
|
|
61
|
+
}
|
|
62
|
+
getLatestSnapshotDate() {
|
|
63
|
+
const row = this.db.prepare("SELECT MAX(timestamp) as latest FROM search_result_snapshots").get();
|
|
64
|
+
return row?.latest ?? "";
|
|
65
|
+
}
|
|
66
|
+
buildSeoRankingData(adKeywords, asins, dbPath) {
|
|
67
|
+
const trackedKeywords = this.getTrackedKeywords();
|
|
68
|
+
const snapshotDate = this.getLatestSnapshotDate();
|
|
69
|
+
// Build normalized lookup: normalized -> original tracked keyword
|
|
70
|
+
const trackedNormMap = new Map();
|
|
71
|
+
for (const tk of trackedKeywords) {
|
|
72
|
+
trackedNormMap.set(normalizeKeyword(tk), tk);
|
|
73
|
+
}
|
|
74
|
+
const rankings = new Map();
|
|
75
|
+
for (const adKw of adKeywords) {
|
|
76
|
+
const normKey = normalizeKeyword(adKw);
|
|
77
|
+
const trackedKw = trackedNormMap.get(normKey);
|
|
78
|
+
if (!trackedKw)
|
|
79
|
+
continue;
|
|
80
|
+
const infos = [];
|
|
81
|
+
for (const asin of asins) {
|
|
82
|
+
const info = this.getLatestRanking(trackedKw, asin);
|
|
83
|
+
if (info.found) {
|
|
84
|
+
infos.push(info);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
if (infos.length > 0) {
|
|
88
|
+
rankings.set(normKey, infos);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return { rankings, dbPath, snapshotDate };
|
|
92
|
+
}
|
|
93
|
+
close() {
|
|
94
|
+
this.db.close();
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=ranking-db.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ranking-db.js","sourceRoot":"","sources":["../../src/ranking/ranking-db.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { SeoConfig, SeoRankingData } from "./types.js";
|
|
2
|
+
import type { CpcRecommendation } from "../pipeline/types.js";
|
|
3
|
+
export declare const calcSeoFactor: (organicPosition: number | null, config?: Pick<SeoConfig, "seoFactors">) => number;
|
|
4
|
+
export declare const applySeoAdjustment: (recommendations: CpcRecommendation[], rankingData: SeoRankingData, config: SeoConfig) => CpcRecommendation[];
|
|
5
|
+
//# sourceMappingURL=seo-factor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"seo-factor.d.ts","sourceRoot":"","sources":["../../src/ranking/seo-factor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC5D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAU9D,eAAO,MAAM,aAAa,GAAI,iBAAiB,MAAM,GAAG,IAAI,EAAE,SAAS,IAAI,CAAC,SAAS,EAAE,YAAY,CAAC,KAAG,MAWtG,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAC7B,iBAAiB,iBAAiB,EAAE,EACpC,aAAa,cAAc,EAC3B,QAAQ,SAAS,KAChB,iBAAiB,EA4CnB,CAAC"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { normalizeKeyword } from "./keyword-matcher.js";
|
|
2
|
+
const DEFAULT_SEO_FACTORS = {
|
|
3
|
+
1: 0.5,
|
|
4
|
+
2: 0.6,
|
|
5
|
+
3: 0.7,
|
|
6
|
+
4: 0.8,
|
|
7
|
+
};
|
|
8
|
+
export const calcSeoFactor = (organicPosition, config) => {
|
|
9
|
+
if (organicPosition === null || organicPosition <= 0)
|
|
10
|
+
return 1.0;
|
|
11
|
+
const factors = config?.seoFactors ?? DEFAULT_SEO_FACTORS;
|
|
12
|
+
// Exact match in the factors table
|
|
13
|
+
if (organicPosition in factors) {
|
|
14
|
+
return factors[organicPosition];
|
|
15
|
+
}
|
|
16
|
+
// Position 5-10 or beyond: no adjustment
|
|
17
|
+
return 1.0;
|
|
18
|
+
};
|
|
19
|
+
export const applySeoAdjustment = (recommendations, rankingData, config) => {
|
|
20
|
+
return recommendations.map((rec) => {
|
|
21
|
+
const normKey = normalizeKeyword(rec.keywordText);
|
|
22
|
+
const rankings = rankingData.rankings.get(normKey);
|
|
23
|
+
if (!rankings || rankings.length === 0) {
|
|
24
|
+
return rec;
|
|
25
|
+
}
|
|
26
|
+
// Find the best organic position across all ASINs tracked for this keyword
|
|
27
|
+
let bestOrganicPosition = null;
|
|
28
|
+
for (const r of rankings) {
|
|
29
|
+
if (r.organicPosition !== null) {
|
|
30
|
+
if (bestOrganicPosition === null || r.organicPosition < bestOrganicPosition) {
|
|
31
|
+
bestOrganicPosition = r.organicPosition;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
const seoFactor = calcSeoFactor(bestOrganicPosition, config);
|
|
36
|
+
if (seoFactor >= 1.0) {
|
|
37
|
+
return {
|
|
38
|
+
...rec,
|
|
39
|
+
seoFactor: 1.0,
|
|
40
|
+
organicPosition: bestOrganicPosition,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
const adjustedBid = rec.recommendedBid * seoFactor;
|
|
44
|
+
const cappedBid = config.cpcCeiling > 0 ? Math.min(adjustedBid, config.cpcCeiling) : adjustedBid;
|
|
45
|
+
const finalBid = Math.max(1, Math.round(cappedBid));
|
|
46
|
+
const seoReason = `seoFactor=${seoFactor.toFixed(2)} organic=#${bestOrganicPosition}`;
|
|
47
|
+
return {
|
|
48
|
+
...rec,
|
|
49
|
+
recommendedBid: finalBid,
|
|
50
|
+
seoFactor,
|
|
51
|
+
organicPosition: bestOrganicPosition,
|
|
52
|
+
seoReason,
|
|
53
|
+
reason: `${rec.reason} ${seoReason}`,
|
|
54
|
+
};
|
|
55
|
+
});
|
|
56
|
+
};
|
|
57
|
+
//# sourceMappingURL=seo-factor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"seo-factor.js","sourceRoot":"","sources":["../../src/ranking/seo-factor.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAExD,MAAM,mBAAmB,GAA2B;IAClD,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;CACP,CAAC;AAEF,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,eAA8B,EAAE,MAAsC,EAAU,EAAE;IAC9G,IAAI,eAAe,KAAK,IAAI,IAAI,eAAe,IAAI,CAAC;QAAE,OAAO,GAAG,CAAC;IACjE,MAAM,OAAO,GAAG,MAAM,EAAE,UAAU,IAAI,mBAAmB,CAAC;IAE1D,mCAAmC;IACnC,IAAI,eAAe,IAAI,OAAO,EAAE,CAAC;QAC/B,OAAO,OAAO,CAAC,eAAe,CAAC,CAAC;IAClC,CAAC;IAED,yCAAyC;IACzC,OAAO,GAAG,CAAC;AACb,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAChC,eAAoC,EACpC,WAA2B,EAC3B,MAAiB,EACI,EAAE;IACvB,OAAO,eAAe,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;QACjC,MAAM,OAAO,GAAG,gBAAgB,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QAClD,MAAM,QAAQ,GAAG,WAAW,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAEnD,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACvC,OAAO,GAAG,CAAC;QACb,CAAC;QAED,2EAA2E;QAC3E,IAAI,mBAAmB,GAAkB,IAAI,CAAC;QAC9C,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;YACzB,IAAI,CAAC,CAAC,eAAe,KAAK,IAAI,EAAE,CAAC;gBAC/B,IAAI,mBAAmB,KAAK,IAAI,IAAI,CAAC,CAAC,eAAe,GAAG,mBAAmB,EAAE,CAAC;oBAC5E,mBAAmB,GAAG,CAAC,CAAC,eAAe,CAAC;gBAC1C,CAAC;YACH,CAAC;QACH,CAAC;QAED,MAAM,SAAS,GAAG,aAAa,CAAC,mBAAmB,EAAE,MAAM,CAAC,CAAC;QAE7D,IAAI,SAAS,IAAI,GAAG,EAAE,CAAC;YACrB,OAAO;gBACL,GAAG,GAAG;gBACN,SAAS,EAAE,GAAG;gBACd,eAAe,EAAE,mBAAmB;aACrC,CAAC;QACJ,CAAC;QAED,MAAM,WAAW,GAAG,GAAG,CAAC,cAAc,GAAG,SAAS,CAAC;QACnD,MAAM,SAAS,GAAG,MAAM,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC;QACjG,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC;QAEpD,MAAM,SAAS,GAAG,aAAa,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,aAAa,mBAAmB,EAAE,CAAC;QAEtF,OAAO;YACL,GAAG,GAAG;YACN,cAAc,EAAE,QAAQ;YACxB,SAAS;YACT,eAAe,EAAE,mBAAmB;YACpC,SAAS;YACT,MAAM,EAAE,GAAG,GAAG,CAAC,MAAM,IAAI,SAAS,EAAE;SACrC,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export interface KeywordRankingInfo {
|
|
2
|
+
keyword: string;
|
|
3
|
+
asin: string;
|
|
4
|
+
organicPosition: number | null;
|
|
5
|
+
sponsoredPosition: number | null;
|
|
6
|
+
snapshotTimestamp: string;
|
|
7
|
+
found: boolean;
|
|
8
|
+
}
|
|
9
|
+
export interface SeoRankingData {
|
|
10
|
+
rankings: Map<string, KeywordRankingInfo[]>;
|
|
11
|
+
dbPath: string;
|
|
12
|
+
snapshotDate: string;
|
|
13
|
+
}
|
|
14
|
+
export interface SeoConfig {
|
|
15
|
+
enabled: boolean;
|
|
16
|
+
seoFactors: Record<number, number>;
|
|
17
|
+
cpcCeiling: number;
|
|
18
|
+
keywordMappingPath?: string;
|
|
19
|
+
targetAsinsPath?: string;
|
|
20
|
+
}
|
|
21
|
+
export interface KeywordMapping {
|
|
22
|
+
adKeyword: string;
|
|
23
|
+
rankingKeyword: string;
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/ranking/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,iBAAiB,EAAE,MAAM,CAAC;IAC1B,KAAK,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,kBAAkB,EAAE,CAAC,CAAC;IAC5C,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;CACxB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/ranking/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export type Primitive = string | number | boolean | null | Date;
|
|
2
|
+
export interface SchemaFieldDefinition {
|
|
3
|
+
source?: string;
|
|
4
|
+
sources?: string[];
|
|
5
|
+
literal?: Primitive;
|
|
6
|
+
default?: Primitive;
|
|
7
|
+
transform?: string;
|
|
8
|
+
required?: boolean;
|
|
9
|
+
description?: string;
|
|
10
|
+
}
|
|
11
|
+
export interface SchemaSkipCondition {
|
|
12
|
+
type: "empty" | "emptyOrZero" | "equals";
|
|
13
|
+
source?: string;
|
|
14
|
+
sources?: string[];
|
|
15
|
+
value?: Primitive;
|
|
16
|
+
values?: Primitive[];
|
|
17
|
+
reason?: string;
|
|
18
|
+
}
|
|
19
|
+
export interface SchemaEntityDefinition {
|
|
20
|
+
requiredColumns?: string[];
|
|
21
|
+
fields: Record<string, SchemaFieldDefinition>;
|
|
22
|
+
skipConditions?: SchemaSkipCondition[];
|
|
23
|
+
}
|
|
24
|
+
export interface BulkSchema {
|
|
25
|
+
id: string;
|
|
26
|
+
version: string;
|
|
27
|
+
description: string;
|
|
28
|
+
header: string[];
|
|
29
|
+
defaults?: Record<string, SchemaFieldDefinition>;
|
|
30
|
+
entities: Record<string, SchemaEntityDefinition>;
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/schemas/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,IAAI,CAAC;AAEhE,MAAM,WAAW,qBAAqB;IACpC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,OAAO,GAAG,aAAa,GAAG,QAAQ,CAAC;IACzC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,MAAM,CAAC,EAAE,SAAS,EAAE,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,sBAAsB;IACrC,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,qBAAqB,CAAC,CAAC;IAC9C,cAAc,CAAC,EAAE,mBAAmB,EAAE,CAAC;CACxC;AAED,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,qBAAqB,CAAC,CAAC;IACjD,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,sBAAsB,CAAC,CAAC;CAClD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/schemas/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export declare const formatDateYYYYMMDD: (value: Date | string | number) => string;
|
|
2
|
+
export interface DateRange {
|
|
3
|
+
startDate: string;
|
|
4
|
+
endDate: string;
|
|
5
|
+
days: number;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Parse date range from Amazon bulk sheet filename.
|
|
9
|
+
* Pattern: bulk-{sellerId}-{YYYYMMDD}-{YYYYMMDD}-{timestamp}.xlsx
|
|
10
|
+
*/
|
|
11
|
+
export declare const parseDateRangeFromFilename: (filename: string) => DateRange | null;
|
|
12
|
+
/**
|
|
13
|
+
* Extract date range from multiple input file paths. Returns the widest range found.
|
|
14
|
+
*/
|
|
15
|
+
export declare const extractDateRangeFromFiles: (filePaths: string[]) => DateRange | null;
|
|
16
|
+
export declare const timestampForFilename: (date?: Date) => string;
|
|
17
|
+
//# sourceMappingURL=date-utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"date-utils.d.ts","sourceRoot":"","sources":["../../src/utils/date-utils.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,kBAAkB,GAAI,OAAO,IAAI,GAAG,MAAM,GAAG,MAAM,KAAG,MAUlE,CAAC;AAEF,MAAM,WAAW,SAAS;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;GAGG;AACH,eAAO,MAAM,0BAA0B,GAAI,UAAU,MAAM,KAAG,SAAS,GAAG,IAgBzE,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,yBAAyB,GAAI,WAAW,MAAM,EAAE,KAAG,SAAS,GAAG,IAW3E,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAAI,WAAiB,KAAG,MAQxD,CAAC"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
export const formatDateYYYYMMDD = (value) => {
|
|
2
|
+
const date = value instanceof Date ? value : new Date(value);
|
|
3
|
+
if (Number.isNaN(date.getTime())) {
|
|
4
|
+
return "";
|
|
5
|
+
}
|
|
6
|
+
const y = date.getFullYear();
|
|
7
|
+
const m = String(date.getMonth() + 1).padStart(2, "0");
|
|
8
|
+
const d = String(date.getDate()).padStart(2, "0");
|
|
9
|
+
return `${y}-${m}-${d}`;
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Parse date range from Amazon bulk sheet filename.
|
|
13
|
+
* Pattern: bulk-{sellerId}-{YYYYMMDD}-{YYYYMMDD}-{timestamp}.xlsx
|
|
14
|
+
*/
|
|
15
|
+
export const parseDateRangeFromFilename = (filename) => {
|
|
16
|
+
const match = filename.match(/(\d{8})-(\d{8})/);
|
|
17
|
+
if (!match)
|
|
18
|
+
return null;
|
|
19
|
+
const [, rawStart, rawEnd] = match;
|
|
20
|
+
const start = new Date(`${rawStart.slice(0, 4)}-${rawStart.slice(4, 6)}-${rawStart.slice(6, 8)}`);
|
|
21
|
+
const end = new Date(`${rawEnd.slice(0, 4)}-${rawEnd.slice(4, 6)}-${rawEnd.slice(6, 8)}`);
|
|
22
|
+
if (Number.isNaN(start.getTime()) || Number.isNaN(end.getTime()))
|
|
23
|
+
return null;
|
|
24
|
+
const days = Math.round((end.getTime() - start.getTime()) / (1000 * 60 * 60 * 24));
|
|
25
|
+
return {
|
|
26
|
+
startDate: formatDateYYYYMMDD(start),
|
|
27
|
+
endDate: formatDateYYYYMMDD(end),
|
|
28
|
+
days,
|
|
29
|
+
};
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Extract date range from multiple input file paths. Returns the widest range found.
|
|
33
|
+
*/
|
|
34
|
+
export const extractDateRangeFromFiles = (filePaths) => {
|
|
35
|
+
const ranges = filePaths.map(parseDateRangeFromFilename).filter((r) => r !== null);
|
|
36
|
+
if (ranges.length === 0)
|
|
37
|
+
return null;
|
|
38
|
+
if (ranges.length === 1)
|
|
39
|
+
return ranges[0];
|
|
40
|
+
const starts = ranges.map((r) => r.startDate).sort();
|
|
41
|
+
const ends = ranges.map((r) => r.endDate).sort();
|
|
42
|
+
const startDate = starts[0];
|
|
43
|
+
const endDate = ends[ends.length - 1];
|
|
44
|
+
const days = Math.round((new Date(endDate).getTime() - new Date(startDate).getTime()) / (1000 * 60 * 60 * 24));
|
|
45
|
+
return { startDate, endDate, days };
|
|
46
|
+
};
|
|
47
|
+
export const timestampForFilename = (date = new Date()) => {
|
|
48
|
+
const y = date.getFullYear();
|
|
49
|
+
const m = String(date.getMonth() + 1).padStart(2, "0");
|
|
50
|
+
const d = String(date.getDate()).padStart(2, "0");
|
|
51
|
+
const hh = String(date.getHours()).padStart(2, "0");
|
|
52
|
+
const mm = String(date.getMinutes()).padStart(2, "0");
|
|
53
|
+
const ss = String(date.getSeconds()).padStart(2, "0");
|
|
54
|
+
return `${y}${m}${d}-${hh}${mm}${ss}`;
|
|
55
|
+
};
|
|
56
|
+
//# sourceMappingURL=date-utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"date-utils.js","sourceRoot":"","sources":["../../src/utils/date-utils.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export type LogLevel = "debug" | "info" | "warn" | "error";
|
|
2
|
+
export declare class Logger {
|
|
3
|
+
private readonly minLevel;
|
|
4
|
+
constructor(minLevel?: LogLevel);
|
|
5
|
+
private canLog;
|
|
6
|
+
log(level: LogLevel, message: string, meta?: Record<string, unknown>): void;
|
|
7
|
+
debug(message: string, meta?: Record<string, unknown>): void;
|
|
8
|
+
info(message: string, meta?: Record<string, unknown>): void;
|
|
9
|
+
warn(message: string, meta?: Record<string, unknown>): void;
|
|
10
|
+
error(message: string, meta?: Record<string, unknown>): void;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=logger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAS3D,qBAAa,MAAM;IACL,OAAO,CAAC,QAAQ,CAAC,QAAQ;gBAAR,QAAQ,GAAE,QAAiB;IAExD,OAAO,CAAC,MAAM;IAId,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAoB3E,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAI5D,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAI3D,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAI3D,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;CAG7D"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
const levelWeight = {
|
|
2
|
+
debug: 10,
|
|
3
|
+
info: 20,
|
|
4
|
+
warn: 30,
|
|
5
|
+
error: 40,
|
|
6
|
+
};
|
|
7
|
+
export class Logger {
|
|
8
|
+
minLevel;
|
|
9
|
+
constructor(minLevel = "info") {
|
|
10
|
+
this.minLevel = minLevel;
|
|
11
|
+
}
|
|
12
|
+
canLog(level) {
|
|
13
|
+
return levelWeight[level] >= levelWeight[this.minLevel];
|
|
14
|
+
}
|
|
15
|
+
log(level, message, meta) {
|
|
16
|
+
if (!this.canLog(level)) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
const ts = new Date().toISOString();
|
|
20
|
+
const metaPart = meta && Object.keys(meta).length > 0 ? ` ${JSON.stringify(meta)}` : "";
|
|
21
|
+
const line = `[${ts}] [${level.toUpperCase()}] ${message}${metaPart}`;
|
|
22
|
+
if (level === "error") {
|
|
23
|
+
console.error(line);
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
if (level === "warn") {
|
|
27
|
+
console.warn(line);
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
console.log(line);
|
|
31
|
+
}
|
|
32
|
+
debug(message, meta) {
|
|
33
|
+
this.log("debug", message, meta);
|
|
34
|
+
}
|
|
35
|
+
info(message, meta) {
|
|
36
|
+
this.log("info", message, meta);
|
|
37
|
+
}
|
|
38
|
+
warn(message, meta) {
|
|
39
|
+
this.log("warn", message, meta);
|
|
40
|
+
}
|
|
41
|
+
error(message, meta) {
|
|
42
|
+
this.log("error", message, meta);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=logger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,GAA6B;IAC5C,KAAK,EAAE,EAAE;IACT,IAAI,EAAE,EAAE;IACR,IAAI,EAAE,EAAE;IACR,KAAK,EAAE,EAAE;CACV,CAAC;AAEF,MAAM,OAAO,MAAM;IACY;IAA7B,YAA6B,WAAqB,MAAM;QAA3B,aAAQ,GAAR,QAAQ,CAAmB;IAAG,CAAC;IAEpD,MAAM,CAAC,KAAe;QAC5B,OAAO,WAAW,CAAC,KAAK,CAAC,IAAI,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC1D,CAAC;IAED,GAAG,CAAC,KAAe,EAAE,OAAe,EAAE,IAA8B;QAClE,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;YACxB,OAAO;QACT,CAAC;QAED,MAAM,EAAE,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QACpC,MAAM,QAAQ,GAAG,IAAI,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACxF,MAAM,IAAI,GAAG,IAAI,EAAE,MAAM,KAAK,CAAC,WAAW,EAAE,KAAK,OAAO,GAAG,QAAQ,EAAE,CAAC;QAEtE,IAAI,KAAK,KAAK,OAAO,EAAE,CAAC;YACtB,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YACpB,OAAO;QACT,CAAC;QACD,IAAI,KAAK,KAAK,MAAM,EAAE,CAAC;YACrB,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACnB,OAAO;QACT,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACpB,CAAC;IAED,KAAK,CAAC,OAAe,EAAE,IAA8B;QACnD,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;IACnC,CAAC;IAED,IAAI,CAAC,OAAe,EAAE,IAA8B;QAClD,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;IAClC,CAAC;IAED,IAAI,CAAC,OAAe,EAAE,IAA8B;QAClD,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;IAClC,CAAC;IAED,KAAK,CAAC,OAAe,EAAE,IAA8B;QACnD,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;IACnC,CAAC;CACF"}
|
package/package.json
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "aads-cli",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"private": false,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"description": "CLI tool for analyzing Amazon Ads Sponsored Products campaign performance",
|
|
7
|
+
"keywords": [
|
|
8
|
+
"amazon-ads",
|
|
9
|
+
"ppc",
|
|
10
|
+
"sponsored-products",
|
|
11
|
+
"cli",
|
|
12
|
+
"cpc-optimization",
|
|
13
|
+
"acos"
|
|
14
|
+
],
|
|
15
|
+
"license": "MIT",
|
|
16
|
+
"author": "yuuki-courage",
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "https://github.com/yuuki-courage/aads.git"
|
|
20
|
+
},
|
|
21
|
+
"bin": {
|
|
22
|
+
"aads": "./dist/cli.js",
|
|
23
|
+
"aads-cli": "./dist/cli.js"
|
|
24
|
+
},
|
|
25
|
+
"files": [
|
|
26
|
+
"dist/",
|
|
27
|
+
"data/",
|
|
28
|
+
"README.md",
|
|
29
|
+
"LICENSE"
|
|
30
|
+
],
|
|
31
|
+
"engines": {
|
|
32
|
+
"node": ">=18.0.0"
|
|
33
|
+
},
|
|
34
|
+
"scripts": {
|
|
35
|
+
"build": "tsc",
|
|
36
|
+
"typecheck": "tsc --noEmit",
|
|
37
|
+
"dev": "tsx src/cli.ts",
|
|
38
|
+
"lint": "eslint src/",
|
|
39
|
+
"format:check": "prettier --check 'src/**/*.ts'",
|
|
40
|
+
"test": "vitest run",
|
|
41
|
+
"test:watch": "vitest",
|
|
42
|
+
"prepublishOnly": "pnpm run build"
|
|
43
|
+
},
|
|
44
|
+
"dependencies": {
|
|
45
|
+
"better-sqlite3": "^12.6.2",
|
|
46
|
+
"commander": "^14.0.1",
|
|
47
|
+
"dotenv": "^17.2.1",
|
|
48
|
+
"exceljs": "^4.4.0"
|
|
49
|
+
},
|
|
50
|
+
"devDependencies": {
|
|
51
|
+
"@types/better-sqlite3": "^7.6.13",
|
|
52
|
+
"@types/node": "^24.2.0",
|
|
53
|
+
"@typescript-eslint/eslint-plugin": "^8.32.1",
|
|
54
|
+
"@typescript-eslint/parser": "^8.32.1",
|
|
55
|
+
"eslint": "^9.27.0",
|
|
56
|
+
"eslint-config-prettier": "^10.1.5",
|
|
57
|
+
"prettier": "^3.5.3",
|
|
58
|
+
"tsx": "^4.20.5",
|
|
59
|
+
"typescript": "^5.9.2",
|
|
60
|
+
"vitest": "^3.2.1"
|
|
61
|
+
},
|
|
62
|
+
"pnpm": {
|
|
63
|
+
"onlyBuiltDependencies": ["better-sqlite3", "esbuild"]
|
|
64
|
+
}
|
|
65
|
+
}
|