@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.
Files changed (113) hide show
  1. package/.github/workflows/release.yml +34 -0
  2. package/.releaserc.json +25 -0
  3. package/commerce/components/Image.tsx +209 -0
  4. package/commerce/components/JsonLd.tsx +285 -0
  5. package/commerce/sdk/analytics.ts +24 -0
  6. package/commerce/sdk/formatPrice.ts +23 -0
  7. package/commerce/sdk/url.ts +9 -0
  8. package/commerce/sdk/useOffer.ts +75 -0
  9. package/commerce/sdk/useVariantPossibilities.ts +43 -0
  10. package/commerce/types/commerce.ts +1105 -0
  11. package/commerce/utils/canonical.ts +11 -0
  12. package/commerce/utils/constants.ts +9 -0
  13. package/commerce/utils/filters.ts +10 -0
  14. package/commerce/utils/productToAnalyticsItem.ts +67 -0
  15. package/commerce/utils/stateByZip.ts +50 -0
  16. package/knip.json +19 -0
  17. package/package.json +77 -0
  18. package/shopify/actions/cart/addItems.ts +37 -0
  19. package/shopify/actions/cart/updateCoupons.ts +32 -0
  20. package/shopify/actions/cart/updateItems.ts +32 -0
  21. package/shopify/actions/user/signIn.ts +45 -0
  22. package/shopify/actions/user/signUp.ts +36 -0
  23. package/shopify/client.ts +58 -0
  24. package/shopify/index.ts +32 -0
  25. package/shopify/init.ts +40 -0
  26. package/shopify/loaders/ProductDetailsPage.ts +35 -0
  27. package/shopify/loaders/ProductList.ts +101 -0
  28. package/shopify/loaders/ProductListingPage.ts +180 -0
  29. package/shopify/loaders/RelatedProducts.ts +45 -0
  30. package/shopify/loaders/cart.ts +73 -0
  31. package/shopify/loaders/shop.ts +40 -0
  32. package/shopify/loaders/user.ts +44 -0
  33. package/shopify/utils/admin/admin.ts +57 -0
  34. package/shopify/utils/admin/queries.ts +29 -0
  35. package/shopify/utils/cart.ts +28 -0
  36. package/shopify/utils/cookies.ts +85 -0
  37. package/shopify/utils/enums.ts +438 -0
  38. package/shopify/utils/graphql.ts +69 -0
  39. package/shopify/utils/storefront/queries.ts +530 -0
  40. package/shopify/utils/storefront/storefront.graphql.gen.ts +113 -0
  41. package/shopify/utils/transform.ts +436 -0
  42. package/shopify/utils/types.ts +191 -0
  43. package/shopify/utils/user.ts +23 -0
  44. package/shopify/utils/utils.ts +164 -0
  45. package/tsconfig.json +11 -0
  46. package/vtex/README.md +6 -0
  47. package/vtex/actions/address.ts +211 -0
  48. package/vtex/actions/auth.ts +337 -0
  49. package/vtex/actions/checkout.ts +497 -0
  50. package/vtex/actions/index.ts +11 -0
  51. package/vtex/actions/masterData.ts +170 -0
  52. package/vtex/actions/misc.ts +196 -0
  53. package/vtex/actions/newsletter.ts +108 -0
  54. package/vtex/actions/orders.ts +37 -0
  55. package/vtex/actions/profile.ts +119 -0
  56. package/vtex/actions/session.ts +87 -0
  57. package/vtex/actions/trigger.ts +43 -0
  58. package/vtex/actions/wishlist.ts +116 -0
  59. package/vtex/client.ts +423 -0
  60. package/vtex/hooks/index.ts +4 -0
  61. package/vtex/hooks/useAutocomplete.ts +89 -0
  62. package/vtex/hooks/useCart.ts +219 -0
  63. package/vtex/hooks/useUser.ts +78 -0
  64. package/vtex/hooks/useWishlist.ts +119 -0
  65. package/vtex/index.ts +14 -0
  66. package/vtex/inline-loaders/productDetailsPage.ts +75 -0
  67. package/vtex/inline-loaders/productList.ts +163 -0
  68. package/vtex/inline-loaders/productListingPage.ts +447 -0
  69. package/vtex/inline-loaders/relatedProducts.ts +83 -0
  70. package/vtex/inline-loaders/suggestions.ts +49 -0
  71. package/vtex/inline-loaders/workflowProducts.ts +68 -0
  72. package/vtex/invoke.ts +202 -0
  73. package/vtex/loaders/address.ts +120 -0
  74. package/vtex/loaders/brands.ts +51 -0
  75. package/vtex/loaders/cart.ts +49 -0
  76. package/vtex/loaders/catalog.ts +165 -0
  77. package/vtex/loaders/collections.ts +57 -0
  78. package/vtex/loaders/index.ts +19 -0
  79. package/vtex/loaders/legacy.ts +671 -0
  80. package/vtex/loaders/logistics.ts +115 -0
  81. package/vtex/loaders/navbar.ts +29 -0
  82. package/vtex/loaders/orders.ts +103 -0
  83. package/vtex/loaders/pageType.ts +62 -0
  84. package/vtex/loaders/payment.ts +107 -0
  85. package/vtex/loaders/profile.ts +138 -0
  86. package/vtex/loaders/promotion.ts +33 -0
  87. package/vtex/loaders/search.ts +127 -0
  88. package/vtex/loaders/session.ts +91 -0
  89. package/vtex/loaders/user.ts +89 -0
  90. package/vtex/loaders/wishlist.ts +89 -0
  91. package/vtex/loaders/wishlistProducts.ts +81 -0
  92. package/vtex/loaders/workflow.ts +323 -0
  93. package/vtex/logo.png +0 -0
  94. package/vtex/middleware.ts +229 -0
  95. package/vtex/types.ts +248 -0
  96. package/vtex/utils/batch.ts +21 -0
  97. package/vtex/utils/cookies.ts +76 -0
  98. package/vtex/utils/enrichment.ts +540 -0
  99. package/vtex/utils/fetchCache.ts +150 -0
  100. package/vtex/utils/index.ts +17 -0
  101. package/vtex/utils/intelligentSearch.ts +84 -0
  102. package/vtex/utils/legacy.ts +155 -0
  103. package/vtex/utils/pickAndOmit.ts +30 -0
  104. package/vtex/utils/proxy.ts +196 -0
  105. package/vtex/utils/resourceRange.ts +10 -0
  106. package/vtex/utils/segment.ts +163 -0
  107. package/vtex/utils/similars.ts +38 -0
  108. package/vtex/utils/sitemap.ts +133 -0
  109. package/vtex/utils/slugCache.ts +32 -0
  110. package/vtex/utils/slugify.ts +13 -0
  111. package/vtex/utils/transform.ts +1331 -0
  112. package/vtex/utils/types.ts +1884 -0
  113. package/vtex/utils/vtexId.ts +103 -0
@@ -0,0 +1,337 @@
1
+ /**
2
+ * VTEX Authentication Actions
3
+ *
4
+ * Ported from deco-cx/apps vtex/actions/authentication/*.ts
5
+ * @see https://github.com/deco-cx/apps/tree/main/vtex/actions/authentication
6
+ */
7
+
8
+ import type { VtexFetchResult } from "../client";
9
+ import {
10
+ getVtexConfig,
11
+ vtexFetchWithCookies,
12
+ } from "../client";
13
+ import { VTEX_AUTH_COOKIE } from "../utils/vtexId";
14
+
15
+ // ---------------------------------------------------------------------------
16
+ // Types
17
+ // ---------------------------------------------------------------------------
18
+
19
+ export interface AuthProvider {
20
+ providerName: string;
21
+ className: string;
22
+ expectedContext: unknown[];
23
+ }
24
+
25
+ export interface StartAuthentication {
26
+ authenticationToken: string | null;
27
+ oauthProviders: AuthProvider[];
28
+ showClassicAuthentication: boolean;
29
+ showAccessKeyAuthentication: boolean;
30
+ showPasskeyAuthentication: boolean;
31
+ authCookie: string | null;
32
+ isAuthenticated: boolean;
33
+ selectedProvider: string | null;
34
+ samlProviders: unknown[];
35
+ }
36
+
37
+ export interface AuthResponse {
38
+ authStatus: string | "WrongCredentials" | "BlockedUser" | "Success";
39
+ promptMFA: boolean;
40
+ clientToken: string | null;
41
+ authCookie: { Name: string; Value: string } | null;
42
+ accountAuthCookie: { Name: string; Value: string } | null;
43
+ expiresIn: number;
44
+ userId: string | null;
45
+ phoneNumber: string | null;
46
+ scope: string | null;
47
+ }
48
+
49
+ export interface RefreshTokenResponse {
50
+ status: string;
51
+ userId: string;
52
+ refreshAfter: string;
53
+ }
54
+
55
+ /**
56
+ * Cookies to set after a successful login.
57
+ * Caller (server function) should use these to set cookies on the response.
58
+ */
59
+ export interface LoginCookies {
60
+ authCookieName: string;
61
+ authCookieValue: string;
62
+ accountAuthCookieName?: string;
63
+ accountAuthCookieValue?: string;
64
+ expiresInSeconds: number;
65
+ }
66
+
67
+ // ---------------------------------------------------------------------------
68
+ // Helpers
69
+ // ---------------------------------------------------------------------------
70
+
71
+ const FORM_HEADERS = {
72
+ "Content-Type": "application/x-www-form-urlencoded",
73
+ Accept: "application/json",
74
+ };
75
+
76
+ /**
77
+ * Extract login cookies from an AuthResponse.
78
+ * Returns null if auth failed.
79
+ */
80
+ export function extractLoginCookies(
81
+ response: AuthResponse,
82
+ ): LoginCookies | null {
83
+ if (response.authStatus !== "Success" || !response.authCookie) {
84
+ return null;
85
+ }
86
+ return {
87
+ authCookieName: response.authCookie.Name,
88
+ authCookieValue: response.authCookie.Value,
89
+ accountAuthCookieName: response.accountAuthCookie?.Name,
90
+ accountAuthCookieValue: response.accountAuthCookie?.Value,
91
+ expiresInSeconds: response.expiresIn,
92
+ };
93
+ }
94
+
95
+ // ---------------------------------------------------------------------------
96
+ // Actions
97
+ // ---------------------------------------------------------------------------
98
+
99
+ export async function startAuthentication(options?: {
100
+ callbackUrl?: string;
101
+ returnUrl?: string;
102
+ locale?: string;
103
+ appStart?: boolean;
104
+ }): Promise<VtexFetchResult<StartAuthentication>> {
105
+ const config = getVtexConfig();
106
+ const {
107
+ callbackUrl = "/",
108
+ returnUrl = "/",
109
+ locale = config.locale ?? "pt-BR",
110
+ appStart = true,
111
+ } = options ?? {};
112
+
113
+ const params = new URLSearchParams({
114
+ locale,
115
+ scope: config.account,
116
+ appStart: String(appStart),
117
+ callbackUrl,
118
+ returnUrl,
119
+ });
120
+
121
+ return vtexFetchWithCookies<StartAuthentication>(
122
+ `/api/vtexid/pub/authentication/start?${params}`,
123
+ );
124
+ }
125
+
126
+ /**
127
+ * Classic email + password sign-in.
128
+ * Calls startAuthentication internally if no authenticationToken provided.
129
+ */
130
+ export async function classicSignIn(
131
+ email: string,
132
+ password: string,
133
+ authenticationToken?: string,
134
+ ): Promise<VtexFetchResult<AuthResponse>> {
135
+ let token = authenticationToken;
136
+ let startCookies: string[] = [];
137
+ if (!token) {
138
+ const startResult = await startAuthentication();
139
+ token = startResult.data.authenticationToken ?? undefined;
140
+ startCookies = startResult.setCookies;
141
+ if (!token)
142
+ throw new Error(
143
+ "Failed to obtain authentication token from startAuthentication",
144
+ );
145
+ }
146
+
147
+ const body = new URLSearchParams({
148
+ email,
149
+ password,
150
+ authenticationToken: token,
151
+ });
152
+ const result = await vtexFetchWithCookies<AuthResponse>(
153
+ "/api/vtexid/pub/authentication/classic/validate",
154
+ { method: "POST", body, headers: FORM_HEADERS },
155
+ );
156
+ result.setCookies = [...startCookies, ...result.setCookies];
157
+ return result;
158
+ }
159
+
160
+ /**
161
+ * Passwordless sign-in via email access key.
162
+ * Reads VtexSessionToken from cookie if not provided directly.
163
+ */
164
+ export async function accessKeySignIn(
165
+ email: string,
166
+ accessKey: string,
167
+ authenticationToken: string,
168
+ ): Promise<VtexFetchResult<AuthResponse>> {
169
+ const body = new URLSearchParams({
170
+ login: email,
171
+ accessKey,
172
+ authenticationToken,
173
+ });
174
+
175
+ return vtexFetchWithCookies<AuthResponse>(
176
+ "/api/vtexid/pub/authentication/accesskey/validate",
177
+ { method: "POST", body, headers: FORM_HEADERS },
178
+ );
179
+ }
180
+
181
+ /**
182
+ * Logout — returns list of cookie names that must be cleared (Max-Age=0).
183
+ * Also calls deleteSession if a sessionId cookie is available.
184
+ */
185
+ export function logout(): { cookiesToClear: string[] } {
186
+ const { account } = getVtexConfig();
187
+ return {
188
+ cookiesToClear: [
189
+ VTEX_AUTH_COOKIE,
190
+ `${VTEX_AUTH_COOKIE}_${account}`,
191
+ "vid_rt",
192
+ `vid_rt_${account}`,
193
+ ],
194
+ };
195
+ }
196
+
197
+ /**
198
+ * Refreshes the VTEX auth token using existing session cookies.
199
+ */
200
+ export async function refreshToken(
201
+ cookieHeader: string,
202
+ fingerprint?: string,
203
+ ): Promise<VtexFetchResult<RefreshTokenResponse>> {
204
+ return vtexFetchWithCookies<RefreshTokenResponse>(
205
+ "/api/vtexid/refreshtoken/webstore",
206
+ {
207
+ method: "POST",
208
+ body: JSON.stringify({ fingerprint }),
209
+ headers: { cookie: cookieHeader },
210
+ },
211
+ );
212
+ }
213
+
214
+ /**
215
+ * Sets a new password using an email access key (password-recovery flow).
216
+ */
217
+ export async function recoveryPassword(
218
+ email: string,
219
+ newPassword: string,
220
+ accessKey: string,
221
+ authenticationToken: string,
222
+ locale?: string,
223
+ ): Promise<VtexFetchResult<AuthResponse>> {
224
+ const config = getVtexConfig();
225
+
226
+ const params = new URLSearchParams({
227
+ scope: config.account,
228
+ locale: locale ?? config.locale ?? "pt-BR",
229
+ });
230
+
231
+ const body = new URLSearchParams({
232
+ login: email,
233
+ accessKey,
234
+ newPassword,
235
+ authenticationToken,
236
+ });
237
+
238
+ return vtexFetchWithCookies<AuthResponse>(
239
+ `/api/vtexid/pub/authentication/classic/setpassword?${params}`,
240
+ { method: "POST", body, headers: FORM_HEADERS },
241
+ );
242
+ }
243
+
244
+ /**
245
+ * Resets password for an already-authenticated user.
246
+ * Calls startAuthentication internally if no authenticationToken provided.
247
+ */
248
+ export async function resetPassword(
249
+ email: string,
250
+ currentPassword: string,
251
+ newPassword: string,
252
+ authenticationToken?: string,
253
+ locale?: string,
254
+ ): Promise<VtexFetchResult<AuthResponse>> {
255
+ const config = getVtexConfig();
256
+
257
+ let token = authenticationToken;
258
+ let startCookies: string[] = [];
259
+ if (!token) {
260
+ const startResult = await startAuthentication({ locale });
261
+ token = startResult.data.authenticationToken ?? undefined;
262
+ startCookies = startResult.setCookies;
263
+ if (!token)
264
+ throw new Error(
265
+ "Failed to obtain authentication token from startAuthentication",
266
+ );
267
+ }
268
+
269
+ const params = new URLSearchParams({
270
+ scope: config.account,
271
+ locale: locale ?? config.locale ?? "pt-BR",
272
+ });
273
+
274
+ const body = new URLSearchParams({
275
+ login: email,
276
+ currentPassword,
277
+ newPassword,
278
+ authenticationToken: token,
279
+ });
280
+
281
+ const result = await vtexFetchWithCookies<AuthResponse>(
282
+ `/api/vtexid/pub/authentication/classic/setpassword?${params}`,
283
+ { method: "POST", body, headers: FORM_HEADERS },
284
+ );
285
+ result.setCookies = [...startCookies, ...result.setCookies];
286
+ return result;
287
+ }
288
+
289
+ /**
290
+ * Sends an access-key verification email.
291
+ * Calls startAuthentication internally if no authenticationToken provided.
292
+ * Returns { success, authenticationToken, setCookies }.
293
+ */
294
+ export async function sendEmailVerification(
295
+ email: string,
296
+ authenticationToken?: string,
297
+ locale?: string,
298
+ parentAppId?: string,
299
+ ): Promise<{
300
+ success: boolean;
301
+ authenticationToken: string | null;
302
+ setCookies: string[];
303
+ }> {
304
+ try {
305
+ let token = authenticationToken;
306
+ let startCookies: string[] = [];
307
+
308
+ if (!token) {
309
+ const startResult = await startAuthentication({ locale });
310
+ token = startResult.data.authenticationToken ?? undefined;
311
+ startCookies = startResult.setCookies;
312
+ if (!token) throw new Error("Failed to obtain authentication token");
313
+ }
314
+
315
+ const body = new URLSearchParams({ authenticationToken: token, email });
316
+ if (locale) body.append("locale", locale);
317
+ if (parentAppId) body.append("parentAppId", parentAppId);
318
+
319
+ const result = await vtexFetchWithCookies<Record<string, string>>(
320
+ "/api/vtexid/pub/authentication/accesskey/send?deliveryMethod=email",
321
+ { method: "POST", body, headers: FORM_HEADERS },
322
+ );
323
+
324
+ if (result.data?.authStatus === "InvalidToken") {
325
+ throw new Error("Authentication token is invalid");
326
+ }
327
+
328
+ return {
329
+ success: true,
330
+ authenticationToken: token,
331
+ setCookies: [...startCookies, ...result.setCookies],
332
+ };
333
+ } catch (error) {
334
+ console.error("[sendEmailVerification]", error);
335
+ return { success: false, authenticationToken: null, setCookies: [] };
336
+ }
337
+ }