@decocms/apps 0.20.1
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/.github/workflows/release.yml +34 -0
- package/.releaserc.json +25 -0
- package/commerce/components/Image.tsx +209 -0
- package/commerce/components/JsonLd.tsx +285 -0
- package/commerce/sdk/analytics.ts +24 -0
- package/commerce/sdk/formatPrice.ts +23 -0
- package/commerce/sdk/url.ts +9 -0
- package/commerce/sdk/useOffer.ts +75 -0
- package/commerce/sdk/useVariantPossibilities.ts +43 -0
- package/commerce/types/commerce.ts +1105 -0
- package/commerce/utils/canonical.ts +11 -0
- package/commerce/utils/constants.ts +9 -0
- package/commerce/utils/filters.ts +10 -0
- package/commerce/utils/productToAnalyticsItem.ts +67 -0
- package/commerce/utils/stateByZip.ts +50 -0
- package/knip.json +19 -0
- package/package.json +77 -0
- package/shopify/actions/cart/addItems.ts +37 -0
- package/shopify/actions/cart/updateCoupons.ts +32 -0
- package/shopify/actions/cart/updateItems.ts +32 -0
- package/shopify/actions/user/signIn.ts +45 -0
- package/shopify/actions/user/signUp.ts +36 -0
- package/shopify/client.ts +58 -0
- package/shopify/index.ts +32 -0
- package/shopify/init.ts +40 -0
- package/shopify/loaders/ProductDetailsPage.ts +35 -0
- package/shopify/loaders/ProductList.ts +101 -0
- package/shopify/loaders/ProductListingPage.ts +180 -0
- package/shopify/loaders/RelatedProducts.ts +45 -0
- package/shopify/loaders/cart.ts +73 -0
- package/shopify/loaders/shop.ts +40 -0
- package/shopify/loaders/user.ts +44 -0
- package/shopify/utils/admin/admin.ts +57 -0
- package/shopify/utils/admin/queries.ts +29 -0
- package/shopify/utils/cart.ts +28 -0
- package/shopify/utils/cookies.ts +85 -0
- package/shopify/utils/enums.ts +438 -0
- package/shopify/utils/graphql.ts +69 -0
- package/shopify/utils/storefront/queries.ts +530 -0
- package/shopify/utils/storefront/storefront.graphql.gen.ts +113 -0
- package/shopify/utils/transform.ts +436 -0
- package/shopify/utils/types.ts +191 -0
- package/shopify/utils/user.ts +23 -0
- package/shopify/utils/utils.ts +164 -0
- package/tsconfig.json +11 -0
- package/vtex/README.md +6 -0
- package/vtex/actions/address.ts +211 -0
- package/vtex/actions/auth.ts +337 -0
- package/vtex/actions/checkout.ts +497 -0
- package/vtex/actions/index.ts +11 -0
- package/vtex/actions/masterData.ts +170 -0
- package/vtex/actions/misc.ts +196 -0
- package/vtex/actions/newsletter.ts +108 -0
- package/vtex/actions/orders.ts +37 -0
- package/vtex/actions/profile.ts +119 -0
- package/vtex/actions/session.ts +87 -0
- package/vtex/actions/trigger.ts +43 -0
- package/vtex/actions/wishlist.ts +116 -0
- package/vtex/client.ts +423 -0
- package/vtex/hooks/index.ts +4 -0
- package/vtex/hooks/useAutocomplete.ts +89 -0
- package/vtex/hooks/useCart.ts +219 -0
- package/vtex/hooks/useUser.ts +78 -0
- package/vtex/hooks/useWishlist.ts +119 -0
- package/vtex/index.ts +14 -0
- package/vtex/inline-loaders/productDetailsPage.ts +75 -0
- package/vtex/inline-loaders/productList.ts +163 -0
- package/vtex/inline-loaders/productListingPage.ts +447 -0
- package/vtex/inline-loaders/relatedProducts.ts +83 -0
- package/vtex/inline-loaders/suggestions.ts +49 -0
- package/vtex/inline-loaders/workflowProducts.ts +68 -0
- package/vtex/invoke.ts +202 -0
- package/vtex/loaders/address.ts +120 -0
- package/vtex/loaders/brands.ts +51 -0
- package/vtex/loaders/cart.ts +49 -0
- package/vtex/loaders/catalog.ts +165 -0
- package/vtex/loaders/collections.ts +57 -0
- package/vtex/loaders/index.ts +19 -0
- package/vtex/loaders/legacy.ts +671 -0
- package/vtex/loaders/logistics.ts +115 -0
- package/vtex/loaders/navbar.ts +29 -0
- package/vtex/loaders/orders.ts +103 -0
- package/vtex/loaders/pageType.ts +62 -0
- package/vtex/loaders/payment.ts +107 -0
- package/vtex/loaders/profile.ts +138 -0
- package/vtex/loaders/promotion.ts +33 -0
- package/vtex/loaders/search.ts +127 -0
- package/vtex/loaders/session.ts +91 -0
- package/vtex/loaders/user.ts +89 -0
- package/vtex/loaders/wishlist.ts +89 -0
- package/vtex/loaders/wishlistProducts.ts +81 -0
- package/vtex/loaders/workflow.ts +323 -0
- package/vtex/logo.png +0 -0
- package/vtex/middleware.ts +229 -0
- package/vtex/types.ts +248 -0
- package/vtex/utils/batch.ts +21 -0
- package/vtex/utils/cookies.ts +76 -0
- package/vtex/utils/enrichment.ts +540 -0
- package/vtex/utils/fetchCache.ts +150 -0
- package/vtex/utils/index.ts +17 -0
- package/vtex/utils/intelligentSearch.ts +84 -0
- package/vtex/utils/legacy.ts +155 -0
- package/vtex/utils/pickAndOmit.ts +30 -0
- package/vtex/utils/proxy.ts +196 -0
- package/vtex/utils/resourceRange.ts +10 -0
- package/vtex/utils/segment.ts +163 -0
- package/vtex/utils/similars.ts +38 -0
- package/vtex/utils/sitemap.ts +133 -0
- package/vtex/utils/slugCache.ts +32 -0
- package/vtex/utils/slugify.ts +13 -0
- package/vtex/utils/transform.ts +1331 -0
- package/vtex/utils/types.ts +1884 -0
- package/vtex/utils/vtexId.ts +103 -0
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Miscellaneous VTEX actions that don't warrant their own module.
|
|
3
|
+
* Ported from deco-cx/apps:
|
|
4
|
+
* - vtex/actions/notifyme.ts
|
|
5
|
+
* - vtex/actions/analytics/sendEvent.ts
|
|
6
|
+
* - vtex/actions/review/submit.ts
|
|
7
|
+
* - vtex/actions/payment/deletePaymentToken.ts
|
|
8
|
+
* @see https://developers.vtex.com/docs/api-reference
|
|
9
|
+
*/
|
|
10
|
+
import { vtexFetch, getVtexConfig } from "../client";
|
|
11
|
+
import { buildAuthCookieHeader, VTEX_AUTH_COOKIE } from "../utils/vtexId";
|
|
12
|
+
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
// Types
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
|
|
17
|
+
export interface NotifyMeProps {
|
|
18
|
+
email: string;
|
|
19
|
+
skuId: string;
|
|
20
|
+
name?: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface ReviewData {
|
|
24
|
+
productId: string;
|
|
25
|
+
rating: number;
|
|
26
|
+
title: string;
|
|
27
|
+
text: string;
|
|
28
|
+
reviewerName: string;
|
|
29
|
+
approved: boolean;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export type AnalyticsEvent =
|
|
33
|
+
| {
|
|
34
|
+
type: "session.ping";
|
|
35
|
+
url: string;
|
|
36
|
+
}
|
|
37
|
+
| {
|
|
38
|
+
type: "page.cart";
|
|
39
|
+
products: { productId: string; quantity: number }[];
|
|
40
|
+
}
|
|
41
|
+
| {
|
|
42
|
+
type: "page.empty_cart";
|
|
43
|
+
products: Record<string, never>;
|
|
44
|
+
}
|
|
45
|
+
| {
|
|
46
|
+
type: "page.confirmation";
|
|
47
|
+
order: string;
|
|
48
|
+
products: { productId: string; quantity: number; price: number }[];
|
|
49
|
+
}
|
|
50
|
+
| {
|
|
51
|
+
type: "search.click";
|
|
52
|
+
position: number;
|
|
53
|
+
text: string;
|
|
54
|
+
productId: string;
|
|
55
|
+
url: string;
|
|
56
|
+
}
|
|
57
|
+
| {
|
|
58
|
+
type: "search.query";
|
|
59
|
+
url: string;
|
|
60
|
+
text: string;
|
|
61
|
+
misspelled: boolean;
|
|
62
|
+
match: number;
|
|
63
|
+
operator: string;
|
|
64
|
+
locale: string;
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
export interface ISCookies {
|
|
68
|
+
anonymous: string;
|
|
69
|
+
session: string;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export interface DeletePaymentTokenResult {
|
|
73
|
+
deletePaymentToken: boolean;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// ---------------------------------------------------------------------------
|
|
77
|
+
// GraphQL helper (myvtex.com private graphql)
|
|
78
|
+
// ---------------------------------------------------------------------------
|
|
79
|
+
|
|
80
|
+
interface GqlResponse<T> {
|
|
81
|
+
data: T;
|
|
82
|
+
errors?: Array<{ message: string }>;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
async function gql<T>(
|
|
86
|
+
query: string,
|
|
87
|
+
variables: Record<string, unknown>,
|
|
88
|
+
authCookie: string,
|
|
89
|
+
): Promise<T> {
|
|
90
|
+
const { account } = getVtexConfig();
|
|
91
|
+
const result = await vtexFetch<GqlResponse<T>>(
|
|
92
|
+
`https://${account}.myvtex.com/_v/private/graphql/v1`,
|
|
93
|
+
{
|
|
94
|
+
method: "POST",
|
|
95
|
+
body: JSON.stringify({ query, variables }),
|
|
96
|
+
headers: { Cookie: buildAuthCookieHeader(authCookie, account) },
|
|
97
|
+
},
|
|
98
|
+
);
|
|
99
|
+
if (result.errors?.length) {
|
|
100
|
+
throw new Error(`GraphQL error: ${result.errors[0].message}`);
|
|
101
|
+
}
|
|
102
|
+
return result.data;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// ---------------------------------------------------------------------------
|
|
106
|
+
// Mutation
|
|
107
|
+
// ---------------------------------------------------------------------------
|
|
108
|
+
|
|
109
|
+
const DELETE_PAYMENT_TOKEN = `mutation DeleteCreditCardToken($tokenId: ID!) {
|
|
110
|
+
deletePaymentToken(tokenId: $tokenId) @context(provider: "vtex.my-cards-graphql@2.x")
|
|
111
|
+
}`;
|
|
112
|
+
|
|
113
|
+
// ---------------------------------------------------------------------------
|
|
114
|
+
// Actions
|
|
115
|
+
// ---------------------------------------------------------------------------
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Register a "notify me when back in stock" request.
|
|
119
|
+
* Uses the legacy VTEX .aspx form endpoint (FormData, not JSON).
|
|
120
|
+
*/
|
|
121
|
+
export async function notifyMe(props: NotifyMeProps): Promise<void> {
|
|
122
|
+
const { account } = getVtexConfig();
|
|
123
|
+
const { email, skuId, name = "" } = props;
|
|
124
|
+
|
|
125
|
+
const form = new FormData();
|
|
126
|
+
form.append("notifymeClientName", name);
|
|
127
|
+
form.append("notifymeClientEmail", email);
|
|
128
|
+
form.append("notifymeIdSku", skuId);
|
|
129
|
+
|
|
130
|
+
await fetch(
|
|
131
|
+
`https://${account}.vtexcommercestable.com.br/no-cache/AviseMe.aspx`,
|
|
132
|
+
{ method: "POST", body: form },
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Send an Intelligent Search analytics event to sp.vtex.com.
|
|
138
|
+
*
|
|
139
|
+
* @param event - The typed event payload.
|
|
140
|
+
* @param isCookies - IS session tracking IDs (anonymous + session).
|
|
141
|
+
* In the original, these came from getISCookiesFromBag(ctx).
|
|
142
|
+
* @param userAgent - Forwarded user-agent string.
|
|
143
|
+
*/
|
|
144
|
+
export async function sendEvent(
|
|
145
|
+
event: AnalyticsEvent,
|
|
146
|
+
isCookies: ISCookies,
|
|
147
|
+
userAgent?: string,
|
|
148
|
+
): Promise<void> {
|
|
149
|
+
const { account } = getVtexConfig();
|
|
150
|
+
|
|
151
|
+
await fetch(`https://sp.vtex.com/event-api/v1/${account}/event`, {
|
|
152
|
+
method: "POST",
|
|
153
|
+
headers: { "Content-Type": "application/json" },
|
|
154
|
+
body: JSON.stringify({
|
|
155
|
+
...event,
|
|
156
|
+
...isCookies,
|
|
157
|
+
agent: userAgent || "deco-sites/apps",
|
|
158
|
+
}),
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Submit a product review via the Reviews & Ratings API.
|
|
164
|
+
* Hits POST https://{account}.myvtex.com/reviews-and-ratings/api/review.
|
|
165
|
+
* Auth is passed via the `VtexIdclientAutCookie` header (not a Cookie header).
|
|
166
|
+
*/
|
|
167
|
+
export async function submitReview(
|
|
168
|
+
data: ReviewData,
|
|
169
|
+
authCookie: string,
|
|
170
|
+
): Promise<unknown> {
|
|
171
|
+
const { account } = getVtexConfig();
|
|
172
|
+
|
|
173
|
+
return vtexFetch<unknown>(
|
|
174
|
+
`https://${account}.myvtex.com/reviews-and-ratings/api/review`,
|
|
175
|
+
{
|
|
176
|
+
method: "POST",
|
|
177
|
+
body: JSON.stringify(data),
|
|
178
|
+
headers: { [VTEX_AUTH_COOKIE]: authCookie },
|
|
179
|
+
},
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Delete a saved payment token (credit card) for the authenticated user.
|
|
185
|
+
* Uses the my-cards-graphql VTEX IO app.
|
|
186
|
+
*/
|
|
187
|
+
export async function deletePaymentToken(
|
|
188
|
+
tokenId: string,
|
|
189
|
+
authCookie: string,
|
|
190
|
+
): Promise<DeletePaymentTokenResult> {
|
|
191
|
+
return gql<DeletePaymentTokenResult>(
|
|
192
|
+
DELETE_PAYMENT_TOKEN,
|
|
193
|
+
{ tokenId },
|
|
194
|
+
authCookie,
|
|
195
|
+
);
|
|
196
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* VTEX Newsletter actions.
|
|
3
|
+
* Ported from deco-cx/apps:
|
|
4
|
+
* - vtex/actions/newsletter/subscribe.ts
|
|
5
|
+
* - vtex/actions/newsletter/updateNewsletterOptIn.ts
|
|
6
|
+
* @see https://developers.vtex.com/docs/guides/newsletter
|
|
7
|
+
*/
|
|
8
|
+
import { vtexFetch, getVtexConfig } from "../client";
|
|
9
|
+
import { buildAuthCookieHeader } from "../utils/vtexId";
|
|
10
|
+
|
|
11
|
+
// ---------------------------------------------------------------------------
|
|
12
|
+
// Types
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
|
|
15
|
+
export interface SubscribeProps {
|
|
16
|
+
email: string;
|
|
17
|
+
name?: string;
|
|
18
|
+
page?: string;
|
|
19
|
+
part?: string;
|
|
20
|
+
/** Intentionally preserving the original typo from the VTEX legacy form field. */
|
|
21
|
+
campaing?: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// ---------------------------------------------------------------------------
|
|
25
|
+
// GraphQL helper (myvtex.com private graphql)
|
|
26
|
+
// ---------------------------------------------------------------------------
|
|
27
|
+
|
|
28
|
+
interface GqlResponse<T> {
|
|
29
|
+
data: T;
|
|
30
|
+
errors?: Array<{ message: string }>;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async function gql<T>(
|
|
34
|
+
query: string,
|
|
35
|
+
variables: Record<string, unknown>,
|
|
36
|
+
authCookie: string,
|
|
37
|
+
): Promise<T> {
|
|
38
|
+
const { account } = getVtexConfig();
|
|
39
|
+
const result = await vtexFetch<GqlResponse<T>>(
|
|
40
|
+
`https://${account}.myvtex.com/_v/private/graphql/v1`,
|
|
41
|
+
{
|
|
42
|
+
method: "POST",
|
|
43
|
+
body: JSON.stringify({ query, variables }),
|
|
44
|
+
headers: { Cookie: buildAuthCookieHeader(authCookie, account) },
|
|
45
|
+
},
|
|
46
|
+
);
|
|
47
|
+
if (result.errors?.length) {
|
|
48
|
+
throw new Error(`GraphQL error: ${result.errors[0].message}`);
|
|
49
|
+
}
|
|
50
|
+
return result.data;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// ---------------------------------------------------------------------------
|
|
54
|
+
// Mutation
|
|
55
|
+
// ---------------------------------------------------------------------------
|
|
56
|
+
|
|
57
|
+
const SUBSCRIBE_NEWSLETTER = `mutation SubscribeNewsletter($email: String!, $isNewsletterOptIn: Boolean!) {
|
|
58
|
+
subscribeNewsletter(email: $email, isNewsletterOptIn: $isNewsletterOptIn) @context(provider: "vtex.store-graphql@2.x")
|
|
59
|
+
}`;
|
|
60
|
+
|
|
61
|
+
// ---------------------------------------------------------------------------
|
|
62
|
+
// Actions
|
|
63
|
+
// ---------------------------------------------------------------------------
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Subscribe to the newsletter via the legacy VTEX .aspx form endpoint.
|
|
67
|
+
* Uses raw fetch because the body is FormData (not JSON).
|
|
68
|
+
*/
|
|
69
|
+
export async function subscribe(props: SubscribeProps): Promise<void> {
|
|
70
|
+
const { account } = getVtexConfig();
|
|
71
|
+
const {
|
|
72
|
+
email,
|
|
73
|
+
name = "",
|
|
74
|
+
part = "newsletter",
|
|
75
|
+
page = "_",
|
|
76
|
+
campaing = "newsletter:opt-in",
|
|
77
|
+
} = props;
|
|
78
|
+
|
|
79
|
+
const form = new FormData();
|
|
80
|
+
form.append("newsletterClientName", name);
|
|
81
|
+
form.append("newsletterClientEmail", email);
|
|
82
|
+
form.append("newsInternalPage", page);
|
|
83
|
+
form.append("newsInternalPart", part);
|
|
84
|
+
form.append("newsInternalCampaign", campaing);
|
|
85
|
+
|
|
86
|
+
await fetch(
|
|
87
|
+
`https://${account}.vtexcommercestable.com.br/no-cache/Newsletter.aspx`,
|
|
88
|
+
{ method: "POST", body: form },
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Toggle the newsletter opt-in flag for an authenticated user.
|
|
94
|
+
* The original Deco action extracted `email` from the auth cookie payload.
|
|
95
|
+
* Here the caller must provide it explicitly.
|
|
96
|
+
*/
|
|
97
|
+
export async function updateNewsletterOptIn(
|
|
98
|
+
subscribed: boolean,
|
|
99
|
+
email: string,
|
|
100
|
+
authCookie: string,
|
|
101
|
+
): Promise<{ subscribed: boolean }> {
|
|
102
|
+
await gql<unknown>(
|
|
103
|
+
SUBSCRIBE_NEWSLETTER,
|
|
104
|
+
{ email, isNewsletterOptIn: subscribed },
|
|
105
|
+
authCookie,
|
|
106
|
+
);
|
|
107
|
+
return { subscribed };
|
|
108
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* VTEX Order management actions.
|
|
3
|
+
* Ported from deco-cx/apps:
|
|
4
|
+
* - vtex/actions/orders/cancel.ts
|
|
5
|
+
* @see https://developers.vtex.com/docs/api-reference/orders-api
|
|
6
|
+
*/
|
|
7
|
+
import { vtexFetch, getVtexConfig } from "../client";
|
|
8
|
+
import { buildAuthCookieHeader } from "../utils/vtexId";
|
|
9
|
+
|
|
10
|
+
// ---------------------------------------------------------------------------
|
|
11
|
+
// Action
|
|
12
|
+
// ---------------------------------------------------------------------------
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Cancel an order on behalf of the authenticated user.
|
|
16
|
+
* Hits POST /api/checkout/pub/orders/{orderId}/user-cancel-request
|
|
17
|
+
* on vtexcommercestable.com.br.
|
|
18
|
+
*/
|
|
19
|
+
export async function cancelOrder(
|
|
20
|
+
orderId: string,
|
|
21
|
+
reason: string,
|
|
22
|
+
authCookie?: string,
|
|
23
|
+
): Promise<void> {
|
|
24
|
+
const headers: Record<string, string> = {};
|
|
25
|
+
if (authCookie) {
|
|
26
|
+
headers.Cookie = buildAuthCookieHeader(authCookie, getVtexConfig().account);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
await vtexFetch<unknown>(
|
|
30
|
+
`/api/checkout/pub/orders/${orderId}/user-cancel-request`,
|
|
31
|
+
{
|
|
32
|
+
method: "POST",
|
|
33
|
+
body: JSON.stringify({ reason }),
|
|
34
|
+
headers,
|
|
35
|
+
},
|
|
36
|
+
);
|
|
37
|
+
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* VTEX Profile update action (store-graphql).
|
|
3
|
+
* Ported from deco-cx/apps:
|
|
4
|
+
* - vtex/actions/profile/updateProfile.ts
|
|
5
|
+
* @see https://developers.vtex.com/docs/guides/profile-system
|
|
6
|
+
*/
|
|
7
|
+
import { vtexFetch, getVtexConfig } from "../client";
|
|
8
|
+
import { buildAuthCookieHeader } from "../utils/vtexId";
|
|
9
|
+
|
|
10
|
+
// ---------------------------------------------------------------------------
|
|
11
|
+
// Types
|
|
12
|
+
// ---------------------------------------------------------------------------
|
|
13
|
+
|
|
14
|
+
export interface ProfileInput {
|
|
15
|
+
firstName?: string;
|
|
16
|
+
lastName?: string;
|
|
17
|
+
birthDate?: string;
|
|
18
|
+
gender?: string;
|
|
19
|
+
homePhone?: string;
|
|
20
|
+
businessPhone?: string;
|
|
21
|
+
document?: string;
|
|
22
|
+
email: string;
|
|
23
|
+
tradeName?: string;
|
|
24
|
+
corporateName?: string;
|
|
25
|
+
corporateDocument?: string;
|
|
26
|
+
stateRegistration?: string;
|
|
27
|
+
isCorporate?: boolean;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface Profile {
|
|
31
|
+
cacheId: string;
|
|
32
|
+
firstName: string;
|
|
33
|
+
lastName: string;
|
|
34
|
+
birthDate: string;
|
|
35
|
+
gender: string;
|
|
36
|
+
homePhone: string;
|
|
37
|
+
businessPhone: string;
|
|
38
|
+
document: string;
|
|
39
|
+
email: string;
|
|
40
|
+
tradeName: string;
|
|
41
|
+
corporateName: string;
|
|
42
|
+
corporateDocument: string;
|
|
43
|
+
stateRegistration: string;
|
|
44
|
+
isCorporate: boolean;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// ---------------------------------------------------------------------------
|
|
48
|
+
// GraphQL helper (myvtex.com private graphql)
|
|
49
|
+
// ---------------------------------------------------------------------------
|
|
50
|
+
|
|
51
|
+
interface GqlResponse<T> {
|
|
52
|
+
data: T;
|
|
53
|
+
errors?: Array<{ message: string }>;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
async function gql<T>(
|
|
57
|
+
query: string,
|
|
58
|
+
variables: Record<string, unknown>,
|
|
59
|
+
authCookie: string,
|
|
60
|
+
): Promise<T> {
|
|
61
|
+
const { account } = getVtexConfig();
|
|
62
|
+
const result = await vtexFetch<GqlResponse<T>>(
|
|
63
|
+
`https://${account}.myvtex.com/_v/private/graphql/v1`,
|
|
64
|
+
{
|
|
65
|
+
method: "POST",
|
|
66
|
+
body: JSON.stringify({ query, variables }),
|
|
67
|
+
headers: { Cookie: buildAuthCookieHeader(authCookie, account) },
|
|
68
|
+
},
|
|
69
|
+
);
|
|
70
|
+
if (result.errors?.length) {
|
|
71
|
+
throw new Error(`GraphQL error: ${result.errors[0].message}`);
|
|
72
|
+
}
|
|
73
|
+
return result.data;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// ---------------------------------------------------------------------------
|
|
77
|
+
// Mutation
|
|
78
|
+
// ---------------------------------------------------------------------------
|
|
79
|
+
|
|
80
|
+
const UPDATE_PROFILE = `mutation UpdateProfile($input: ProfileInput!) {
|
|
81
|
+
updateProfile(fields: $input) @context(provider: "vtex.store-graphql") {
|
|
82
|
+
cacheId
|
|
83
|
+
firstName
|
|
84
|
+
lastName
|
|
85
|
+
birthDate
|
|
86
|
+
gender
|
|
87
|
+
homePhone
|
|
88
|
+
businessPhone
|
|
89
|
+
document
|
|
90
|
+
email
|
|
91
|
+
tradeName
|
|
92
|
+
corporateName
|
|
93
|
+
corporateDocument
|
|
94
|
+
stateRegistration
|
|
95
|
+
isCorporate
|
|
96
|
+
}
|
|
97
|
+
}`;
|
|
98
|
+
|
|
99
|
+
// ---------------------------------------------------------------------------
|
|
100
|
+
// Action
|
|
101
|
+
// ---------------------------------------------------------------------------
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Update user profile.
|
|
105
|
+
* The original Deco action extracted `email` from the auth cookie payload.
|
|
106
|
+
* Here the caller must provide it explicitly.
|
|
107
|
+
*/
|
|
108
|
+
export async function updateProfile(
|
|
109
|
+
fields: Omit<ProfileInput, "email">,
|
|
110
|
+
email: string,
|
|
111
|
+
authCookie: string,
|
|
112
|
+
): Promise<Profile> {
|
|
113
|
+
const { updateProfile: profile } = await gql<{ updateProfile: Profile }>(
|
|
114
|
+
UPDATE_PROFILE,
|
|
115
|
+
{ input: { ...fields, email } },
|
|
116
|
+
authCookie,
|
|
117
|
+
);
|
|
118
|
+
return profile;
|
|
119
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* VTEX Sessions API actions.
|
|
3
|
+
* All session-mutating actions return Set-Cookie headers for propagation.
|
|
4
|
+
*/
|
|
5
|
+
import { vtexFetchWithCookies, vtexIOGraphQL, getVtexConfig } from "../client";
|
|
6
|
+
import type { VtexFetchResult } from "../client";
|
|
7
|
+
import { buildAuthCookieHeader } from "../utils/vtexId";
|
|
8
|
+
|
|
9
|
+
// ---------------------------------------------------------------------------
|
|
10
|
+
// createSession
|
|
11
|
+
// ---------------------------------------------------------------------------
|
|
12
|
+
|
|
13
|
+
export interface SessionData {
|
|
14
|
+
id: string;
|
|
15
|
+
namespaces: Record<string, Record<string, { value: string }>>;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export async function createSession(
|
|
19
|
+
data: Record<string, any>,
|
|
20
|
+
cookieHeader?: string,
|
|
21
|
+
): Promise<VtexFetchResult<SessionData>> {
|
|
22
|
+
const headers: Record<string, string> = {};
|
|
23
|
+
if (cookieHeader) headers["cookie"] = cookieHeader;
|
|
24
|
+
return vtexFetchWithCookies<SessionData>("/api/sessions", {
|
|
25
|
+
method: "POST",
|
|
26
|
+
body: JSON.stringify(data),
|
|
27
|
+
headers,
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// ---------------------------------------------------------------------------
|
|
32
|
+
// editSession
|
|
33
|
+
// ---------------------------------------------------------------------------
|
|
34
|
+
|
|
35
|
+
export interface EditSessionResponse {
|
|
36
|
+
id: string;
|
|
37
|
+
namespaces: Record<string, Record<string, { value: string }>>;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Edit the current VTEX session (public properties).
|
|
42
|
+
* Returns data + Set-Cookie headers.
|
|
43
|
+
*/
|
|
44
|
+
export async function editSession(
|
|
45
|
+
publicProperties: Record<string, { value: string }>,
|
|
46
|
+
cookieHeader?: string,
|
|
47
|
+
): Promise<VtexFetchResult<EditSessionResponse>> {
|
|
48
|
+
const headers: Record<string, string> = {};
|
|
49
|
+
if (cookieHeader) headers["cookie"] = cookieHeader;
|
|
50
|
+
|
|
51
|
+
return vtexFetchWithCookies<EditSessionResponse>("/api/sessions", {
|
|
52
|
+
method: "PATCH",
|
|
53
|
+
body: JSON.stringify({ public: { ...publicProperties } }),
|
|
54
|
+
headers,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// ---------------------------------------------------------------------------
|
|
59
|
+
// deleteSession
|
|
60
|
+
// ---------------------------------------------------------------------------
|
|
61
|
+
|
|
62
|
+
export interface DeleteSessionResponse {
|
|
63
|
+
logOutFromSession: string;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const DELETE_SESSION_MUTATION = `mutation LogOutFromSession($sessionId: ID) {
|
|
67
|
+
logOutFromSession(sessionId: $sessionId) @context(provider: "vtex.store-graphql@2.x")
|
|
68
|
+
}`;
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Log out / delete a VTEX session via the store-graphql mutation.
|
|
72
|
+
* Requires a valid auth cookie.
|
|
73
|
+
*/
|
|
74
|
+
export async function deleteSession(
|
|
75
|
+
sessionId: string,
|
|
76
|
+
authCookie: string,
|
|
77
|
+
): Promise<DeleteSessionResponse> {
|
|
78
|
+
if (!authCookie) throw new Error("Auth cookie is required to delete session");
|
|
79
|
+
const { account } = getVtexConfig();
|
|
80
|
+
return vtexIOGraphQL<DeleteSessionResponse>(
|
|
81
|
+
{
|
|
82
|
+
query: DELETE_SESSION_MUTATION,
|
|
83
|
+
variables: { sessionId },
|
|
84
|
+
},
|
|
85
|
+
{ cookie: buildAuthCookieHeader(authCookie, account) },
|
|
86
|
+
);
|
|
87
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* VTEX SKU change notification (trigger/webhook) types.
|
|
3
|
+
*
|
|
4
|
+
* Ported from `vtex/_to-port/actions/trigger.ts`.
|
|
5
|
+
* The original Deco action forwarded the payload to a Durable Object workflow.
|
|
6
|
+
* Actual webhook handling is framework-specific, so we only export the
|
|
7
|
+
* canonical payload interface and a handler signature type here.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/** Payload sent by VTEX when a SKU changes in the catalog. */
|
|
11
|
+
export interface VTEXNotificationPayload {
|
|
12
|
+
/** SKU ID in VTEX. */
|
|
13
|
+
IdSku: string;
|
|
14
|
+
/** Seller's account name in VTEX (visible in the store's Admin URL). */
|
|
15
|
+
An: string;
|
|
16
|
+
/** Affiliate ID generated automatically in the configuration. */
|
|
17
|
+
IdAffiliate: string;
|
|
18
|
+
/** Product ID in VTEX. */
|
|
19
|
+
ProductId: number;
|
|
20
|
+
/** Date when the item was updated. */
|
|
21
|
+
DateModified: string;
|
|
22
|
+
/**
|
|
23
|
+
* Whether the product is active. `false` means the product was
|
|
24
|
+
* deactivated and should be blocked / zeroed in the marketplace.
|
|
25
|
+
*/
|
|
26
|
+
IsActive: boolean;
|
|
27
|
+
/** Inventory level has changed -- run a Fulfillment Simulation to refresh. */
|
|
28
|
+
StockModified: boolean;
|
|
29
|
+
/** Price has changed -- run a Fulfillment Simulation to refresh. */
|
|
30
|
+
PriceModified: boolean;
|
|
31
|
+
/** Product/SKU registration data changed (name, description, weight, etc.). */
|
|
32
|
+
HasStockKeepingUnitModified: boolean;
|
|
33
|
+
/** Product is no longer associated with the trade policy. */
|
|
34
|
+
HasStockKeepingUnitRemovedFromAffiliate: boolean;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Generic handler signature for the VTEX trigger webhook.
|
|
39
|
+
* Implement this in your framework layer (e.g. TanStack Start API route).
|
|
40
|
+
*/
|
|
41
|
+
export type VTEXTriggerHandler = (
|
|
42
|
+
payload: VTEXNotificationPayload,
|
|
43
|
+
) => Promise<{ id: string } | void>;
|