@koda-sl/baker-cli 0.23.0 → 0.25.0-dev.f89d9a60

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 (98) hide show
  1. package/README.md +73 -0
  2. package/dist/cli.js +1 -1
  3. package/dist/commands/ads/index.d.ts.map +1 -1
  4. package/dist/commands/ads/index.js +8 -3
  5. package/dist/commands/ads/index.js.map +1 -1
  6. package/dist/commands/ads/x/accounts.d.ts +14 -0
  7. package/dist/commands/ads/x/accounts.d.ts.map +1 -0
  8. package/dist/commands/ads/x/accounts.js +73 -0
  9. package/dist/commands/ads/x/accounts.js.map +1 -0
  10. package/dist/commands/ads/x/active-entities.d.ts +43 -0
  11. package/dist/commands/ads/x/active-entities.d.ts.map +1 -0
  12. package/dist/commands/ads/x/active-entities.js +88 -0
  13. package/dist/commands/ads/x/active-entities.js.map +1 -0
  14. package/dist/commands/ads/x/audiences.d.ts +19 -0
  15. package/dist/commands/ads/x/audiences.d.ts.map +1 -0
  16. package/dist/commands/ads/x/audiences.js +65 -0
  17. package/dist/commands/ads/x/audiences.js.map +1 -0
  18. package/dist/commands/ads/x/campaigns.d.ts +34 -0
  19. package/dist/commands/ads/x/campaigns.d.ts.map +1 -0
  20. package/dist/commands/ads/x/campaigns.js +56 -0
  21. package/dist/commands/ads/x/campaigns.js.map +1 -0
  22. package/dist/commands/ads/x/cards.d.ts +19 -0
  23. package/dist/commands/ads/x/cards.d.ts.map +1 -0
  24. package/dist/commands/ads/x/cards.js +65 -0
  25. package/dist/commands/ads/x/cards.js.map +1 -0
  26. package/dist/commands/ads/x/error-parser.d.ts +3 -0
  27. package/dist/commands/ads/x/error-parser.d.ts.map +1 -0
  28. package/dist/commands/ads/x/error-parser.js +80 -0
  29. package/dist/commands/ads/x/error-parser.js.map +1 -0
  30. package/dist/commands/ads/x/funding.d.ts +19 -0
  31. package/dist/commands/ads/x/funding.d.ts.map +1 -0
  32. package/dist/commands/ads/x/funding.js +65 -0
  33. package/dist/commands/ads/x/funding.js.map +1 -0
  34. package/dist/commands/ads/x/index.d.ts +2 -0
  35. package/dist/commands/ads/x/index.d.ts.map +1 -0
  36. package/dist/commands/ads/x/index.js +50 -0
  37. package/dist/commands/ads/x/index.js.map +1 -0
  38. package/dist/commands/ads/x/line-items.d.ts +34 -0
  39. package/dist/commands/ads/x/line-items.d.ts.map +1 -0
  40. package/dist/commands/ads/x/line-items.js +55 -0
  41. package/dist/commands/ads/x/line-items.js.map +1 -0
  42. package/dist/commands/ads/x/media.d.ts +24 -0
  43. package/dist/commands/ads/x/media.d.ts.map +1 -0
  44. package/dist/commands/ads/x/media.js +70 -0
  45. package/dist/commands/ads/x/media.js.map +1 -0
  46. package/dist/commands/ads/x/output.d.ts +13 -0
  47. package/dist/commands/ads/x/output.d.ts.map +1 -0
  48. package/dist/commands/ads/x/output.js +75 -0
  49. package/dist/commands/ads/x/output.js.map +1 -0
  50. package/dist/commands/ads/x/presets.d.ts +15 -0
  51. package/dist/commands/ads/x/presets.d.ts.map +1 -0
  52. package/dist/commands/ads/x/presets.js +60 -0
  53. package/dist/commands/ads/x/presets.js.map +1 -0
  54. package/dist/commands/ads/x/promoted-tweets.d.ts +29 -0
  55. package/dist/commands/ads/x/promoted-tweets.d.ts.map +1 -0
  56. package/dist/commands/ads/x/promoted-tweets.js +74 -0
  57. package/dist/commands/ads/x/promoted-tweets.js.map +1 -0
  58. package/dist/commands/ads/x/run-list.d.ts +17 -0
  59. package/dist/commands/ads/x/run-list.d.ts.map +1 -0
  60. package/dist/commands/ads/x/run-list.js +60 -0
  61. package/dist/commands/ads/x/run-list.js.map +1 -0
  62. package/dist/commands/ads/x/stats/index.d.ts +2 -0
  63. package/dist/commands/ads/x/stats/index.d.ts.map +1 -0
  64. package/dist/commands/ads/x/stats/index.js +32 -0
  65. package/dist/commands/ads/x/stats/index.js.map +1 -0
  66. package/dist/commands/ads/x/stats/job-create.d.ts +58 -0
  67. package/dist/commands/ads/x/stats/job-create.d.ts.map +1 -0
  68. package/dist/commands/ads/x/stats/job-create.js +95 -0
  69. package/dist/commands/ads/x/stats/job-create.js.map +1 -0
  70. package/dist/commands/ads/x/stats/job-status.d.ts +18 -0
  71. package/dist/commands/ads/x/stats/job-status.d.ts.map +1 -0
  72. package/dist/commands/ads/x/stats/job-status.js +58 -0
  73. package/dist/commands/ads/x/stats/job-status.js.map +1 -0
  74. package/dist/commands/ads/x/stats/job.d.ts +63 -0
  75. package/dist/commands/ads/x/stats/job.d.ts.map +1 -0
  76. package/dist/commands/ads/x/stats/job.js +183 -0
  77. package/dist/commands/ads/x/stats/job.js.map +1 -0
  78. package/dist/commands/ads/x/stats/sync.d.ts +73 -0
  79. package/dist/commands/ads/x/stats/sync.d.ts.map +1 -0
  80. package/dist/commands/ads/x/stats/sync.js +151 -0
  81. package/dist/commands/ads/x/stats/sync.js.map +1 -0
  82. package/dist/commands/ads/x/targeting-constants.d.ts +34 -0
  83. package/dist/commands/ads/x/targeting-constants.d.ts.map +1 -0
  84. package/dist/commands/ads/x/targeting-constants.js +80 -0
  85. package/dist/commands/ads/x/targeting-constants.js.map +1 -0
  86. package/dist/commands/ads/x/targeting-criteria.d.ts +24 -0
  87. package/dist/commands/ads/x/targeting-criteria.d.ts.map +1 -0
  88. package/dist/commands/ads/x/targeting-criteria.js +69 -0
  89. package/dist/commands/ads/x/targeting-criteria.js.map +1 -0
  90. package/dist/env.d.ts +1 -0
  91. package/dist/env.d.ts.map +1 -1
  92. package/dist/env.js +4 -0
  93. package/dist/env.js.map +1 -1
  94. package/dist/error-handler.d.ts +1 -1
  95. package/dist/error-handler.d.ts.map +1 -1
  96. package/dist/error-handler.js +3 -0
  97. package/dist/error-handler.js.map +1 -1
  98. package/package.json +1 -1
@@ -0,0 +1,63 @@
1
+ export declare const statsJobCommand: import("citty").CommandDef<{
2
+ readonly "account-id": {
3
+ readonly type: "string";
4
+ readonly description: "X Ads account ID";
5
+ readonly required: false;
6
+ };
7
+ readonly entity: {
8
+ readonly type: "string";
9
+ readonly description: "Entity type";
10
+ readonly required: true;
11
+ };
12
+ readonly "entity-ids": {
13
+ readonly type: "string";
14
+ readonly description: "CSV of entity IDs";
15
+ readonly required: true;
16
+ };
17
+ readonly "start-time": {
18
+ readonly type: "string";
19
+ readonly description: "ISO start";
20
+ readonly required: true;
21
+ };
22
+ readonly "end-time": {
23
+ readonly type: "string";
24
+ readonly description: "ISO end";
25
+ readonly required: true;
26
+ };
27
+ readonly granularity: {
28
+ readonly type: "string";
29
+ readonly description: "Granularity";
30
+ readonly required: false;
31
+ };
32
+ readonly "metric-groups": {
33
+ readonly type: "string";
34
+ readonly description: "Metric groups CSV";
35
+ readonly required: true;
36
+ };
37
+ readonly placement: {
38
+ readonly type: "string";
39
+ readonly description: "Placement";
40
+ readonly required: false;
41
+ };
42
+ readonly "segmentation-type": {
43
+ readonly type: "string";
44
+ readonly description: "Segmentation type";
45
+ readonly required: false;
46
+ };
47
+ readonly country: {
48
+ readonly type: "string";
49
+ readonly description: "Country filter";
50
+ readonly required: false;
51
+ };
52
+ readonly platform: {
53
+ readonly type: "string";
54
+ readonly description: "Platform filter";
55
+ readonly required: false;
56
+ };
57
+ readonly "no-cache": {
58
+ readonly type: "boolean";
59
+ readonly description: "Skip result cache";
60
+ readonly required: false;
61
+ };
62
+ }>;
63
+ //# sourceMappingURL=job.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"job.d.ts","sourceRoot":"","sources":["../../../../../src/commands/ads/x/stats/job.ts"],"names":[],"mappings":"AA+FA,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA2G1B,CAAC"}
@@ -0,0 +1,183 @@
1
+ import { gunzipSync } from "node:zlib";
2
+ import { defineCommand } from "citty";
3
+ import { ApiError, apiGet, apiPost } from "../../../../client.js";
4
+ import { registerSchema } from "../../../../schemas.js";
5
+ import { cacheGet, cacheSet } from "../../cache.js";
6
+ import { writeAdsJson } from "../../output.js";
7
+ import { parseXApiError } from "../error-parser.js";
8
+ import { resolveXAccountId } from "../output.js";
9
+ const POLL_INTERVAL_MS = 10_000;
10
+ const DEADLINE_MS = 12 * 60 * 1000;
11
+ const RESULT_CACHE_TTL_MS = 6 * 60 * 60 * 1000;
12
+ registerSchema({
13
+ command: "ads.x.statsJob",
14
+ description: "Asynchronous X Ads stats job, fully synchronous from the CLI's perspective. Creates the job, polls every 10s, downloads + decompresses the gzip result, returns inline JSON. Hard deadline 12 min — must run in the background. Use this for ranges >7 days, segmented stats, or any query that hits sync limits. For fine-grained control, use `stats job-create` + `stats job-status` separately.",
15
+ args: {
16
+ "account-id": { type: "string", description: "X Ads account ID", required: false },
17
+ entity: { type: "string", description: "CAMPAIGN | LINE_ITEM | PROMOTED_TWEET | ...", required: true },
18
+ "entity-ids": { type: "string", description: "CSV of entity IDs (max 20)", required: true },
19
+ "start-time": { type: "string", description: "ISO 8601 hour-aligned start", required: true },
20
+ "end-time": { type: "string", description: "ISO 8601 hour-aligned end", required: true },
21
+ granularity: { type: "string", description: "TOTAL | DAY | HOUR", required: false },
22
+ "metric-groups": { type: "string", description: "CSV of metric groups", required: true },
23
+ placement: { type: "string", description: "ALL_ON_TWITTER | PUBLISHER_NETWORK", required: false },
24
+ "segmentation-type": { type: "string", description: "Segmentation (e.g. AGE, GENDER, LOCATIONS)", required: false },
25
+ country: { type: "string", description: "Country filter", required: false },
26
+ platform: { type: "string", description: "Platform filter", required: false },
27
+ "no-cache": { type: "boolean", description: "Skip result cache (still does the live job)", required: false },
28
+ },
29
+ });
30
+ function parseCsv(v) {
31
+ if (typeof v !== "string" || v.length === 0)
32
+ return undefined;
33
+ const parts = v
34
+ .split(",")
35
+ .map((s) => s.trim())
36
+ .filter(Boolean);
37
+ return parts.length > 0 ? parts : undefined;
38
+ }
39
+ function sleep(ms) {
40
+ return new Promise((resolve) => setTimeout(resolve, ms));
41
+ }
42
+ async function downloadAndDecompress(url) {
43
+ const res = await fetch(url, { signal: AbortSignal.timeout(60_000) });
44
+ if (!res.ok) {
45
+ throw new ApiError("INTERNAL_ERROR", `Stats job download failed (${res.status})`);
46
+ }
47
+ const buf = Buffer.from(await res.arrayBuffer());
48
+ const decompressed = gunzipSync(buf);
49
+ return JSON.parse(decompressed.toString("utf-8"));
50
+ }
51
+ async function pollUntilDone(accountId, jobId) {
52
+ const deadline = Date.now() + DEADLINE_MS;
53
+ let lastLog = 0;
54
+ while (Date.now() < deadline) {
55
+ await sleep(POLL_INTERVAL_MS);
56
+ const jobs = await apiGet("/api/ads/x/stats/jobs", {
57
+ "account-id": accountId,
58
+ "job-id": jobId,
59
+ });
60
+ const job = jobs[0];
61
+ if (!job) {
62
+ throw new ApiError("NOT_FOUND", `Stats job ${jobId} not found`);
63
+ }
64
+ if (job.status === "SUCCESS") {
65
+ return job;
66
+ }
67
+ if (job.status === "FAILED" || job.status === "CANCELLED") {
68
+ throw new ApiError("INTERNAL_ERROR", `Stats job ${jobId} ended in status ${job.status}`);
69
+ }
70
+ const elapsed = DEADLINE_MS - (deadline - Date.now());
71
+ if (elapsed - lastLog > 30_000) {
72
+ process.stderr.write(` polling... (${job.status}, ${Math.round(elapsed / 1000)}s elapsed)\n`);
73
+ lastLog = elapsed;
74
+ }
75
+ }
76
+ throw new ApiError("TIMEOUT", `Stats job ${jobId} did not complete within ${DEADLINE_MS / 60_000} minutes`);
77
+ }
78
+ function buildCacheKey(body) {
79
+ return `stats-job:${JSON.stringify(body)}`;
80
+ }
81
+ export const statsJobCommand = defineCommand({
82
+ meta: {
83
+ name: "job",
84
+ description: `Async X Ads stats job, sync from the CLI's perspective. Creates → polls → downloads → returns.
85
+
86
+ Must run in the background (the harness enforces this).
87
+
88
+ Use this when:
89
+ • Date range > 7 days
90
+ • Need segmentation (AGE, GENDER, LOCATIONS, ...)
91
+ • Sync stats hit a limit
92
+
93
+ Examples:
94
+ baker ads x stats job --account-id 18ce53xyz --entity CAMPAIGN \\
95
+ --entity-ids abc,def --start-time 2026-04-01T00:00:00Z \\
96
+ --end-time 2026-05-01T00:00:00Z --metric-groups ENGAGEMENT,BILLING
97
+
98
+ baker ads x stats job --account-id 18ce53xyz --entity LINE_ITEM \\
99
+ --entity-ids abc --start-time 2026-04-01T00:00:00Z \\
100
+ --end-time 2026-05-01T00:00:00Z --metric-groups ENGAGEMENT \\
101
+ --segmentation-type LOCATIONS
102
+
103
+ For fine-grained control (don't wait, poll yourself), use:
104
+ baker ads x stats job-create — create + return job ID immediately
105
+ baker ads x stats job-status — poll job status / get download URL`,
106
+ },
107
+ args: {
108
+ "account-id": { type: "string", description: "X Ads account ID", required: false },
109
+ entity: { type: "string", description: "Entity type", required: true },
110
+ "entity-ids": { type: "string", description: "CSV of entity IDs", required: true },
111
+ "start-time": { type: "string", description: "ISO start", required: true },
112
+ "end-time": { type: "string", description: "ISO end", required: true },
113
+ granularity: { type: "string", description: "Granularity", required: false },
114
+ "metric-groups": { type: "string", description: "Metric groups CSV", required: true },
115
+ placement: { type: "string", description: "Placement", required: false },
116
+ "segmentation-type": { type: "string", description: "Segmentation type", required: false },
117
+ country: { type: "string", description: "Country filter", required: false },
118
+ platform: { type: "string", description: "Platform filter", required: false },
119
+ "no-cache": { type: "boolean", description: "Skip result cache", required: false },
120
+ },
121
+ run: async ({ args }) => {
122
+ const accountId = await resolveXAccountId(args);
123
+ const entityIds = parseCsv(args["entity-ids"]);
124
+ const metricGroups = parseCsv(args["metric-groups"]);
125
+ if (!entityIds || !metricGroups) {
126
+ writeAdsJson({
127
+ ok: false,
128
+ error: { code: "MISSING_PARAMETER", message: "entity-ids and metric-groups are required" },
129
+ });
130
+ process.exit(1);
131
+ }
132
+ const body = {
133
+ accountId,
134
+ entity: args.entity,
135
+ entityIds,
136
+ startTime: args["start-time"],
137
+ endTime: args["end-time"],
138
+ granularity: args.granularity ?? "DAY",
139
+ metricGroups,
140
+ placement: args.placement ?? "ALL_ON_TWITTER",
141
+ segmentationType: args["segmentation-type"],
142
+ country: args.country,
143
+ platform: args.platform,
144
+ };
145
+ const useCache = !args["no-cache"];
146
+ const cacheKey = buildCacheKey(body);
147
+ if (useCache) {
148
+ const cached = cacheGet("x-stats", cacheKey);
149
+ if (cached) {
150
+ process.stderr.write("Result served from cache.\n");
151
+ writeAdsJson({ ok: true, data: cached.data, cached: true });
152
+ return;
153
+ }
154
+ }
155
+ try {
156
+ process.stderr.write(`Creating X Ads stats job for entity=${body.entity}, ${entityIds.length} IDs...\n`);
157
+ const job = await apiPost("/api/ads/x/stats/jobs", body);
158
+ process.stderr.write(`Job ${job.id} queued. Polling every ${POLL_INTERVAL_MS / 1000}s...\n`);
159
+ const finished = await pollUntilDone(accountId, job.id);
160
+ if (!finished.url) {
161
+ throw new ApiError("INTERNAL_ERROR", `Stats job ${job.id} succeeded but returned no download URL`);
162
+ }
163
+ process.stderr.write("Job complete. Downloading + decompressing results...\n");
164
+ const data = await downloadAndDecompress(finished.url);
165
+ if (useCache) {
166
+ cacheSet("x-stats", cacheKey, data, RESULT_CACHE_TTL_MS);
167
+ }
168
+ writeAdsJson({ ok: true, data });
169
+ }
170
+ catch (err) {
171
+ if (err instanceof ApiError) {
172
+ writeAdsJson(parseXApiError(err.message, accountId));
173
+ process.exit(1);
174
+ }
175
+ writeAdsJson({
176
+ ok: false,
177
+ error: { code: "NETWORK_ERROR", message: err instanceof Error ? err.message : "Unexpected error" },
178
+ });
179
+ process.exit(1);
180
+ }
181
+ },
182
+ });
183
+ //# sourceMappingURL=job.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"job.js","sourceRoot":"","sources":["../../../../../src/commands/ads/x/stats/job.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,73 @@
1
+ export declare const statsSyncCommand: import("citty").CommandDef<{
2
+ readonly "account-id": {
3
+ readonly type: "string";
4
+ readonly description: "X Ads account ID";
5
+ readonly required: false;
6
+ };
7
+ readonly preset: {
8
+ readonly type: "string";
9
+ readonly description: "Stats preset name";
10
+ readonly required: false;
11
+ };
12
+ readonly "list-presets": {
13
+ readonly type: "boolean";
14
+ readonly description: "List presets and exit";
15
+ readonly required: false;
16
+ };
17
+ readonly days: {
18
+ readonly type: "string";
19
+ readonly description: "Override days (1–7)";
20
+ readonly required: false;
21
+ };
22
+ readonly entity: {
23
+ readonly type: "string";
24
+ readonly description: "Entity type";
25
+ readonly required: false;
26
+ };
27
+ readonly "entity-ids": {
28
+ readonly type: "string";
29
+ readonly description: "CSV of entity IDs";
30
+ readonly required: false;
31
+ };
32
+ readonly "start-time": {
33
+ readonly type: "string";
34
+ readonly description: "ISO 8601 start";
35
+ readonly required: false;
36
+ };
37
+ readonly "end-time": {
38
+ readonly type: "string";
39
+ readonly description: "ISO 8601 end";
40
+ readonly required: false;
41
+ };
42
+ readonly granularity: {
43
+ readonly type: "string";
44
+ readonly description: "Granularity";
45
+ readonly required: false;
46
+ };
47
+ readonly "metric-groups": {
48
+ readonly type: "string";
49
+ readonly description: "Metric groups CSV";
50
+ readonly required: false;
51
+ };
52
+ readonly placement: {
53
+ readonly type: "string";
54
+ readonly description: "Placement";
55
+ readonly required: false;
56
+ };
57
+ readonly country: {
58
+ readonly type: "string";
59
+ readonly description: "Country filter";
60
+ readonly required: false;
61
+ };
62
+ readonly platform: {
63
+ readonly type: "string";
64
+ readonly description: "Platform filter";
65
+ readonly required: false;
66
+ };
67
+ readonly "no-cache": {
68
+ readonly type: "boolean";
69
+ readonly description: "Skip cache";
70
+ readonly required: false;
71
+ };
72
+ }>;
73
+ //# sourceMappingURL=sync.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../../../../src/commands/ads/x/stats/sync.ts"],"names":[],"mappings":"AA8HA,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAwC3B,CAAC"}
@@ -0,0 +1,151 @@
1
+ import { defineCommand } from "citty";
2
+ import { ApiError, apiPost } from "../../../../client.js";
3
+ import { registerSchema } from "../../../../schemas.js";
4
+ import { cacheGet, cacheSet } from "../../cache.js";
5
+ import { writeAdsJson } from "../../output.js";
6
+ import { parseXApiError } from "../error-parser.js";
7
+ import { resolveXAccountId } from "../output.js";
8
+ import { getPreset, isoHourFloor, X_STATS_PRESETS } from "../presets.js";
9
+ registerSchema({
10
+ command: "ads.x.statsSync",
11
+ description: "Synchronous analytics for an X Ads account (max 7 days). Use --preset for common queries or pass --entity, --entity-ids (CSV, max 20), --metric-groups (CSV), --start-time, --end-time, --granularity (DAY|HOUR|TOTAL), --placement (ALL_ON_TWITTER|PUBLISHER_NETWORK).",
12
+ args: {
13
+ "account-id": { type: "string", description: "X Ads account ID", required: false },
14
+ preset: { type: "string", description: "Use a stats preset (see --list-presets)", required: false },
15
+ "list-presets": { type: "boolean", description: "List available presets and exit", required: false },
16
+ days: { type: "string", description: "Override preset days (max 7)", required: false },
17
+ entity: { type: "string", description: "CAMPAIGN | LINE_ITEM | PROMOTED_TWEET | ...", required: false },
18
+ "entity-ids": { type: "string", description: "CSV of entity IDs (max 20)", required: false },
19
+ "start-time": { type: "string", description: "ISO 8601 hour-aligned start", required: false },
20
+ "end-time": { type: "string", description: "ISO 8601 hour-aligned end", required: false },
21
+ granularity: { type: "string", description: "TOTAL | DAY | HOUR", required: false },
22
+ "metric-groups": {
23
+ type: "string",
24
+ description: "CSV: ENGAGEMENT,BILLING,VIDEO,MEDIA,WEB_CONVERSION,MOBILE_CONVERSION,LIFE_TIME_VALUE_MOBILE_CONVERSION",
25
+ required: false,
26
+ },
27
+ placement: { type: "string", description: "ALL_ON_TWITTER | PUBLISHER_NETWORK", required: false },
28
+ country: { type: "string", description: "Country filter (mobile_conversion only)", required: false },
29
+ platform: { type: "string", description: "Platform filter (mobile_conversion only)", required: false },
30
+ "no-cache": { type: "boolean", description: "Skip cache", required: false },
31
+ },
32
+ });
33
+ function parseCsv(v) {
34
+ if (typeof v !== "string" || v.length === 0)
35
+ return undefined;
36
+ const parts = v
37
+ .split(",")
38
+ .map((s) => s.trim())
39
+ .filter(Boolean);
40
+ return parts.length > 0 ? parts : undefined;
41
+ }
42
+ function resolveQueryFromArgs(args) {
43
+ let entity = args.entity;
44
+ let metricGroups = parseCsv(args["metric-groups"]);
45
+ let granularity = args.granularity ?? "DAY";
46
+ let placement = args.placement ?? "ALL_ON_TWITTER";
47
+ let startTime = args["start-time"];
48
+ let endTime = args["end-time"];
49
+ if (args.preset) {
50
+ const preset = getPreset(args.preset);
51
+ if (!preset) {
52
+ return { error: `Unknown preset '${args.preset}'. Run with --list-presets to see options.` };
53
+ }
54
+ entity ??= preset.entity;
55
+ metricGroups ??= preset.metricGroups;
56
+ granularity = args.granularity ?? preset.granularity;
57
+ placement = args.placement ?? preset.placement;
58
+ const days = args.days ? Math.min(7, Math.max(1, Number(args.days))) : preset.defaultDays;
59
+ startTime ??= isoHourFloor(days);
60
+ endTime ??= isoHourFloor(0);
61
+ }
62
+ const entityIds = parseCsv(args["entity-ids"]);
63
+ if (!entity || !metricGroups || metricGroups.length === 0 || !startTime || !endTime || !entityIds) {
64
+ return {
65
+ error: "stats sync requires entity, entity-ids, metric-groups, start-time, end-time. Use --preset for defaults.",
66
+ };
67
+ }
68
+ return { entity, metricGroups, granularity, placement, startTime, endTime, entityIds };
69
+ }
70
+ async function runSync(args, q) {
71
+ const accountId = await resolveXAccountId(args);
72
+ const useCache = !args["no-cache"];
73
+ const body = {
74
+ accountId,
75
+ entity: q.entity,
76
+ entityIds: q.entityIds,
77
+ startTime: q.startTime,
78
+ endTime: q.endTime,
79
+ granularity: q.granularity,
80
+ metricGroups: q.metricGroups,
81
+ placement: q.placement,
82
+ country: args.country ?? undefined,
83
+ platform: args.platform ?? undefined,
84
+ skipCache: !useCache || undefined,
85
+ };
86
+ const cacheKey = `stats-sync:${JSON.stringify(body)}`;
87
+ if (useCache) {
88
+ const cached = cacheGet("x-stats", cacheKey);
89
+ if (cached) {
90
+ writeAdsJson({ ok: true, data: cached.data, cached: true });
91
+ return;
92
+ }
93
+ }
94
+ try {
95
+ const data = await apiPost("/api/ads/x/stats", body);
96
+ if (useCache) {
97
+ cacheSet("x-stats", cacheKey, data, 60 * 60 * 1000);
98
+ }
99
+ writeAdsJson({ ok: true, data });
100
+ }
101
+ catch (err) {
102
+ if (err instanceof ApiError) {
103
+ writeAdsJson(parseXApiError(err.message, accountId));
104
+ process.exit(1);
105
+ }
106
+ writeAdsJson({ ok: false, error: { code: "NETWORK_ERROR", message: "Unexpected error" } });
107
+ process.exit(1);
108
+ }
109
+ }
110
+ export const statsSyncCommand = defineCommand({
111
+ meta: {
112
+ name: "sync",
113
+ description: `Synchronous X Ads analytics (max 7-day window).
114
+
115
+ Examples:
116
+ baker ads x stats sync --preset campaign-engagement-7d --account-id 18ce53xyz --entity-ids abc,def
117
+ baker ads x stats sync --account-id 18ce53xyz --entity LINE_ITEM --entity-ids abc \\
118
+ --start-time 2026-05-01T00:00:00Z --end-time 2026-05-07T00:00:00Z \\
119
+ --metric-groups ENGAGEMENT,BILLING --granularity DAY
120
+ baker ads x stats sync --list-presets`,
121
+ },
122
+ args: {
123
+ "account-id": { type: "string", description: "X Ads account ID", required: false },
124
+ preset: { type: "string", description: "Stats preset name", required: false },
125
+ "list-presets": { type: "boolean", description: "List presets and exit", required: false },
126
+ days: { type: "string", description: "Override days (1–7)", required: false },
127
+ entity: { type: "string", description: "Entity type", required: false },
128
+ "entity-ids": { type: "string", description: "CSV of entity IDs", required: false },
129
+ "start-time": { type: "string", description: "ISO 8601 start", required: false },
130
+ "end-time": { type: "string", description: "ISO 8601 end", required: false },
131
+ granularity: { type: "string", description: "Granularity", required: false },
132
+ "metric-groups": { type: "string", description: "Metric groups CSV", required: false },
133
+ placement: { type: "string", description: "Placement", required: false },
134
+ country: { type: "string", description: "Country filter", required: false },
135
+ platform: { type: "string", description: "Platform filter", required: false },
136
+ "no-cache": { type: "boolean", description: "Skip cache", required: false },
137
+ },
138
+ run: async ({ args }) => {
139
+ if (args["list-presets"]) {
140
+ writeAdsJson({ ok: true, data: X_STATS_PRESETS });
141
+ return;
142
+ }
143
+ const resolved = resolveQueryFromArgs(args);
144
+ if ("error" in resolved) {
145
+ writeAdsJson({ ok: false, error: { code: "INVALID_PARAMETER", message: resolved.error } });
146
+ process.exit(1);
147
+ }
148
+ await runSync(args, resolved);
149
+ },
150
+ });
151
+ //# sourceMappingURL=sync.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync.js","sourceRoot":"","sources":["../../../../../src/commands/ads/x/stats/sync.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ export declare const targetingConstantsCommand: import("citty").CommandDef<{
2
+ readonly constant: {
3
+ readonly type: "string";
4
+ readonly description: "Targeting constant name";
5
+ readonly required: true;
6
+ };
7
+ readonly q: {
8
+ readonly type: "string";
9
+ readonly description: "Search query";
10
+ readonly required: false;
11
+ };
12
+ readonly "country-code": {
13
+ readonly type: "string";
14
+ readonly description: "Country filter";
15
+ readonly required: false;
16
+ };
17
+ readonly "location-type": {
18
+ readonly type: "string";
19
+ readonly description: "Location type filter";
20
+ readonly required: false;
21
+ };
22
+ readonly "no-cache": {
23
+ readonly type: "boolean";
24
+ readonly description: "Skip cache";
25
+ readonly required: false;
26
+ };
27
+ readonly output: {
28
+ readonly type: "string";
29
+ readonly description: "Format: json|csv|md";
30
+ readonly required: false;
31
+ readonly default: "json";
32
+ };
33
+ }>;
34
+ //# sourceMappingURL=targeting-constants.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"targeting-constants.d.ts","sourceRoot":"","sources":["../../../../src/commands/ads/x/targeting-constants.ts"],"names":[],"mappings":"AAmCA,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA+CpC,CAAC"}
@@ -0,0 +1,80 @@
1
+ import { defineCommand } from "citty";
2
+ import { registerSchema } from "../../../schemas.js";
3
+ import { writeAdsJson } from "../output.js";
4
+ import { runListCommand } from "./run-list.js";
5
+ const ALLOWED_CONSTANTS = [
6
+ "locations",
7
+ "interests",
8
+ "events",
9
+ "platforms",
10
+ "platform_versions",
11
+ "devices",
12
+ "app_store_categories",
13
+ "network_operators",
14
+ "tv_markets",
15
+ "tv_shows",
16
+ ];
17
+ registerSchema({
18
+ command: "ads.x.targetingConstants",
19
+ description: "Lookup X Ads targeting constants (locations, interests, events, platforms, devices, etc.). Cached 7 days. For locations: --q to filter by name, --country-code to scope.",
20
+ args: {
21
+ constant: {
22
+ type: "string",
23
+ description: `One of: ${ALLOWED_CONSTANTS.join(", ")}`,
24
+ required: true,
25
+ },
26
+ q: { type: "string", description: "Search query (locations only)", required: false },
27
+ "country-code": { type: "string", description: "ISO country code filter", required: false },
28
+ "location-type": { type: "string", description: "COUNTRY|REGION|CITY|... (locations only)", required: false },
29
+ "no-cache": { type: "boolean", description: "Skip cache", required: false },
30
+ },
31
+ });
32
+ export const targetingConstantsCommand = defineCommand({
33
+ meta: {
34
+ name: "targeting-constants",
35
+ description: `Lookup X Ads targeting constants.
36
+
37
+ Examples:
38
+ baker ads x targeting-constants --constant locations --q Madrid --country-code ES
39
+ baker ads x targeting-constants --constant interests
40
+ baker ads x targeting-constants --constant devices`,
41
+ },
42
+ args: {
43
+ constant: { type: "string", description: "Targeting constant name", required: true },
44
+ q: { type: "string", description: "Search query", required: false },
45
+ "country-code": { type: "string", description: "Country filter", required: false },
46
+ "location-type": { type: "string", description: "Location type filter", required: false },
47
+ "no-cache": { type: "boolean", description: "Skip cache", required: false },
48
+ output: { type: "string", description: "Format: json|csv|md", required: false, default: "json" },
49
+ },
50
+ run: async ({ args }) => {
51
+ const constant = args.constant;
52
+ if (!ALLOWED_CONSTANTS.includes(constant)) {
53
+ writeAdsJson({
54
+ ok: false,
55
+ error: {
56
+ code: "INVALID_PARAMETER",
57
+ message: `Unsupported constant '${constant}'. Allowed: ${ALLOWED_CONSTANTS.join(", ")}`,
58
+ },
59
+ });
60
+ process.exit(1);
61
+ }
62
+ const useCache = !args["no-cache"];
63
+ const cacheKey = `targeting-constants:${constant}:${args.q ?? ""}:${args["country-code"] ?? ""}:${args["location-type"] ?? ""}`;
64
+ await runListCommand({
65
+ path: "/api/ads/x/targeting-constants",
66
+ cacheCategory: "x-targeting-constants",
67
+ cacheKey,
68
+ cacheTtlMs: 7 * 24 * 60 * 60 * 1000,
69
+ params: {
70
+ constant,
71
+ q: args.q,
72
+ "country-code": args["country-code"],
73
+ "location-type": args["location-type"],
74
+ },
75
+ format: args.output || "json",
76
+ useCache,
77
+ });
78
+ },
79
+ });
80
+ //# sourceMappingURL=targeting-constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"targeting-constants.js","sourceRoot":"","sources":["../../../../src/commands/ads/x/targeting-constants.ts"],"names":[],"mappings":"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"}