@decocms/apps 0.27.0 → 0.28.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/commerce/app-types.ts +62 -0
- package/commerce/manifest-utils.ts +38 -0
- package/commerce/resolve.ts +114 -0
- package/commerce/sdk/formatPrice.ts +1 -4
- package/package.json +11 -4
- package/resend/manifest.gen.ts +15 -0
- package/resend/mod.ts +33 -19
- package/shopify/index.ts +3 -0
- package/shopify/manifest.gen.ts +39 -0
- package/shopify/mod.ts +67 -0
- package/vtex/actions/auth.ts +77 -68
- package/vtex/actions/checkout.ts +224 -205
- package/vtex/actions/masterData.ts +32 -18
- package/vtex/actions/session.ts +20 -23
- package/vtex/client.ts +51 -76
- package/vtex/index.ts +2 -1
- package/vtex/manifest.gen.ts +75 -0
- package/vtex/mod.ts +83 -0
- package/vtex/invoke.ts +0 -196
|
@@ -16,25 +16,37 @@ export interface CreateDocumentResult {
|
|
|
16
16
|
DocumentId: string;
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
export
|
|
20
|
-
entity: string
|
|
21
|
-
data: Record<string, any
|
|
22
|
-
|
|
19
|
+
export interface CreateDocumentProps {
|
|
20
|
+
entity: string;
|
|
21
|
+
data: Record<string, any>;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export async function createDocument(props: CreateDocumentProps): Promise<CreateDocumentResult> {
|
|
25
|
+
const { entity, data } = props;
|
|
23
26
|
return vtexFetch<CreateDocumentResult>(`/api/dataentities/${entity}/documents`, {
|
|
24
27
|
method: "POST",
|
|
25
28
|
body: JSON.stringify(removeEmptyFields(data)),
|
|
26
29
|
});
|
|
27
30
|
}
|
|
28
31
|
|
|
29
|
-
export
|
|
32
|
+
export interface GetDocumentProps {
|
|
33
|
+
entity: string;
|
|
34
|
+
documentId: string;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export async function getDocument<T = unknown>(props: GetDocumentProps): Promise<T> {
|
|
38
|
+
const { entity, documentId } = props;
|
|
30
39
|
return vtexFetch<T>(`/api/dataentities/${entity}/documents/${documentId}`);
|
|
31
40
|
}
|
|
32
41
|
|
|
33
|
-
export
|
|
34
|
-
entity: string
|
|
35
|
-
documentId: string
|
|
36
|
-
data: Record<string, any
|
|
37
|
-
|
|
42
|
+
export interface PatchDocumentProps {
|
|
43
|
+
entity: string;
|
|
44
|
+
documentId: string;
|
|
45
|
+
data: Record<string, any>;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export async function patchDocument(props: PatchDocumentProps): Promise<void> {
|
|
49
|
+
const { entity, documentId, data } = props;
|
|
38
50
|
await vtexFetch<any>(`/api/dataentities/${entity}/documents/${documentId}`, {
|
|
39
51
|
method: "PATCH",
|
|
40
52
|
body: JSON.stringify(removeEmptyFields(data)),
|
|
@@ -49,13 +61,18 @@ export interface MasterDataSearchResult {
|
|
|
49
61
|
[key: string]: any;
|
|
50
62
|
}
|
|
51
63
|
|
|
64
|
+
export interface SearchDocumentsProps {
|
|
65
|
+
entity: string;
|
|
66
|
+
filter: string;
|
|
67
|
+
}
|
|
68
|
+
|
|
52
69
|
/**
|
|
53
70
|
* Simple search — kept for backward compat.
|
|
54
71
|
*/
|
|
55
72
|
export async function searchDocuments<T = MasterDataSearchResult>(
|
|
56
|
-
|
|
57
|
-
filter: string,
|
|
73
|
+
props: SearchDocumentsProps,
|
|
58
74
|
): Promise<T[]> {
|
|
75
|
+
const { entity, filter } = props;
|
|
59
76
|
return vtexFetch<T[]>(`/api/dataentities/${entity}/search?_where=${encodeURIComponent(filter)}`);
|
|
60
77
|
}
|
|
61
78
|
|
|
@@ -65,7 +82,7 @@ export async function searchDocuments<T = MasterDataSearchResult>(
|
|
|
65
82
|
*
|
|
66
83
|
* @see https://developers.vtex.com/docs/api-reference/masterdata-api#get-/api/dataentities/-acronym-/search
|
|
67
84
|
*/
|
|
68
|
-
export interface
|
|
85
|
+
export interface SearchDocumentsFullProps {
|
|
69
86
|
acronym: string;
|
|
70
87
|
fields?: string;
|
|
71
88
|
where?: string;
|
|
@@ -74,14 +91,12 @@ export interface SearchDocumentsOpts {
|
|
|
74
91
|
take?: number;
|
|
75
92
|
/** @default 0 */
|
|
76
93
|
skip?: number;
|
|
77
|
-
/** Auth cookie header for authenticated queries */
|
|
78
|
-
cookieHeader?: string;
|
|
79
94
|
}
|
|
80
95
|
|
|
81
96
|
export async function searchDocumentsFull<T = Record<string, unknown>>(
|
|
82
|
-
|
|
97
|
+
props: SearchDocumentsFullProps,
|
|
83
98
|
): Promise<T[]> {
|
|
84
|
-
const { acronym, fields, where, sort, skip = 0, take = 10
|
|
99
|
+
const { acronym, fields, where, sort, skip = 0, take = 10 } = props;
|
|
85
100
|
const from = Math.max(skip, 0);
|
|
86
101
|
const to = from + Math.min(100, take);
|
|
87
102
|
|
|
@@ -95,7 +110,6 @@ export async function searchDocumentsFull<T = Record<string, unknown>>(
|
|
|
95
110
|
"content-type": "application/json",
|
|
96
111
|
"REST-Range": `resources=${from}-${to}`,
|
|
97
112
|
};
|
|
98
|
-
if (cookieHeader) headers.cookie = cookieHeader;
|
|
99
113
|
|
|
100
114
|
return vtexFetchResponse(`/api/dataentities/${acronym}/search?${params}`, {
|
|
101
115
|
headers,
|
package/vtex/actions/session.ts
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* VTEX Sessions API actions.
|
|
3
|
-
*
|
|
3
|
+
* Cookie forwarding happens automatically via RequestContext.responseHeaders.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import type { VtexFetchResult } from "../client";
|
|
7
6
|
import { getVtexConfig, vtexFetchWithCookies, vtexIOGraphQL } from "../client";
|
|
8
7
|
import { buildAuthCookieHeader } from "../utils/vtexId";
|
|
9
8
|
|
|
@@ -16,16 +15,15 @@ export interface SessionData {
|
|
|
16
15
|
namespaces: Record<string, Record<string, { value: string }>>;
|
|
17
16
|
}
|
|
18
17
|
|
|
19
|
-
export
|
|
20
|
-
data: Record<string, any
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
18
|
+
export interface CreateSessionProps {
|
|
19
|
+
data: Record<string, any>;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export async function createSession(props: CreateSessionProps): Promise<SessionData> {
|
|
23
|
+
const { data } = props;
|
|
25
24
|
return vtexFetchWithCookies<SessionData>("/api/sessions", {
|
|
26
25
|
method: "POST",
|
|
27
26
|
body: JSON.stringify(data),
|
|
28
|
-
headers,
|
|
29
27
|
});
|
|
30
28
|
}
|
|
31
29
|
|
|
@@ -38,21 +36,17 @@ export interface EditSessionResponse {
|
|
|
38
36
|
namespaces: Record<string, Record<string, { value: string }>>;
|
|
39
37
|
}
|
|
40
38
|
|
|
39
|
+
export interface EditSessionProps {
|
|
40
|
+
public: Record<string, { value: string }>;
|
|
41
|
+
}
|
|
42
|
+
|
|
41
43
|
/**
|
|
42
44
|
* Edit the current VTEX session (public properties).
|
|
43
|
-
* Returns data + Set-Cookie headers.
|
|
44
45
|
*/
|
|
45
|
-
export async function editSession(
|
|
46
|
-
publicProperties: Record<string, { value: string }>,
|
|
47
|
-
cookieHeader?: string,
|
|
48
|
-
): Promise<VtexFetchResult<EditSessionResponse>> {
|
|
49
|
-
const headers: Record<string, string> = {};
|
|
50
|
-
if (cookieHeader) headers.cookie = cookieHeader;
|
|
51
|
-
|
|
46
|
+
export async function editSession(props: EditSessionProps): Promise<EditSessionResponse> {
|
|
52
47
|
return vtexFetchWithCookies<EditSessionResponse>("/api/sessions", {
|
|
53
48
|
method: "PATCH",
|
|
54
|
-
body: JSON.stringify({ public: { ...
|
|
55
|
-
headers,
|
|
49
|
+
body: JSON.stringify({ public: { ...props.public } }),
|
|
56
50
|
});
|
|
57
51
|
}
|
|
58
52
|
|
|
@@ -68,14 +62,17 @@ const DELETE_SESSION_MUTATION = `mutation LogOutFromSession($sessionId: ID) {
|
|
|
68
62
|
logOutFromSession(sessionId: $sessionId) @context(provider: "vtex.store-graphql@2.x")
|
|
69
63
|
}`;
|
|
70
64
|
|
|
65
|
+
export interface DeleteSessionProps {
|
|
66
|
+
sessionId: string;
|
|
67
|
+
authCookie: string;
|
|
68
|
+
}
|
|
69
|
+
|
|
71
70
|
/**
|
|
72
71
|
* Log out / delete a VTEX session via the store-graphql mutation.
|
|
73
72
|
* Requires a valid auth cookie.
|
|
74
73
|
*/
|
|
75
|
-
export async function deleteSession(
|
|
76
|
-
sessionId
|
|
77
|
-
authCookie: string,
|
|
78
|
-
): Promise<DeleteSessionResponse> {
|
|
74
|
+
export async function deleteSession(props: DeleteSessionProps): Promise<DeleteSessionResponse> {
|
|
75
|
+
const { sessionId, authCookie } = props;
|
|
79
76
|
if (!authCookie) throw new Error("Auth cookie is required to delete session");
|
|
80
77
|
const { account } = getVtexConfig();
|
|
81
78
|
return vtexIOGraphQL<DeleteSessionResponse>(
|
package/vtex/client.ts
CHANGED
|
@@ -3,9 +3,29 @@
|
|
|
3
3
|
* Uses VTEX's public REST APIs (Intelligent Search + Catalog + Checkout).
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
+
import { RequestContext } from "@decocms/start/sdk/requestContext";
|
|
6
7
|
import { type FetchCacheOptions, fetchWithCache } from "./utils/fetchCache";
|
|
7
8
|
import { parseSegment, SEGMENT_COOKIE_NAME } from "./utils/segment";
|
|
8
9
|
|
|
10
|
+
/**
|
|
11
|
+
* Get the response headers from RequestContext.
|
|
12
|
+
* Uses `responseHeaders` when available (@decocms/start PR#57),
|
|
13
|
+
* falls back to the bag with a lazily-created Headers instance.
|
|
14
|
+
* TODO: Remove fallback once @decocms/start PR#57 is published.
|
|
15
|
+
*/
|
|
16
|
+
function getResponseHeaders(): Headers | null {
|
|
17
|
+
const ctx = RequestContext.current;
|
|
18
|
+
if (!ctx) return null;
|
|
19
|
+
// biome-ignore lint/suspicious/noExplicitAny: forward-compat with upcoming responseHeaders property
|
|
20
|
+
if ((ctx as any).responseHeaders instanceof Headers) return (ctx as any).responseHeaders;
|
|
21
|
+
let headers = ctx.bag.get("responseHeaders") as Headers | undefined;
|
|
22
|
+
if (!headers) {
|
|
23
|
+
headers = new Headers();
|
|
24
|
+
ctx.bag.set("responseHeaders", headers);
|
|
25
|
+
}
|
|
26
|
+
return headers;
|
|
27
|
+
}
|
|
28
|
+
|
|
9
29
|
// ---------------------------------------------------------------------------
|
|
10
30
|
// URL sanitization (ported from deco-cx/apps vtex/utils/fetchVTEX.ts)
|
|
11
31
|
// ---------------------------------------------------------------------------
|
|
@@ -82,8 +102,6 @@ export interface VtexConfig {
|
|
|
82
102
|
|
|
83
103
|
let _config: VtexConfig | null = null;
|
|
84
104
|
let _fetch: typeof fetch = globalThis.fetch;
|
|
85
|
-
let _getCookieHeader: (() => string | undefined) | null = null;
|
|
86
|
-
let _forwardSetCookies: ((cookies: string[]) => void) | null = null;
|
|
87
105
|
|
|
88
106
|
export function configureVtex(config: VtexConfig) {
|
|
89
107
|
_config = config;
|
|
@@ -105,37 +123,6 @@ export function setVtexFetch(fetchFn: typeof fetch) {
|
|
|
105
123
|
_fetch = fetchFn;
|
|
106
124
|
}
|
|
107
125
|
|
|
108
|
-
/**
|
|
109
|
-
* Register a provider that returns the Cookie header from the current request.
|
|
110
|
-
* Called automatically by vtexFetchWithCookies when no explicit cookieHeader
|
|
111
|
-
* is present in the request init — so checkout/session/auth actions
|
|
112
|
-
* transparently forward browser cookies to the VTEX API.
|
|
113
|
-
*
|
|
114
|
-
* @example
|
|
115
|
-
* ```ts
|
|
116
|
-
* import { getRequestHeader } from "@tanstack/react-start/server";
|
|
117
|
-
* setRequestCookieProvider(() => getRequestHeader("cookie") ?? undefined);
|
|
118
|
-
* ```
|
|
119
|
-
*/
|
|
120
|
-
export function setRequestCookieProvider(fn: () => string | undefined) {
|
|
121
|
-
_getCookieHeader = fn;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
/**
|
|
125
|
-
* Register a callback that forwards VTEX Set-Cookie headers back to the browser.
|
|
126
|
-
* Called automatically by vtexFetchWithCookies after every response that
|
|
127
|
-
* carries Set-Cookie headers.
|
|
128
|
-
*
|
|
129
|
-
* @example
|
|
130
|
-
* ```ts
|
|
131
|
-
* import { setResponseHeader } from "@tanstack/react-start/server";
|
|
132
|
-
* setResponseCookieForwarder((cookies) => setResponseHeader("set-cookie", cookies));
|
|
133
|
-
* ```
|
|
134
|
-
*/
|
|
135
|
-
export function setResponseCookieForwarder(fn: (cookies: string[]) => void) {
|
|
136
|
-
_forwardSetCookies = fn;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
126
|
export function getVtexConfig(): VtexConfig {
|
|
140
127
|
if (!_config) throw new Error("VTEX not configured. Call configureVtex() first.");
|
|
141
128
|
return _config;
|
|
@@ -174,11 +161,12 @@ function authHeaders(): Record<string, string> {
|
|
|
174
161
|
|
|
175
162
|
/**
|
|
176
163
|
* Read regionId from the current request's vtex_segment cookie.
|
|
177
|
-
* Returns null when
|
|
164
|
+
* Returns null when outside a request context or no regionId is set.
|
|
178
165
|
*/
|
|
179
166
|
function extractRegionIdFromCookies(): string | null {
|
|
180
|
-
|
|
181
|
-
|
|
167
|
+
const ctx = RequestContext.current;
|
|
168
|
+
if (!ctx) return null;
|
|
169
|
+
const cookies = ctx.request.headers.get("cookie");
|
|
182
170
|
if (!cookies) return null;
|
|
183
171
|
const match = cookies.match(new RegExp(`(?:^|;\\s*)${SEGMENT_COOKIE_NAME}=([^;]+)`));
|
|
184
172
|
if (!match?.[1]) return null;
|
|
@@ -240,56 +228,43 @@ export async function vtexCachedFetch<T>(
|
|
|
240
228
|
}
|
|
241
229
|
|
|
242
230
|
/**
|
|
243
|
-
*
|
|
244
|
-
* In TanStack Start, the caller (server function) is responsible for
|
|
245
|
-
* forwarding these cookies to the client via `setCookie` from vinxi/http.
|
|
246
|
-
*/
|
|
247
|
-
export interface VtexFetchResult<T> {
|
|
248
|
-
data: T;
|
|
249
|
-
setCookies: string[];
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
/**
|
|
253
|
-
* Like vtexFetch, but also returns Set-Cookie headers from the response.
|
|
231
|
+
* Like vtexFetch, but also forwards Set-Cookie headers via RequestContext.
|
|
254
232
|
* Use for checkout, session, and auth actions that set cookies.
|
|
233
|
+
*
|
|
234
|
+
* Cookie propagation happens automatically:
|
|
235
|
+
* - Reads the browser's Cookie header from RequestContext.request
|
|
236
|
+
* - Writes upstream Set-Cookie headers to RequestContext.responseHeaders
|
|
237
|
+
* - The invoke handler copies responseHeaders into the HTTP Response
|
|
238
|
+
*
|
|
239
|
+
* This mirrors deco-cx/deco's `proxySetCookie(response.headers, ctx.response.headers)`.
|
|
255
240
|
*/
|
|
256
|
-
export async function vtexFetchWithCookies<T>(
|
|
257
|
-
|
|
258
|
-
init
|
|
259
|
-
)
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
const cookies = _getCookieHeader();
|
|
265
|
-
if (cookies) {
|
|
266
|
-
init = {
|
|
267
|
-
...init,
|
|
268
|
-
headers: { ...existingHeaders, cookie: cookies },
|
|
269
|
-
};
|
|
270
|
-
}
|
|
241
|
+
export async function vtexFetchWithCookies<T>(path: string, init?: RequestInit): Promise<T> {
|
|
242
|
+
// Auto-inject request cookies from RequestContext
|
|
243
|
+
const existingHeaders = init?.headers as Record<string, string> | undefined;
|
|
244
|
+
if (!existingHeaders?.["cookie"]) {
|
|
245
|
+
const ctx = RequestContext.current;
|
|
246
|
+
const cookies = ctx?.request.headers.get("cookie");
|
|
247
|
+
if (cookies) {
|
|
248
|
+
init = { ...init, headers: { ...existingHeaders, cookie: cookies } };
|
|
271
249
|
}
|
|
272
250
|
}
|
|
273
251
|
|
|
274
252
|
const response = await vtexFetchResponse(path, init);
|
|
275
253
|
const data = (await response.json()) as T;
|
|
276
|
-
const setCookies: string[] = [];
|
|
277
|
-
if (typeof response.headers.getSetCookie === "function") {
|
|
278
|
-
setCookies.push(...response.headers.getSetCookie());
|
|
279
|
-
} else {
|
|
280
|
-
response.headers.forEach((value, key) => {
|
|
281
|
-
if (key.toLowerCase() === "set-cookie") {
|
|
282
|
-
setCookies.push(value);
|
|
283
|
-
}
|
|
284
|
-
});
|
|
285
|
-
}
|
|
286
254
|
|
|
287
|
-
//
|
|
288
|
-
|
|
289
|
-
|
|
255
|
+
// Forward Set-Cookie headers to RequestContext.responseHeaders
|
|
256
|
+
// (mirrors proxySetCookie from deco-cx/deco)
|
|
257
|
+
const responseHeaders = getResponseHeaders();
|
|
258
|
+
if (responseHeaders) {
|
|
259
|
+
const setCookies =
|
|
260
|
+
typeof response.headers.getSetCookie === "function" ? response.headers.getSetCookie() : [];
|
|
261
|
+
for (const cookie of setCookies) {
|
|
262
|
+
const stripped = cookie.replace(/;\s*domain=[^;]*/gi, "");
|
|
263
|
+
responseHeaders.append("set-cookie", stripped);
|
|
264
|
+
}
|
|
290
265
|
}
|
|
291
266
|
|
|
292
|
-
return
|
|
267
|
+
return data;
|
|
293
268
|
}
|
|
294
269
|
|
|
295
270
|
export async function intelligentSearch<T>(
|
package/vtex/index.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* VTEX app entry point for @decocms/apps.
|
|
3
|
-
* Re-exports client config + initializer.
|
|
3
|
+
* Re-exports client config + initializer + app contract.
|
|
4
4
|
*
|
|
5
5
|
* For actions/loaders/utils, use sub-path imports:
|
|
6
6
|
* import { addItemsToCart } from "@decocms/apps/vtex/actions/checkout"
|
|
@@ -12,3 +12,4 @@
|
|
|
12
12
|
* import { searchProducts } from "@decocms/apps/vtex/loaders"
|
|
13
13
|
*/
|
|
14
14
|
export * from "./client";
|
|
15
|
+
export { configure, type VtexState } from "./mod";
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
// AUTO-GENERATED by scripts/generate-manifests.ts — DO NOT EDIT
|
|
2
|
+
// This file is checked into source control and updated via: npm run generate:manifests
|
|
3
|
+
|
|
4
|
+
import * as actions_address from "./actions/address";
|
|
5
|
+
import * as actions_auth from "./actions/auth";
|
|
6
|
+
import * as actions_checkout from "./actions/checkout";
|
|
7
|
+
import * as actions_masterData from "./actions/masterData";
|
|
8
|
+
import * as actions_misc from "./actions/misc";
|
|
9
|
+
import * as actions_newsletter from "./actions/newsletter";
|
|
10
|
+
import * as actions_orders from "./actions/orders";
|
|
11
|
+
import * as actions_profile from "./actions/profile";
|
|
12
|
+
import * as actions_session from "./actions/session";
|
|
13
|
+
import * as actions_trigger from "./actions/trigger";
|
|
14
|
+
import * as actions_wishlist from "./actions/wishlist";
|
|
15
|
+
import * as loaders_address from "./loaders/address";
|
|
16
|
+
import * as loaders_brands from "./loaders/brands";
|
|
17
|
+
import * as loaders_cart from "./loaders/cart";
|
|
18
|
+
import * as loaders_catalog from "./loaders/catalog";
|
|
19
|
+
import * as loaders_collections from "./loaders/collections";
|
|
20
|
+
import * as loaders_legacy from "./loaders/legacy";
|
|
21
|
+
import * as loaders_logistics from "./loaders/logistics";
|
|
22
|
+
import * as loaders_navbar from "./loaders/navbar";
|
|
23
|
+
import * as loaders_orders from "./loaders/orders";
|
|
24
|
+
import * as loaders_pageType from "./loaders/pageType";
|
|
25
|
+
import * as loaders_payment from "./loaders/payment";
|
|
26
|
+
import * as loaders_profile from "./loaders/profile";
|
|
27
|
+
import * as loaders_promotion from "./loaders/promotion";
|
|
28
|
+
import * as loaders_search from "./loaders/search";
|
|
29
|
+
import * as loaders_session from "./loaders/session";
|
|
30
|
+
import * as loaders_user from "./loaders/user";
|
|
31
|
+
import * as loaders_wishlist from "./loaders/wishlist";
|
|
32
|
+
import * as loaders_wishlistProducts from "./loaders/wishlistProducts";
|
|
33
|
+
import * as loaders_workflow from "./loaders/workflow";
|
|
34
|
+
|
|
35
|
+
const manifest = {
|
|
36
|
+
name: "vtex",
|
|
37
|
+
loaders: {
|
|
38
|
+
"vtex/loaders/address": loaders_address,
|
|
39
|
+
"vtex/loaders/brands": loaders_brands,
|
|
40
|
+
"vtex/loaders/cart": loaders_cart,
|
|
41
|
+
"vtex/loaders/catalog": loaders_catalog,
|
|
42
|
+
"vtex/loaders/collections": loaders_collections,
|
|
43
|
+
"vtex/loaders/legacy": loaders_legacy,
|
|
44
|
+
"vtex/loaders/logistics": loaders_logistics,
|
|
45
|
+
"vtex/loaders/navbar": loaders_navbar,
|
|
46
|
+
"vtex/loaders/orders": loaders_orders,
|
|
47
|
+
"vtex/loaders/pageType": loaders_pageType,
|
|
48
|
+
"vtex/loaders/payment": loaders_payment,
|
|
49
|
+
"vtex/loaders/profile": loaders_profile,
|
|
50
|
+
"vtex/loaders/promotion": loaders_promotion,
|
|
51
|
+
"vtex/loaders/search": loaders_search,
|
|
52
|
+
"vtex/loaders/session": loaders_session,
|
|
53
|
+
"vtex/loaders/user": loaders_user,
|
|
54
|
+
"vtex/loaders/wishlist": loaders_wishlist,
|
|
55
|
+
"vtex/loaders/wishlistProducts": loaders_wishlistProducts,
|
|
56
|
+
"vtex/loaders/workflow": loaders_workflow,
|
|
57
|
+
},
|
|
58
|
+
actions: {
|
|
59
|
+
"vtex/actions/address": actions_address,
|
|
60
|
+
"vtex/actions/auth": actions_auth,
|
|
61
|
+
"vtex/actions/checkout": actions_checkout,
|
|
62
|
+
"vtex/actions/masterData": actions_masterData,
|
|
63
|
+
"vtex/actions/misc": actions_misc,
|
|
64
|
+
"vtex/actions/newsletter": actions_newsletter,
|
|
65
|
+
"vtex/actions/orders": actions_orders,
|
|
66
|
+
"vtex/actions/profile": actions_profile,
|
|
67
|
+
"vtex/actions/session": actions_session,
|
|
68
|
+
"vtex/actions/trigger": actions_trigger,
|
|
69
|
+
"vtex/actions/wishlist": actions_wishlist,
|
|
70
|
+
},
|
|
71
|
+
sections: {},
|
|
72
|
+
} as const;
|
|
73
|
+
|
|
74
|
+
export type Manifest = typeof manifest;
|
|
75
|
+
export default manifest;
|
package/vtex/mod.ts
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* VTEX app module — standard autoconfig contract.
|
|
3
|
+
*
|
|
4
|
+
* Exports `configure` following the AppModContract pattern.
|
|
5
|
+
* The framework's `autoconfigApps()` calls these generically.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```ts
|
|
9
|
+
* import * as vtexApp from "@decocms/apps/vtex/mod";
|
|
10
|
+
*
|
|
11
|
+
* const app = await vtexApp.configure(blocks.vtex, resolveSecret);
|
|
12
|
+
* if (app) {
|
|
13
|
+
* // app.manifest, app.state, app.middleware are available
|
|
14
|
+
* }
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import type { AppDefinition, AppMiddleware, ResolveSecretFn } from "../commerce/app-types";
|
|
19
|
+
import { configureVtex, type VtexConfig } from "./client";
|
|
20
|
+
import manifest from "./manifest.gen";
|
|
21
|
+
import { extractVtexContext, propagateISCookies, vtexCacheControl } from "./middleware";
|
|
22
|
+
|
|
23
|
+
// -------------------------------------------------------------------------
|
|
24
|
+
// State
|
|
25
|
+
// -------------------------------------------------------------------------
|
|
26
|
+
|
|
27
|
+
export interface VtexState {
|
|
28
|
+
config: VtexConfig;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// -------------------------------------------------------------------------
|
|
32
|
+
// Middleware
|
|
33
|
+
// -------------------------------------------------------------------------
|
|
34
|
+
|
|
35
|
+
const vtexMiddleware: AppMiddleware = async (request, next) => {
|
|
36
|
+
const ctx = extractVtexContext(request);
|
|
37
|
+
const response = await next();
|
|
38
|
+
response.headers.set("Cache-Control", vtexCacheControl(ctx));
|
|
39
|
+
propagateISCookies(ctx, response);
|
|
40
|
+
return response;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
// -------------------------------------------------------------------------
|
|
44
|
+
// Configure
|
|
45
|
+
// -------------------------------------------------------------------------
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Configure the VTEX app from CMS block data.
|
|
49
|
+
* Returns an AppDefinition or null if required fields are missing.
|
|
50
|
+
*/
|
|
51
|
+
export async function configure(
|
|
52
|
+
block: any,
|
|
53
|
+
resolveSecret: ResolveSecretFn,
|
|
54
|
+
): Promise<AppDefinition<VtexState> | null> {
|
|
55
|
+
if (!block?.account) return null;
|
|
56
|
+
|
|
57
|
+
const appKey = await resolveSecret(block.appKey, "VTEX_APP_KEY");
|
|
58
|
+
const appToken = await resolveSecret(block.appToken, "VTEX_APP_TOKEN");
|
|
59
|
+
|
|
60
|
+
const config: VtexConfig = {
|
|
61
|
+
account: block.account,
|
|
62
|
+
publicUrl: block.publicUrl,
|
|
63
|
+
salesChannel: block.salesChannel || "1",
|
|
64
|
+
locale: block.locale || block.defaultLocale,
|
|
65
|
+
appKey: appKey ?? undefined,
|
|
66
|
+
appToken: appToken ?? undefined,
|
|
67
|
+
country: block.country,
|
|
68
|
+
domain: block.domain,
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
// Bridge: maintain global singleton for backward compat
|
|
72
|
+
configureVtex(config);
|
|
73
|
+
|
|
74
|
+
return {
|
|
75
|
+
name: "vtex",
|
|
76
|
+
manifest,
|
|
77
|
+
state: { config },
|
|
78
|
+
middleware: vtexMiddleware,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** Placeholder preview for CMS editor — evolves when admin supports it. */
|
|
83
|
+
export const preview = undefined;
|