@yoryoboy/bi-mcp 1.1.0 → 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.
- package/README.md +126 -9
- package/dist/.tsbuildinfo +1 -1
- package/dist/index.js +30 -0
- package/dist/index.js.map +2 -2
- package/dist/mcp-use.json +2 -2
- package/dist/scripts/_helpers.js +44 -0
- package/dist/scripts/_helpers.js.map +7 -0
- package/dist/scripts/admin-profile-delete.js +72 -0
- package/dist/scripts/admin-profile-delete.js.map +7 -0
- package/dist/scripts/admin-profile-list.js +24 -0
- package/dist/scripts/admin-profile-list.js.map +7 -0
- package/dist/scripts/admin-profile-upsert.js +25 -0
- package/dist/scripts/admin-profile-upsert.js.map +7 -0
- package/dist/scripts/admin-vtex-list.js +28 -0
- package/dist/scripts/admin-vtex-list.js.map +7 -0
- package/dist/scripts/admin-vtex-upsert.js +73 -0
- package/dist/scripts/admin-vtex-upsert.js.map +7 -0
- package/dist/scripts/admin-vtex-validate.js +55 -0
- package/dist/scripts/admin-vtex-validate.js.map +7 -0
- package/dist/scripts/run-migrations.js +50 -0
- package/dist/scripts/run-migrations.js.map +7 -0
- package/dist/scripts/test-db-connection.js +19 -0
- package/dist/scripts/test-db-connection.js.map +7 -0
- package/dist/src/config/profile-store.js +86 -0
- package/dist/src/config/profile-store.js.map +7 -0
- package/dist/src/config/vtex-crypto.js +43 -0
- package/dist/src/config/vtex-crypto.js.map +7 -0
- package/dist/src/config/vtex-profile-store.js +132 -0
- package/dist/src/config/vtex-profile-store.js.map +7 -0
- package/dist/src/config/vtex.js +27 -21
- package/dist/src/config/vtex.js.map +2 -2
- package/dist/src/db/client.js +58 -0
- package/dist/src/db/client.js.map +7 -0
- package/dist/src/services/vtex/vtex-api.js +24 -8
- package/dist/src/services/vtex/vtex-api.js.map +2 -2
- package/dist/src/services/vtex/vtex-catalog.js +5 -3
- package/dist/src/services/vtex/vtex-catalog.js.map +2 -2
- package/dist/src/services/vtex/vtex-logistics.js +18 -9
- package/dist/src/services/vtex/vtex-logistics.js.map +2 -2
- package/dist/src/services/vtex/vtex-orders.js +13 -7
- package/dist/src/services/vtex/vtex-orders.js.map +2 -2
- package/dist/src/services/vtex/vtex-pricing.js +5 -3
- package/dist/src/services/vtex/vtex-pricing.js.map +2 -2
- package/dist/src/tools/config/check-database-connection.js +59 -0
- package/dist/src/tools/config/check-database-connection.js.map +7 -0
- package/dist/src/tools/config/index.js +3 -0
- package/dist/src/tools/config/index.js.map +7 -0
- package/dist/src/tools/config/list-profiles.js +26 -0
- package/dist/src/tools/config/list-profiles.js.map +7 -0
- package/dist/src/tools/index.js +1 -0
- package/dist/src/tools/index.js.map +2 -2
- package/dist/src/tools/vtex/computed-price.js +12 -1
- package/dist/src/tools/vtex/computed-price.js.map +2 -2
- package/dist/src/tools/vtex/index.js +1 -0
- package/dist/src/tools/vtex/index.js.map +2 -2
- package/dist/src/tools/vtex/inventory-check.js +15 -2
- package/dist/src/tools/vtex/inventory-check.js.map +2 -2
- package/dist/src/tools/vtex/order-details.js +16 -2
- package/dist/src/tools/vtex/order-details.js.map +2 -2
- package/dist/src/tools/vtex/orders-summary.js +11 -1
- package/dist/src/tools/vtex/orders-summary.js.map +2 -2
- package/dist/src/tools/vtex/product-offers.js +15 -2
- package/dist/src/tools/vtex/product-offers.js.map +2 -2
- package/dist/src/tools/vtex/profile-resolution.js +57 -0
- package/dist/src/tools/vtex/profile-resolution.js.map +7 -0
- package/dist/src/tools/vtex/sku-offers.js +16 -2
- package/dist/src/tools/vtex/sku-offers.js.map +2 -2
- package/dist/src/tools/vtex/sku-price.js +12 -2
- package/dist/src/tools/vtex/sku-price.js.map +2 -2
- package/dist/src/tools/vtex/update-inventory.js +12 -1
- package/dist/src/tools/vtex/update-inventory.js.map +2 -2
- package/dist/src/tools/vtex/update-lead-time.js +12 -1
- package/dist/src/tools/vtex/update-lead-time.js.map +2 -2
- package/dist/src/tools/vtex/warehouse-inventory.js +12 -1
- package/dist/src/tools/vtex/warehouse-inventory.js.map +2 -2
- package/package.json +12 -2
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import axios from "axios";
|
|
2
|
-
import {
|
|
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":
|
|
8
|
-
"X-VTEX-API-AppToken":
|
|
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
|
-
|
|
30
|
-
const
|
|
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
|
-
|
|
49
|
-
|
|
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 {
|
|
5
|
-
"mappings": "AAAA,OAAO,WAAW;AAGlB,SAAS
|
|
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 {
|
|
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 {
|
|
5
|
-
"mappings": "AAAA,SAAS,
|
|
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 {
|
|
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
|
|
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 {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/services/vtex/vtex-logistics.ts"],
|
|
4
|
-
"sourcesContent": ["import axios from \"axios\";\nimport {
|
|
5
|
-
"mappings": "AAAA,OAAO,WAAW;
|
|
4
|
+
"sourcesContent": ["import axios from \"axios\";\nimport type { AxiosInstance } from \"axios\";\n\nimport { getVtexApiClients } from \"./vtex-api.js\";\n\nexport interface WarehouseBalance {\n warehouseId?: string;\n warehouseName?: string;\n totalQuantity?: number;\n reservedQuantity?: number;\n availableQuantity?: number;\n isUnlimited?: boolean;\n hasUnlimitedQuantity?: boolean;\n timeToRefill?: string;\n dateOfSupplyUtc?: string;\n leadTime?: string;\n}\n\nexport interface InventoryBySkuResponse {\n skuId?: string;\n balance?: WarehouseBalance[];\n}\n\nexport interface InventoryByWarehouseItem {\n skuId?: string;\n warehouseId?: string;\n totalQuantity?: number;\n reservedQuantity?: number;\n availableQuantity?: number;\n isUnlimited?: boolean;\n keepSellingAfterExpiration?: boolean;\n}\n\nexport interface UpdateInventoryQuantityPayload {\n quantity: number;\n unlimitedQuantity: boolean;\n dateUtcOnBalanceSystem?: string;\n}\n\nexport interface UpdateLeadTimePayload {\n leadTime: string;\n}\n\nexport interface GetInventoryBatchOptions {\n maxConcurrency?: number;\n maxRetries?: number;\n baseRetryDelayMs?: number;\n}\n\nexport interface InventoryBatchSuccess {\n skuId: string;\n document: InventoryBySkuResponse;\n}\n\nexport interface InventoryBatchFailure {\n skuId: string;\n message: string;\n statusCode?: number;\n attempts: number;\n retryable: boolean;\n}\n\nexport interface InventoryBatchResult {\n successful: InventoryBatchSuccess[];\n failed: InventoryBatchFailure[];\n}\n\ninterface InventoryFetchError extends Error {\n skuId: string;\n statusCode?: number;\n attempts: number;\n retryable: boolean;\n}\n\nconst RETRYABLE_STATUS_CODES = new Set([408, 429, 500, 502, 503, 504]);\nconst DEFAULT_BATCH_CONCURRENCY = 10;\nconst DEFAULT_MAX_RETRIES = 2;\nconst DEFAULT_BASE_RETRY_DELAY_MS = 250;\n\nexport async function getInventoryBySku(\n profileId: string,\n skuId: string\n): Promise<InventoryBySkuResponse> {\n const { vtexApi } = await getVtexApiClients(profileId);\n const response = await vtexApi.get<InventoryBySkuResponse>(`/api/logistics/pvt/inventory/skus/${skuId}`);\n return response.data;\n}\n\nasync function getInventoryBySkuWithClient(\n vtexApi: AxiosInstance,\n skuId: string\n): Promise<InventoryBySkuResponse> {\n const response = await vtexApi.get<InventoryBySkuResponse>(`/api/logistics/pvt/inventory/skus/${skuId}`);\n return response.data;\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => {\n setTimeout(resolve, ms);\n });\n}\n\nfunction parseRetryAfterMs(headerValue: unknown): number | undefined {\n if (Array.isArray(headerValue)) {\n return parseRetryAfterMs(headerValue[0]);\n }\n\n if (typeof headerValue === \"number\" && Number.isFinite(headerValue)) {\n return Math.max(0, Math.floor(headerValue * 1000));\n }\n\n if (typeof headerValue !== \"string\") {\n return undefined;\n }\n\n const trimmedValue = headerValue.trim();\n if (!trimmedValue) {\n return undefined;\n }\n\n const seconds = Number(trimmedValue);\n if (Number.isFinite(seconds)) {\n return Math.max(0, Math.floor(seconds * 1000));\n }\n\n const absoluteDateMs = Date.parse(trimmedValue);\n if (Number.isNaN(absoluteDateMs)) {\n return undefined;\n }\n\n return Math.max(0, absoluteDateMs - Date.now());\n}\n\nfunction computeBackoffDelayMs(attempt: number, baseDelayMs: number): number {\n const exponential = baseDelayMs * 2 ** Math.max(0, attempt - 1);\n const jitter = Math.floor(Math.random() * 150);\n return exponential + jitter;\n}\n\nfunction isRetryableRequestError(error: unknown): boolean {\n if (!axios.isAxiosError(error)) {\n return false;\n }\n\n if (!error.response?.status) {\n return true;\n }\n\n return RETRYABLE_STATUS_CODES.has(error.response.status);\n}\n\nfunction toInventoryFetchError(\n skuId: string,\n source: unknown,\n attempts: number,\n retryable: boolean\n): InventoryFetchError {\n const statusCode = axios.isAxiosError(source) ? source.response?.status : undefined;\n const message =\n source instanceof Error\n ? source.message\n : typeof source === \"string\"\n ? source\n : \"Unexpected error while fetching inventory details\";\n\n const error = new Error(message) as InventoryFetchError;\n error.skuId = skuId;\n error.statusCode = statusCode;\n error.attempts = attempts;\n error.retryable = retryable;\n return error;\n}\n\nfunction isInventoryFetchError(error: unknown): error is InventoryFetchError {\n if (!(error instanceof Error)) {\n return false;\n }\n\n return (\n \"skuId\" in error &&\n \"attempts\" in error &&\n \"retryable\" in error &&\n typeof (error as Partial<InventoryFetchError>).skuId === \"string\"\n );\n}\n\nasync function getInventoryBySkuWithRetry(\n vtexApi: AxiosInstance,\n skuId: string,\n options: GetInventoryBatchOptions\n): Promise<InventoryBatchSuccess> {\n const maxRetries = Math.max(0, Math.floor(options.maxRetries ?? DEFAULT_MAX_RETRIES));\n const baseRetryDelayMs = Math.max(\n 50,\n Math.floor(options.baseRetryDelayMs ?? DEFAULT_BASE_RETRY_DELAY_MS)\n );\n let attempts = 0;\n\n while (true) {\n attempts += 1;\n\n try {\n const document = await getInventoryBySkuWithClient(vtexApi, skuId);\n return { skuId, document };\n } catch (error) {\n const retryable = isRetryableRequestError(error);\n\n if (!retryable || attempts > maxRetries) {\n throw toInventoryFetchError(skuId, error, attempts, retryable);\n }\n\n const retryAfterHeader = axios.isAxiosError(error)\n ? error.response?.headers?.[\"retry-after\"]\n : undefined;\n const retryAfterMs = parseRetryAfterMs(retryAfterHeader);\n const delayMs = retryAfterMs ?? computeBackoffDelayMs(attempts, baseRetryDelayMs);\n await sleep(delayMs);\n }\n }\n}\n\nexport async function getInventoryBySkuBatch(\n profileId: string,\n skuIds: string[],\n options: GetInventoryBatchOptions = {}\n): Promise<InventoryBatchResult> {\n const { vtexApi } = await getVtexApiClients(profileId);\n const maxConcurrency = Math.max(\n 1,\n Math.floor(options.maxConcurrency ?? DEFAULT_BATCH_CONCURRENCY)\n );\n const successful: InventoryBatchSuccess[] = [];\n const failed: InventoryBatchFailure[] = [];\n\n for (let start = 0; start < skuIds.length; start += maxConcurrency) {\n const chunk = skuIds.slice(start, start + maxConcurrency);\n const settledChunk = await Promise.allSettled(\n chunk.map((skuId) => getInventoryBySkuWithRetry(vtexApi, skuId, options))\n );\n\n settledChunk.forEach((result, index) => {\n const skuId = chunk[index];\n\n if (result.status === \"fulfilled\") {\n successful.push(result.value);\n return;\n }\n\n if (isInventoryFetchError(result.reason)) {\n failed.push({\n skuId: result.reason.skuId,\n message: result.reason.message,\n statusCode: result.reason.statusCode,\n attempts: result.reason.attempts,\n retryable: result.reason.retryable,\n });\n return;\n }\n\n failed.push({\n skuId,\n message:\n result.reason instanceof Error\n ? result.reason.message\n : \"Unexpected error while fetching inventory details\",\n attempts: 1,\n retryable: false,\n });\n });\n }\n\n return { successful, failed };\n}\n\nexport async function getInventoryByWarehouse(\n profileId: string,\n skuId: string,\n warehouseId: string\n): Promise<InventoryByWarehouseItem[]> {\n const { vtexApi } = await getVtexApiClients(profileId);\n const response = await vtexApi.get<InventoryByWarehouseItem[]>(\n `/api/logistics/pvt/inventory/items/${skuId}/warehouses/${warehouseId}`\n );\n return response.data;\n}\n\nexport async function updateInventoryQuantity(\n profileId: string,\n skuId: string,\n warehouseId: string,\n payload: UpdateInventoryQuantityPayload\n): Promise<void> {\n const { vtexApi } = await getVtexApiClients(profileId);\n await vtexApi.patch(`/api/logistics/pvt/inventory/skus/${skuId}/warehouses/${warehouseId}/quantity`, payload);\n}\n\nexport async function updateInventoryLeadTime(\n profileId: string,\n skuId: string,\n warehouseId: string,\n payload: UpdateLeadTimePayload\n): Promise<void> {\n const { vtexApi } = await getVtexApiClients(profileId);\n await vtexApi.patch(`/api/logistics/pvt/inventory/skus/${skuId}/warehouses/${warehouseId}/lead-time`, payload);\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import axios from "axios";
|
|
2
|
-
import {
|
|
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 listOrders(params) {
|
|
7
|
+
async function listOrders(profileId, params) {
|
|
8
|
+
const { vtexApi } = await getVtexApiClients(profileId);
|
|
8
9
|
const response = await vtexApi.get("/api/oms/pvt/orders", { params });
|
|
9
10
|
return response.data;
|
|
10
11
|
}
|
|
11
|
-
async function getOrderDocument(orderId, reason) {
|
|
12
|
+
async function getOrderDocument(profileId, orderId, reason) {
|
|
13
|
+
const { vtexApi } = await getVtexApiClients(profileId);
|
|
12
14
|
const response = await vtexApi.get(`/api/orders/pvt/document/${orderId}`, {
|
|
13
15
|
params: reason ? { reason } : void 0
|
|
14
16
|
});
|
|
@@ -73,7 +75,7 @@ function isOrderDocumentFetchError(error) {
|
|
|
73
75
|
}
|
|
74
76
|
return "orderId" in error && "attempts" in error && "retryable" in error && typeof error.orderId === "string";
|
|
75
77
|
}
|
|
76
|
-
async function getOrderDocumentWithRetry(orderId, options) {
|
|
78
|
+
async function getOrderDocumentWithRetry(vtexApi, orderId, options) {
|
|
77
79
|
const maxRetries = Math.max(0, Math.floor(options.maxRetries ?? DEFAULT_MAX_RETRIES));
|
|
78
80
|
const baseRetryDelayMs = Math.max(
|
|
79
81
|
50,
|
|
@@ -83,7 +85,10 @@ async function getOrderDocumentWithRetry(orderId, options) {
|
|
|
83
85
|
while (true) {
|
|
84
86
|
attempts += 1;
|
|
85
87
|
try {
|
|
86
|
-
const
|
|
88
|
+
const response = await vtexApi.get(`/api/orders/pvt/document/${orderId}`, {
|
|
89
|
+
params: options.reason ? { reason: options.reason } : void 0
|
|
90
|
+
});
|
|
91
|
+
const document = response.data;
|
|
87
92
|
return { orderId, document };
|
|
88
93
|
} catch (error) {
|
|
89
94
|
const retryable = isRetryableRequestError(error);
|
|
@@ -97,7 +102,8 @@ async function getOrderDocumentWithRetry(orderId, options) {
|
|
|
97
102
|
}
|
|
98
103
|
}
|
|
99
104
|
}
|
|
100
|
-
async function getOrderDocumentsBatch(orderIds, options = {}) {
|
|
105
|
+
async function getOrderDocumentsBatch(profileId, orderIds, options = {}) {
|
|
106
|
+
const { vtexApi } = await getVtexApiClients(profileId);
|
|
101
107
|
const maxConcurrency = Math.max(
|
|
102
108
|
1,
|
|
103
109
|
Math.floor(options.maxConcurrency ?? DEFAULT_BATCH_CONCURRENCY)
|
|
@@ -107,7 +113,7 @@ async function getOrderDocumentsBatch(orderIds, options = {}) {
|
|
|
107
113
|
for (let start = 0; start < orderIds.length; start += maxConcurrency) {
|
|
108
114
|
const chunk = orderIds.slice(start, start + maxConcurrency);
|
|
109
115
|
const settledChunk = await Promise.allSettled(
|
|
110
|
-
chunk.map((orderId) => getOrderDocumentWithRetry(orderId, options))
|
|
116
|
+
chunk.map((orderId) => getOrderDocumentWithRetry(vtexApi, orderId, options))
|
|
111
117
|
);
|
|
112
118
|
settledChunk.forEach((result, index) => {
|
|
113
119
|
const orderId = chunk[index];
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/services/vtex/vtex-orders.ts"],
|
|
4
|
-
"sourcesContent": ["import axios from \"axios\";\nimport {
|
|
5
|
-
"mappings": "AAAA,OAAO,WAAW;
|
|
4
|
+
"sourcesContent": ["import axios from \"axios\";\nimport type { AxiosInstance } from \"axios\";\n\nimport { getVtexApiClients } from \"./vtex-api.js\";\n\nexport interface VtexOrderListItem {\n orderId: string;\n creationDate?: string;\n status?: string;\n totalValue?: number;\n currencyCode?: string;\n paymentNames?: string;\n salesChannel?: string;\n origin?: string;\n totalItems?: number;\n lastChange?: string;\n orderIsComplete?: boolean;\n authorizedDate?: string;\n paymentApprovedDate?: string;\n readyForHandlingDate?: string;\n}\n\nexport interface VtexOrdersPaging {\n total?: number;\n pages?: number;\n currentPage?: number;\n perPage?: number;\n}\n\nexport interface VtexOrdersListResponse {\n list: VtexOrderListItem[];\n paging: VtexOrdersPaging;\n stats?: unknown;\n}\n\nexport interface ListOrdersParams {\n page?: number;\n per_page?: number;\n orderBy?: string;\n f_creationDate?: string;\n f_invoicedDate?: string;\n f_status?: string;\n f_salesChannel?: string;\n f_paymentNames?: string;\n f_UtmSource?: string;\n q?: string;\n}\n\nexport interface GetOrderDocumentsBatchOptions {\n reason?: string;\n maxConcurrency?: number;\n maxRetries?: number;\n baseRetryDelayMs?: number;\n}\n\nexport interface OrderDocumentSuccess {\n orderId: string;\n document: Record<string, unknown>;\n}\n\nexport interface OrderDocumentFailure {\n orderId: string;\n message: string;\n statusCode?: number;\n attempts: number;\n retryable: boolean;\n}\n\nexport interface OrderDocumentsBatchResult {\n successful: OrderDocumentSuccess[];\n failed: OrderDocumentFailure[];\n}\n\nconst RETRYABLE_STATUS_CODES = new Set([408, 429, 500, 502, 503, 504]);\nconst DEFAULT_BATCH_CONCURRENCY = 10;\nconst DEFAULT_MAX_RETRIES = 2;\nconst DEFAULT_BASE_RETRY_DELAY_MS = 250;\n\nexport async function listOrders(\n profileId: string,\n params: ListOrdersParams\n): Promise<VtexOrdersListResponse> {\n const { vtexApi } = await getVtexApiClients(profileId);\n const response = await vtexApi.get<VtexOrdersListResponse>(\"/api/oms/pvt/orders\", { params });\n return response.data;\n}\n\nexport async function getOrderDocument(\n profileId: string,\n orderId: string,\n reason?: string\n): Promise<Record<string, unknown>> {\n const { vtexApi } = await getVtexApiClients(profileId);\n const response = await vtexApi.get<Record<string, unknown>>(`/api/orders/pvt/document/${orderId}`, {\n params: reason ? { reason } : undefined,\n });\n\n return response.data;\n}\n\ninterface OrderDocumentFetchError extends Error {\n orderId: string;\n statusCode?: number;\n attempts: number;\n retryable: boolean;\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => {\n setTimeout(resolve, ms);\n });\n}\n\nfunction parseRetryAfterMs(headerValue: unknown): number | undefined {\n if (Array.isArray(headerValue)) {\n return parseRetryAfterMs(headerValue[0]);\n }\n\n if (typeof headerValue === \"number\" && Number.isFinite(headerValue)) {\n return Math.max(0, Math.floor(headerValue * 1000));\n }\n\n if (typeof headerValue !== \"string\") {\n return undefined;\n }\n\n const trimmedValue = headerValue.trim();\n if (!trimmedValue) {\n return undefined;\n }\n\n const seconds = Number(trimmedValue);\n if (Number.isFinite(seconds)) {\n return Math.max(0, Math.floor(seconds * 1000));\n }\n\n const absoluteDateMs = Date.parse(trimmedValue);\n if (Number.isNaN(absoluteDateMs)) {\n return undefined;\n }\n\n return Math.max(0, absoluteDateMs - Date.now());\n}\n\nfunction computeBackoffDelayMs(attempt: number, baseDelayMs: number): number {\n const exponential = baseDelayMs * 2 ** Math.max(0, attempt - 1);\n const jitter = Math.floor(Math.random() * 150);\n return exponential + jitter;\n}\n\nfunction isRetryableRequestError(error: unknown): boolean {\n if (!axios.isAxiosError(error)) {\n return false;\n }\n\n if (!error.response?.status) {\n return true;\n }\n\n return RETRYABLE_STATUS_CODES.has(error.response.status);\n}\n\nfunction toOrderDocumentFetchError(\n orderId: string,\n source: unknown,\n attempts: number,\n retryable: boolean\n): OrderDocumentFetchError {\n const statusCode = axios.isAxiosError(source) ? source.response?.status : undefined;\n const message =\n source instanceof Error\n ? source.message\n : typeof source === \"string\"\n ? source\n : \"Unexpected error while fetching order details\";\n\n const error = new Error(message) as OrderDocumentFetchError;\n error.orderId = orderId;\n error.statusCode = statusCode;\n error.attempts = attempts;\n error.retryable = retryable;\n return error;\n}\n\nfunction isOrderDocumentFetchError(error: unknown): error is OrderDocumentFetchError {\n if (!(error instanceof Error)) {\n return false;\n }\n\n return (\n \"orderId\" in error &&\n \"attempts\" in error &&\n \"retryable\" in error &&\n typeof (error as Partial<OrderDocumentFetchError>).orderId === \"string\"\n );\n}\n\nasync function getOrderDocumentWithRetry(\n vtexApi: AxiosInstance,\n orderId: string,\n options: GetOrderDocumentsBatchOptions\n): Promise<OrderDocumentSuccess> {\n const maxRetries = Math.max(0, Math.floor(options.maxRetries ?? DEFAULT_MAX_RETRIES));\n const baseRetryDelayMs = Math.max(\n 50,\n Math.floor(options.baseRetryDelayMs ?? DEFAULT_BASE_RETRY_DELAY_MS)\n );\n let attempts = 0;\n\n while (true) {\n attempts += 1;\n\n try {\n const response = await vtexApi.get<Record<string, unknown>>(`/api/orders/pvt/document/${orderId}`, {\n params: options.reason ? { reason: options.reason } : undefined,\n });\n const document = response.data;\n return { orderId, document };\n } catch (error) {\n const retryable = isRetryableRequestError(error);\n\n if (!retryable || attempts > maxRetries) {\n throw toOrderDocumentFetchError(orderId, error, attempts, retryable);\n }\n\n const retryAfterHeader = axios.isAxiosError(error)\n ? error.response?.headers?.[\"retry-after\"]\n : undefined;\n const retryAfterMs = parseRetryAfterMs(retryAfterHeader);\n const delayMs = retryAfterMs ?? computeBackoffDelayMs(attempts, baseRetryDelayMs);\n await sleep(delayMs);\n }\n }\n}\n\nexport async function getOrderDocumentsBatch(\n profileId: string,\n orderIds: string[],\n options: GetOrderDocumentsBatchOptions = {}\n): Promise<OrderDocumentsBatchResult> {\n const { vtexApi } = await getVtexApiClients(profileId);\n const maxConcurrency = Math.max(\n 1,\n Math.floor(options.maxConcurrency ?? DEFAULT_BATCH_CONCURRENCY)\n );\n const successful: OrderDocumentSuccess[] = [];\n const failed: OrderDocumentFailure[] = [];\n\n for (let start = 0; start < orderIds.length; start += maxConcurrency) {\n const chunk = orderIds.slice(start, start + maxConcurrency);\n const settledChunk = await Promise.allSettled(\n chunk.map((orderId) => getOrderDocumentWithRetry(vtexApi, orderId, options))\n );\n\n settledChunk.forEach((result, index) => {\n const orderId = chunk[index];\n\n if (result.status === \"fulfilled\") {\n successful.push(result.value);\n return;\n }\n\n if (isOrderDocumentFetchError(result.reason)) {\n failed.push({\n orderId: result.reason.orderId,\n message: result.reason.message,\n statusCode: result.reason.statusCode,\n attempts: result.reason.attempts,\n retryable: result.reason.retryable,\n });\n return;\n }\n\n failed.push({\n orderId,\n message:\n result.reason instanceof Error\n ? result.reason.message\n : \"Unexpected error while fetching order details\",\n attempts: 1,\n retryable: false,\n });\n });\n }\n\n return { successful, failed };\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
async function getSkuPrice(itemId) {
|
|
1
|
+
import { getVtexApiClients } from "./vtex-api.js";
|
|
2
|
+
async function getSkuPrice(profileId, itemId) {
|
|
3
|
+
const { vtexPricingApi } = await getVtexApiClients(profileId);
|
|
3
4
|
const response = await vtexPricingApi.get(`/pricing/prices/${itemId}`);
|
|
4
5
|
return response.data;
|
|
5
6
|
}
|
|
6
|
-
async function getComputedPrice(itemId, priceTableId, params) {
|
|
7
|
+
async function getComputedPrice(profileId, itemId, priceTableId, params) {
|
|
8
|
+
const { vtexPricingApi } = await getVtexApiClients(profileId);
|
|
7
9
|
const response = await vtexPricingApi.get(
|
|
8
10
|
`/pricing/prices/${itemId}/computed/${priceTableId}`,
|
|
9
11
|
{ params }
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/services/vtex/vtex-pricing.ts"],
|
|
4
|
-
"sourcesContent": ["import {
|
|
5
|
-
"mappings": "AAAA,SAAS,
|
|
4
|
+
"sourcesContent": ["import { getVtexApiClients } from \"./vtex-api.js\";\n\nexport interface SkuFixedPrice {\n value?: number;\n listPrice?: number;\n minQuantity?: number;\n dateRange?: {\n from?: string;\n to?: string;\n };\n tradePolicyId?: string;\n}\n\nexport interface SkuPriceResponse {\n itemId: string;\n listPrice: number;\n costPrice: number;\n markup: number;\n basePrice: number;\n fixedPrices: SkuFixedPrice[];\n}\n\nexport interface ComputedPriceParams {\n categoryId: number;\n brandId: number;\n quantity: number;\n}\n\nexport interface ComputedPriceResponse {\n tradePolicyId: string;\n listPrice: number;\n costPrice?: number;\n sellingPrice: number;\n priceValidUntil: string;\n}\n\nexport async function getSkuPrice(\n profileId: string,\n itemId: string\n): Promise<SkuPriceResponse> {\n const { vtexPricingApi } = await getVtexApiClients(profileId);\n const response = await vtexPricingApi.get<SkuPriceResponse>(`/pricing/prices/${itemId}`);\n return response.data;\n}\n\nexport async function getComputedPrice(\n profileId: string,\n itemId: string,\n priceTableId: string,\n params: ComputedPriceParams\n): Promise<ComputedPriceResponse> {\n const { vtexPricingApi } = await getVtexApiClients(profileId);\n const response = await vtexPricingApi.get<ComputedPriceResponse>(\n `/pricing/prices/${itemId}/computed/${priceTableId}`,\n { params }\n );\n\n return response.data;\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,yBAAyB;AAoClC,eAAsB,YACpB,WACA,QAC2B;AAC3B,QAAM,EAAE,eAAe,IAAI,MAAM,kBAAkB,SAAS;AAC5D,QAAM,WAAW,MAAM,eAAe,IAAsB,mBAAmB,MAAM,EAAE;AACvF,SAAO,SAAS;AAClB;AAEA,eAAsB,iBACpB,WACA,QACA,cACA,QACgC;AAChC,QAAM,EAAE,eAAe,IAAI,MAAM,kBAAkB,SAAS;AAC5D,QAAM,WAAW,MAAM,eAAe;AAAA,IACpC,mBAAmB,MAAM,aAAa,YAAY;AAAA,IAClD,EAAE,OAAO;AAAA,EACX;AAEA,SAAO,SAAS;AAClB;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { error, object } from "mcp-use/server";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { checkTableExists, getDatabaseUrl, testDatabaseConnection } from "../../db/client.js";
|
|
4
|
+
import { stripNulls } from "../../utils/strip-payload.js";
|
|
5
|
+
const checkDatabaseConnectionSchema = z.object({});
|
|
6
|
+
function getConnectionHints() {
|
|
7
|
+
const databaseUrl = getDatabaseUrl();
|
|
8
|
+
if (!databaseUrl) {
|
|
9
|
+
return {
|
|
10
|
+
database_url_present: false,
|
|
11
|
+
host_hint: void 0,
|
|
12
|
+
port_hint: void 0
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
try {
|
|
16
|
+
const parsedUrl = new URL(databaseUrl);
|
|
17
|
+
return {
|
|
18
|
+
database_url_present: true,
|
|
19
|
+
host_hint: parsedUrl.hostname || void 0,
|
|
20
|
+
port_hint: parsedUrl.port || void 0
|
|
21
|
+
};
|
|
22
|
+
} catch {
|
|
23
|
+
return {
|
|
24
|
+
database_url_present: true,
|
|
25
|
+
host_hint: void 0,
|
|
26
|
+
port_hint: void 0
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
async function checkDatabaseConnectionHandler() {
|
|
31
|
+
try {
|
|
32
|
+
const result = await testDatabaseConnection();
|
|
33
|
+
const schemaMigrationsTablePresent = await checkTableExists("schema_migrations");
|
|
34
|
+
const profilesTablePresent = await checkTableExists("profiles");
|
|
35
|
+
const profileVtexConnectionsTablePresent = await checkTableExists("profile_vtex_connections");
|
|
36
|
+
const hints = getConnectionHints();
|
|
37
|
+
return object(
|
|
38
|
+
stripNulls({
|
|
39
|
+
status: "ok",
|
|
40
|
+
database: result.current_database,
|
|
41
|
+
user: result.current_user,
|
|
42
|
+
server_time: result.now.toISOString(),
|
|
43
|
+
database_url_present: hints.database_url_present,
|
|
44
|
+
host_hint: hints.host_hint,
|
|
45
|
+
port_hint: hints.port_hint,
|
|
46
|
+
schema_migrations_table_present: schemaMigrationsTablePresent,
|
|
47
|
+
profiles_table_present: profilesTablePresent,
|
|
48
|
+
profile_vtex_connections_table_present: profileVtexConnectionsTablePresent
|
|
49
|
+
})
|
|
50
|
+
);
|
|
51
|
+
} catch (err) {
|
|
52
|
+
return error(err instanceof Error ? err.message : "Database connection check failed");
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
export {
|
|
56
|
+
checkDatabaseConnectionHandler,
|
|
57
|
+
checkDatabaseConnectionSchema
|
|
58
|
+
};
|
|
59
|
+
//# sourceMappingURL=check-database-connection.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/tools/config/check-database-connection.ts"],
|
|
4
|
+
"sourcesContent": ["import { error, object } from \"mcp-use/server\";\nimport { z } from \"zod\";\n\nimport { checkTableExists, getDatabaseUrl, testDatabaseConnection } from \"../../db/client.js\";\nimport { stripNulls } from \"../../utils/strip-payload.js\";\n\nexport const checkDatabaseConnectionSchema = z.object({});\n\nfunction getConnectionHints() {\n const databaseUrl = getDatabaseUrl();\n if (!databaseUrl) {\n return {\n database_url_present: false,\n host_hint: undefined,\n port_hint: undefined,\n };\n }\n\n try {\n const parsedUrl = new URL(databaseUrl);\n\n return {\n database_url_present: true,\n host_hint: parsedUrl.hostname || undefined,\n port_hint: parsedUrl.port || undefined,\n };\n } catch {\n return {\n database_url_present: true,\n host_hint: undefined,\n port_hint: undefined,\n };\n }\n}\n\nexport async function checkDatabaseConnectionHandler() {\n try {\n const result = await testDatabaseConnection();\n const schemaMigrationsTablePresent = await checkTableExists(\"schema_migrations\");\n const profilesTablePresent = await checkTableExists(\"profiles\");\n const profileVtexConnectionsTablePresent = await checkTableExists(\"profile_vtex_connections\");\n const hints = getConnectionHints();\n\n return object(\n stripNulls({\n status: \"ok\",\n database: result.current_database,\n user: result.current_user,\n server_time: result.now.toISOString(),\n database_url_present: hints.database_url_present,\n host_hint: hints.host_hint,\n port_hint: hints.port_hint,\n schema_migrations_table_present: schemaMigrationsTablePresent,\n profiles_table_present: profilesTablePresent,\n profile_vtex_connections_table_present: profileVtexConnectionsTablePresent,\n })\n );\n } catch (err) {\n return error(err instanceof Error ? err.message : \"Database connection check failed\");\n }\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,OAAO,cAAc;AAC9B,SAAS,SAAS;AAElB,SAAS,kBAAkB,gBAAgB,8BAA8B;AACzE,SAAS,kBAAkB;AAEpB,MAAM,gCAAgC,EAAE,OAAO,CAAC,CAAC;AAExD,SAAS,qBAAqB;AAC5B,QAAM,cAAc,eAAe;AACnC,MAAI,CAAC,aAAa;AAChB,WAAO;AAAA,MACL,sBAAsB;AAAA,MACtB,WAAW;AAAA,MACX,WAAW;AAAA,IACb;AAAA,EACF;AAEA,MAAI;AACF,UAAM,YAAY,IAAI,IAAI,WAAW;AAErC,WAAO;AAAA,MACL,sBAAsB;AAAA,MACtB,WAAW,UAAU,YAAY;AAAA,MACjC,WAAW,UAAU,QAAQ;AAAA,IAC/B;AAAA,EACF,QAAQ;AACN,WAAO;AAAA,MACL,sBAAsB;AAAA,MACtB,WAAW;AAAA,MACX,WAAW;AAAA,IACb;AAAA,EACF;AACF;AAEA,eAAsB,iCAAiC;AACrD,MAAI;AACF,UAAM,SAAS,MAAM,uBAAuB;AAC5C,UAAM,+BAA+B,MAAM,iBAAiB,mBAAmB;AAC/E,UAAM,uBAAuB,MAAM,iBAAiB,UAAU;AAC9D,UAAM,qCAAqC,MAAM,iBAAiB,0BAA0B;AAC5F,UAAM,QAAQ,mBAAmB;AAEjC,WAAO;AAAA,MACL,WAAW;AAAA,QACT,QAAQ;AAAA,QACR,UAAU,OAAO;AAAA,QACjB,MAAM,OAAO;AAAA,QACb,aAAa,OAAO,IAAI,YAAY;AAAA,QACpC,sBAAsB,MAAM;AAAA,QAC5B,WAAW,MAAM;AAAA,QACjB,WAAW,MAAM;AAAA,QACjB,iCAAiC;AAAA,QACjC,wBAAwB;AAAA,QACxB,wCAAwC;AAAA,MAC1C,CAAC;AAAA,IACH;AAAA,EACF,SAAS,KAAK;AACZ,WAAO,MAAM,eAAe,QAAQ,IAAI,UAAU,kCAAkC;AAAA,EACtF;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { error, object } from "mcp-use/server";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { listProfiles } from "../../config/profile-store.js";
|
|
4
|
+
const listProfilesSchema = z.object({});
|
|
5
|
+
async function listProfilesHandler() {
|
|
6
|
+
try {
|
|
7
|
+
const profiles = await listProfiles();
|
|
8
|
+
return object({
|
|
9
|
+
total_profiles: profiles.length,
|
|
10
|
+
profiles: profiles.map((profile) => ({
|
|
11
|
+
profile_id: profile.id,
|
|
12
|
+
name: profile.name,
|
|
13
|
+
is_active: profile.isActive,
|
|
14
|
+
created_at: profile.createdAt.toISOString(),
|
|
15
|
+
updated_at: profile.updatedAt.toISOString()
|
|
16
|
+
}))
|
|
17
|
+
});
|
|
18
|
+
} catch (err) {
|
|
19
|
+
return error(err instanceof Error ? err.message : "Failed to list profiles");
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
export {
|
|
23
|
+
listProfilesHandler,
|
|
24
|
+
listProfilesSchema
|
|
25
|
+
};
|
|
26
|
+
//# sourceMappingURL=list-profiles.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/tools/config/list-profiles.ts"],
|
|
4
|
+
"sourcesContent": ["import { error, object } from \"mcp-use/server\";\nimport { z } from \"zod\";\n\nimport { listProfiles } from \"../../config/profile-store.js\";\n\nexport const listProfilesSchema = z.object({});\n\nexport async function listProfilesHandler() {\n try {\n const profiles = await listProfiles();\n\n return object({\n total_profiles: profiles.length,\n profiles: profiles.map((profile) => ({\n profile_id: profile.id,\n name: profile.name,\n is_active: profile.isActive,\n created_at: profile.createdAt.toISOString(),\n updated_at: profile.updatedAt.toISOString(),\n })),\n });\n } catch (err) {\n return error(err instanceof Error ? err.message : \"Failed to list profiles\");\n }\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,OAAO,cAAc;AAC9B,SAAS,SAAS;AAElB,SAAS,oBAAoB;AAEtB,MAAM,qBAAqB,EAAE,OAAO,CAAC,CAAC;AAE7C,eAAsB,sBAAsB;AAC1C,MAAI;AACF,UAAM,WAAW,MAAM,aAAa;AAEpC,WAAO,OAAO;AAAA,MACZ,gBAAgB,SAAS;AAAA,MACzB,UAAU,SAAS,IAAI,CAAC,aAAa;AAAA,QACnC,YAAY,QAAQ;AAAA,QACpB,MAAM,QAAQ;AAAA,QACd,WAAW,QAAQ;AAAA,QACnB,YAAY,QAAQ,UAAU,YAAY;AAAA,QAC1C,YAAY,QAAQ,UAAU,YAAY;AAAA,MAC5C,EAAE;AAAA,IACJ,CAAC;AAAA,EACH,SAAS,KAAK;AACZ,WAAO,MAAM,eAAe,QAAQ,IAAI,UAAU,yBAAyB;AAAA,EAC7E;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
package/dist/src/tools/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/tools/index.ts"],
|
|
4
|
-
"sourcesContent": ["export * from \"./vtex/index.js\";\nexport * from \"./analytics/index.js\";\nexport * from \"./google-ads/index.js\";\nexport * from \"./meta/index.js\";\nexport * from \"./search-console/index.js\";\n"],
|
|
5
|
-
"mappings": "AAAA,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;",
|
|
4
|
+
"sourcesContent": ["export * from \"./config/index.js\";\nexport * from \"./vtex/index.js\";\nexport * from \"./analytics/index.js\";\nexport * from \"./google-ads/index.js\";\nexport * from \"./meta/index.js\";\nexport * from \"./search-console/index.js\";\n"],
|
|
5
|
+
"mappings": "AAAA,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -4,7 +4,11 @@ import { formatVtexError } from "../../services/vtex/vtex-api.js";
|
|
|
4
4
|
import { getComputedPrice } from "../../services/vtex/vtex-pricing.js";
|
|
5
5
|
import { moneyFromCentsOptional } from "../../utils/money.js";
|
|
6
6
|
import { stripNulls } from "../../utils/strip-payload.js";
|
|
7
|
+
import { resolveVtexProfileOrSelection } from "./profile-resolution.js";
|
|
7
8
|
const computedPriceSchema = z.object({
|
|
9
|
+
profileId: z.string().trim().min(1).optional().describe(
|
|
10
|
+
"Explicit VTEX profile id to use. If omitted, the tool returns a guided selection payload with available active profiles."
|
|
11
|
+
),
|
|
8
12
|
itemId: z.string().min(1).describe("SKU item identifier"),
|
|
9
13
|
priceTableId: z.string().min(1).describe("Price table or trade policy identifier"),
|
|
10
14
|
categoryId: z.number().int().positive().describe("Category identifier"),
|
|
@@ -12,6 +16,7 @@ const computedPriceSchema = z.object({
|
|
|
12
16
|
quantity: z.number().int().positive().describe("SKU quantity context")
|
|
13
17
|
});
|
|
14
18
|
async function computedPriceHandler({
|
|
19
|
+
profileId,
|
|
15
20
|
itemId,
|
|
16
21
|
priceTableId,
|
|
17
22
|
categoryId,
|
|
@@ -19,13 +24,19 @@ async function computedPriceHandler({
|
|
|
19
24
|
quantity
|
|
20
25
|
}) {
|
|
21
26
|
try {
|
|
22
|
-
const
|
|
27
|
+
const profileResolution = await resolveVtexProfileOrSelection(profileId);
|
|
28
|
+
if (!profileResolution.ok) {
|
|
29
|
+
return profileResolution.response;
|
|
30
|
+
}
|
|
31
|
+
const resolvedProfileId = profileResolution.value.profileId;
|
|
32
|
+
const computedPrice = await getComputedPrice(resolvedProfileId, itemId, priceTableId, {
|
|
23
33
|
categoryId,
|
|
24
34
|
brandId,
|
|
25
35
|
quantity
|
|
26
36
|
});
|
|
27
37
|
return object(
|
|
28
38
|
stripNulls({
|
|
39
|
+
profile_id: resolvedProfileId,
|
|
29
40
|
item_id: itemId,
|
|
30
41
|
price_table_id: priceTableId,
|
|
31
42
|
trade_policy_id: computedPrice.tradePolicyId,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/tools/vtex/computed-price.ts"],
|
|
4
|
-
"sourcesContent": ["import { error, object } from \"mcp-use/server\";\nimport { z } from \"zod\";\n\nimport { formatVtexError } from \"../../services/vtex/vtex-api.js\";\nimport { getComputedPrice } from \"../../services/vtex/vtex-pricing.js\";\nimport { moneyFromCentsOptional } from \"../../utils/money.js\";\nimport { stripNulls } from \"../../utils/strip-payload.js\";\n\nexport const computedPriceSchema = z.object({\n itemId: z.string().min(1).describe(\"SKU item identifier\"),\n priceTableId: z.string().min(1).describe(\"Price table or trade policy identifier\"),\n categoryId: z.number().int().positive().describe(\"Category identifier\"),\n brandId: z.number().int().positive().describe(\"Brand identifier\"),\n quantity: z.number().int().positive().describe(\"SKU quantity context\"),\n});\n\nexport async function computedPriceHandler({\n itemId,\n priceTableId,\n categoryId,\n brandId,\n quantity,\n}: z.infer<typeof computedPriceSchema>) {\n try {\n const computedPrice = await getComputedPrice(itemId, priceTableId, {\n categoryId,\n brandId,\n quantity,\n });\n\n return object(\n stripNulls({\n item_id: itemId,\n price_table_id: priceTableId,\n trade_policy_id: computedPrice.tradePolicyId,\n list_price: moneyFromCentsOptional(computedPrice.listPrice),\n cost_price: moneyFromCentsOptional(computedPrice.costPrice),\n selling_price: moneyFromCentsOptional(computedPrice.sellingPrice),\n price_valid_until: computedPrice.priceValidUntil,\n })\n );\n } catch (err) {\n return error(\n formatVtexError(err, `Failed to fetch computed price for item ${itemId} and table ${priceTableId}`)\n );\n }\n}\n"],
|
|
5
|
-
"mappings": "AAAA,SAAS,OAAO,cAAc;AAC9B,SAAS,SAAS;AAElB,SAAS,uBAAuB;AAChC,SAAS,wBAAwB;AACjC,SAAS,8BAA8B;AACvC,SAAS,kBAAkB;
|
|
4
|
+
"sourcesContent": ["import { error, object } from \"mcp-use/server\";\nimport { z } from \"zod\";\n\nimport { formatVtexError } from \"../../services/vtex/vtex-api.js\";\nimport { getComputedPrice } from \"../../services/vtex/vtex-pricing.js\";\nimport { moneyFromCentsOptional } from \"../../utils/money.js\";\nimport { stripNulls } from \"../../utils/strip-payload.js\";\nimport { resolveVtexProfileOrSelection } from \"./profile-resolution.js\";\n\nexport const computedPriceSchema = z.object({\n profileId: z\n .string()\n .trim()\n .min(1)\n .optional()\n .describe(\n \"Explicit VTEX profile id to use. If omitted, the tool returns a guided selection payload with available active profiles.\"\n ),\n itemId: z.string().min(1).describe(\"SKU item identifier\"),\n priceTableId: z.string().min(1).describe(\"Price table or trade policy identifier\"),\n categoryId: z.number().int().positive().describe(\"Category identifier\"),\n brandId: z.number().int().positive().describe(\"Brand identifier\"),\n quantity: z.number().int().positive().describe(\"SKU quantity context\"),\n});\n\nexport async function computedPriceHandler({\n profileId,\n itemId,\n priceTableId,\n categoryId,\n brandId,\n quantity,\n}: z.infer<typeof computedPriceSchema>) {\n try {\n const profileResolution = await resolveVtexProfileOrSelection(profileId);\n if (!profileResolution.ok) {\n return profileResolution.response;\n }\n\n const resolvedProfileId = profileResolution.value.profileId;\n const computedPrice = await getComputedPrice(resolvedProfileId, itemId, priceTableId, {\n categoryId,\n brandId,\n quantity,\n });\n\n return object(\n stripNulls({\n profile_id: resolvedProfileId,\n item_id: itemId,\n price_table_id: priceTableId,\n trade_policy_id: computedPrice.tradePolicyId,\n list_price: moneyFromCentsOptional(computedPrice.listPrice),\n cost_price: moneyFromCentsOptional(computedPrice.costPrice),\n selling_price: moneyFromCentsOptional(computedPrice.sellingPrice),\n price_valid_until: computedPrice.priceValidUntil,\n })\n );\n } catch (err) {\n return error(\n formatVtexError(err, `Failed to fetch computed price for item ${itemId} and table ${priceTableId}`)\n );\n }\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,OAAO,cAAc;AAC9B,SAAS,SAAS;AAElB,SAAS,uBAAuB;AAChC,SAAS,wBAAwB;AACjC,SAAS,8BAA8B;AACvC,SAAS,kBAAkB;AAC3B,SAAS,qCAAqC;AAEvC,MAAM,sBAAsB,EAAE,OAAO;AAAA,EAC1C,WAAW,EACR,OAAO,EACP,KAAK,EACL,IAAI,CAAC,EACL,SAAS,EACT;AAAA,IACC;AAAA,EACF;AAAA,EACF,QAAQ,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,SAAS,qBAAqB;AAAA,EACxD,cAAc,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,SAAS,wCAAwC;AAAA,EACjF,YAAY,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,qBAAqB;AAAA,EACtE,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,kBAAkB;AAAA,EAChE,UAAU,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,sBAAsB;AACvE,CAAC;AAED,eAAsB,qBAAqB;AAAA,EACzC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAwC;AACtC,MAAI;AACF,UAAM,oBAAoB,MAAM,8BAA8B,SAAS;AACvE,QAAI,CAAC,kBAAkB,IAAI;AACzB,aAAO,kBAAkB;AAAA,IAC3B;AAEA,UAAM,oBAAoB,kBAAkB,MAAM;AAClD,UAAM,gBAAgB,MAAM,iBAAiB,mBAAmB,QAAQ,cAAc;AAAA,MACpF;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAED,WAAO;AAAA,MACL,WAAW;AAAA,QACT,YAAY;AAAA,QACZ,SAAS;AAAA,QACT,gBAAgB;AAAA,QAChB,iBAAiB,cAAc;AAAA,QAC/B,YAAY,uBAAuB,cAAc,SAAS;AAAA,QAC1D,YAAY,uBAAuB,cAAc,SAAS;AAAA,QAC1D,eAAe,uBAAuB,cAAc,YAAY;AAAA,QAChE,mBAAmB,cAAc;AAAA,MACnC,CAAC;AAAA,IACH;AAAA,EACF,SAAS,KAAK;AACZ,WAAO;AAAA,MACL,gBAAgB,KAAK,2CAA2C,MAAM,cAAc,YAAY,EAAE;AAAA,IACpG;AAAA,EACF;AACF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|