@decocms/apps-wake 8.1.0-next.0 → 8.1.0-next.2
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/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/storefront.d.ts +14 -0
- package/dist/storefront.d.ts.map +1 -0
- package/dist/storefront.js +14 -0
- package/dist/storefront.js.map +1 -0
- package/dist/storefrontTypes.d.ts +7 -0
- package/dist/storefrontTypes.d.ts.map +1 -0
- package/dist/storefrontTypes.js +2 -0
- package/dist/storefrontTypes.js.map +1 -0
- package/dist/utils/client.d.ts +12 -0
- package/dist/utils/client.d.ts.map +1 -0
- package/dist/utils/client.js +2 -0
- package/dist/utils/client.js.map +1 -0
- package/dist/utils/gql.d.ts +16 -0
- package/dist/utils/gql.d.ts.map +1 -0
- package/dist/utils/gql.js +16 -0
- package/dist/utils/gql.js.map +1 -0
- package/dist/utils/graphql/queries.d.ts +117 -0
- package/dist/utils/graphql/queries.d.ts.map +1 -0
- package/dist/utils/graphql/queries.js +1323 -0
- package/dist/utils/graphql/queries.js.map +1 -0
- package/dist/utils/graphql/storefront.graphql.gen.d.ts +10344 -0
- package/dist/utils/graphql/storefront.graphql.gen.d.ts.map +1 -0
- package/dist/utils/graphql/storefront.graphql.gen.js +9 -0
- package/dist/utils/graphql/storefront.graphql.gen.js.map +1 -0
- package/dist/utils/graphqlOperationName.d.ts +36 -0
- package/dist/utils/graphqlOperationName.d.ts.map +1 -0
- package/dist/utils/graphqlOperationName.js +59 -0
- package/dist/utils/graphqlOperationName.js.map +1 -0
- package/dist/wakeClient.d.ts +54 -0
- package/dist/wakeClient.d.ts.map +1 -0
- package/dist/wakeClient.js +85 -0
- package/dist/wakeClient.js.map +1 -0
- package/package.json +26 -37
- package/src/index.ts +3 -63
- package/src/storefront.ts +1 -1
- package/src/storefrontTypes.ts +1 -1
- package/src/utils/gql.ts +1 -2
- package/src/utils/graphql/queries.ts +1 -1
- package/src/wakeClient.ts +3 -3
- package/src/__tests__/wakeClient.test.ts +0 -136
- package/src/actions/cart/addCoupon.ts +0 -43
- package/src/actions/cart/addItem.ts +0 -10
- package/src/actions/cart/addItems.ts +0 -50
- package/src/actions/cart/addKit.ts +0 -53
- package/src/actions/cart/partnerAssociate.ts +0 -48
- package/src/actions/cart/partnerDisassociate.ts +0 -43
- package/src/actions/cart/removeCoupon.ts +0 -39
- package/src/actions/cart/removeKit.ts +0 -56
- package/src/actions/cart/updateItemQuantity.ts +0 -69
- package/src/actions/newsletter/register.ts +0 -32
- package/src/actions/notifyme.ts +0 -28
- package/src/actions/review/create.ts +0 -30
- package/src/actions/shippingSimulation.ts +0 -60
- package/src/actions/submmitForm.ts +0 -25
- package/src/actions/wishlist/addProduct.ts +0 -43
- package/src/actions/wishlist/removeProduct.ts +0 -45
- package/src/client.ts +0 -123
- package/src/commerceLoaders.ts +0 -137
- package/src/handlers/sitemap.ts +0 -61
- package/src/loaders/cart.ts +0 -46
- package/src/loaders/partners.ts +0 -58
- package/src/loaders/productDetailsPage.ts +0 -174
- package/src/loaders/productList.ts +0 -262
- package/src/loaders/productListingPage.ts +0 -333
- package/src/loaders/proxy.ts +0 -79
- package/src/loaders/recommendations.ts +0 -84
- package/src/loaders/shop.ts +0 -37
- package/src/loaders/suggestion.ts +0 -67
- package/src/loaders/user.ts +0 -48
- package/src/loaders/wishlist.ts +0 -40
- package/src/manifest.gen.ts +0 -69
- package/src/mod.ts +0 -88
- package/src/registry.ts +0 -9
- package/src/utils/authError.ts +0 -107
- package/src/utils/authenticate.ts +0 -42
- package/src/utils/capitalize.ts +0 -9
- package/src/utils/cart.ts +0 -33
- package/src/utils/cookies.ts +0 -82
- package/src/utils/getVariations.ts +0 -47
- package/src/utils/graphql.ts +0 -72
- package/src/utils/httpError.ts +0 -15
- package/src/utils/instrumentedFetch.ts +0 -46
- package/src/utils/operationRouter.ts +0 -51
- package/src/utils/parseHeaders.ts +0 -19
- package/src/utils/partner.ts +0 -34
- package/src/utils/requestCtx.ts +0 -41
- package/src/utils/transform.ts +0 -460
- package/src/utils/types.ts +0 -6
- package/src/utils/user.ts +0 -9
- package/tsconfig.json +0 -7
package/src/client.ts
DELETED
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
import type { FetchFn } from "@decocms/blocks/sdk/fetchTimeout";
|
|
2
|
-
import { createGraphqlClient, type GraphQLClient } from "./utils/graphql";
|
|
3
|
-
|
|
4
|
-
export interface WakeConfig {
|
|
5
|
-
/** Wake account name, e.g. "erploja2". */
|
|
6
|
-
account: string;
|
|
7
|
-
/**
|
|
8
|
-
* Checkout/login domain, e.g. "https://secure.sprint55.com.br". Used only for
|
|
9
|
-
* the checkout REST API (login/cart) and proxy — NOT for the storefront
|
|
10
|
-
* GraphQL, which is a fixed multi-tenant endpoint resolved by the token.
|
|
11
|
-
*/
|
|
12
|
-
checkoutUrl: string;
|
|
13
|
-
/** Wake Storefront API token (sent as `TCS-Access-Token`). */
|
|
14
|
-
storefrontToken: string;
|
|
15
|
-
/**
|
|
16
|
-
* Storefront GraphQL endpoint. Defaults to Wake's canonical multi-tenant
|
|
17
|
-
* endpoint; override only for a custom storefront host.
|
|
18
|
-
*/
|
|
19
|
-
storefrontEndpoint?: string;
|
|
20
|
-
/** Wake Admin API token (Basic auth). Currently unused by the loaders/actions. */
|
|
21
|
-
token?: string;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
const STOREFRONT_ENDPOINT = "https://storefront-api.fbits.net/graphql";
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Read an env var. Wake's tokens are provided ONLY via environment variables
|
|
28
|
-
* (no CMS secret / `resolveSecret`): `WAKE_TOKEN` (storefront) and, if ever
|
|
29
|
-
* needed, `WAKE_KEY` (admin). `process.env` is populated in Node and in
|
|
30
|
-
* Cloudflare Workers via `nodejs_compat` — the same source the framework's
|
|
31
|
-
* own `getEnvVar()` reads first.
|
|
32
|
-
*/
|
|
33
|
-
function readEnv(name: string): string | undefined {
|
|
34
|
-
const env = (globalThis as { process?: { env?: Record<string, string | undefined> } }).process
|
|
35
|
-
?.env;
|
|
36
|
-
const value = env?.[name];
|
|
37
|
-
return value && value.length > 0 ? value : undefined;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/** Wake Storefront API token from `WAKE_TOKEN`. */
|
|
41
|
-
export function getWakeStorefrontTokenFromEnv(): string | undefined {
|
|
42
|
-
return readEnv("WAKE_TOKEN");
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/** Wake Admin API token from `WAKE_KEY` (currently unused by loaders/actions). */
|
|
46
|
-
export function getWakeAdminTokenFromEnv(): string | undefined {
|
|
47
|
-
return readEnv("WAKE_KEY");
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
let _client: GraphQLClient | null = null;
|
|
51
|
-
let _config: WakeConfig | null = null;
|
|
52
|
-
let _fetch: FetchFn | undefined;
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Override the fetch function used by the Wake GraphQL client. Use this to plug
|
|
56
|
-
* in an instrumented fetch for logging/tracing.
|
|
57
|
-
*
|
|
58
|
-
* @example
|
|
59
|
-
* ```ts
|
|
60
|
-
* import { createInstrumentedFetch } from "@decocms/blocks/sdk/instrumentedFetch";
|
|
61
|
-
* import { setWakeFetch } from "@decocms/apps-wake";
|
|
62
|
-
* setWakeFetch(createInstrumentedFetch("wake"));
|
|
63
|
-
* ```
|
|
64
|
-
*/
|
|
65
|
-
export function setWakeFetch(fetchFn: FetchFn) {
|
|
66
|
-
_fetch = fetchFn;
|
|
67
|
-
if (_config) configureWake(_config);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
export function configureWake(config: WakeConfig) {
|
|
71
|
-
_config = config;
|
|
72
|
-
const endpoint = config.storefrontEndpoint || STOREFRONT_ENDPOINT;
|
|
73
|
-
_client = createGraphqlClient(
|
|
74
|
-
endpoint,
|
|
75
|
-
{
|
|
76
|
-
"TCS-Access-Token": config.storefrontToken,
|
|
77
|
-
},
|
|
78
|
-
_fetch,
|
|
79
|
-
);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
export function getWakeClient(): GraphQLClient {
|
|
83
|
-
if (!_client || !_config) {
|
|
84
|
-
throw new Error(
|
|
85
|
-
"Wake not configured. Call configureWake() first or check deco-wake.json block.",
|
|
86
|
-
);
|
|
87
|
-
}
|
|
88
|
-
return _client;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
export function getWakeConfig(): WakeConfig {
|
|
92
|
-
if (!_config) {
|
|
93
|
-
throw new Error("Wake not configured.");
|
|
94
|
-
}
|
|
95
|
-
return _config;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
/** Base URL of the checkout REST API (`GET /api/Login/Get`, proxied paths). */
|
|
99
|
-
export function getCheckoutUrl(): string {
|
|
100
|
-
const config = getWakeConfig();
|
|
101
|
-
return config.checkoutUrl || `https://${config.account}.checkout.fbits.store`;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
export function getBaseUrl(): string {
|
|
105
|
-
return _config?.checkoutUrl || "";
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* Convenience initializer used by the site setup: reads the Wake app block from
|
|
110
|
-
* the generated blocks map and configures the singleton.
|
|
111
|
-
*/
|
|
112
|
-
export function initWakeFromBlocks(blocks: Record<string, unknown>) {
|
|
113
|
-
const block = (blocks.wake ?? blocks["deco-wake"]) as Partial<WakeConfig> | undefined;
|
|
114
|
-
if (!block?.account) return;
|
|
115
|
-
configureWake({
|
|
116
|
-
account: block.account as string,
|
|
117
|
-
checkoutUrl: (block.checkoutUrl as string) ?? "",
|
|
118
|
-
// Tokens come from env only (WAKE_TOKEN / WAKE_KEY), never the CMS block.
|
|
119
|
-
storefrontToken: getWakeStorefrontTokenFromEnv() ?? "",
|
|
120
|
-
storefrontEndpoint: block.storefrontEndpoint as string | undefined,
|
|
121
|
-
token: getWakeAdminTokenFromEnv(),
|
|
122
|
-
});
|
|
123
|
-
}
|
package/src/commerceLoaders.ts
DELETED
|
@@ -1,137 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Standard Wake commerce loader map factory for CMS block resolution.
|
|
3
|
-
*
|
|
4
|
-
* Wraps the cacheable catalog loaders with `createCachedLoader` (single-flight
|
|
5
|
-
* dedup + SWR + stale-if-error via the unified cache profiles), applies the
|
|
6
|
-
* PDP slug fallback and PLP page-URL resolution, and registers both `.ts` and
|
|
7
|
-
* `.ts`-less aliases.
|
|
8
|
-
*
|
|
9
|
-
* Sites call `createWakeCommerceLoaders()` and hand the result to
|
|
10
|
-
* `registerCommerceLoaders(...)` instead of wiring each loader (and its cache
|
|
11
|
-
* policy) by hand — mirroring `createVtexCommerceLoaders()`.
|
|
12
|
-
*
|
|
13
|
-
* User-specific loaders (cart/user/wishlist) are intentionally NOT included:
|
|
14
|
-
* they are per-session and must not be cached; the app manifest registers them
|
|
15
|
-
* uncached via `autoconfigApps`.
|
|
16
|
-
*/
|
|
17
|
-
|
|
18
|
-
import { createCachedLoader } from "@decocms/blocks/sdk/cachedLoader";
|
|
19
|
-
import type { CacheProfileName } from "@decocms/blocks/sdk/cacheHeaders";
|
|
20
|
-
import { RequestContext } from "@decocms/blocks/sdk/requestContext";
|
|
21
|
-
import partnersLoader from "./loaders/partners";
|
|
22
|
-
import productDetailsPage from "./loaders/productDetailsPage";
|
|
23
|
-
import productList from "./loaders/productList";
|
|
24
|
-
import productListingPage from "./loaders/productListingPage";
|
|
25
|
-
import recommendations from "./loaders/recommendations";
|
|
26
|
-
import shopLoader from "./loaders/shop";
|
|
27
|
-
import suggestion from "./loaders/suggestion";
|
|
28
|
-
|
|
29
|
-
export type CommerceLoaderFn = (props: any) => Promise<any>;
|
|
30
|
-
|
|
31
|
-
export interface WakeCommerceLoadersOptions {
|
|
32
|
-
/** Override cache profiles per loader type. */
|
|
33
|
-
cacheProfiles?: {
|
|
34
|
-
listing?: CacheProfileName;
|
|
35
|
-
product?: CacheProfileName;
|
|
36
|
-
search?: CacheProfileName;
|
|
37
|
-
static?: CacheProfileName;
|
|
38
|
-
};
|
|
39
|
-
/** Additional loaders to merge into the map (site-specific). */
|
|
40
|
-
extra?: Record<string, CommerceLoaderFn>;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
const PAGE_URL_HEADER = "x-deco-page-url";
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Resolve the real page URL for the productListingPage loader. Wake's PLP reads
|
|
47
|
-
* the URL from `props.pageHref`; the framework injects `__pageUrl`, but on CSR
|
|
48
|
-
* home navigations that is unreliable, so an explicit `x-deco-page-url` header
|
|
49
|
-
* (set by the site) wins, then `__pageUrl`, then the worker request URL.
|
|
50
|
-
*/
|
|
51
|
-
function resolvePageHref(props: any): string | undefined {
|
|
52
|
-
try {
|
|
53
|
-
const headerUrl = RequestContext.request.headers.get(PAGE_URL_HEADER);
|
|
54
|
-
if (headerUrl) return new URL(headerUrl, "http://localhost").href;
|
|
55
|
-
} catch {
|
|
56
|
-
// RequestContext may be unavailable in isolated calls.
|
|
57
|
-
}
|
|
58
|
-
if (props?.__pageUrl) {
|
|
59
|
-
try {
|
|
60
|
-
return new URL(props.__pageUrl, "http://localhost").href;
|
|
61
|
-
} catch {
|
|
62
|
-
// ignore malformed injected URL
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
try {
|
|
66
|
-
return new URL(RequestContext.request.url).href;
|
|
67
|
-
} catch {
|
|
68
|
-
return props?.pageHref;
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/** Bridge `__pagePath` → `slug` when the CMS doesn't set slug explicitly. */
|
|
73
|
-
function pdpWithSlugFallback(props: any): Promise<any> {
|
|
74
|
-
if ((!props.slug || props.slug.length === 0) && props.__pagePath) {
|
|
75
|
-
props = { ...props, slug: props.__pagePath };
|
|
76
|
-
}
|
|
77
|
-
return productDetailsPage(props);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
export function createWakeCommerceLoaders(
|
|
81
|
-
options?: WakeCommerceLoadersOptions,
|
|
82
|
-
): Record<string, CommerceLoaderFn> {
|
|
83
|
-
const profiles = {
|
|
84
|
-
listing: options?.cacheProfiles?.listing ?? "listing",
|
|
85
|
-
product: options?.cacheProfiles?.product ?? "product",
|
|
86
|
-
search: options?.cacheProfiles?.search ?? "search",
|
|
87
|
-
static: options?.cacheProfiles?.static ?? "static",
|
|
88
|
-
};
|
|
89
|
-
|
|
90
|
-
const cachedPDP = createCachedLoader(
|
|
91
|
-
"wake/productDetailsPage",
|
|
92
|
-
pdpWithSlugFallback,
|
|
93
|
-
profiles.product,
|
|
94
|
-
);
|
|
95
|
-
const _cachedPLP = createCachedLoader(
|
|
96
|
-
"wake/productListingPage",
|
|
97
|
-
productListingPage,
|
|
98
|
-
profiles.listing,
|
|
99
|
-
);
|
|
100
|
-
const cachedProductList = createCachedLoader("wake/productList", productList, profiles.listing);
|
|
101
|
-
const cachedSuggestion = createCachedLoader("wake/suggestion", suggestion, profiles.search);
|
|
102
|
-
const cachedRecommendations = createCachedLoader(
|
|
103
|
-
"wake/recommendations",
|
|
104
|
-
recommendations,
|
|
105
|
-
profiles.product,
|
|
106
|
-
);
|
|
107
|
-
const cachedShop = createCachedLoader("wake/shop", shopLoader, profiles.static);
|
|
108
|
-
const cachedPartners = createCachedLoader("wake/partners", partnersLoader, profiles.static);
|
|
109
|
-
|
|
110
|
-
// PLP wrapper: forward the resolved page URL as `pageHref` before caching.
|
|
111
|
-
const cachedPLP: CommerceLoaderFn = (props) =>
|
|
112
|
-
_cachedPLP({ ...props, pageHref: resolvePageHref(props) ?? props?.pageHref });
|
|
113
|
-
|
|
114
|
-
const loaders: Record<string, CommerceLoaderFn> = {
|
|
115
|
-
"wake/loaders/productDetailsPage.ts": cachedPDP,
|
|
116
|
-
"wake/loaders/productListingPage.ts": cachedPLP,
|
|
117
|
-
"wake/loaders/productList.ts": cachedProductList,
|
|
118
|
-
"wake/loaders/suggestion.ts": cachedSuggestion,
|
|
119
|
-
"wake/loaders/recommendations.ts": cachedRecommendations,
|
|
120
|
-
"wake/loaders/shop.ts": cachedShop,
|
|
121
|
-
"wake/loaders/partners.ts": cachedPartners,
|
|
122
|
-
};
|
|
123
|
-
|
|
124
|
-
// Register .ts-less aliases for invoke compatibility.
|
|
125
|
-
const withAliases: Record<string, CommerceLoaderFn> = { ...loaders };
|
|
126
|
-
for (const key of Object.keys(loaders)) {
|
|
127
|
-
if (key.endsWith(".ts")) {
|
|
128
|
-
withAliases[key.slice(0, -3)] = loaders[key];
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
if (options?.extra) {
|
|
133
|
-
Object.assign(withAliases, options.extra);
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
return withAliases;
|
|
137
|
-
}
|
package/src/handlers/sitemap.ts
DELETED
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
import { withFetchTimeout } from "@decocms/blocks/sdk/fetchTimeout";
|
|
2
|
-
import { getWakeConfig } from "../client";
|
|
3
|
-
|
|
4
|
-
const fetchSafe = withFetchTimeout();
|
|
5
|
-
|
|
6
|
-
const BASE_SITEMAP_URL = "https://p-general-sitemap-public.s3.us-east-2.amazonaws.com/Sitemap";
|
|
7
|
-
|
|
8
|
-
const xmlHeader = '<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">';
|
|
9
|
-
|
|
10
|
-
const includeSiteMaps = (currentXML: string, origin: string, includes?: string[]) => {
|
|
11
|
-
const siteMapIncludeTags: string[] = [];
|
|
12
|
-
|
|
13
|
-
for (const include of includes ?? []) {
|
|
14
|
-
siteMapIncludeTags.push(`
|
|
15
|
-
<sitemap>
|
|
16
|
-
<loc>${include.startsWith("/") ? `${origin}${include}` : include}</loc>
|
|
17
|
-
<lastmod>${new Date().toISOString().substring(0, 10)}</lastmod>
|
|
18
|
-
</sitemap>
|
|
19
|
-
`);
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
return siteMapIncludeTags.length > 0
|
|
23
|
-
? currentXML.replace(xmlHeader, `${xmlHeader}\n${siteMapIncludeTags.join("\n")}`)
|
|
24
|
-
: currentXML;
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
export interface Props {
|
|
28
|
-
include?: string[];
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* @title Sitemap Proxy
|
|
33
|
-
*
|
|
34
|
-
* Returns a request handler that proxies the Wake public S3 sitemap for the
|
|
35
|
-
* configured account, rewriting the public URL to the current origin and
|
|
36
|
-
* optionally injecting extra `<sitemap>` entries.
|
|
37
|
-
*/
|
|
38
|
-
export default function Sitemap({ include }: Props = {}) {
|
|
39
|
-
return async (req: Request): Promise<Response> => {
|
|
40
|
-
const { account } = getWakeConfig();
|
|
41
|
-
|
|
42
|
-
if (!account) {
|
|
43
|
-
throw new Error("Missing account");
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
const publicUrl = `${BASE_SITEMAP_URL}/${encodeURIComponent(account)}/`;
|
|
47
|
-
|
|
48
|
-
const response = await fetchSafe(publicUrl);
|
|
49
|
-
|
|
50
|
-
const reqUrl = new URL(req.url);
|
|
51
|
-
const text = await response.text();
|
|
52
|
-
|
|
53
|
-
return new Response(
|
|
54
|
-
includeSiteMaps(text.replaceAll(publicUrl, `${reqUrl.origin}/`), reqUrl.origin, include),
|
|
55
|
-
{
|
|
56
|
-
headers: response.headers,
|
|
57
|
-
status: response.status,
|
|
58
|
-
},
|
|
59
|
-
);
|
|
60
|
-
};
|
|
61
|
-
}
|
package/src/loaders/cart.ts
DELETED
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import { getWakeClient } from "../client";
|
|
2
|
-
import { handleAuthError } from "../utils/authError";
|
|
3
|
-
import { getCartCookie, setCartCookie } from "../utils/cart";
|
|
4
|
-
import { CreateCart, GetCart } from "../utils/graphql/queries";
|
|
5
|
-
import type {
|
|
6
|
-
CheckoutFragment,
|
|
7
|
-
CreateCartMutation,
|
|
8
|
-
GetCartQuery,
|
|
9
|
-
} from "../utils/graphql/storefront.graphql.gen";
|
|
10
|
-
import {
|
|
11
|
-
currentRequestHeaders,
|
|
12
|
-
currentResponseHeaders,
|
|
13
|
-
forwardedHeaders,
|
|
14
|
-
} from "../utils/requestCtx";
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* @title Wake Integration
|
|
18
|
-
* @description Cart loader
|
|
19
|
-
*/
|
|
20
|
-
const loader = async (): Promise<Partial<CheckoutFragment>> => {
|
|
21
|
-
const storefront = getWakeClient();
|
|
22
|
-
const cartId = getCartCookie(currentRequestHeaders());
|
|
23
|
-
const headers = forwardedHeaders();
|
|
24
|
-
|
|
25
|
-
let data: GetCartQuery | CreateCartMutation;
|
|
26
|
-
try {
|
|
27
|
-
data = cartId
|
|
28
|
-
? await storefront.query<GetCartQuery>(GetCart, { checkoutId: cartId }, headers)
|
|
29
|
-
: await storefront.query<CreateCartMutation>(CreateCart, {}, headers);
|
|
30
|
-
} catch (error: unknown) {
|
|
31
|
-
handleAuthError(error, "load cart");
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
const checkoutId = data.checkout?.checkoutId;
|
|
35
|
-
|
|
36
|
-
if (checkoutId && cartId !== checkoutId) {
|
|
37
|
-
setCartCookie(currentResponseHeaders(), checkoutId);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
return data.checkout ?? {};
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
export default loader;
|
|
44
|
-
|
|
45
|
-
// User-specific cart data; must not be cached/shared.
|
|
46
|
-
export const cache = "no-store";
|
package/src/loaders/partners.ts
DELETED
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
import { getWakeClient } from "../client";
|
|
2
|
-
import { handleAuthError } from "../utils/authError";
|
|
3
|
-
import { GetPartners } from "../utils/graphql/queries";
|
|
4
|
-
import type { GetPartnersQuery } from "../utils/graphql/storefront.graphql.gen";
|
|
5
|
-
import { getPartnerCookie } from "../utils/partner";
|
|
6
|
-
import { currentRequestHeaders, forwardedHeaders } from "../utils/requestCtx";
|
|
7
|
-
import type { RequestURLParam } from "../utils/types";
|
|
8
|
-
|
|
9
|
-
export interface Props {
|
|
10
|
-
slug: RequestURLParam;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* @title Wake Integration - Partners
|
|
15
|
-
* @description Partners loader
|
|
16
|
-
*/
|
|
17
|
-
const loader = async (props: Props): Promise<GetPartnersQuery["partners"]> => {
|
|
18
|
-
const storefront = getWakeClient();
|
|
19
|
-
const { slug } = props;
|
|
20
|
-
|
|
21
|
-
const headers = forwardedHeaders();
|
|
22
|
-
|
|
23
|
-
// Guard against missing slug to prevent querying with [undefined]
|
|
24
|
-
if (!slug) {
|
|
25
|
-
return undefined;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
let data: GetPartnersQuery | undefined;
|
|
29
|
-
try {
|
|
30
|
-
data = await storefront.query<GetPartnersQuery>(
|
|
31
|
-
GetPartners,
|
|
32
|
-
{ first: 1, alias: [slug] },
|
|
33
|
-
headers,
|
|
34
|
-
);
|
|
35
|
-
} catch (error: unknown) {
|
|
36
|
-
handleAuthError(error, "load partner information");
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
return data?.partners ?? undefined;
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
export const cache = "stale-while-revalidate";
|
|
43
|
-
|
|
44
|
-
export const cacheKey = (props: Props): string | null => {
|
|
45
|
-
// Don't cache if no slug is provided
|
|
46
|
-
if (!props.slug) {
|
|
47
|
-
return null;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
// Don't cache if partner cookie is present - partner-specific content should not be cached
|
|
51
|
-
if (getPartnerCookie(currentRequestHeaders())) {
|
|
52
|
-
return null;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
return `wake:partners:${props.slug}:1`;
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
export default loader;
|
|
@@ -1,174 +0,0 @@
|
|
|
1
|
-
import type { Product, ProductDetailsPage } from "@decocms/apps-commerce/types";
|
|
2
|
-
import { getWakeClient } from "../client";
|
|
3
|
-
import { handleAuthError } from "../utils/authError";
|
|
4
|
-
import { MAXIMUM_REQUEST_QUANTITY } from "../utils/getVariations";
|
|
5
|
-
import { GetBuyList, GetProduct } from "../utils/graphql/queries";
|
|
6
|
-
import type { BuyListQuery, GetProductQuery } from "../utils/graphql/storefront.graphql.gen";
|
|
7
|
-
import { getPartnerCookie } from "../utils/partner";
|
|
8
|
-
import { currentRequestHeaders, currentUrl, forwardedHeaders } from "../utils/requestCtx";
|
|
9
|
-
import { parseSlug, toBreadcrumbList, toProduct } from "../utils/transform";
|
|
10
|
-
import type { RequestURLParam } from "../utils/types";
|
|
11
|
-
import productListLoader from "./productList";
|
|
12
|
-
|
|
13
|
-
export interface Props {
|
|
14
|
-
slug: RequestURLParam;
|
|
15
|
-
buyTogether?: boolean;
|
|
16
|
-
includeSameParent?: boolean;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* @title Wake Integration
|
|
21
|
-
* @description Product Details Page loader
|
|
22
|
-
*/
|
|
23
|
-
async function loader(props: Props): Promise<ProductDetailsPage | null> {
|
|
24
|
-
const url = currentUrl();
|
|
25
|
-
const { slug, buyTogether, includeSameParent } = props;
|
|
26
|
-
const storefront = getWakeClient();
|
|
27
|
-
|
|
28
|
-
const partnerAccessToken = getPartnerCookie(currentRequestHeaders());
|
|
29
|
-
|
|
30
|
-
const headers = forwardedHeaders();
|
|
31
|
-
|
|
32
|
-
if (!slug) return null;
|
|
33
|
-
|
|
34
|
-
const variantId = Number(url.searchParams.get("skuId")) || null;
|
|
35
|
-
const { id: productId } = parseSlug(slug);
|
|
36
|
-
|
|
37
|
-
if (!productId) {
|
|
38
|
-
throw new Error("Missing product id");
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
let wakeBuyList: BuyListQuery["buyList"] | undefined;
|
|
42
|
-
try {
|
|
43
|
-
const buyListResult = await storefront.query<BuyListQuery>(
|
|
44
|
-
GetBuyList,
|
|
45
|
-
{ id: productId, partnerAccessToken },
|
|
46
|
-
headers,
|
|
47
|
-
);
|
|
48
|
-
wakeBuyList = buyListResult.buyList;
|
|
49
|
-
} catch (error: unknown) {
|
|
50
|
-
handleAuthError(error, "load buy list");
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
const buyListProducts = await Promise.all(
|
|
54
|
-
wakeBuyList?.buyListProducts?.map(async (buyListProduct) => {
|
|
55
|
-
if (!buyListProduct) return;
|
|
56
|
-
|
|
57
|
-
const { productId, includeSameParent, quantity } = buyListProduct;
|
|
58
|
-
|
|
59
|
-
const buyListProductPage = await loader({
|
|
60
|
-
// 'slug' its just to fit the parse function of loader
|
|
61
|
-
slug: `slug-${productId}`,
|
|
62
|
-
includeSameParent,
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
if (!buyListProductPage) return;
|
|
66
|
-
|
|
67
|
-
buyListProductPage.product.additionalProperty?.push({
|
|
68
|
-
"@type": "PropertyValue",
|
|
69
|
-
name: "SuggestedQuantity",
|
|
70
|
-
value: String(quantity),
|
|
71
|
-
alternateName: "Buy List Suggested Quantity",
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
return buyListProductPage.product;
|
|
75
|
-
}) ?? [],
|
|
76
|
-
).then((maybeProductList) => maybeProductList.filter((node): node is Product => Boolean(node)));
|
|
77
|
-
|
|
78
|
-
let wakeProduct: GetProductQuery["product"] | undefined;
|
|
79
|
-
try {
|
|
80
|
-
const productResult = await storefront.query<GetProductQuery>(
|
|
81
|
-
GetProduct,
|
|
82
|
-
{
|
|
83
|
-
productId,
|
|
84
|
-
includeParentIdVariants: includeSameParent,
|
|
85
|
-
partnerAccessToken,
|
|
86
|
-
},
|
|
87
|
-
headers,
|
|
88
|
-
);
|
|
89
|
-
wakeProduct = productResult.product;
|
|
90
|
-
} catch (error: unknown) {
|
|
91
|
-
handleAuthError(error, "load product details");
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
const wakeProductOrBuyList = wakeProduct || wakeBuyList;
|
|
95
|
-
|
|
96
|
-
if (!wakeProductOrBuyList) {
|
|
97
|
-
return null;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
const variantsItems =
|
|
101
|
-
(await productListLoader({
|
|
102
|
-
first: MAXIMUM_REQUEST_QUANTITY,
|
|
103
|
-
sortDirection: "ASC",
|
|
104
|
-
sortKey: "RANDOM",
|
|
105
|
-
filters: { productId: [productId] },
|
|
106
|
-
})) ?? [];
|
|
107
|
-
|
|
108
|
-
const buyTogetherItens =
|
|
109
|
-
buyTogether && wakeProductOrBuyList.buyTogether?.length
|
|
110
|
-
? ((await productListLoader({
|
|
111
|
-
first: MAXIMUM_REQUEST_QUANTITY,
|
|
112
|
-
sortDirection: "ASC",
|
|
113
|
-
sortKey: "RANDOM",
|
|
114
|
-
filters: {
|
|
115
|
-
productId: wakeProductOrBuyList.buyTogether
|
|
116
|
-
?.map((bt) => bt?.productId)
|
|
117
|
-
.filter((id): id is number => id != null),
|
|
118
|
-
mainVariant: true,
|
|
119
|
-
},
|
|
120
|
-
getVariations: true,
|
|
121
|
-
})) ?? [])
|
|
122
|
-
: [];
|
|
123
|
-
|
|
124
|
-
const product = toProduct(wakeProductOrBuyList, { base: url }, variantsItems, variantId);
|
|
125
|
-
return {
|
|
126
|
-
"@type": "ProductDetailsPage",
|
|
127
|
-
breadcrumbList: toBreadcrumbList(
|
|
128
|
-
wakeProductOrBuyList.breadcrumbs ?? [],
|
|
129
|
-
{
|
|
130
|
-
base: url,
|
|
131
|
-
},
|
|
132
|
-
product,
|
|
133
|
-
),
|
|
134
|
-
product: {
|
|
135
|
-
...product,
|
|
136
|
-
isAccessoryOrSparePartFor: buyListProducts,
|
|
137
|
-
isRelatedTo:
|
|
138
|
-
buyTogetherItens?.map((buyItem) => {
|
|
139
|
-
return {
|
|
140
|
-
...buyItem,
|
|
141
|
-
additionalType: "BuyTogether",
|
|
142
|
-
};
|
|
143
|
-
}) ?? [],
|
|
144
|
-
},
|
|
145
|
-
seo: {
|
|
146
|
-
canonical: product.isVariantOf?.url ?? "",
|
|
147
|
-
title: wakeProductOrBuyList.productName ?? "",
|
|
148
|
-
description: wakeProductOrBuyList.seo?.find((m) => m?.name === "description")?.content ?? "",
|
|
149
|
-
},
|
|
150
|
-
};
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
export const cache = "stale-while-revalidate";
|
|
154
|
-
|
|
155
|
-
export const cacheKey = (props: Props): string | null => {
|
|
156
|
-
const url = currentUrl();
|
|
157
|
-
const skuId = url.searchParams.get("skuId") ?? "";
|
|
158
|
-
|
|
159
|
-
// Avoid cross-tenant cache bleed when a partner token is present
|
|
160
|
-
if (getPartnerCookie(currentRequestHeaders())) {
|
|
161
|
-
return null;
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
const params = new URLSearchParams([
|
|
165
|
-
["slug", String(props.slug)],
|
|
166
|
-
["buyTogether", String(props.buyTogether ?? false)],
|
|
167
|
-
["includeSameParent", String(props.includeSameParent ?? false)],
|
|
168
|
-
["skuId", skuId],
|
|
169
|
-
]);
|
|
170
|
-
|
|
171
|
-
return `wake:pdp?${params.toString()}`;
|
|
172
|
-
};
|
|
173
|
-
|
|
174
|
-
export default loader;
|