@yoryoboy/bi-mcp 1.0.5 → 1.2.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 (102) hide show
  1. package/README.md +140 -9
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/index.js +151 -1
  4. package/dist/index.js.map +2 -2
  5. package/dist/mcp-use.json +2 -2
  6. package/dist/scripts/_helpers.js +44 -0
  7. package/dist/scripts/_helpers.js.map +7 -0
  8. package/dist/scripts/admin-profile-delete.js +72 -0
  9. package/dist/scripts/admin-profile-delete.js.map +7 -0
  10. package/dist/scripts/admin-profile-list.js +24 -0
  11. package/dist/scripts/admin-profile-list.js.map +7 -0
  12. package/dist/scripts/admin-profile-upsert.js +25 -0
  13. package/dist/scripts/admin-profile-upsert.js.map +7 -0
  14. package/dist/scripts/admin-vtex-list.js +28 -0
  15. package/dist/scripts/admin-vtex-list.js.map +7 -0
  16. package/dist/scripts/admin-vtex-upsert.js +73 -0
  17. package/dist/scripts/admin-vtex-upsert.js.map +7 -0
  18. package/dist/scripts/admin-vtex-validate.js +55 -0
  19. package/dist/scripts/admin-vtex-validate.js.map +7 -0
  20. package/dist/scripts/run-migrations.js +50 -0
  21. package/dist/scripts/run-migrations.js.map +7 -0
  22. package/dist/scripts/test-db-connection.js +19 -0
  23. package/dist/scripts/test-db-connection.js.map +7 -0
  24. package/dist/src/config/meta.js +29 -0
  25. package/dist/src/config/meta.js.map +7 -0
  26. package/dist/src/config/profile-store.js +86 -0
  27. package/dist/src/config/profile-store.js.map +7 -0
  28. package/dist/src/config/vtex-crypto.js +43 -0
  29. package/dist/src/config/vtex-crypto.js.map +7 -0
  30. package/dist/src/config/vtex-profile-store.js +132 -0
  31. package/dist/src/config/vtex-profile-store.js.map +7 -0
  32. package/dist/src/config/vtex.js +27 -21
  33. package/dist/src/config/vtex.js.map +2 -2
  34. package/dist/src/db/client.js +58 -0
  35. package/dist/src/db/client.js.map +7 -0
  36. package/dist/src/meta/meta-utils.js +148 -0
  37. package/dist/src/meta/meta-utils.js.map +7 -0
  38. package/dist/src/services/meta/meta-ads.js +89 -0
  39. package/dist/src/services/meta/meta-ads.js.map +7 -0
  40. package/dist/src/services/meta/meta-api.js +35 -0
  41. package/dist/src/services/meta/meta-api.js.map +7 -0
  42. package/dist/src/services/vtex/vtex-api.js +24 -8
  43. package/dist/src/services/vtex/vtex-api.js.map +2 -2
  44. package/dist/src/services/vtex/vtex-catalog.js +5 -3
  45. package/dist/src/services/vtex/vtex-catalog.js.map +2 -2
  46. package/dist/src/services/vtex/vtex-logistics.js +18 -9
  47. package/dist/src/services/vtex/vtex-logistics.js.map +2 -2
  48. package/dist/src/services/vtex/vtex-orders.js +13 -7
  49. package/dist/src/services/vtex/vtex-orders.js.map +2 -2
  50. package/dist/src/services/vtex/vtex-pricing.js +5 -3
  51. package/dist/src/services/vtex/vtex-pricing.js.map +2 -2
  52. package/dist/src/tools/config/check-database-connection.js +59 -0
  53. package/dist/src/tools/config/check-database-connection.js.map +7 -0
  54. package/dist/src/tools/config/index.js +3 -0
  55. package/dist/src/tools/config/index.js.map +7 -0
  56. package/dist/src/tools/config/list-profiles.js +26 -0
  57. package/dist/src/tools/config/list-profiles.js.map +7 -0
  58. package/dist/src/tools/index.js +2 -0
  59. package/dist/src/tools/index.js.map +2 -2
  60. package/dist/src/tools/meta/account-overview.js +92 -0
  61. package/dist/src/tools/meta/account-overview.js.map +7 -0
  62. package/dist/src/tools/meta/ad-account-info.js +37 -0
  63. package/dist/src/tools/meta/ad-account-info.js.map +7 -0
  64. package/dist/src/tools/meta/ads-performance.js +79 -0
  65. package/dist/src/tools/meta/ads-performance.js.map +7 -0
  66. package/dist/src/tools/meta/campaign-performance.js +81 -0
  67. package/dist/src/tools/meta/campaign-performance.js.map +7 -0
  68. package/dist/src/tools/meta/index.js +9 -0
  69. package/dist/src/tools/meta/index.js.map +7 -0
  70. package/dist/src/tools/meta/list-accessible-ad-accounts.js +44 -0
  71. package/dist/src/tools/meta/list-accessible-ad-accounts.js.map +7 -0
  72. package/dist/src/tools/meta/list-accessible-businesses.js +36 -0
  73. package/dist/src/tools/meta/list-accessible-businesses.js.map +7 -0
  74. package/dist/src/tools/meta/placement-mix.js +67 -0
  75. package/dist/src/tools/meta/placement-mix.js.map +7 -0
  76. package/dist/src/tools/meta/time-series.js +69 -0
  77. package/dist/src/tools/meta/time-series.js.map +7 -0
  78. package/dist/src/tools/vtex/computed-price.js +12 -1
  79. package/dist/src/tools/vtex/computed-price.js.map +2 -2
  80. package/dist/src/tools/vtex/index.js +1 -0
  81. package/dist/src/tools/vtex/index.js.map +2 -2
  82. package/dist/src/tools/vtex/inventory-check.js +15 -2
  83. package/dist/src/tools/vtex/inventory-check.js.map +2 -2
  84. package/dist/src/tools/vtex/order-details.js +16 -2
  85. package/dist/src/tools/vtex/order-details.js.map +2 -2
  86. package/dist/src/tools/vtex/orders-summary.js +11 -1
  87. package/dist/src/tools/vtex/orders-summary.js.map +2 -2
  88. package/dist/src/tools/vtex/product-offers.js +15 -2
  89. package/dist/src/tools/vtex/product-offers.js.map +2 -2
  90. package/dist/src/tools/vtex/profile-resolution.js +57 -0
  91. package/dist/src/tools/vtex/profile-resolution.js.map +7 -0
  92. package/dist/src/tools/vtex/sku-offers.js +16 -2
  93. package/dist/src/tools/vtex/sku-offers.js.map +2 -2
  94. package/dist/src/tools/vtex/sku-price.js +12 -2
  95. package/dist/src/tools/vtex/sku-price.js.map +2 -2
  96. package/dist/src/tools/vtex/update-inventory.js +12 -1
  97. package/dist/src/tools/vtex/update-inventory.js.map +2 -2
  98. package/dist/src/tools/vtex/update-lead-time.js +12 -1
  99. package/dist/src/tools/vtex/update-lead-time.js.map +2 -2
  100. package/dist/src/tools/vtex/warehouse-inventory.js +12 -1
  101. package/dist/src/tools/vtex/warehouse-inventory.js.map +2 -2
  102. package/package.json +12 -2
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/config/vtex.ts"],
4
- "sourcesContent": ["const REQUIRED_ENV_VARS = [\n \"VTEX_ACCOUNT_NAME\",\n \"VTEX_API_KEY\",\n \"VTEX_API_TOKEN\",\n] as const;\n\ntype RequiredEnvVar = (typeof REQUIRED_ENV_VARS)[number];\n\nfunction requireEnv(name: RequiredEnvVar): string {\n const value = process.env[name]?.trim();\n if (!value) {\n throw new Error(`Missing required environment variable: ${name}`);\n }\n return value;\n}\n\nconst accountName = requireEnv(\"VTEX_ACCOUNT_NAME\");\nconst apiKey = requireEnv(\"VTEX_API_KEY\");\nconst apiToken = requireEnv(\"VTEX_API_TOKEN\");\n\nexport interface VtexConfig {\n accountName: string;\n apiKey: string;\n apiToken: string;\n baseUrl: string;\n pricingBaseUrl: string;\n}\n\nexport const vtexConfig: VtexConfig = {\n accountName,\n apiKey,\n apiToken,\n baseUrl: `https://${accountName}.vtexcommercestable.com.br`,\n pricingBaseUrl: `https://api.vtex.com/${accountName}`,\n};\n"],
5
- "mappings": "AAAA,MAAM,oBAAoB;AAAA,EACxB;AAAA,EACA;AAAA,EACA;AACF;AAIA,SAAS,WAAW,MAA8B;AAChD,QAAM,QAAQ,QAAQ,IAAI,IAAI,GAAG,KAAK;AACtC,MAAI,CAAC,OAAO;AACV,UAAM,IAAI,MAAM,0CAA0C,IAAI,EAAE;AAAA,EAClE;AACA,SAAO;AACT;AAEA,MAAM,cAAc,WAAW,mBAAmB;AAClD,MAAM,SAAS,WAAW,cAAc;AACxC,MAAM,WAAW,WAAW,gBAAgB;AAUrC,MAAM,aAAyB;AAAA,EACpC;AAAA,EACA;AAAA,EACA;AAAA,EACA,SAAS,WAAW,WAAW;AAAA,EAC/B,gBAAgB,wBAAwB,WAAW;AACrD;",
4
+ "sourcesContent": ["import { assertActiveProfile } from \"./profile-store.js\";\nimport { decryptSecret } from \"./vtex-crypto.js\";\nimport { getVtexConnectionRow } from \"./vtex-profile-store.js\";\n\nexport interface VtexConfig {\n accountName: string;\n apiKey: string;\n apiToken: string;\n baseUrl: string;\n pricingBaseUrl: string;\n}\n\nexport function buildVtexUrls(accountName: string) {\n return {\n baseUrl: `https://${accountName}.vtexcommercestable.com.br`,\n pricingBaseUrl: `https://api.vtex.com/${accountName}`,\n };\n}\n\nexport async function getVtexConfigForProfile(profileId: string): Promise<VtexConfig> {\n await assertActiveProfile(profileId);\n\n const connection = await getVtexConnectionRow(profileId);\n if (!connection) {\n throw new Error(`VTEX connection not found for profileId \"${profileId}\"`);\n }\n\n if (!connection.isActive || connection.status === \"disabled\") {\n throw new Error(`VTEX connection for profileId \"${profileId}\" is disabled`);\n }\n\n const urls = buildVtexUrls(connection.accountName);\n\n return {\n accountName: connection.accountName,\n apiKey: decryptSecret(connection.apiKeyEncrypted),\n apiToken: decryptSecret(connection.apiTokenEncrypted),\n baseUrl: urls.baseUrl,\n pricingBaseUrl: urls.pricingBaseUrl,\n };\n}\n"],
5
+ "mappings": "AAAA,SAAS,2BAA2B;AACpC,SAAS,qBAAqB;AAC9B,SAAS,4BAA4B;AAU9B,SAAS,cAAc,aAAqB;AACjD,SAAO;AAAA,IACL,SAAS,WAAW,WAAW;AAAA,IAC/B,gBAAgB,wBAAwB,WAAW;AAAA,EACrD;AACF;AAEA,eAAsB,wBAAwB,WAAwC;AACpF,QAAM,oBAAoB,SAAS;AAEnC,QAAM,aAAa,MAAM,qBAAqB,SAAS;AACvD,MAAI,CAAC,YAAY;AACf,UAAM,IAAI,MAAM,4CAA4C,SAAS,GAAG;AAAA,EAC1E;AAEA,MAAI,CAAC,WAAW,YAAY,WAAW,WAAW,YAAY;AAC5D,UAAM,IAAI,MAAM,kCAAkC,SAAS,eAAe;AAAA,EAC5E;AAEA,QAAM,OAAO,cAAc,WAAW,WAAW;AAEjD,SAAO;AAAA,IACL,aAAa,WAAW;AAAA,IACxB,QAAQ,cAAc,WAAW,eAAe;AAAA,IAChD,UAAU,cAAc,WAAW,iBAAiB;AAAA,IACpD,SAAS,KAAK;AAAA,IACd,gBAAgB,KAAK;AAAA,EACvB;AACF;",
6
6
  "names": []
7
7
  }
@@ -0,0 +1,58 @@
1
+ import { Pool } from "pg";
2
+ function requireDatabaseUrl() {
3
+ const value = process.env.DATABASE_URL?.trim();
4
+ if (!value) {
5
+ throw new Error(
6
+ "Missing DATABASE_URL. Configure it in your environment before using the database client."
7
+ );
8
+ }
9
+ return value;
10
+ }
11
+ let pool = null;
12
+ function getDb() {
13
+ if (!pool) {
14
+ pool = new Pool({
15
+ connectionString: requireDatabaseUrl()
16
+ });
17
+ }
18
+ return pool;
19
+ }
20
+ function getDatabaseUrl() {
21
+ const value = process.env.DATABASE_URL?.trim();
22
+ return value ? value : void 0;
23
+ }
24
+ async function testDatabaseConnection() {
25
+ const result = await getDb().query(
26
+ `select current_database(), current_user, now()`
27
+ );
28
+ return result.rows[0];
29
+ }
30
+ async function checkTableExists(tableName) {
31
+ const result = await getDb().query(
32
+ `
33
+ select exists (
34
+ select 1
35
+ from information_schema.tables
36
+ where table_schema = 'public'
37
+ and table_name = $1
38
+ ) as exists
39
+ `,
40
+ [tableName]
41
+ );
42
+ return Boolean(result.rows[0]?.exists);
43
+ }
44
+ async function closeDb() {
45
+ if (!pool) {
46
+ return;
47
+ }
48
+ await pool.end();
49
+ pool = null;
50
+ }
51
+ export {
52
+ checkTableExists,
53
+ closeDb,
54
+ getDatabaseUrl,
55
+ getDb,
56
+ testDatabaseConnection
57
+ };
58
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/db/client.ts"],
4
+ "sourcesContent": ["import { Pool } from \"pg\";\n\nfunction requireDatabaseUrl(): string {\n const value = process.env.DATABASE_URL?.trim();\n if (!value) {\n throw new Error(\n \"Missing DATABASE_URL. Configure it in your environment before using the database client.\"\n );\n }\n\n return value;\n}\n\nlet pool: Pool | null = null;\n\nexport function getDb(): Pool {\n if (!pool) {\n pool = new Pool({\n connectionString: requireDatabaseUrl(),\n });\n }\n\n return pool;\n}\n\nexport function getDatabaseUrl(): string | undefined {\n const value = process.env.DATABASE_URL?.trim();\n return value ? value : undefined;\n}\n\nexport async function testDatabaseConnection() {\n const result = await getDb().query<{\n current_database: string;\n current_user: string;\n now: Date;\n }>(\n `select current_database(), current_user, now()`\n );\n\n return result.rows[0];\n}\n\nexport async function checkTableExists(tableName: string): Promise<boolean> {\n const result = await getDb().query<{ exists: boolean }>(\n `\n select exists (\n select 1\n from information_schema.tables\n where table_schema = 'public'\n and table_name = $1\n ) as exists\n `,\n [tableName]\n );\n\n return Boolean(result.rows[0]?.exists);\n}\n\nexport async function closeDb() {\n if (!pool) {\n return;\n }\n\n await pool.end();\n pool = null;\n}\n"],
5
+ "mappings": "AAAA,SAAS,YAAY;AAErB,SAAS,qBAA6B;AACpC,QAAM,QAAQ,QAAQ,IAAI,cAAc,KAAK;AAC7C,MAAI,CAAC,OAAO;AACV,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAEA,IAAI,OAAoB;AAEjB,SAAS,QAAc;AAC5B,MAAI,CAAC,MAAM;AACT,WAAO,IAAI,KAAK;AAAA,MACd,kBAAkB,mBAAmB;AAAA,IACvC,CAAC;AAAA,EACH;AAEA,SAAO;AACT;AAEO,SAAS,iBAAqC;AACnD,QAAM,QAAQ,QAAQ,IAAI,cAAc,KAAK;AAC7C,SAAO,QAAQ,QAAQ;AACzB;AAEA,eAAsB,yBAAyB;AAC7C,QAAM,SAAS,MAAM,MAAM,EAAE;AAAA,IAK3B;AAAA,EACF;AAEA,SAAO,OAAO,KAAK,CAAC;AACtB;AAEA,eAAsB,iBAAiB,WAAqC;AAC1E,QAAM,SAAS,MAAM,MAAM,EAAE;AAAA,IAC3B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAQA,CAAC,SAAS;AAAA,EACZ;AAEA,SAAO,QAAQ,OAAO,KAAK,CAAC,GAAG,MAAM;AACvC;AAEA,eAAsB,UAAU;AAC9B,MAAI,CAAC,MAAM;AACT;AAAA,EACF;AAEA,QAAM,KAAK,IAAI;AACf,SAAO;AACT;",
6
+ "names": []
7
+ }
@@ -0,0 +1,148 @@
1
+ const dateRegex = /^\d{4}-\d{2}-\d{2}$/;
2
+ const metaAdAccountStatusLabels = {
3
+ 1: "active"
4
+ };
5
+ function normalizeMetaAdAccountId(adAccountId) {
6
+ const normalized = adAccountId.trim().replace(/^act_/i, "");
7
+ if (!/^\d+$/.test(normalized)) {
8
+ throw new Error(
9
+ "Invalid Meta ad account ID. Use digits only, with or without the act_ prefix."
10
+ );
11
+ }
12
+ return normalized;
13
+ }
14
+ function toActId(adAccountId) {
15
+ return `act_${normalizeMetaAdAccountId(adAccountId)}`;
16
+ }
17
+ function parseNumber(value) {
18
+ if (typeof value === "number" && Number.isFinite(value)) {
19
+ return value;
20
+ }
21
+ if (typeof value === "string") {
22
+ const parsedValue = Number(value);
23
+ return Number.isFinite(parsedValue) ? parsedValue : 0;
24
+ }
25
+ return 0;
26
+ }
27
+ function round(value, decimals = 2) {
28
+ if (!Number.isFinite(value)) {
29
+ return 0;
30
+ }
31
+ const factor = 10 ** decimals;
32
+ return Math.round(value * factor) / factor;
33
+ }
34
+ function getMetaAdAccountStatusLabel(accountStatus) {
35
+ if (typeof accountStatus !== "number" || !Number.isFinite(accountStatus)) {
36
+ return void 0;
37
+ }
38
+ return metaAdAccountStatusLabels[accountStatus];
39
+ }
40
+ function toPercent(numerator, denominator) {
41
+ if (!Number.isFinite(numerator) || !Number.isFinite(denominator) || denominator <= 0) {
42
+ return 0;
43
+ }
44
+ return numerator / denominator * 100;
45
+ }
46
+ function getActionValue(actions, actionType) {
47
+ const match = actions?.find((entry) => entry.action_type === actionType);
48
+ return parseNumber(match?.value);
49
+ }
50
+ function getMetricBundle(insight) {
51
+ const spend = parseNumber(insight?.spend);
52
+ const impressions = parseNumber(insight?.impressions);
53
+ const clicks = parseNumber(insight?.clicks);
54
+ const reach = parseNumber(insight?.reach);
55
+ const ctrPercent = parseNumber(insight?.ctr);
56
+ const cpc = parseNumber(insight?.cpc);
57
+ const cpm = parseNumber(insight?.cpm);
58
+ const purchases = getActionValue(insight?.actions, "purchase");
59
+ const purchaseValue = getActionValue(insight?.action_values, "purchase") || parseNumber(insight?.purchase_roas?.[0]?.value) * spend;
60
+ return {
61
+ spend: round(spend),
62
+ impressions,
63
+ clicks,
64
+ reach,
65
+ purchases: round(purchases),
66
+ purchase_value: round(purchaseValue),
67
+ ctr_percent: round(ctrPercent),
68
+ cpc: round(cpc),
69
+ cpm: round(cpm),
70
+ roas: round(purchaseValue / spend),
71
+ conversion_rate_percent: round(toPercent(purchases, clicks))
72
+ };
73
+ }
74
+ function aggregateInsightsByCurrency(entries) {
75
+ const aggregates = /* @__PURE__ */ new Map();
76
+ for (const entry of entries) {
77
+ const currencyCode = entry.currencyCode?.trim() || "UNKNOWN";
78
+ const metrics = getMetricBundle(entry.insight);
79
+ const current = aggregates.get(currencyCode) ?? {
80
+ currency_code: currencyCode,
81
+ spend: 0,
82
+ purchases: 0,
83
+ purchase_value: 0,
84
+ impressions: 0,
85
+ clicks: 0,
86
+ reach: 0,
87
+ ctr_percent: 0,
88
+ cpc: 0,
89
+ cpm: 0,
90
+ roas: 0
91
+ };
92
+ current.spend += metrics.spend;
93
+ current.purchases += metrics.purchases;
94
+ current.purchase_value += metrics.purchase_value;
95
+ current.impressions += metrics.impressions;
96
+ current.clicks += metrics.clicks;
97
+ current.reach += metrics.reach;
98
+ aggregates.set(currencyCode, current);
99
+ }
100
+ return Array.from(aggregates.values()).map((aggregate) => ({
101
+ ...aggregate,
102
+ spend: round(aggregate.spend),
103
+ purchases: round(aggregate.purchases),
104
+ purchase_value: round(aggregate.purchase_value),
105
+ ctr_percent: round(toPercent(aggregate.clicks, aggregate.impressions)),
106
+ cpc: round(aggregate.spend / aggregate.clicks),
107
+ cpm: round(aggregate.spend * 1e3 / aggregate.impressions),
108
+ roas: round(aggregate.purchase_value / aggregate.spend)
109
+ }));
110
+ }
111
+ function normalizeRequestedAccountIds(adAccountIds) {
112
+ const normalized = adAccountIds?.map((accountId) => normalizeMetaAdAccountId(accountId)).filter(Boolean);
113
+ if (!normalized?.length) {
114
+ return void 0;
115
+ }
116
+ return Array.from(new Set(normalized));
117
+ }
118
+ function resolveRequestedAccounts(requestedIds, accessibleAccounts) {
119
+ if (!accessibleAccounts.length) {
120
+ throw new Error("No accessible Meta ad accounts were found for the configured token.");
121
+ }
122
+ if (!requestedIds?.length) {
123
+ return accessibleAccounts;
124
+ }
125
+ const accountMap = new Map(
126
+ accessibleAccounts.map((account) => [normalizeMetaAdAccountId(account.account_id || account.id || ""), account])
127
+ );
128
+ const resolvedAccounts = requestedIds.map((accountId) => accountMap.get(accountId)).filter((account) => Boolean(account));
129
+ if (!resolvedAccounts.length) {
130
+ throw new Error("None of the requested Meta ad accounts are accessible with the configured token.");
131
+ }
132
+ return resolvedAccounts;
133
+ }
134
+ export {
135
+ aggregateInsightsByCurrency,
136
+ dateRegex,
137
+ getActionValue,
138
+ getMetaAdAccountStatusLabel,
139
+ getMetricBundle,
140
+ normalizeMetaAdAccountId,
141
+ normalizeRequestedAccountIds,
142
+ parseNumber,
143
+ resolveRequestedAccounts,
144
+ round,
145
+ toActId,
146
+ toPercent
147
+ };
148
+ //# sourceMappingURL=meta-utils.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/meta/meta-utils.ts"],
4
+ "sourcesContent": ["import type { MetaAdAccount, MetaAdInsight } from \"../services/meta/meta-ads.js\";\n\nexport const dateRegex = /^\\d{4}-\\d{2}-\\d{2}$/;\n\nexport interface MetaCurrencyAggregate {\n currency_code: string;\n spend: number;\n purchases: number;\n purchase_value: number;\n impressions: number;\n clicks: number;\n reach: number;\n ctr_percent: number;\n cpc: number;\n cpm: number;\n roas: number;\n}\n\nconst metaAdAccountStatusLabels: Record<number, string> = {\n 1: \"active\",\n};\n\nexport function normalizeMetaAdAccountId(adAccountId: string): string {\n const normalized = adAccountId.trim().replace(/^act_/i, \"\");\n if (!/^\\d+$/.test(normalized)) {\n throw new Error(\n \"Invalid Meta ad account ID. Use digits only, with or without the act_ prefix.\"\n );\n }\n\n return normalized;\n}\n\nexport function toActId(adAccountId: string): string {\n return `act_${normalizeMetaAdAccountId(adAccountId)}`;\n}\n\nexport function parseNumber(value: string | number | undefined): number {\n if (typeof value === \"number\" && Number.isFinite(value)) {\n return value;\n }\n\n if (typeof value === \"string\") {\n const parsedValue = Number(value);\n return Number.isFinite(parsedValue) ? parsedValue : 0;\n }\n\n return 0;\n}\n\nexport function round(value: number, decimals = 2): number {\n if (!Number.isFinite(value)) {\n return 0;\n }\n\n const factor = 10 ** decimals;\n return Math.round(value * factor) / factor;\n}\n\nexport function getMetaAdAccountStatusLabel(accountStatus: number | undefined): string | undefined {\n if (typeof accountStatus !== \"number\" || !Number.isFinite(accountStatus)) {\n return undefined;\n }\n\n return metaAdAccountStatusLabels[accountStatus];\n}\n\nexport function toPercent(numerator: number, denominator: number): number {\n if (!Number.isFinite(numerator) || !Number.isFinite(denominator) || denominator <= 0) {\n return 0;\n }\n\n return (numerator / denominator) * 100;\n}\n\nexport function getActionValue(\n actions: Array<{ action_type?: string; value?: string }> | undefined,\n actionType: string\n): number {\n const match = actions?.find((entry) => entry.action_type === actionType);\n return parseNumber(match?.value);\n}\n\nexport function getMetricBundle(insight: MetaAdInsight | undefined) {\n const spend = parseNumber(insight?.spend);\n const impressions = parseNumber(insight?.impressions);\n const clicks = parseNumber(insight?.clicks);\n const reach = parseNumber(insight?.reach);\n const ctrPercent = parseNumber(insight?.ctr);\n const cpc = parseNumber(insight?.cpc);\n const cpm = parseNumber(insight?.cpm);\n const purchases = getActionValue(insight?.actions, \"purchase\");\n const purchaseValue =\n getActionValue(insight?.action_values, \"purchase\") ||\n parseNumber(insight?.purchase_roas?.[0]?.value) * spend;\n\n return {\n spend: round(spend),\n impressions,\n clicks,\n reach,\n purchases: round(purchases),\n purchase_value: round(purchaseValue),\n ctr_percent: round(ctrPercent),\n cpc: round(cpc),\n cpm: round(cpm),\n roas: round(purchaseValue / spend),\n conversion_rate_percent: round(toPercent(purchases, clicks)),\n };\n}\n\nexport function aggregateInsightsByCurrency(\n entries: Array<{ currencyCode?: string; insight?: MetaAdInsight }>\n): MetaCurrencyAggregate[] {\n const aggregates = new Map<string, MetaCurrencyAggregate>();\n\n for (const entry of entries) {\n const currencyCode = entry.currencyCode?.trim() || \"UNKNOWN\";\n const metrics = getMetricBundle(entry.insight);\n const current = aggregates.get(currencyCode) ?? {\n currency_code: currencyCode,\n spend: 0,\n purchases: 0,\n purchase_value: 0,\n impressions: 0,\n clicks: 0,\n reach: 0,\n ctr_percent: 0,\n cpc: 0,\n cpm: 0,\n roas: 0,\n };\n\n current.spend += metrics.spend;\n current.purchases += metrics.purchases;\n current.purchase_value += metrics.purchase_value;\n current.impressions += metrics.impressions;\n current.clicks += metrics.clicks;\n current.reach += metrics.reach;\n\n aggregates.set(currencyCode, current);\n }\n\n return Array.from(aggregates.values()).map((aggregate) => ({\n ...aggregate,\n spend: round(aggregate.spend),\n purchases: round(aggregate.purchases),\n purchase_value: round(aggregate.purchase_value),\n ctr_percent: round(toPercent(aggregate.clicks, aggregate.impressions)),\n cpc: round(aggregate.spend / aggregate.clicks),\n cpm: round((aggregate.spend * 1000) / aggregate.impressions),\n roas: round(aggregate.purchase_value / aggregate.spend),\n }));\n}\n\nexport function normalizeRequestedAccountIds(adAccountIds?: string[]): string[] | undefined {\n const normalized = adAccountIds\n ?.map((accountId) => normalizeMetaAdAccountId(accountId))\n .filter(Boolean);\n\n if (!normalized?.length) {\n return undefined;\n }\n\n return Array.from(new Set(normalized));\n}\n\nexport function resolveRequestedAccounts(\n requestedIds: string[] | undefined,\n accessibleAccounts: MetaAdAccount[]\n): MetaAdAccount[] {\n if (!accessibleAccounts.length) {\n throw new Error(\"No accessible Meta ad accounts were found for the configured token.\");\n }\n\n if (!requestedIds?.length) {\n return accessibleAccounts;\n }\n\n const accountMap = new Map(\n accessibleAccounts.map((account) => [normalizeMetaAdAccountId(account.account_id || account.id || \"\"), account])\n );\n const resolvedAccounts = requestedIds\n .map((accountId) => accountMap.get(accountId))\n .filter((account): account is MetaAdAccount => Boolean(account));\n\n if (!resolvedAccounts.length) {\n throw new Error(\"None of the requested Meta ad accounts are accessible with the configured token.\");\n }\n\n return resolvedAccounts;\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,89 @@
1
+ import { metaFetch } from "./meta-api.js";
2
+ import { normalizeMetaAdAccountId, toActId } from "../../meta/meta-utils.js";
3
+ function decodePagingCursor(url) {
4
+ if (!url) {
5
+ return void 0;
6
+ }
7
+ try {
8
+ return new URL(url).searchParams.get("after") || void 0;
9
+ } catch {
10
+ return void 0;
11
+ }
12
+ }
13
+ async function listAccessibleMetaBusinesses(after) {
14
+ const response = await metaFetch("/me/businesses", {
15
+ fields: "id,name,verification_status",
16
+ limit: 100,
17
+ after
18
+ });
19
+ return {
20
+ businesses: response.data ?? [],
21
+ paging: {
22
+ after: response.paging?.cursors?.after || decodePagingCursor(response.paging?.next),
23
+ before: response.paging?.cursors?.before,
24
+ has_more: Boolean(response.paging?.next)
25
+ }
26
+ };
27
+ }
28
+ async function listAccessibleMetaAdAccounts(after) {
29
+ const response = await metaFetch("/me/adaccounts", {
30
+ fields: "id,account_id,name,currency,account_status,timezone_name,timezone_offset_hours_utc,business{id,name}",
31
+ limit: 100,
32
+ after
33
+ });
34
+ const accounts = (response.data ?? []).map((account) => ({
35
+ ...account,
36
+ account_id: account.account_id || normalizeMetaAdAccountId(account.id || "")
37
+ }));
38
+ return {
39
+ adAccounts: accounts,
40
+ paging: {
41
+ after: response.paging?.cursors?.after || decodePagingCursor(response.paging?.next),
42
+ before: response.paging?.cursors?.before,
43
+ has_more: Boolean(response.paging?.next)
44
+ }
45
+ };
46
+ }
47
+ async function getMetaAdAccountInfo(adAccountId) {
48
+ return metaFetch(`/${toActId(adAccountId)}`, {
49
+ fields: "id,account_id,name,currency,account_status,timezone_name,timezone_offset_hours_utc,business{id,name},amount_spent,balance,spend_cap"
50
+ });
51
+ }
52
+ async function getMetaInsights(objectId, params) {
53
+ const response = await metaFetch(`/${objectId}/insights`, {
54
+ fields: "impressions,reach,clicks,spend,ctr,cpc,cpm,actions,action_values,purchase_roas,date_start,date_stop",
55
+ ...params
56
+ });
57
+ return response.data ?? [];
58
+ }
59
+ async function getMetaCampaigns(adAccountId, limit = 50) {
60
+ const response = await metaFetch(`/${toActId(adAccountId)}/campaigns`, {
61
+ fields: "id,name,status,effective_status,objective",
62
+ limit
63
+ });
64
+ return response.data ?? [];
65
+ }
66
+ async function getMetaAds(adAccountId, limit = 50) {
67
+ const response = await metaFetch(`/${toActId(adAccountId)}/ads`, {
68
+ fields: "id,name,status,effective_status,creative{id}",
69
+ limit
70
+ });
71
+ return response.data ?? [];
72
+ }
73
+ async function getMetaPlacementInsights(adAccountId, params) {
74
+ const response = await metaFetch(`/${toActId(adAccountId)}/insights`, {
75
+ fields: "impressions,reach,clicks,spend,ctr,cpc,cpm,actions,action_values,purchase_roas",
76
+ ...params
77
+ });
78
+ return response.data ?? [];
79
+ }
80
+ export {
81
+ getMetaAdAccountInfo,
82
+ getMetaAds,
83
+ getMetaCampaigns,
84
+ getMetaInsights,
85
+ getMetaPlacementInsights,
86
+ listAccessibleMetaAdAccounts,
87
+ listAccessibleMetaBusinesses
88
+ };
89
+ //# sourceMappingURL=meta-ads.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/services/meta/meta-ads.ts"],
4
+ "sourcesContent": ["import { metaFetch, type MetaListResponse } from \"./meta-api.js\";\nimport { normalizeMetaAdAccountId, toActId } from \"../../meta/meta-utils.js\";\n\nexport interface MetaBusiness {\n id?: string;\n name?: string;\n verification_status?: string;\n}\n\nexport interface MetaBusinessRef {\n id?: string;\n name?: string;\n}\n\nexport interface MetaAdAccount {\n id?: string;\n account_id?: string;\n name?: string;\n currency?: string;\n account_status?: number;\n timezone_name?: string;\n timezone_offset_hours_utc?: number;\n business?: MetaBusinessRef;\n}\n\nexport interface MetaActionMetric {\n action_type?: string;\n value?: string;\n}\n\nexport interface MetaRoasMetric {\n action_type?: string;\n value?: string;\n}\n\nexport interface MetaAdInsight {\n date_start?: string;\n date_stop?: string;\n impressions?: string;\n reach?: string;\n clicks?: string;\n spend?: string;\n ctr?: string;\n cpc?: string;\n cpm?: string;\n actions?: MetaActionMetric[];\n action_values?: MetaActionMetric[];\n purchase_roas?: MetaRoasMetric[];\n}\n\nexport interface MetaCampaign {\n id?: string;\n name?: string;\n status?: string;\n effective_status?: string;\n objective?: string;\n}\n\nexport interface MetaAd {\n id?: string;\n name?: string;\n status?: string;\n effective_status?: string;\n creative?: {\n id?: string;\n };\n}\n\nexport interface MetaPlacementRow extends MetaAdInsight {\n publisher_platform?: string;\n platform_position?: string;\n impression_device?: string;\n}\n\nfunction decodePagingCursor(url: string | undefined): string | undefined {\n if (!url) {\n return undefined;\n }\n\n try {\n return new URL(url).searchParams.get(\"after\") || undefined;\n } catch {\n return undefined;\n }\n}\n\nexport async function listAccessibleMetaBusinesses(after?: string) {\n const response = await metaFetch<MetaListResponse<MetaBusiness>>(\"/me/businesses\", {\n fields: \"id,name,verification_status\",\n limit: 100,\n after,\n });\n\n return {\n businesses: response.data ?? [],\n paging: {\n after: response.paging?.cursors?.after || decodePagingCursor(response.paging?.next),\n before: response.paging?.cursors?.before,\n has_more: Boolean(response.paging?.next),\n },\n };\n}\n\nexport async function listAccessibleMetaAdAccounts(after?: string) {\n const response = await metaFetch<MetaListResponse<MetaAdAccount>>(\"/me/adaccounts\", {\n fields:\n \"id,account_id,name,currency,account_status,timezone_name,timezone_offset_hours_utc,business{id,name}\",\n limit: 100,\n after,\n });\n\n const accounts = (response.data ?? []).map((account) => ({\n ...account,\n account_id: account.account_id || normalizeMetaAdAccountId(account.id || \"\"),\n }));\n\n return {\n adAccounts: accounts,\n paging: {\n after: response.paging?.cursors?.after || decodePagingCursor(response.paging?.next),\n before: response.paging?.cursors?.before,\n has_more: Boolean(response.paging?.next),\n },\n };\n}\n\nexport async function getMetaAdAccountInfo(adAccountId: string): Promise<MetaAdAccount> {\n return metaFetch<MetaAdAccount>(`/${toActId(adAccountId)}`, {\n fields:\n \"id,account_id,name,currency,account_status,timezone_name,timezone_offset_hours_utc,business{id,name},amount_spent,balance,spend_cap\",\n });\n}\n\nexport async function getMetaInsights(\n objectId: string,\n params: Record<string, string | number | undefined>\n): Promise<MetaAdInsight[]> {\n const response = await metaFetch<MetaListResponse<MetaAdInsight>>(`/${objectId}/insights`, {\n fields:\n \"impressions,reach,clicks,spend,ctr,cpc,cpm,actions,action_values,purchase_roas,date_start,date_stop\",\n ...params,\n });\n\n return response.data ?? [];\n}\n\nexport async function getMetaCampaigns(adAccountId: string, limit = 50): Promise<MetaCampaign[]> {\n const response = await metaFetch<MetaListResponse<MetaCampaign>>(`/${toActId(adAccountId)}/campaigns`, {\n fields: \"id,name,status,effective_status,objective\",\n limit,\n });\n\n return response.data ?? [];\n}\n\nexport async function getMetaAds(adAccountId: string, limit = 50): Promise<MetaAd[]> {\n const response = await metaFetch<MetaListResponse<MetaAd>>(`/${toActId(adAccountId)}/ads`, {\n fields: \"id,name,status,effective_status,creative{id}\",\n limit,\n });\n\n return response.data ?? [];\n}\n\nexport async function getMetaPlacementInsights(\n adAccountId: string,\n params: Record<string, string | number | undefined>\n): Promise<MetaPlacementRow[]> {\n const response = await metaFetch<MetaListResponse<MetaPlacementRow>>(`/${toActId(adAccountId)}/insights`, {\n fields:\n \"impressions,reach,clicks,spend,ctr,cpc,cpm,actions,action_values,purchase_roas\",\n ...params,\n });\n\n return response.data ?? [];\n}\n"],
5
+ "mappings": "AAAA,SAAS,iBAAwC;AACjD,SAAS,0BAA0B,eAAe;AAyElD,SAAS,mBAAmB,KAA6C;AACvE,MAAI,CAAC,KAAK;AACR,WAAO;AAAA,EACT;AAEA,MAAI;AACF,WAAO,IAAI,IAAI,GAAG,EAAE,aAAa,IAAI,OAAO,KAAK;AAAA,EACnD,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,eAAsB,6BAA6B,OAAgB;AACjE,QAAM,WAAW,MAAM,UAA0C,kBAAkB;AAAA,IACjF,QAAQ;AAAA,IACR,OAAO;AAAA,IACP;AAAA,EACF,CAAC;AAED,SAAO;AAAA,IACL,YAAY,SAAS,QAAQ,CAAC;AAAA,IAC9B,QAAQ;AAAA,MACN,OAAO,SAAS,QAAQ,SAAS,SAAS,mBAAmB,SAAS,QAAQ,IAAI;AAAA,MAClF,QAAQ,SAAS,QAAQ,SAAS;AAAA,MAClC,UAAU,QAAQ,SAAS,QAAQ,IAAI;AAAA,IACzC;AAAA,EACF;AACF;AAEA,eAAsB,6BAA6B,OAAgB;AACjE,QAAM,WAAW,MAAM,UAA2C,kBAAkB;AAAA,IAClF,QACE;AAAA,IACF,OAAO;AAAA,IACP;AAAA,EACF,CAAC;AAED,QAAM,YAAY,SAAS,QAAQ,CAAC,GAAG,IAAI,CAAC,aAAa;AAAA,IACvD,GAAG;AAAA,IACH,YAAY,QAAQ,cAAc,yBAAyB,QAAQ,MAAM,EAAE;AAAA,EAC7E,EAAE;AAEF,SAAO;AAAA,IACL,YAAY;AAAA,IACZ,QAAQ;AAAA,MACN,OAAO,SAAS,QAAQ,SAAS,SAAS,mBAAmB,SAAS,QAAQ,IAAI;AAAA,MAClF,QAAQ,SAAS,QAAQ,SAAS;AAAA,MAClC,UAAU,QAAQ,SAAS,QAAQ,IAAI;AAAA,IACzC;AAAA,EACF;AACF;AAEA,eAAsB,qBAAqB,aAA6C;AACtF,SAAO,UAAyB,IAAI,QAAQ,WAAW,CAAC,IAAI;AAAA,IAC1D,QACE;AAAA,EACJ,CAAC;AACH;AAEA,eAAsB,gBACpB,UACA,QAC0B;AAC1B,QAAM,WAAW,MAAM,UAA2C,IAAI,QAAQ,aAAa;AAAA,IACzF,QACE;AAAA,IACF,GAAG;AAAA,EACL,CAAC;AAED,SAAO,SAAS,QAAQ,CAAC;AAC3B;AAEA,eAAsB,iBAAiB,aAAqB,QAAQ,IAA6B;AAC/F,QAAM,WAAW,MAAM,UAA0C,IAAI,QAAQ,WAAW,CAAC,cAAc;AAAA,IACrG,QAAQ;AAAA,IACR;AAAA,EACF,CAAC;AAED,SAAO,SAAS,QAAQ,CAAC;AAC3B;AAEA,eAAsB,WAAW,aAAqB,QAAQ,IAAuB;AACnF,QAAM,WAAW,MAAM,UAAoC,IAAI,QAAQ,WAAW,CAAC,QAAQ;AAAA,IACzF,QAAQ;AAAA,IACR;AAAA,EACF,CAAC;AAED,SAAO,SAAS,QAAQ,CAAC;AAC3B;AAEA,eAAsB,yBACpB,aACA,QAC6B;AAC7B,QAAM,WAAW,MAAM,UAA8C,IAAI,QAAQ,WAAW,CAAC,aAAa;AAAA,IACxG,QACE;AAAA,IACF,GAAG;AAAA,EACL,CAAC;AAED,SAAO,SAAS,QAAQ,CAAC;AAC3B;",
6
+ "names": []
7
+ }
@@ -0,0 +1,35 @@
1
+ import { createMetaAppSecretProof, getMetaConfig } from "../../config/meta.js";
2
+ function buildUrl(path, query) {
3
+ const config = getMetaConfig();
4
+ const accessToken = config.accessToken;
5
+ const appSecretProof = createMetaAppSecretProof(accessToken, config.appSecret);
6
+ const normalizedPath = path.startsWith("/") ? path : `/${path}`;
7
+ const searchParams = new URLSearchParams();
8
+ searchParams.set("access_token", accessToken);
9
+ searchParams.set("appsecret_proof", appSecretProof);
10
+ for (const [key, value] of Object.entries(query)) {
11
+ if (value === void 0 || value === null || value === "") {
12
+ continue;
13
+ }
14
+ searchParams.set(key, String(value));
15
+ }
16
+ return `${config.baseUrl}${normalizedPath}?${searchParams.toString()}`;
17
+ }
18
+ async function metaFetch(path, query = {}) {
19
+ const response = await fetch(buildUrl(path, query), {
20
+ method: "GET",
21
+ headers: {
22
+ Accept: "application/json"
23
+ }
24
+ });
25
+ if (!response.ok) {
26
+ const payload = await response.json().catch(() => ({}));
27
+ const message = payload.error?.error_user_msg || payload.error?.error_user_title || payload.error?.message || `Meta API request failed with status ${response.status}`;
28
+ throw new Error(message);
29
+ }
30
+ return await response.json();
31
+ }
32
+ export {
33
+ metaFetch
34
+ };
35
+ //# sourceMappingURL=meta-api.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/services/meta/meta-api.ts"],
4
+ "sourcesContent": ["import { createMetaAppSecretProof, getMetaConfig } from \"../../config/meta.js\";\n\ninterface MetaErrorPayload {\n error?: {\n message?: string;\n type?: string;\n code?: number;\n error_subcode?: number;\n error_user_title?: string;\n error_user_msg?: string;\n fbtrace_id?: string;\n };\n}\n\nexport interface MetaPagingCursor {\n before?: string;\n after?: string;\n}\n\nexport interface MetaPaging {\n cursors?: MetaPagingCursor;\n next?: string;\n previous?: string;\n}\n\nexport interface MetaListResponse<T> {\n data?: T[];\n paging?: MetaPaging;\n}\n\nfunction buildUrl(path: string, query: Record<string, string | number | undefined>): string {\n const config = getMetaConfig();\n const accessToken = config.accessToken;\n const appSecretProof = createMetaAppSecretProof(accessToken, config.appSecret);\n const normalizedPath = path.startsWith(\"/\") ? path : `/${path}`;\n const searchParams = new URLSearchParams();\n\n searchParams.set(\"access_token\", accessToken);\n searchParams.set(\"appsecret_proof\", appSecretProof);\n\n for (const [key, value] of Object.entries(query)) {\n if (value === undefined || value === null || value === \"\") {\n continue;\n }\n\n searchParams.set(key, String(value));\n }\n\n return `${config.baseUrl}${normalizedPath}?${searchParams.toString()}`;\n}\n\nexport async function metaFetch<T>(\n path: string,\n query: Record<string, string | number | undefined> = {}\n): Promise<T> {\n const response = await fetch(buildUrl(path, query), {\n method: \"GET\",\n headers: {\n Accept: \"application/json\",\n },\n });\n\n if (!response.ok) {\n const payload = (await response.json().catch(() => ({}))) as MetaErrorPayload;\n const message =\n payload.error?.error_user_msg ||\n payload.error?.error_user_title ||\n payload.error?.message ||\n `Meta API request failed with status ${response.status}`;\n\n throw new Error(message);\n }\n\n return (await response.json()) as T;\n}\n"],
5
+ "mappings": "AAAA,SAAS,0BAA0B,qBAAqB;AA8BxD,SAAS,SAAS,MAAc,OAA4D;AAC1F,QAAM,SAAS,cAAc;AAC7B,QAAM,cAAc,OAAO;AAC3B,QAAM,iBAAiB,yBAAyB,aAAa,OAAO,SAAS;AAC7E,QAAM,iBAAiB,KAAK,WAAW,GAAG,IAAI,OAAO,IAAI,IAAI;AAC7D,QAAM,eAAe,IAAI,gBAAgB;AAEzC,eAAa,IAAI,gBAAgB,WAAW;AAC5C,eAAa,IAAI,mBAAmB,cAAc;AAElD,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,KAAK,GAAG;AAChD,QAAI,UAAU,UAAa,UAAU,QAAQ,UAAU,IAAI;AACzD;AAAA,IACF;AAEA,iBAAa,IAAI,KAAK,OAAO,KAAK,CAAC;AAAA,EACrC;AAEA,SAAO,GAAG,OAAO,OAAO,GAAG,cAAc,IAAI,aAAa,SAAS,CAAC;AACtE;AAEA,eAAsB,UACpB,MACA,QAAqD,CAAC,GAC1C;AACZ,QAAM,WAAW,MAAM,MAAM,SAAS,MAAM,KAAK,GAAG;AAAA,IAClD,QAAQ;AAAA,IACR,SAAS;AAAA,MACP,QAAQ;AAAA,IACV;AAAA,EACF,CAAC;AAED,MAAI,CAAC,SAAS,IAAI;AAChB,UAAM,UAAW,MAAM,SAAS,KAAK,EAAE,MAAM,OAAO,CAAC,EAAE;AACvD,UAAM,UACJ,QAAQ,OAAO,kBACf,QAAQ,OAAO,oBACf,QAAQ,OAAO,WACf,uCAAuC,SAAS,MAAM;AAExD,UAAM,IAAI,MAAM,OAAO;AAAA,EACzB;AAEA,SAAQ,MAAM,SAAS,KAAK;AAC9B;",
6
+ "names": []
7
+ }
@@ -1,11 +1,11 @@
1
1
  import axios from "axios";
2
- import { vtexConfig } from "../../config/vtex.js";
3
- function createVtexClient(baseURL) {
2
+ import { getVtexConfigForProfile } from "../../config/vtex.js";
3
+ function createVtexClient(config, baseURL) {
4
4
  const client = axios.create({
5
5
  baseURL,
6
6
  headers: {
7
- "X-VTEX-API-AppKey": vtexConfig.apiKey,
8
- "X-VTEX-API-AppToken": vtexConfig.apiToken,
7
+ "X-VTEX-API-AppKey": config.apiKey,
8
+ "X-VTEX-API-AppToken": config.apiToken,
9
9
  Accept: "application/json",
10
10
  "Content-Type": "application/json"
11
11
  },
@@ -26,8 +26,23 @@ function createVtexClient(baseURL) {
26
26
  );
27
27
  return client;
28
28
  }
29
- const vtexApi = createVtexClient(vtexConfig.baseUrl);
30
- const vtexPricingApi = createVtexClient(vtexConfig.pricingBaseUrl);
29
+ async function getVtexApiClients(profileId) {
30
+ const config = await getVtexConfigForProfile(profileId);
31
+ return {
32
+ config,
33
+ vtexApi: createVtexClient(config, config.baseUrl),
34
+ vtexPricingApi: createVtexClient(config, config.pricingBaseUrl)
35
+ };
36
+ }
37
+ async function validateVtexConfig(config) {
38
+ const client = createVtexClient(config, config.baseUrl);
39
+ await client.get("/api/oms/pvt/orders", {
40
+ params: {
41
+ page: 1,
42
+ per_page: 1
43
+ }
44
+ });
45
+ }
31
46
  function formatVtexError(error, fallback = "Unexpected VTEX API error") {
32
47
  if (axios.isAxiosError(error)) {
33
48
  const status = error.response?.status;
@@ -44,8 +59,9 @@ function formatVtexError(error, fallback = "Unexpected VTEX API error") {
44
59
  return fallback;
45
60
  }
46
61
  export {
62
+ createVtexClient,
47
63
  formatVtexError,
48
- vtexApi,
49
- vtexPricingApi
64
+ getVtexApiClients,
65
+ validateVtexConfig
50
66
  };
51
67
  //# sourceMappingURL=vtex-api.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/services/vtex/vtex-api.ts"],
4
- "sourcesContent": ["import axios from \"axios\";\nimport type { AxiosError, AxiosInstance } from \"axios\";\n\nimport { vtexConfig } from \"../../config/vtex.js\";\n\nfunction createVtexClient(baseURL: string): AxiosInstance {\n const client = axios.create({\n baseURL,\n headers: {\n \"X-VTEX-API-AppKey\": vtexConfig.apiKey,\n \"X-VTEX-API-AppToken\": vtexConfig.apiToken,\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n },\n timeout: 30000,\n });\n\n client.interceptors.response.use(\n (response) => response,\n (error: AxiosError) => {\n const method = error.config?.method?.toUpperCase() ?? \"UNKNOWN\";\n const url = error.config?.url ?? \"UNKNOWN_URL\";\n const status = error.response?.status ?? \"NO_STATUS\";\n\n console.error(`[VTEX API ERROR] ${method} ${url} -> ${status}`);\n\n if (error.response?.data) {\n console.error(\"[VTEX API ERROR BODY]\", error.response.data);\n }\n\n return Promise.reject(error);\n }\n );\n\n return client;\n}\n\nexport const vtexApi = createVtexClient(vtexConfig.baseUrl);\nexport const vtexPricingApi = createVtexClient(vtexConfig.pricingBaseUrl);\n\nexport function formatVtexError(error: unknown, fallback = \"Unexpected VTEX API error\"): string {\n if (axios.isAxiosError(error)) {\n const status = error.response?.status;\n const responseData = error.response?.data;\n const responseMessage =\n typeof responseData === \"object\" && responseData !== null && \"message\" in responseData\n ? String((responseData as { message?: unknown }).message)\n : typeof responseData === \"string\"\n ? responseData\n : undefined;\n\n if (status) {\n return `VTEX API request failed (${status}): ${responseMessage ?? error.message}`;\n }\n\n return `VTEX API request failed: ${responseMessage ?? error.message}`;\n }\n\n if (error instanceof Error) {\n return error.message;\n }\n\n return fallback;\n}\n"],
5
- "mappings": "AAAA,OAAO,WAAW;AAGlB,SAAS,kBAAkB;AAE3B,SAAS,iBAAiB,SAAgC;AACxD,QAAM,SAAS,MAAM,OAAO;AAAA,IAC1B;AAAA,IACA,SAAS;AAAA,MACP,qBAAqB,WAAW;AAAA,MAChC,uBAAuB,WAAW;AAAA,MAClC,QAAQ;AAAA,MACR,gBAAgB;AAAA,IAClB;AAAA,IACA,SAAS;AAAA,EACX,CAAC;AAED,SAAO,aAAa,SAAS;AAAA,IAC3B,CAAC,aAAa;AAAA,IACd,CAAC,UAAsB;AACrB,YAAM,SAAS,MAAM,QAAQ,QAAQ,YAAY,KAAK;AACtD,YAAM,MAAM,MAAM,QAAQ,OAAO;AACjC,YAAM,SAAS,MAAM,UAAU,UAAU;AAEzC,cAAQ,MAAM,oBAAoB,MAAM,IAAI,GAAG,OAAO,MAAM,EAAE;AAE9D,UAAI,MAAM,UAAU,MAAM;AACxB,gBAAQ,MAAM,yBAAyB,MAAM,SAAS,IAAI;AAAA,MAC5D;AAEA,aAAO,QAAQ,OAAO,KAAK;AAAA,IAC7B;AAAA,EACF;AAEA,SAAO;AACT;AAEO,MAAM,UAAU,iBAAiB,WAAW,OAAO;AACnD,MAAM,iBAAiB,iBAAiB,WAAW,cAAc;AAEjE,SAAS,gBAAgB,OAAgB,WAAW,6BAAqC;AAC9F,MAAI,MAAM,aAAa,KAAK,GAAG;AAC7B,UAAM,SAAS,MAAM,UAAU;AAC/B,UAAM,eAAe,MAAM,UAAU;AACrC,UAAM,kBACJ,OAAO,iBAAiB,YAAY,iBAAiB,QAAQ,aAAa,eACtE,OAAQ,aAAuC,OAAO,IACtD,OAAO,iBAAiB,WACtB,eACA;AAER,QAAI,QAAQ;AACV,aAAO,4BAA4B,MAAM,MAAM,mBAAmB,MAAM,OAAO;AAAA,IACjF;AAEA,WAAO,4BAA4B,mBAAmB,MAAM,OAAO;AAAA,EACrE;AAEA,MAAI,iBAAiB,OAAO;AAC1B,WAAO,MAAM;AAAA,EACf;AAEA,SAAO;AACT;",
4
+ "sourcesContent": ["import axios from \"axios\";\nimport type { AxiosError, AxiosInstance } from \"axios\";\n\nimport { getVtexConfigForProfile, type VtexConfig } from \"../../config/vtex.js\";\n\nexport function createVtexClient(config: VtexConfig, baseURL: string): AxiosInstance {\n const client = axios.create({\n baseURL,\n headers: {\n \"X-VTEX-API-AppKey\": config.apiKey,\n \"X-VTEX-API-AppToken\": config.apiToken,\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n },\n timeout: 30000,\n });\n\n client.interceptors.response.use(\n (response) => response,\n (error: AxiosError) => {\n const method = error.config?.method?.toUpperCase() ?? \"UNKNOWN\";\n const url = error.config?.url ?? \"UNKNOWN_URL\";\n const status = error.response?.status ?? \"NO_STATUS\";\n\n console.error(`[VTEX API ERROR] ${method} ${url} -> ${status}`);\n\n if (error.response?.data) {\n console.error(\"[VTEX API ERROR BODY]\", error.response.data);\n }\n\n return Promise.reject(error);\n }\n );\n\n return client;\n}\n\nexport async function getVtexApiClients(profileId: string) {\n const config = await getVtexConfigForProfile(profileId);\n\n return {\n config,\n vtexApi: createVtexClient(config, config.baseUrl),\n vtexPricingApi: createVtexClient(config, config.pricingBaseUrl),\n };\n}\n\nexport async function validateVtexConfig(config: VtexConfig): Promise<void> {\n const client = createVtexClient(config, config.baseUrl);\n await client.get(\"/api/oms/pvt/orders\", {\n params: {\n page: 1,\n per_page: 1,\n },\n });\n}\n\nexport function formatVtexError(error: unknown, fallback = \"Unexpected VTEX API error\"): string {\n if (axios.isAxiosError(error)) {\n const status = error.response?.status;\n const responseData = error.response?.data;\n const responseMessage =\n typeof responseData === \"object\" && responseData !== null && \"message\" in responseData\n ? String((responseData as { message?: unknown }).message)\n : typeof responseData === \"string\"\n ? responseData\n : undefined;\n\n if (status) {\n return `VTEX API request failed (${status}): ${responseMessage ?? error.message}`;\n }\n\n return `VTEX API request failed: ${responseMessage ?? error.message}`;\n }\n\n if (error instanceof Error) {\n return error.message;\n }\n\n return fallback;\n}\n"],
5
+ "mappings": "AAAA,OAAO,WAAW;AAGlB,SAAS,+BAAgD;AAElD,SAAS,iBAAiB,QAAoB,SAAgC;AACnF,QAAM,SAAS,MAAM,OAAO;AAAA,IAC1B;AAAA,IACA,SAAS;AAAA,MACP,qBAAqB,OAAO;AAAA,MAC5B,uBAAuB,OAAO;AAAA,MAC9B,QAAQ;AAAA,MACR,gBAAgB;AAAA,IAClB;AAAA,IACA,SAAS;AAAA,EACX,CAAC;AAED,SAAO,aAAa,SAAS;AAAA,IAC3B,CAAC,aAAa;AAAA,IACd,CAAC,UAAsB;AACrB,YAAM,SAAS,MAAM,QAAQ,QAAQ,YAAY,KAAK;AACtD,YAAM,MAAM,MAAM,QAAQ,OAAO;AACjC,YAAM,SAAS,MAAM,UAAU,UAAU;AAEzC,cAAQ,MAAM,oBAAoB,MAAM,IAAI,GAAG,OAAO,MAAM,EAAE;AAE9D,UAAI,MAAM,UAAU,MAAM;AACxB,gBAAQ,MAAM,yBAAyB,MAAM,SAAS,IAAI;AAAA,MAC5D;AAEA,aAAO,QAAQ,OAAO,KAAK;AAAA,IAC7B;AAAA,EACF;AAEA,SAAO;AACT;AAEA,eAAsB,kBAAkB,WAAmB;AACzD,QAAM,SAAS,MAAM,wBAAwB,SAAS;AAEtD,SAAO;AAAA,IACL;AAAA,IACA,SAAS,iBAAiB,QAAQ,OAAO,OAAO;AAAA,IAChD,gBAAgB,iBAAiB,QAAQ,OAAO,cAAc;AAAA,EAChE;AACF;AAEA,eAAsB,mBAAmB,QAAmC;AAC1E,QAAM,SAAS,iBAAiB,QAAQ,OAAO,OAAO;AACtD,QAAM,OAAO,IAAI,uBAAuB;AAAA,IACtC,QAAQ;AAAA,MACN,MAAM;AAAA,MACN,UAAU;AAAA,IACZ;AAAA,EACF,CAAC;AACH;AAEO,SAAS,gBAAgB,OAAgB,WAAW,6BAAqC;AAC9F,MAAI,MAAM,aAAa,KAAK,GAAG;AAC7B,UAAM,SAAS,MAAM,UAAU;AAC/B,UAAM,eAAe,MAAM,UAAU;AACrC,UAAM,kBACJ,OAAO,iBAAiB,YAAY,iBAAiB,QAAQ,aAAa,eACtE,OAAQ,aAAuC,OAAO,IACtD,OAAO,iBAAiB,WACtB,eACA;AAER,QAAI,QAAQ;AACV,aAAO,4BAA4B,MAAM,MAAM,mBAAmB,MAAM,OAAO;AAAA,IACjF;AAEA,WAAO,4BAA4B,mBAAmB,MAAM,OAAO;AAAA,EACrE;AAEA,MAAI,iBAAiB,OAAO;AAC1B,WAAO,MAAM;AAAA,EACf;AAEA,SAAO;AACT;",
6
6
  "names": []
7
7
  }
@@ -1,11 +1,13 @@
1
- import { vtexApi } from "./vtex-api.js";
2
- async function getProductOffers(productId) {
1
+ import { getVtexApiClients } from "./vtex-api.js";
2
+ async function getProductOffers(profileId, productId) {
3
+ const { vtexApi } = await getVtexApiClients(profileId);
3
4
  const response = await vtexApi.get(
4
5
  `/api/catalog_system/pub/products/offers/${productId}`
5
6
  );
6
7
  return response.data;
7
8
  }
8
- async function getSkuOffers(productId, skuId) {
9
+ async function getSkuOffers(profileId, productId, skuId) {
10
+ const { vtexApi } = await getVtexApiClients(profileId);
9
11
  const response = await vtexApi.get(
10
12
  `/api/catalog_system/pub/products/offers/${productId}/sku/${skuId}`
11
13
  );
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/services/vtex/vtex-catalog.ts"],
4
- "sourcesContent": ["import { vtexApi } from \"./vtex-api.js\";\n\nexport type ProductOffersResponse = Record<string, unknown>[];\n\nexport async function getProductOffers(productId: string): Promise<ProductOffersResponse> {\n const response = await vtexApi.get<ProductOffersResponse>(\n `/api/catalog_system/pub/products/offers/${productId}`\n );\n\n return response.data;\n}\n\nexport async function getSkuOffers(productId: string, skuId: string): Promise<ProductOffersResponse> {\n const response = await vtexApi.get<ProductOffersResponse>(\n `/api/catalog_system/pub/products/offers/${productId}/sku/${skuId}`\n );\n\n return response.data;\n}\n"],
5
- "mappings": "AAAA,SAAS,eAAe;AAIxB,eAAsB,iBAAiB,WAAmD;AACxF,QAAM,WAAW,MAAM,QAAQ;AAAA,IAC7B,2CAA2C,SAAS;AAAA,EACtD;AAEA,SAAO,SAAS;AAClB;AAEA,eAAsB,aAAa,WAAmB,OAA+C;AACnG,QAAM,WAAW,MAAM,QAAQ;AAAA,IAC7B,2CAA2C,SAAS,QAAQ,KAAK;AAAA,EACnE;AAEA,SAAO,SAAS;AAClB;",
4
+ "sourcesContent": ["import { getVtexApiClients } from \"./vtex-api.js\";\n\nexport type ProductOffersResponse = Record<string, unknown>[];\n\nexport async function getProductOffers(\n profileId: string,\n productId: string\n): Promise<ProductOffersResponse> {\n const { vtexApi } = await getVtexApiClients(profileId);\n const response = await vtexApi.get<ProductOffersResponse>(\n `/api/catalog_system/pub/products/offers/${productId}`\n );\n\n return response.data;\n}\n\nexport async function getSkuOffers(\n profileId: string,\n productId: string,\n skuId: string\n): Promise<ProductOffersResponse> {\n const { vtexApi } = await getVtexApiClients(profileId);\n const response = await vtexApi.get<ProductOffersResponse>(\n `/api/catalog_system/pub/products/offers/${productId}/sku/${skuId}`\n );\n\n return response.data;\n}\n"],
5
+ "mappings": "AAAA,SAAS,yBAAyB;AAIlC,eAAsB,iBACpB,WACA,WACgC;AAChC,QAAM,EAAE,QAAQ,IAAI,MAAM,kBAAkB,SAAS;AACrD,QAAM,WAAW,MAAM,QAAQ;AAAA,IAC7B,2CAA2C,SAAS;AAAA,EACtD;AAEA,SAAO,SAAS;AAClB;AAEA,eAAsB,aACpB,WACA,WACA,OACgC;AAChC,QAAM,EAAE,QAAQ,IAAI,MAAM,kBAAkB,SAAS;AACrD,QAAM,WAAW,MAAM,QAAQ;AAAA,IAC7B,2CAA2C,SAAS,QAAQ,KAAK;AAAA,EACnE;AAEA,SAAO,SAAS;AAClB;",
6
6
  "names": []
7
7
  }
@@ -1,10 +1,15 @@
1
1
  import axios from "axios";
2
- import { vtexApi } from "./vtex-api.js";
2
+ import { getVtexApiClients } from "./vtex-api.js";
3
3
  const RETRYABLE_STATUS_CODES = /* @__PURE__ */ new Set([408, 429, 500, 502, 503, 504]);
4
4
  const DEFAULT_BATCH_CONCURRENCY = 10;
5
5
  const DEFAULT_MAX_RETRIES = 2;
6
6
  const DEFAULT_BASE_RETRY_DELAY_MS = 250;
7
- async function getInventoryBySku(skuId) {
7
+ async function getInventoryBySku(profileId, skuId) {
8
+ const { vtexApi } = await getVtexApiClients(profileId);
9
+ const response = await vtexApi.get(`/api/logistics/pvt/inventory/skus/${skuId}`);
10
+ return response.data;
11
+ }
12
+ async function getInventoryBySkuWithClient(vtexApi, skuId) {
8
13
  const response = await vtexApi.get(`/api/logistics/pvt/inventory/skus/${skuId}`);
9
14
  return response.data;
10
15
  }
@@ -67,7 +72,7 @@ function isInventoryFetchError(error) {
67
72
  }
68
73
  return "skuId" in error && "attempts" in error && "retryable" in error && typeof error.skuId === "string";
69
74
  }
70
- async function getInventoryBySkuWithRetry(skuId, options) {
75
+ async function getInventoryBySkuWithRetry(vtexApi, skuId, options) {
71
76
  const maxRetries = Math.max(0, Math.floor(options.maxRetries ?? DEFAULT_MAX_RETRIES));
72
77
  const baseRetryDelayMs = Math.max(
73
78
  50,
@@ -77,7 +82,7 @@ async function getInventoryBySkuWithRetry(skuId, options) {
77
82
  while (true) {
78
83
  attempts += 1;
79
84
  try {
80
- const document = await getInventoryBySku(skuId);
85
+ const document = await getInventoryBySkuWithClient(vtexApi, skuId);
81
86
  return { skuId, document };
82
87
  } catch (error) {
83
88
  const retryable = isRetryableRequestError(error);
@@ -91,7 +96,8 @@ async function getInventoryBySkuWithRetry(skuId, options) {
91
96
  }
92
97
  }
93
98
  }
94
- async function getInventoryBySkuBatch(skuIds, options = {}) {
99
+ async function getInventoryBySkuBatch(profileId, skuIds, options = {}) {
100
+ const { vtexApi } = await getVtexApiClients(profileId);
95
101
  const maxConcurrency = Math.max(
96
102
  1,
97
103
  Math.floor(options.maxConcurrency ?? DEFAULT_BATCH_CONCURRENCY)
@@ -101,7 +107,7 @@ async function getInventoryBySkuBatch(skuIds, options = {}) {
101
107
  for (let start = 0; start < skuIds.length; start += maxConcurrency) {
102
108
  const chunk = skuIds.slice(start, start + maxConcurrency);
103
109
  const settledChunk = await Promise.allSettled(
104
- chunk.map((skuId) => getInventoryBySkuWithRetry(skuId, options))
110
+ chunk.map((skuId) => getInventoryBySkuWithRetry(vtexApi, skuId, options))
105
111
  );
106
112
  settledChunk.forEach((result, index) => {
107
113
  const skuId = chunk[index];
@@ -129,16 +135,19 @@ async function getInventoryBySkuBatch(skuIds, options = {}) {
129
135
  }
130
136
  return { successful, failed };
131
137
  }
132
- async function getInventoryByWarehouse(skuId, warehouseId) {
138
+ async function getInventoryByWarehouse(profileId, skuId, warehouseId) {
139
+ const { vtexApi } = await getVtexApiClients(profileId);
133
140
  const response = await vtexApi.get(
134
141
  `/api/logistics/pvt/inventory/items/${skuId}/warehouses/${warehouseId}`
135
142
  );
136
143
  return response.data;
137
144
  }
138
- async function updateInventoryQuantity(skuId, warehouseId, payload) {
145
+ async function updateInventoryQuantity(profileId, skuId, warehouseId, payload) {
146
+ const { vtexApi } = await getVtexApiClients(profileId);
139
147
  await vtexApi.patch(`/api/logistics/pvt/inventory/skus/${skuId}/warehouses/${warehouseId}/quantity`, payload);
140
148
  }
141
- async function updateInventoryLeadTime(skuId, warehouseId, payload) {
149
+ async function updateInventoryLeadTime(profileId, skuId, warehouseId, payload) {
150
+ const { vtexApi } = await getVtexApiClients(profileId);
142
151
  await vtexApi.patch(`/api/logistics/pvt/inventory/skus/${skuId}/warehouses/${warehouseId}/lead-time`, payload);
143
152
  }
144
153
  export {