@yoryoboy/bi-mcp 1.1.0 → 1.3.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 +332 -2
- 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-write.js +233 -0
- package/dist/src/services/vtex/vtex-catalog-write.js.map +7 -0
- 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-write.js +152 -0
- package/dist/src/services/vtex/vtex-orders-write.js.map +7 -0
- 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-write.js +24 -0
- package/dist/src/services/vtex/vtex-pricing-write.js.map +7 -0
- package/dist/src/services/vtex/vtex-pricing.js +5 -3
- package/dist/src/services/vtex/vtex-pricing.js.map +2 -2
- package/dist/src/services/vtex/vtex-write.js +38 -0
- package/dist/src/services/vtex/vtex-write.js.map +7 -0
- 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/activate-sku.js +53 -0
- package/dist/src/tools/vtex/activate-sku.js.map +7 -0
- package/dist/src/tools/vtex/add-order-tracking.js +103 -0
- package/dist/src/tools/vtex/add-order-tracking.js.map +7 -0
- package/dist/src/tools/vtex/associate-specification.js +60 -0
- package/dist/src/tools/vtex/associate-specification.js.map +7 -0
- package/dist/src/tools/vtex/attach-catalog-image.js +63 -0
- package/dist/src/tools/vtex/attach-catalog-image.js.map +7 -0
- package/dist/src/tools/vtex/cancel-order.js +67 -0
- package/dist/src/tools/vtex/cancel-order.js.map +7 -0
- 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/create-brand.js +69 -0
- package/dist/src/tools/vtex/create-brand.js.map +7 -0
- package/dist/src/tools/vtex/create-category.js +81 -0
- package/dist/src/tools/vtex/create-category.js.map +7 -0
- package/dist/src/tools/vtex/create-product-with-sku.js +120 -0
- package/dist/src/tools/vtex/create-product-with-sku.js.map +7 -0
- package/dist/src/tools/vtex/create-product.js +111 -0
- package/dist/src/tools/vtex/create-product.js.map +7 -0
- package/dist/src/tools/vtex/create-sku.js +103 -0
- package/dist/src/tools/vtex/create-sku.js.map +7 -0
- package/dist/src/tools/vtex/create-specification-value.js +53 -0
- package/dist/src/tools/vtex/create-specification-value.js.map +7 -0
- package/dist/src/tools/vtex/create-specification.js +85 -0
- package/dist/src/tools/vtex/create-specification.js.map +7 -0
- package/dist/src/tools/vtex/deactivate-sku.js +53 -0
- package/dist/src/tools/vtex/deactivate-sku.js.map +7 -0
- package/dist/src/tools/vtex/delete-fixed-price.js +53 -0
- package/dist/src/tools/vtex/delete-fixed-price.js.map +7 -0
- package/dist/src/tools/vtex/index.js +21 -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/invoice-order.js +84 -0
- package/dist/src/tools/vtex/invoice-order.js.map +7 -0
- 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/toggle-unlimited-quantity.js +65 -0
- package/dist/src/tools/vtex/toggle-unlimited-quantity.js.map +7 -0
- package/dist/src/tools/vtex/update-inventory.js +40 -14
- package/dist/src/tools/vtex/update-inventory.js.map +2 -2
- package/dist/src/tools/vtex/update-lead-time.js +40 -12
- package/dist/src/tools/vtex/update-lead-time.js.map +2 -2
- package/dist/src/tools/vtex/update-product-basic-fields.js +71 -0
- package/dist/src/tools/vtex/update-product-basic-fields.js.map +7 -0
- package/dist/src/tools/vtex/update-sku-basic-fields.js +92 -0
- package/dist/src/tools/vtex/update-sku-basic-fields.js.map +7 -0
- package/dist/src/tools/vtex/update-sku-price.js +81 -0
- package/dist/src/tools/vtex/update-sku-price.js.map +7 -0
- package/dist/src/tools/vtex/upsert-fixed-price.js +69 -0
- package/dist/src/tools/vtex/upsert-fixed-price.js.map +7 -0
- package/dist/src/tools/vtex/warehouse-inventory.js +12 -1
- package/dist/src/tools/vtex/warehouse-inventory.js.map +2 -2
- package/dist/src/tools/vtex/write-helpers.js +73 -0
- package/dist/src/tools/vtex/write-helpers.js.map +7 -0
- package/package.json +12 -2
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { createCipheriv, createDecipheriv, randomBytes } from "node:crypto";
|
|
2
|
+
const ALGORITHM = "aes-256-gcm";
|
|
3
|
+
const IV_LENGTH = 12;
|
|
4
|
+
function getEncryptionKey() {
|
|
5
|
+
const rawValue = process.env.DB_ENCRYPTION_KEY?.trim();
|
|
6
|
+
if (!rawValue) {
|
|
7
|
+
throw new Error(
|
|
8
|
+
"Missing DB_ENCRYPTION_KEY. Configure it before encrypting or decrypting persisted secrets."
|
|
9
|
+
);
|
|
10
|
+
}
|
|
11
|
+
const buffer = Buffer.from(rawValue, "hex");
|
|
12
|
+
if (buffer.length !== 32) {
|
|
13
|
+
throw new Error(
|
|
14
|
+
"Invalid DB_ENCRYPTION_KEY. Expected a 32-byte key encoded as 64 hex characters."
|
|
15
|
+
);
|
|
16
|
+
}
|
|
17
|
+
return buffer;
|
|
18
|
+
}
|
|
19
|
+
function encryptSecret(plainText) {
|
|
20
|
+
const iv = randomBytes(IV_LENGTH);
|
|
21
|
+
const cipher = createCipheriv(ALGORITHM, getEncryptionKey(), iv);
|
|
22
|
+
const encrypted = Buffer.concat([cipher.update(plainText, "utf8"), cipher.final()]);
|
|
23
|
+
const authTag = cipher.getAuthTag();
|
|
24
|
+
return `${iv.toString("hex")}:${authTag.toString("hex")}:${encrypted.toString("hex")}`;
|
|
25
|
+
}
|
|
26
|
+
function decryptSecret(payload) {
|
|
27
|
+
const [ivHex, authTagHex, encryptedHex] = payload.split(":");
|
|
28
|
+
if (!ivHex || !authTagHex || !encryptedHex) {
|
|
29
|
+
throw new Error("Invalid encrypted secret payload");
|
|
30
|
+
}
|
|
31
|
+
const decipher = createDecipheriv(ALGORITHM, getEncryptionKey(), Buffer.from(ivHex, "hex"));
|
|
32
|
+
decipher.setAuthTag(Buffer.from(authTagHex, "hex"));
|
|
33
|
+
const decrypted = Buffer.concat([
|
|
34
|
+
decipher.update(Buffer.from(encryptedHex, "hex")),
|
|
35
|
+
decipher.final()
|
|
36
|
+
]);
|
|
37
|
+
return decrypted.toString("utf8");
|
|
38
|
+
}
|
|
39
|
+
export {
|
|
40
|
+
decryptSecret,
|
|
41
|
+
encryptSecret
|
|
42
|
+
};
|
|
43
|
+
//# sourceMappingURL=vtex-crypto.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/config/vtex-crypto.ts"],
|
|
4
|
+
"sourcesContent": ["import { createCipheriv, createDecipheriv, randomBytes } from \"node:crypto\";\n\nconst ALGORITHM = \"aes-256-gcm\";\nconst IV_LENGTH = 12;\n\nfunction getEncryptionKey(): Buffer {\n const rawValue = process.env.DB_ENCRYPTION_KEY?.trim();\n if (!rawValue) {\n throw new Error(\n \"Missing DB_ENCRYPTION_KEY. Configure it before encrypting or decrypting persisted secrets.\"\n );\n }\n\n const buffer = Buffer.from(rawValue, \"hex\");\n if (buffer.length !== 32) {\n throw new Error(\n \"Invalid DB_ENCRYPTION_KEY. Expected a 32-byte key encoded as 64 hex characters.\"\n );\n }\n\n return buffer;\n}\n\nexport function encryptSecret(plainText: string): string {\n const iv = randomBytes(IV_LENGTH);\n const cipher = createCipheriv(ALGORITHM, getEncryptionKey(), iv);\n const encrypted = Buffer.concat([cipher.update(plainText, \"utf8\"), cipher.final()]);\n const authTag = cipher.getAuthTag();\n\n return `${iv.toString(\"hex\")}:${authTag.toString(\"hex\")}:${encrypted.toString(\"hex\")}`;\n}\n\nexport function decryptSecret(payload: string): string {\n const [ivHex, authTagHex, encryptedHex] = payload.split(\":\");\n if (!ivHex || !authTagHex || !encryptedHex) {\n throw new Error(\"Invalid encrypted secret payload\");\n }\n\n const decipher = createDecipheriv(ALGORITHM, getEncryptionKey(), Buffer.from(ivHex, \"hex\"));\n decipher.setAuthTag(Buffer.from(authTagHex, \"hex\"));\n\n const decrypted = Buffer.concat([\n decipher.update(Buffer.from(encryptedHex, \"hex\")),\n decipher.final(),\n ]);\n\n return decrypted.toString(\"utf8\");\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,gBAAgB,kBAAkB,mBAAmB;AAE9D,MAAM,YAAY;AAClB,MAAM,YAAY;AAElB,SAAS,mBAA2B;AAClC,QAAM,WAAW,QAAQ,IAAI,mBAAmB,KAAK;AACrD,MAAI,CAAC,UAAU;AACb,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAEA,QAAM,SAAS,OAAO,KAAK,UAAU,KAAK;AAC1C,MAAI,OAAO,WAAW,IAAI;AACxB,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAEO,SAAS,cAAc,WAA2B;AACvD,QAAM,KAAK,YAAY,SAAS;AAChC,QAAM,SAAS,eAAe,WAAW,iBAAiB,GAAG,EAAE;AAC/D,QAAM,YAAY,OAAO,OAAO,CAAC,OAAO,OAAO,WAAW,MAAM,GAAG,OAAO,MAAM,CAAC,CAAC;AAClF,QAAM,UAAU,OAAO,WAAW;AAElC,SAAO,GAAG,GAAG,SAAS,KAAK,CAAC,IAAI,QAAQ,SAAS,KAAK,CAAC,IAAI,UAAU,SAAS,KAAK,CAAC;AACtF;AAEO,SAAS,cAAc,SAAyB;AACrD,QAAM,CAAC,OAAO,YAAY,YAAY,IAAI,QAAQ,MAAM,GAAG;AAC3D,MAAI,CAAC,SAAS,CAAC,cAAc,CAAC,cAAc;AAC1C,UAAM,IAAI,MAAM,kCAAkC;AAAA,EACpD;AAEA,QAAM,WAAW,iBAAiB,WAAW,iBAAiB,GAAG,OAAO,KAAK,OAAO,KAAK,CAAC;AAC1F,WAAS,WAAW,OAAO,KAAK,YAAY,KAAK,CAAC;AAElD,QAAM,YAAY,OAAO,OAAO;AAAA,IAC9B,SAAS,OAAO,OAAO,KAAK,cAAc,KAAK,CAAC;AAAA,IAChD,SAAS,MAAM;AAAA,EACjB,CAAC;AAED,SAAO,UAAU,SAAS,MAAM;AAClC;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { getDb } from "../db/client.js";
|
|
2
|
+
function mapVtexConnectionRow(row) {
|
|
3
|
+
return {
|
|
4
|
+
profileId: row.profile_id,
|
|
5
|
+
profileName: row.profile_name,
|
|
6
|
+
accountName: row.account_name,
|
|
7
|
+
apiKeyEncrypted: row.api_key_encrypted,
|
|
8
|
+
apiTokenEncrypted: row.api_token_encrypted,
|
|
9
|
+
isActive: row.is_active,
|
|
10
|
+
status: row.status,
|
|
11
|
+
lastValidatedAt: row.last_validated_at,
|
|
12
|
+
lastError: row.last_error,
|
|
13
|
+
createdAt: row.created_at,
|
|
14
|
+
updatedAt: row.updated_at
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
async function getVtexConnectionRow(profileId) {
|
|
18
|
+
const result = await getDb().query(
|
|
19
|
+
`
|
|
20
|
+
select
|
|
21
|
+
pvc.profile_id,
|
|
22
|
+
p.name as profile_name,
|
|
23
|
+
pvc.account_name,
|
|
24
|
+
pvc.api_key_encrypted,
|
|
25
|
+
pvc.api_token_encrypted,
|
|
26
|
+
pvc.is_active,
|
|
27
|
+
pvc.status,
|
|
28
|
+
pvc.last_validated_at,
|
|
29
|
+
pvc.last_error,
|
|
30
|
+
pvc.created_at,
|
|
31
|
+
pvc.updated_at
|
|
32
|
+
from profile_vtex_connections pvc
|
|
33
|
+
inner join profiles p on p.id = pvc.profile_id
|
|
34
|
+
where pvc.profile_id = $1
|
|
35
|
+
`,
|
|
36
|
+
[profileId]
|
|
37
|
+
);
|
|
38
|
+
const row = result.rows[0];
|
|
39
|
+
return row ? mapVtexConnectionRow(row) : null;
|
|
40
|
+
}
|
|
41
|
+
async function upsertVtexConnection(input) {
|
|
42
|
+
const result = await getDb().query(
|
|
43
|
+
`
|
|
44
|
+
insert into profile_vtex_connections (
|
|
45
|
+
profile_id,
|
|
46
|
+
account_name,
|
|
47
|
+
api_key_encrypted,
|
|
48
|
+
api_token_encrypted,
|
|
49
|
+
is_active,
|
|
50
|
+
status,
|
|
51
|
+
last_validated_at,
|
|
52
|
+
last_error
|
|
53
|
+
)
|
|
54
|
+
values ($1, $2, $3, $4, $5, $6, $7, $8)
|
|
55
|
+
on conflict (profile_id) do update
|
|
56
|
+
set
|
|
57
|
+
account_name = excluded.account_name,
|
|
58
|
+
api_key_encrypted = excluded.api_key_encrypted,
|
|
59
|
+
api_token_encrypted = excluded.api_token_encrypted,
|
|
60
|
+
is_active = excluded.is_active,
|
|
61
|
+
status = excluded.status,
|
|
62
|
+
last_validated_at = excluded.last_validated_at,
|
|
63
|
+
last_error = excluded.last_error,
|
|
64
|
+
updated_at = now()
|
|
65
|
+
returning
|
|
66
|
+
profile_id,
|
|
67
|
+
account_name,
|
|
68
|
+
api_key_encrypted,
|
|
69
|
+
api_token_encrypted,
|
|
70
|
+
is_active,
|
|
71
|
+
status,
|
|
72
|
+
last_validated_at,
|
|
73
|
+
last_error,
|
|
74
|
+
created_at,
|
|
75
|
+
updated_at
|
|
76
|
+
`,
|
|
77
|
+
[
|
|
78
|
+
input.profileId,
|
|
79
|
+
input.accountName,
|
|
80
|
+
input.apiKeyEncrypted,
|
|
81
|
+
input.apiTokenEncrypted,
|
|
82
|
+
input.isActive,
|
|
83
|
+
input.status,
|
|
84
|
+
input.lastValidatedAt ?? null,
|
|
85
|
+
input.lastError ?? null
|
|
86
|
+
]
|
|
87
|
+
);
|
|
88
|
+
return mapVtexConnectionRow(result.rows[0]);
|
|
89
|
+
}
|
|
90
|
+
async function markVtexConnectionValidation(profileId, status, lastError) {
|
|
91
|
+
await getDb().query(
|
|
92
|
+
`
|
|
93
|
+
update profile_vtex_connections
|
|
94
|
+
set
|
|
95
|
+
status = $2,
|
|
96
|
+
last_validated_at = now(),
|
|
97
|
+
last_error = $3,
|
|
98
|
+
updated_at = now()
|
|
99
|
+
where profile_id = $1
|
|
100
|
+
`,
|
|
101
|
+
[profileId, status, lastError ?? null]
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
async function listVtexConnections() {
|
|
105
|
+
const result = await getDb().query(
|
|
106
|
+
`
|
|
107
|
+
select
|
|
108
|
+
pvc.profile_id,
|
|
109
|
+
p.name as profile_name,
|
|
110
|
+
pvc.account_name,
|
|
111
|
+
pvc.api_key_encrypted,
|
|
112
|
+
pvc.api_token_encrypted,
|
|
113
|
+
pvc.is_active,
|
|
114
|
+
pvc.status,
|
|
115
|
+
pvc.last_validated_at,
|
|
116
|
+
pvc.last_error,
|
|
117
|
+
pvc.created_at,
|
|
118
|
+
pvc.updated_at
|
|
119
|
+
from profile_vtex_connections pvc
|
|
120
|
+
inner join profiles p on p.id = pvc.profile_id
|
|
121
|
+
order by pvc.profile_id asc
|
|
122
|
+
`
|
|
123
|
+
);
|
|
124
|
+
return result.rows.map(mapVtexConnectionRow);
|
|
125
|
+
}
|
|
126
|
+
export {
|
|
127
|
+
getVtexConnectionRow,
|
|
128
|
+
listVtexConnections,
|
|
129
|
+
markVtexConnectionValidation,
|
|
130
|
+
upsertVtexConnection
|
|
131
|
+
};
|
|
132
|
+
//# sourceMappingURL=vtex-profile-store.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/config/vtex-profile-store.ts"],
|
|
4
|
+
"sourcesContent": ["import { getDb } from \"../db/client.js\";\n\nexport type VtexConnectionStatus = \"pending\" | \"valid\" | \"invalid\" | \"disabled\";\n\nexport interface VtexConnectionRecord {\n profileId: string;\n profileName?: string;\n accountName: string;\n apiKeyEncrypted: string;\n apiTokenEncrypted: string;\n isActive: boolean;\n status: VtexConnectionStatus;\n lastValidatedAt: Date | null;\n lastError: string | null;\n createdAt: Date;\n updatedAt: Date;\n}\n\ninterface VtexConnectionRow {\n profile_id: string;\n profile_name?: string;\n account_name: string;\n api_key_encrypted: string;\n api_token_encrypted: string;\n is_active: boolean;\n status: VtexConnectionStatus;\n last_validated_at: Date | null;\n last_error: string | null;\n created_at: Date;\n updated_at: Date;\n}\n\nfunction mapVtexConnectionRow(row: VtexConnectionRow): VtexConnectionRecord {\n return {\n profileId: row.profile_id,\n profileName: row.profile_name,\n accountName: row.account_name,\n apiKeyEncrypted: row.api_key_encrypted,\n apiTokenEncrypted: row.api_token_encrypted,\n isActive: row.is_active,\n status: row.status,\n lastValidatedAt: row.last_validated_at,\n lastError: row.last_error,\n createdAt: row.created_at,\n updatedAt: row.updated_at,\n };\n}\n\nexport async function getVtexConnectionRow(\n profileId: string\n): Promise<VtexConnectionRecord | null> {\n const result = await getDb().query<VtexConnectionRow>(\n `\n select\n pvc.profile_id,\n p.name as profile_name,\n pvc.account_name,\n pvc.api_key_encrypted,\n pvc.api_token_encrypted,\n pvc.is_active,\n pvc.status,\n pvc.last_validated_at,\n pvc.last_error,\n pvc.created_at,\n pvc.updated_at\n from profile_vtex_connections pvc\n inner join profiles p on p.id = pvc.profile_id\n where pvc.profile_id = $1\n `,\n [profileId]\n );\n\n const row = result.rows[0];\n return row ? mapVtexConnectionRow(row) : null;\n}\n\nexport async function upsertVtexConnection(input: {\n profileId: string;\n accountName: string;\n apiKeyEncrypted: string;\n apiTokenEncrypted: string;\n isActive: boolean;\n status: VtexConnectionStatus;\n lastValidatedAt?: Date | null;\n lastError?: string | null;\n}): Promise<VtexConnectionRecord> {\n const result = await getDb().query<VtexConnectionRow>(\n `\n insert into profile_vtex_connections (\n profile_id,\n account_name,\n api_key_encrypted,\n api_token_encrypted,\n is_active,\n status,\n last_validated_at,\n last_error\n )\n values ($1, $2, $3, $4, $5, $6, $7, $8)\n on conflict (profile_id) do update\n set\n account_name = excluded.account_name,\n api_key_encrypted = excluded.api_key_encrypted,\n api_token_encrypted = excluded.api_token_encrypted,\n is_active = excluded.is_active,\n status = excluded.status,\n last_validated_at = excluded.last_validated_at,\n last_error = excluded.last_error,\n updated_at = now()\n returning\n profile_id,\n account_name,\n api_key_encrypted,\n api_token_encrypted,\n is_active,\n status,\n last_validated_at,\n last_error,\n created_at,\n updated_at\n `,\n [\n input.profileId,\n input.accountName,\n input.apiKeyEncrypted,\n input.apiTokenEncrypted,\n input.isActive,\n input.status,\n input.lastValidatedAt ?? null,\n input.lastError ?? null,\n ]\n );\n\n return mapVtexConnectionRow(result.rows[0]);\n}\n\nexport async function markVtexConnectionValidation(\n profileId: string,\n status: VtexConnectionStatus,\n lastError?: string | null\n): Promise<void> {\n await getDb().query(\n `\n update profile_vtex_connections\n set\n status = $2,\n last_validated_at = now(),\n last_error = $3,\n updated_at = now()\n where profile_id = $1\n `,\n [profileId, status, lastError ?? null]\n );\n}\n\nexport async function listVtexConnections(): Promise<VtexConnectionRecord[]> {\n const result = await getDb().query<VtexConnectionRow>(\n `\n select\n pvc.profile_id,\n p.name as profile_name,\n pvc.account_name,\n pvc.api_key_encrypted,\n pvc.api_token_encrypted,\n pvc.is_active,\n pvc.status,\n pvc.last_validated_at,\n pvc.last_error,\n pvc.created_at,\n pvc.updated_at\n from profile_vtex_connections pvc\n inner join profiles p on p.id = pvc.profile_id\n order by pvc.profile_id asc\n `\n );\n\n return result.rows.map(mapVtexConnectionRow);\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,aAAa;AAgCtB,SAAS,qBAAqB,KAA8C;AAC1E,SAAO;AAAA,IACL,WAAW,IAAI;AAAA,IACf,aAAa,IAAI;AAAA,IACjB,aAAa,IAAI;AAAA,IACjB,iBAAiB,IAAI;AAAA,IACrB,mBAAmB,IAAI;AAAA,IACvB,UAAU,IAAI;AAAA,IACd,QAAQ,IAAI;AAAA,IACZ,iBAAiB,IAAI;AAAA,IACrB,WAAW,IAAI;AAAA,IACf,WAAW,IAAI;AAAA,IACf,WAAW,IAAI;AAAA,EACjB;AACF;AAEA,eAAsB,qBACpB,WACsC;AACtC,QAAM,SAAS,MAAM,MAAM,EAAE;AAAA,IAC3B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAiBA,CAAC,SAAS;AAAA,EACZ;AAEA,QAAM,MAAM,OAAO,KAAK,CAAC;AACzB,SAAO,MAAM,qBAAqB,GAAG,IAAI;AAC3C;AAEA,eAAsB,qBAAqB,OAST;AAChC,QAAM,SAAS,MAAM,MAAM,EAAE;AAAA,IAC3B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAkCA;AAAA,MACE,MAAM;AAAA,MACN,MAAM;AAAA,MACN,MAAM;AAAA,MACN,MAAM;AAAA,MACN,MAAM;AAAA,MACN,MAAM;AAAA,MACN,MAAM,mBAAmB;AAAA,MACzB,MAAM,aAAa;AAAA,IACrB;AAAA,EACF;AAEA,SAAO,qBAAqB,OAAO,KAAK,CAAC,CAAC;AAC5C;AAEA,eAAsB,6BACpB,WACA,QACA,WACe;AACf,QAAM,MAAM,EAAE;AAAA,IACZ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IASA,CAAC,WAAW,QAAQ,aAAa,IAAI;AAAA,EACvC;AACF;AAEA,eAAsB,sBAAuD;AAC3E,QAAM,SAAS,MAAM,MAAM,EAAE;AAAA,IAC3B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAiBF;AAEA,SAAO,OAAO,KAAK,IAAI,oBAAoB;AAC7C;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
package/dist/src/config/vtex.js
CHANGED
|
@@ -1,26 +1,32 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
1
|
+
import { assertActiveProfile } from "./profile-store.js";
|
|
2
|
+
import { decryptSecret } from "./vtex-crypto.js";
|
|
3
|
+
import { getVtexConnectionRow } from "./vtex-profile-store.js";
|
|
4
|
+
function buildVtexUrls(accountName) {
|
|
5
|
+
return {
|
|
6
|
+
baseUrl: `https://${accountName}.vtexcommercestable.com.br`,
|
|
7
|
+
pricingBaseUrl: `https://api.vtex.com/${accountName}`
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
async function getVtexConfigForProfile(profileId) {
|
|
11
|
+
await assertActiveProfile(profileId);
|
|
12
|
+
const connection = await getVtexConnectionRow(profileId);
|
|
13
|
+
if (!connection) {
|
|
14
|
+
throw new Error(`VTEX connection not found for profileId "${profileId}"`);
|
|
15
|
+
}
|
|
16
|
+
if (!connection.isActive || connection.status === "disabled") {
|
|
17
|
+
throw new Error(`VTEX connection for profileId "${profileId}" is disabled`);
|
|
10
18
|
}
|
|
11
|
-
|
|
19
|
+
const urls = buildVtexUrls(connection.accountName);
|
|
20
|
+
return {
|
|
21
|
+
accountName: connection.accountName,
|
|
22
|
+
apiKey: decryptSecret(connection.apiKeyEncrypted),
|
|
23
|
+
apiToken: decryptSecret(connection.apiTokenEncrypted),
|
|
24
|
+
baseUrl: urls.baseUrl,
|
|
25
|
+
pricingBaseUrl: urls.pricingBaseUrl
|
|
26
|
+
};
|
|
12
27
|
}
|
|
13
|
-
const accountName = requireEnv("VTEX_ACCOUNT_NAME");
|
|
14
|
-
const apiKey = requireEnv("VTEX_API_KEY");
|
|
15
|
-
const apiToken = requireEnv("VTEX_API_TOKEN");
|
|
16
|
-
const vtexConfig = {
|
|
17
|
-
accountName,
|
|
18
|
-
apiKey,
|
|
19
|
-
apiToken,
|
|
20
|
-
baseUrl: `https://${accountName}.vtexcommercestable.com.br`,
|
|
21
|
-
pricingBaseUrl: `https://api.vtex.com/${accountName}`
|
|
22
|
-
};
|
|
23
28
|
export {
|
|
24
|
-
|
|
29
|
+
buildVtexUrls,
|
|
30
|
+
getVtexConfigForProfile
|
|
25
31
|
};
|
|
26
32
|
//# sourceMappingURL=vtex.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/config/vtex.ts"],
|
|
4
|
-
"sourcesContent": ["
|
|
5
|
-
"mappings": "AAAA,
|
|
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
|
+
}
|
|
@@ -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
|
}
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
import { getVtexApiClients } from "./vtex-api.js";
|
|
2
|
+
function pickRecord(source, keys) {
|
|
3
|
+
const picked = {};
|
|
4
|
+
for (const key of keys) {
|
|
5
|
+
if (key in source) {
|
|
6
|
+
picked[key] = source[key];
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
return picked;
|
|
10
|
+
}
|
|
11
|
+
async function getProduct(profileId, productId) {
|
|
12
|
+
const { vtexApi } = await getVtexApiClients(profileId);
|
|
13
|
+
const response = await vtexApi.get(`/api/catalog/pvt/product/${productId}`);
|
|
14
|
+
return response.data;
|
|
15
|
+
}
|
|
16
|
+
async function createProduct(profileId, payload) {
|
|
17
|
+
const { vtexApi } = await getVtexApiClients(profileId);
|
|
18
|
+
const response = await vtexApi.post("/api/catalog/pvt/product", payload);
|
|
19
|
+
return response.data;
|
|
20
|
+
}
|
|
21
|
+
async function updateProduct(profileId, productId, payload) {
|
|
22
|
+
const { vtexApi } = await getVtexApiClients(profileId);
|
|
23
|
+
const response = await vtexApi.put(`/api/catalog/pvt/product/${productId}`, payload);
|
|
24
|
+
return response.data;
|
|
25
|
+
}
|
|
26
|
+
function buildProductUpdatePayload(current, updates) {
|
|
27
|
+
const payload = pickRecord(current, [
|
|
28
|
+
"Name",
|
|
29
|
+
"DepartmentId",
|
|
30
|
+
"CategoryId",
|
|
31
|
+
"BrandId",
|
|
32
|
+
"LinkId",
|
|
33
|
+
"RefId",
|
|
34
|
+
"IsVisible",
|
|
35
|
+
"Description",
|
|
36
|
+
"DescriptionShort",
|
|
37
|
+
"ReleaseDate",
|
|
38
|
+
"KeyWords",
|
|
39
|
+
"Title",
|
|
40
|
+
"IsActive",
|
|
41
|
+
"TaxCode",
|
|
42
|
+
"MetaTagDescription",
|
|
43
|
+
"SupplierId",
|
|
44
|
+
"ShowWithoutStock",
|
|
45
|
+
"AdWordsRemarketingCode",
|
|
46
|
+
"LomadeeCampaignCode",
|
|
47
|
+
"Score"
|
|
48
|
+
]);
|
|
49
|
+
if (updates.name !== void 0) payload.Name = updates.name;
|
|
50
|
+
if (updates.categoryId !== void 0) payload.CategoryId = updates.categoryId;
|
|
51
|
+
if (updates.brandId !== void 0) payload.BrandId = updates.brandId;
|
|
52
|
+
if (updates.description !== void 0) payload.Description = updates.description;
|
|
53
|
+
if (updates.descriptionShort !== void 0) payload.DescriptionShort = updates.descriptionShort;
|
|
54
|
+
if (updates.title !== void 0) payload.Title = updates.title;
|
|
55
|
+
if (updates.linkId !== void 0) payload.LinkId = updates.linkId;
|
|
56
|
+
if (updates.refId !== void 0) payload.RefId = updates.refId;
|
|
57
|
+
if (updates.isVisible !== void 0) payload.IsVisible = updates.isVisible;
|
|
58
|
+
if (updates.isActive !== void 0) payload.IsActive = updates.isActive;
|
|
59
|
+
if (updates.keyWords !== void 0) payload.KeyWords = updates.keyWords;
|
|
60
|
+
if (updates.releaseDate !== void 0) payload.ReleaseDate = updates.releaseDate;
|
|
61
|
+
if (updates.metaTagDescription !== void 0) {
|
|
62
|
+
payload.MetaTagDescription = updates.metaTagDescription;
|
|
63
|
+
}
|
|
64
|
+
if (updates.showWithoutStock !== void 0) {
|
|
65
|
+
payload.ShowWithoutStock = updates.showWithoutStock;
|
|
66
|
+
}
|
|
67
|
+
return payload;
|
|
68
|
+
}
|
|
69
|
+
async function getSku(profileId, skuId) {
|
|
70
|
+
const { vtexApi } = await getVtexApiClients(profileId);
|
|
71
|
+
const response = await vtexApi.get(`/api/catalog/pvt/stockkeepingunit/${skuId}`);
|
|
72
|
+
return response.data;
|
|
73
|
+
}
|
|
74
|
+
async function createSku(profileId, payload) {
|
|
75
|
+
const { vtexApi } = await getVtexApiClients(profileId);
|
|
76
|
+
const response = await vtexApi.post("/api/catalog/pvt/stockkeepingunit", payload);
|
|
77
|
+
return response.data;
|
|
78
|
+
}
|
|
79
|
+
async function updateSku(profileId, skuId, payload) {
|
|
80
|
+
const { vtexApi } = await getVtexApiClients(profileId);
|
|
81
|
+
const response = await vtexApi.put(`/api/catalog/pvt/stockkeepingunit/${skuId}`, payload);
|
|
82
|
+
return response.data;
|
|
83
|
+
}
|
|
84
|
+
function buildSkuUpdatePayload(current, updates) {
|
|
85
|
+
const payload = pickRecord(current, [
|
|
86
|
+
"ProductId",
|
|
87
|
+
"IsActive",
|
|
88
|
+
"ActivateIfPossible",
|
|
89
|
+
"Name",
|
|
90
|
+
"RefId",
|
|
91
|
+
"PackagedHeight",
|
|
92
|
+
"PackagedLength",
|
|
93
|
+
"PackagedWidth",
|
|
94
|
+
"PackagedWeightKg",
|
|
95
|
+
"Height",
|
|
96
|
+
"Length",
|
|
97
|
+
"Width",
|
|
98
|
+
"WeightKg",
|
|
99
|
+
"CubicWeight",
|
|
100
|
+
"IsKit",
|
|
101
|
+
"CreationDate",
|
|
102
|
+
"RewardValue",
|
|
103
|
+
"EstimatedDateArrival",
|
|
104
|
+
"ManufacturerCode",
|
|
105
|
+
"CommercialConditionId",
|
|
106
|
+
"MeasurementUnit",
|
|
107
|
+
"UnitMultiplier",
|
|
108
|
+
"ModalType",
|
|
109
|
+
"KitItensSellApart",
|
|
110
|
+
"Videos"
|
|
111
|
+
]);
|
|
112
|
+
if (updates.name !== void 0) payload.Name = updates.name;
|
|
113
|
+
if (updates.refId !== void 0) payload.RefId = updates.refId;
|
|
114
|
+
if (updates.packagedHeight !== void 0) payload.PackagedHeight = updates.packagedHeight;
|
|
115
|
+
if (updates.packagedLength !== void 0) payload.PackagedLength = updates.packagedLength;
|
|
116
|
+
if (updates.packagedWidth !== void 0) payload.PackagedWidth = updates.packagedWidth;
|
|
117
|
+
if (updates.packagedWeightKg !== void 0) payload.PackagedWeightKg = updates.packagedWeightKg;
|
|
118
|
+
if (updates.height !== void 0) payload.Height = updates.height;
|
|
119
|
+
if (updates.length !== void 0) payload.Length = updates.length;
|
|
120
|
+
if (updates.width !== void 0) payload.Width = updates.width;
|
|
121
|
+
if (updates.weightKg !== void 0) payload.WeightKg = updates.weightKg;
|
|
122
|
+
if (updates.measurementUnit !== void 0) payload.MeasurementUnit = updates.measurementUnit;
|
|
123
|
+
if (updates.unitMultiplier !== void 0) payload.UnitMultiplier = updates.unitMultiplier;
|
|
124
|
+
if (updates.manufacturerCode !== void 0) payload.ManufacturerCode = updates.manufacturerCode;
|
|
125
|
+
if (updates.commercialConditionId !== void 0) {
|
|
126
|
+
payload.CommercialConditionId = updates.commercialConditionId;
|
|
127
|
+
}
|
|
128
|
+
if (updates.isActive !== void 0) payload.IsActive = updates.isActive;
|
|
129
|
+
if (updates.activateIfPossible !== void 0) {
|
|
130
|
+
payload.ActivateIfPossible = updates.activateIfPossible;
|
|
131
|
+
}
|
|
132
|
+
return payload;
|
|
133
|
+
}
|
|
134
|
+
async function getSkuEans(profileId, skuId) {
|
|
135
|
+
const { vtexApi } = await getVtexApiClients(profileId);
|
|
136
|
+
const response = await vtexApi.get(`/api/catalog/pvt/stockkeepingunit/${skuId}/ean`);
|
|
137
|
+
const data = response.data;
|
|
138
|
+
if (Array.isArray(data)) {
|
|
139
|
+
return data.map((item) => String(item)).filter(Boolean);
|
|
140
|
+
}
|
|
141
|
+
if (data == null) {
|
|
142
|
+
return [];
|
|
143
|
+
}
|
|
144
|
+
return [String(data)];
|
|
145
|
+
}
|
|
146
|
+
async function createSkuEan(profileId, skuId, ean) {
|
|
147
|
+
const { vtexApi } = await getVtexApiClients(profileId);
|
|
148
|
+
await vtexApi.post(`/api/catalog/pvt/stockkeepingunit/${skuId}/ean/${ean}`);
|
|
149
|
+
}
|
|
150
|
+
async function deleteAllSkuEans(profileId, skuId) {
|
|
151
|
+
const { vtexApi } = await getVtexApiClients(profileId);
|
|
152
|
+
await vtexApi.delete(`/api/catalog/pvt/stockkeepingunit/${skuId}/ean`);
|
|
153
|
+
}
|
|
154
|
+
async function createBrand(profileId, payload) {
|
|
155
|
+
const { vtexApi } = await getVtexApiClients(profileId);
|
|
156
|
+
const response = await vtexApi.post("/api/catalog/pvt/brand", payload);
|
|
157
|
+
return response.data;
|
|
158
|
+
}
|
|
159
|
+
async function getBrand(profileId, brandId) {
|
|
160
|
+
const { vtexApi } = await getVtexApiClients(profileId);
|
|
161
|
+
const response = await vtexApi.get(`/api/catalog/pvt/brand/${brandId}`);
|
|
162
|
+
return response.data;
|
|
163
|
+
}
|
|
164
|
+
async function createCategory(profileId, payload) {
|
|
165
|
+
const { vtexApi } = await getVtexApiClients(profileId);
|
|
166
|
+
const response = await vtexApi.post("/api/catalog/pvt/category", payload);
|
|
167
|
+
return response.data;
|
|
168
|
+
}
|
|
169
|
+
async function getCategory(profileId, categoryId) {
|
|
170
|
+
const { vtexApi } = await getVtexApiClients(profileId);
|
|
171
|
+
const response = await vtexApi.get(`/api/catalog/pvt/category/${categoryId}`);
|
|
172
|
+
return response.data;
|
|
173
|
+
}
|
|
174
|
+
async function createSpecification(profileId, payload) {
|
|
175
|
+
const { vtexApi } = await getVtexApiClients(profileId);
|
|
176
|
+
const response = await vtexApi.post("/api/catalog/pvt/specification", payload);
|
|
177
|
+
return response.data;
|
|
178
|
+
}
|
|
179
|
+
async function createSpecificationValue(profileId, payload) {
|
|
180
|
+
const { vtexApi } = await getVtexApiClients(profileId);
|
|
181
|
+
const response = await vtexApi.post(
|
|
182
|
+
"/api/catalog/pvt/specificationvalue",
|
|
183
|
+
payload
|
|
184
|
+
);
|
|
185
|
+
return response.data;
|
|
186
|
+
}
|
|
187
|
+
async function associateProductSpecification(profileId, productId, payload) {
|
|
188
|
+
const { vtexApi } = await getVtexApiClients(profileId);
|
|
189
|
+
const response = await vtexApi.post(
|
|
190
|
+
`/api/catalog/pvt/product/${productId}/specification`,
|
|
191
|
+
payload
|
|
192
|
+
);
|
|
193
|
+
return response.data;
|
|
194
|
+
}
|
|
195
|
+
async function associateSkuSpecification(profileId, skuId, payload) {
|
|
196
|
+
const { vtexApi } = await getVtexApiClients(profileId);
|
|
197
|
+
const response = await vtexApi.post(
|
|
198
|
+
`/api/catalog/pvt/stockkeepingunit/${skuId}/specification`,
|
|
199
|
+
payload
|
|
200
|
+
);
|
|
201
|
+
return response.data;
|
|
202
|
+
}
|
|
203
|
+
async function createSkuFile(profileId, skuId, payload) {
|
|
204
|
+
const { vtexApi } = await getVtexApiClients(profileId);
|
|
205
|
+
const response = await vtexApi.post(
|
|
206
|
+
`/api/catalog/pvt/stockkeepingunit/${skuId}/file`,
|
|
207
|
+
payload
|
|
208
|
+
);
|
|
209
|
+
return response.data;
|
|
210
|
+
}
|
|
211
|
+
export {
|
|
212
|
+
associateProductSpecification,
|
|
213
|
+
associateSkuSpecification,
|
|
214
|
+
buildProductUpdatePayload,
|
|
215
|
+
buildSkuUpdatePayload,
|
|
216
|
+
createBrand,
|
|
217
|
+
createCategory,
|
|
218
|
+
createProduct,
|
|
219
|
+
createSku,
|
|
220
|
+
createSkuEan,
|
|
221
|
+
createSkuFile,
|
|
222
|
+
createSpecification,
|
|
223
|
+
createSpecificationValue,
|
|
224
|
+
deleteAllSkuEans,
|
|
225
|
+
getBrand,
|
|
226
|
+
getCategory,
|
|
227
|
+
getProduct,
|
|
228
|
+
getSku,
|
|
229
|
+
getSkuEans,
|
|
230
|
+
updateProduct,
|
|
231
|
+
updateSku
|
|
232
|
+
};
|
|
233
|
+
//# sourceMappingURL=vtex-catalog-write.js.map
|