@replohq/sdk 2.8.0 → 2.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/_vendor/replo-utils/lib/url.d.ts +10 -3
- package/_vendor/schemas/generated/consent.d.ts +2 -2
- package/consent/script-snippets.js +10 -0
- package/consent/types.d.ts +2 -2
- package/lib/buildMetadata.js +3 -3
- package/loaders/collection-loader.d.ts +4 -1
- package/loaders/collection-loader.js +5 -9
- package/loaders/collection-products-loader.d.ts +4 -1
- package/loaders/collection-products-loader.js +5 -9
- package/loaders/contentful-entries-loader.d.ts +4 -1
- package/loaders/contentful-entries-loader.js +2 -6
- package/loaders/contentful-entry-loader.d.ts +4 -1
- package/loaders/contentful-entry-loader.js +2 -6
- package/loaders/invoke-loader-action.d.ts +2 -1
- package/loaders/invoke-loader-action.js +2 -4
- package/loaders/invoke-loader-server.js +8 -4
- package/loaders/invoke-loader.d.ts +11 -3
- package/loaders/invoke-loader.js +6 -5
- package/loaders/judgeme-review-aggregate-loader.d.ts +4 -1
- package/loaders/judgeme-review-aggregate-loader.js +5 -11
- package/loaders/judgeme-reviews-loader.d.ts +4 -1
- package/loaders/judgeme-reviews-loader.js +2 -6
- package/loaders/junip-review-aggregate-loader.d.ts +4 -1
- package/loaders/junip-review-aggregate-loader.js +5 -11
- package/loaders/junip-reviews-loader.d.ts +4 -1
- package/loaders/junip-reviews-loader.js +2 -6
- package/loaders/kaching-bundles-loader.d.ts +4 -1
- package/loaders/kaching-bundles-loader.js +5 -6
- package/loaders/levanta-product-loader.d.ts +4 -1
- package/loaders/levanta-product-loader.js +5 -9
- package/loaders/loader-output.d.ts +28 -0
- package/loaders/loader-output.js +122 -0
- package/loaders/loader-outputs.d.ts +55 -0
- package/loaders/loader-outputs.js +0 -0
- package/loaders/loox-review-aggregate-loader.d.ts +4 -1
- package/loaders/loox-review-aggregate-loader.js +5 -11
- package/loaders/loox-reviews-loader.d.ts +4 -1
- package/loaders/loox-reviews-loader.js +5 -9
- package/loaders/loyaltylion-earning-rules-loader.js +5 -11
- package/loaders/loyaltylion-points-for-price-loader.js +5 -11
- package/loaders/loyaltylion-rewards-loader.js +5 -9
- package/loaders/loyaltylion-tiers-loader.js +5 -9
- package/loaders/metaobject-loader.d.ts +4 -1
- package/loaders/metaobject-loader.js +2 -6
- package/loaders/metaobjects-loader.d.ts +4 -1
- package/loaders/metaobjects-loader.js +2 -6
- package/loaders/okendo-review-aggregate-loader.d.ts +4 -1
- package/loaders/okendo-review-aggregate-loader.js +5 -9
- package/loaders/okendo-reviews-loader.d.ts +4 -1
- package/loaders/okendo-reviews-loader.js +2 -6
- package/loaders/product-loader.d.ts +4 -1
- package/loaders/product-loader.js +2 -6
- package/loaders/rebuy-recommendations-loader.d.ts +4 -1
- package/loaders/rebuy-recommendations-loader.js +5 -9
- package/loaders/reviews-io-review-aggregate-loader.d.ts +4 -1
- package/loaders/reviews-io-review-aggregate-loader.js +2 -8
- package/loaders/reviews-io-reviews-loader.d.ts +4 -1
- package/loaders/reviews-io-reviews-loader.js +2 -8
- package/loaders/shopify-integration-details-loader.d.ts +4 -1
- package/loaders/shopify-integration-details-loader.js +5 -11
- package/loaders/smile-earning-rules-loader.d.ts +4 -1
- package/loaders/smile-earning-rules-loader.js +5 -9
- package/loaders/smile-rewards-loader.d.ts +4 -1
- package/loaders/smile-rewards-loader.js +5 -9
- package/loaders/smile-vip-tiers-loader.d.ts +4 -1
- package/loaders/smile-vip-tiers-loader.js +5 -9
- package/loaders/statsig-experiment-loader.d.ts +4 -1
- package/loaders/statsig-experiment-loader.js +2 -6
- package/loaders/yotpo-review-aggregate-loader.d.ts +4 -1
- package/loaders/yotpo-review-aggregate-loader.js +5 -11
- package/loaders/yotpo-reviews-loader.d.ts +4 -1
- package/loaders/yotpo-reviews-loader.js +2 -6
- package/package.json +4 -4
- package/size-budget/fixture/app/fixture-pdp/page.d.ts +1 -1
- package/size-budget/fixture/app/fixture-pdp/product-details.d.ts +1 -0
|
@@ -1,8 +1,14 @@
|
|
|
1
|
+
type UrlSearchParamValues = Record<string, string | number | boolean | string[] | null | undefined>;
|
|
1
2
|
/**
|
|
2
|
-
* Builds a URLSearchParams from a record, omitting undefined values.
|
|
3
|
-
* values are appended as repeated keys; scalars are stringified.
|
|
3
|
+
* Builds a URLSearchParams from a record, omitting null and undefined values.
|
|
4
|
+
* Array values are appended as repeated keys; scalars are stringified.
|
|
4
5
|
*/
|
|
5
|
-
export declare function buildUrlSearchParams(values:
|
|
6
|
+
export declare function buildUrlSearchParams(values: UrlSearchParamValues): URLSearchParams;
|
|
7
|
+
/**
|
|
8
|
+
* Appends a query string built by `buildUrlSearchParams` to a path, leaving
|
|
9
|
+
* the path bare when every value is omitted.
|
|
10
|
+
*/
|
|
11
|
+
export declare function pathWithSearchParams(path: string, values: UrlSearchParamValues): string;
|
|
6
12
|
export declare function isValidHttpUrl(url: string, options?: {
|
|
7
13
|
allowBlockedHostnames?: boolean;
|
|
8
14
|
allowedHostnames?: string[];
|
|
@@ -72,3 +78,4 @@ export declare function sanitizePublicHttpUrl(value: string | null, { preservePr
|
|
|
72
78
|
}): string | null;
|
|
73
79
|
export declare function isPublicHttpsUrl(value: string): boolean;
|
|
74
80
|
export declare function safeHost(url: string): string | null;
|
|
81
|
+
export {};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type ReploScriptType = "GA4" | "GoogleTagManager" | "Meta" | "TikTok" | "Pinterest" | "Reddit" | "Snapchat" | "X" | "Hotjar" | "MicrosoftClarity" | "Contentsquare" | "Segment" | "Northbeam" | "Gorgias" | "Converge" | "Mixpanel" | "HubSpot" | "Cookiebot" | "snippet" | "custom" | "consentPlatform";
|
|
1
|
+
export type ReploScriptType = "GA4" | "GoogleTagManager" | "Meta" | "TikTok" | "Pinterest" | "Reddit" | "Snapchat" | "X" | "Hotjar" | "MicrosoftClarity" | "Contentsquare" | "Segment" | "Northbeam" | "Gorgias" | "Converge" | "Mixpanel" | "HubSpot" | "Attentive" | "Cookiebot" | "snippet" | "custom" | "consentPlatform";
|
|
2
2
|
export type ConsentCategory = "necessary" | "analytics" | "marketing" | "preferences" | "sale_of_data";
|
|
3
3
|
export type ConsentMode = "off" | "simple" | "per-category";
|
|
4
4
|
export type ScriptTagDescriptor = {
|
|
@@ -27,7 +27,7 @@ export type ScriptRuntimeOwner = {
|
|
|
27
27
|
};
|
|
28
28
|
export type MixpanelRegion = "us" | "eu" | "in";
|
|
29
29
|
export type ReploScriptEntry = {
|
|
30
|
-
type: "GoogleTagManager" | "Meta" | "TikTok" | "Pinterest" | "Reddit" | "Snapchat" | "Hotjar" | "MicrosoftClarity" | "Contentsquare" | "Segment" | "Northbeam" | "Gorgias" | "Converge" | "HubSpot";
|
|
30
|
+
type: "GoogleTagManager" | "Meta" | "TikTok" | "Pinterest" | "Reddit" | "Snapchat" | "Hotjar" | "MicrosoftClarity" | "Contentsquare" | "Segment" | "Northbeam" | "Gorgias" | "Converge" | "HubSpot" | "Attentive";
|
|
31
31
|
identifier: string;
|
|
32
32
|
requiredConsent?: ConsentCategory[];
|
|
33
33
|
} | {
|
|
@@ -175,6 +175,16 @@ gtag('config', '${id}');`
|
|
|
175
175
|
attributes: { id: "hs-script-loader", async: "true", defer: "true" }
|
|
176
176
|
}
|
|
177
177
|
]
|
|
178
|
+
},
|
|
179
|
+
Attentive: {
|
|
180
|
+
defaultConsent: ["marketing"],
|
|
181
|
+
buildTags: (id) => [
|
|
182
|
+
{
|
|
183
|
+
kind: "external",
|
|
184
|
+
src: `https://cdn.attn.tv/${id}/dtag.js`,
|
|
185
|
+
attributes: { async: "true" }
|
|
186
|
+
}
|
|
187
|
+
]
|
|
178
188
|
}
|
|
179
189
|
};
|
|
180
190
|
function isXEventIdForPixel({
|
package/consent/types.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type ReploScriptType = "GA4" | "GoogleTagManager" | "Meta" | "TikTok" | "Pinterest" | "Reddit" | "Snapchat" | "X" | "Hotjar" | "MicrosoftClarity" | "Contentsquare" | "Segment" | "Northbeam" | "Gorgias" | "Converge" | "HubSpot" | "Mixpanel" | "Cookiebot" | "snippet" | "custom" | "consentPlatform";
|
|
1
|
+
export type ReploScriptType = "GA4" | "GoogleTagManager" | "Meta" | "TikTok" | "Pinterest" | "Reddit" | "Snapchat" | "X" | "Hotjar" | "MicrosoftClarity" | "Contentsquare" | "Segment" | "Northbeam" | "Gorgias" | "Converge" | "HubSpot" | "Mixpanel" | "Attentive" | "Cookiebot" | "snippet" | "custom" | "consentPlatform";
|
|
2
2
|
export type ConsentCategory = "necessary" | "analytics" | "marketing" | "preferences" | "sale_of_data";
|
|
3
3
|
export type ConsentMode = "off" | "simple" | "per-category";
|
|
4
4
|
declare module "react" {
|
|
@@ -36,7 +36,7 @@ export type ScriptRuntimeOwner = {
|
|
|
36
36
|
};
|
|
37
37
|
export type MixpanelRegion = "us" | "eu" | "in";
|
|
38
38
|
export type ReploScriptEntry = {
|
|
39
|
-
type: "GoogleTagManager" | "Meta" | "TikTok" | "Pinterest" | "Reddit" | "Snapchat" | "Hotjar" | "MicrosoftClarity" | "Contentsquare" | "Segment" | "Northbeam" | "Gorgias" | "Converge" | "HubSpot";
|
|
39
|
+
type: "GoogleTagManager" | "Meta" | "TikTok" | "Pinterest" | "Reddit" | "Snapchat" | "Hotjar" | "MicrosoftClarity" | "Contentsquare" | "Segment" | "Northbeam" | "Gorgias" | "Converge" | "HubSpot" | "Attentive";
|
|
40
40
|
identifier: string;
|
|
41
41
|
requiredConsent?: ConsentCategory[];
|
|
42
42
|
} | {
|
package/lib/buildMetadata.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export const BUILD_METADATA = {
|
|
2
2
|
"packageName": "@replohq/sdk",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.10.0",
|
|
4
4
|
"branch": "HEAD",
|
|
5
|
-
"commit": "
|
|
6
|
-
"builtAt": "2026-10-
|
|
5
|
+
"commit": "96a07333d34af59c46f8874351df866542e7c2e9",
|
|
6
|
+
"builtAt": "2026-10-26T22:54:01.502Z"
|
|
7
7
|
};
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import type { ReactNode } from "react";
|
|
2
2
|
import type { CollectionLoaderArgs } from "./collection-loader-args";
|
|
3
|
+
import type { DATA_LOADER_KEYS } from "./loader-keys";
|
|
4
|
+
import type { LoaderKeyProp } from "./loader-outputs";
|
|
3
5
|
import type { FullCollection } from "./loader-schemas";
|
|
6
|
+
type LoaderKey = (typeof DATA_LOADER_KEYS)["SHOPIFY_COLLECTION"];
|
|
4
7
|
type CollectionLoaderProps = CollectionLoaderArgs & {
|
|
5
|
-
loaderKey:
|
|
8
|
+
loaderKey: LoaderKeyProp<LoaderKey>;
|
|
6
9
|
children: (data: FullCollection) => ReactNode;
|
|
7
10
|
fallback?: ReactNode;
|
|
8
11
|
};
|
|
@@ -13,15 +13,11 @@ function CollectionLoaderInner({
|
|
|
13
13
|
}) {
|
|
14
14
|
const queryResult = useSuspenseQuery({
|
|
15
15
|
queryKey: [loaderKey, args],
|
|
16
|
-
queryFn:
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
}),
|
|
22
|
-
import("./loader-schemas")
|
|
23
|
-
]);
|
|
24
|
-
return schemas.fullCollectionSchema.parse(loadedData);
|
|
16
|
+
queryFn: () => {
|
|
17
|
+
return invokeLoader({
|
|
18
|
+
loaderKey,
|
|
19
|
+
args
|
|
20
|
+
});
|
|
25
21
|
}
|
|
26
22
|
});
|
|
27
23
|
useReportPreviewPlaceholderRender(queryResult.data);
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import type { ReactNode } from "react";
|
|
2
2
|
import type { CollectionProductsLoaderArgs } from "./collection-products-loader-args";
|
|
3
|
+
import type { DATA_LOADER_KEYS } from "./loader-keys";
|
|
4
|
+
import type { LoaderKeyProp } from "./loader-outputs";
|
|
3
5
|
import type { PaginatedProducts } from "./loader-schemas";
|
|
6
|
+
type LoaderKey = (typeof DATA_LOADER_KEYS)["SHOPIFY_COLLECTION_PRODUCTS"];
|
|
4
7
|
type CollectionProductsLoaderProps = CollectionProductsLoaderArgs & {
|
|
5
|
-
loaderKey:
|
|
8
|
+
loaderKey: LoaderKeyProp<LoaderKey>;
|
|
6
9
|
children: (data: PaginatedProducts) => ReactNode;
|
|
7
10
|
fallback?: ReactNode;
|
|
8
11
|
};
|
|
@@ -13,15 +13,11 @@ function CollectionProductsLoaderInner({
|
|
|
13
13
|
}) {
|
|
14
14
|
const queryResult = useSuspenseQuery({
|
|
15
15
|
queryKey: [loaderKey, args],
|
|
16
|
-
queryFn:
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
}),
|
|
22
|
-
import("./loader-schemas")
|
|
23
|
-
]);
|
|
24
|
-
return schemas.paginatedProductsSchema.parse(loadedData);
|
|
16
|
+
queryFn: () => {
|
|
17
|
+
return invokeLoader({
|
|
18
|
+
loaderKey,
|
|
19
|
+
args
|
|
20
|
+
});
|
|
25
21
|
}
|
|
26
22
|
});
|
|
27
23
|
useReportPreviewPlaceholderRender(queryResult.data);
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import type { ReactNode } from "react";
|
|
2
|
+
import type { DATA_LOADER_KEYS } from "./loader-keys";
|
|
3
|
+
import type { LoaderKeyProp } from "./loader-outputs";
|
|
2
4
|
import type { ContentfulEntriesLoaderOutput } from "./loader-schemas";
|
|
5
|
+
type LoaderKey = (typeof DATA_LOADER_KEYS)["CONTENTFUL_ENTRIES"];
|
|
3
6
|
type ContentfulEntriesLoaderProps = {
|
|
4
|
-
loaderKey:
|
|
7
|
+
loaderKey: LoaderKeyProp<LoaderKey>;
|
|
5
8
|
spaceId: string;
|
|
6
9
|
contentType: string;
|
|
7
10
|
environmentId?: string;
|
|
@@ -32,12 +32,8 @@ function ContentfulEntriesLoaderInner({
|
|
|
32
32
|
}) {
|
|
33
33
|
const { data } = useSuspenseQuery({
|
|
34
34
|
queryKey: [loaderKey, args],
|
|
35
|
-
queryFn:
|
|
36
|
-
|
|
37
|
-
invokeLoader({ loaderKey, args }),
|
|
38
|
-
import("./loader-schemas")
|
|
39
|
-
]);
|
|
40
|
-
return schemas.contentfulEntriesLoaderOutputSchema.parse(loadedData);
|
|
35
|
+
queryFn: () => {
|
|
36
|
+
return invokeLoader({ loaderKey, args });
|
|
41
37
|
}
|
|
42
38
|
});
|
|
43
39
|
return /* @__PURE__ */ jsx(Fragment, { children: children(data) });
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import type { ReactNode } from "react";
|
|
2
|
+
import type { DATA_LOADER_KEYS } from "./loader-keys";
|
|
3
|
+
import type { LoaderKeyProp } from "./loader-outputs";
|
|
2
4
|
import type { ContentfulEntryLoaderOutput } from "./loader-schemas";
|
|
5
|
+
type LoaderKey = (typeof DATA_LOADER_KEYS)["CONTENTFUL_ENTRY"];
|
|
3
6
|
type ContentfulEntryLoaderProps = {
|
|
4
|
-
loaderKey:
|
|
7
|
+
loaderKey: LoaderKeyProp<LoaderKey>;
|
|
5
8
|
spaceId: string;
|
|
6
9
|
entryId: string;
|
|
7
10
|
environmentId?: string;
|
|
@@ -26,12 +26,8 @@ function ContentfulEntryLoaderInner({
|
|
|
26
26
|
}) {
|
|
27
27
|
const { data } = useSuspenseQuery({
|
|
28
28
|
queryKey: [loaderKey, args],
|
|
29
|
-
queryFn:
|
|
30
|
-
|
|
31
|
-
invokeLoader({ loaderKey, args }),
|
|
32
|
-
import("./loader-schemas")
|
|
33
|
-
]);
|
|
34
|
-
return schemas.contentfulEntryLoaderOutputSchema.parse(loadedData);
|
|
29
|
+
queryFn: () => {
|
|
30
|
+
return invokeLoader({ loaderKey, args });
|
|
35
31
|
}
|
|
36
32
|
});
|
|
37
33
|
return /* @__PURE__ */ jsx(Fragment, { children: children(data) });
|
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
* Called from client-side loader components when React Query needs to
|
|
4
4
|
* fetch data in the browser (e.g., client-side navigation, cache miss).
|
|
5
5
|
* This runs on the server — Next.js handles the client/server boundary
|
|
6
|
-
* automatically.
|
|
6
|
+
* automatically. The output is validated here, before it crosses to the
|
|
7
|
+
* browser.
|
|
7
8
|
*/
|
|
8
9
|
export declare function invokeLoaderAction({ loaderKey, args, }: {
|
|
9
10
|
loaderKey: string;
|
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
"use server";
|
|
2
|
-
import {
|
|
2
|
+
import { fetchValidatedLoaderOutput } from "./loader-output";
|
|
3
3
|
async function invokeLoaderAction({
|
|
4
4
|
loaderKey,
|
|
5
5
|
args
|
|
6
6
|
}) {
|
|
7
|
-
|
|
8
|
-
const response = await gateway.invokeLoader({ loaderKey, args });
|
|
9
|
-
return response.data;
|
|
7
|
+
return fetchValidatedLoaderOutput({ loaderKey, args });
|
|
10
8
|
}
|
|
11
9
|
export {
|
|
12
10
|
invokeLoaderAction
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { unstable_cache } from "next/cache";
|
|
2
2
|
import {
|
|
3
3
|
CanopyApiGatewayError,
|
|
4
|
-
getCanopyApiGateway,
|
|
5
4
|
shouldIncludeInactiveProducts
|
|
6
5
|
} from "../gateways/canopy-api";
|
|
6
|
+
import { fetchValidatedLoaderOutput, LoaderOutputError } from "./loader-output";
|
|
7
7
|
import { resolvePreviewPlaceholderData } from "./preview-placeholder";
|
|
8
8
|
const DEFAULT_REVALIDATE_SECONDS = 60;
|
|
9
9
|
class LoaderDataNotFoundError extends CanopyApiGatewayError {
|
|
@@ -46,11 +46,15 @@ async function invokeLoaderServer({
|
|
|
46
46
|
});
|
|
47
47
|
const cachedInvocation = await unstable_cache(
|
|
48
48
|
async () => {
|
|
49
|
-
const gateway = await getCanopyApiGateway();
|
|
50
49
|
try {
|
|
51
|
-
|
|
52
|
-
|
|
50
|
+
return {
|
|
51
|
+
kind: "data",
|
|
52
|
+
data: await fetchValidatedLoaderOutput({ loaderKey, args })
|
|
53
|
+
};
|
|
53
54
|
} catch (error) {
|
|
55
|
+
if (error instanceof LoaderOutputError) {
|
|
56
|
+
return { kind: "data", data: error.unvalidatedOutput };
|
|
57
|
+
}
|
|
54
58
|
if (error instanceof CanopyApiGatewayError && error.statusCode === 404) {
|
|
55
59
|
return { kind: "notFound" };
|
|
56
60
|
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { DataLoaderKey } from "./loader-keys";
|
|
2
|
+
import type { LoaderKeyProp, LoaderOutput } from "./loader-outputs";
|
|
1
3
|
import { CanopyError } from "../lib/canopy-error";
|
|
2
4
|
/** Scoped error for loader invocation failures. */
|
|
3
5
|
export declare class LoaderInvokeError extends CanopyError {
|
|
@@ -7,6 +9,12 @@ export declare class LoaderInvokeError extends CanopyError {
|
|
|
7
9
|
* In the browser, dynamically imports a server action so React 19 never sees
|
|
8
10
|
* the "use server" reference during render.
|
|
9
11
|
*
|
|
12
|
+
* `Key` names the loader the caller expects, and the result is typed from it.
|
|
13
|
+
* It is not checked here: `loaderKey` can be any string a site passed to a
|
|
14
|
+
* component, and the server validates the output against the schema
|
|
15
|
+
* registered for the key actually sent (`loader-output.ts`), so the browser
|
|
16
|
+
* never downloads Zod or the schemas. Callers pass `Key` explicitly.
|
|
17
|
+
*
|
|
10
18
|
* Next defines `process.env.NEXT_RUNTIME` as "" in browser bundles, so the
|
|
11
19
|
* bundler drops the server branch and never emits the gateway, its env
|
|
12
20
|
* handling, or its Zod schemas as a client chunk. `typeof window` is not
|
|
@@ -15,7 +23,7 @@ export declare class LoaderInvokeError extends CanopyError {
|
|
|
15
23
|
* In an editor iframe previewing an unfilled dynamic route, returns sample
|
|
16
24
|
* data instead of fetching — see `preview-placeholder.ts`.
|
|
17
25
|
*/
|
|
18
|
-
export declare function invokeLoader
|
|
19
|
-
loaderKey:
|
|
26
|
+
export declare function invokeLoader<Key extends DataLoaderKey>(params: {
|
|
27
|
+
loaderKey: LoaderKeyProp<Key>;
|
|
20
28
|
args: Record<string, unknown>;
|
|
21
|
-
}): Promise<
|
|
29
|
+
}): Promise<LoaderOutput<Key>>;
|
package/loaders/invoke-loader.js
CHANGED
|
@@ -2,7 +2,7 @@ import { CanopyError } from "../lib/canopy-error";
|
|
|
2
2
|
import { resolvePreviewPlaceholderData } from "./preview-placeholder";
|
|
3
3
|
class LoaderInvokeError extends CanopyError {
|
|
4
4
|
}
|
|
5
|
-
async function
|
|
5
|
+
async function invokeUntypedLoader({
|
|
6
6
|
loaderKey,
|
|
7
7
|
args
|
|
8
8
|
}) {
|
|
@@ -12,10 +12,8 @@ async function invokeLoader({
|
|
|
12
12
|
}
|
|
13
13
|
try {
|
|
14
14
|
if (process.env.NEXT_RUNTIME) {
|
|
15
|
-
const {
|
|
16
|
-
|
|
17
|
-
const response = await gateway.invokeLoader({ loaderKey, args });
|
|
18
|
-
return response.data;
|
|
15
|
+
const { fetchValidatedLoaderOutput } = await import("./loader-output");
|
|
16
|
+
return await fetchValidatedLoaderOutput({ loaderKey, args });
|
|
19
17
|
}
|
|
20
18
|
const { invokeLoaderAction } = await import("./invoke-loader-action");
|
|
21
19
|
return await invokeLoaderAction({ loaderKey, args });
|
|
@@ -30,6 +28,9 @@ async function invokeLoader({
|
|
|
30
28
|
});
|
|
31
29
|
}
|
|
32
30
|
}
|
|
31
|
+
async function invokeLoader(params) {
|
|
32
|
+
return await invokeUntypedLoader(params);
|
|
33
|
+
}
|
|
33
34
|
export {
|
|
34
35
|
LoaderInvokeError,
|
|
35
36
|
invokeLoader
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import type { ReactNode } from "react";
|
|
2
2
|
import type { z } from "zod";
|
|
3
|
+
import type { DATA_LOADER_KEYS } from "./loader-keys";
|
|
4
|
+
import type { LoaderKeyProp } from "./loader-outputs";
|
|
3
5
|
import type { judgemeProductReviewAggregateLoaderOutputSchema } from "./loader-schemas";
|
|
6
|
+
type LoaderKey = (typeof DATA_LOADER_KEYS)["JUDGEME_PRODUCT_REVIEW_AGGREGATE"];
|
|
4
7
|
type JudgemeReviewAggregateData = z.infer<typeof judgemeProductReviewAggregateLoaderOutputSchema>;
|
|
5
8
|
type JudgemeReviewAggregateLoaderProps = {
|
|
6
|
-
loaderKey:
|
|
9
|
+
loaderKey: LoaderKeyProp<LoaderKey>;
|
|
7
10
|
productId: string;
|
|
8
11
|
children: (data: JudgemeReviewAggregateData) => ReactNode;
|
|
9
12
|
fallback?: ReactNode;
|
|
@@ -11,17 +11,11 @@ function JudgemeReviewAggregateLoaderInner({
|
|
|
11
11
|
}) {
|
|
12
12
|
const { data } = useSuspenseQuery({
|
|
13
13
|
queryKey: [loaderKey, { productId }],
|
|
14
|
-
queryFn:
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
}),
|
|
20
|
-
import("./loader-schemas")
|
|
21
|
-
]);
|
|
22
|
-
return schemas.judgemeProductReviewAggregateLoaderOutputSchema.parse(
|
|
23
|
-
loadedData
|
|
24
|
-
);
|
|
14
|
+
queryFn: () => {
|
|
15
|
+
return invokeLoader({
|
|
16
|
+
loaderKey,
|
|
17
|
+
args: { productId }
|
|
18
|
+
});
|
|
25
19
|
}
|
|
26
20
|
});
|
|
27
21
|
return /* @__PURE__ */ jsx(Fragment, { children: children(data) });
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import type { ReactNode } from "react";
|
|
2
2
|
import type { z } from "zod";
|
|
3
|
+
import type { DATA_LOADER_KEYS } from "./loader-keys";
|
|
4
|
+
import type { LoaderKeyProp } from "./loader-outputs";
|
|
3
5
|
import type { judgemeProductReviewsLoaderOutputSchema } from "./loader-schemas";
|
|
6
|
+
type LoaderKey = (typeof DATA_LOADER_KEYS)["JUDGEME_PRODUCT_REVIEWS"];
|
|
4
7
|
type JudgemeReviewsData = z.infer<typeof judgemeProductReviewsLoaderOutputSchema>;
|
|
5
8
|
type JudgemeReviewsLoaderProps = {
|
|
6
|
-
loaderKey:
|
|
9
|
+
loaderKey: LoaderKeyProp<LoaderKey>;
|
|
7
10
|
productId: string;
|
|
8
11
|
perPage?: number;
|
|
9
12
|
page?: number;
|
|
@@ -25,12 +25,8 @@ function JudgemeReviewsLoaderInner({
|
|
|
25
25
|
const args = buildReviewsArgs({ productId, perPage, page });
|
|
26
26
|
const { data } = useSuspenseQuery({
|
|
27
27
|
queryKey: [loaderKey, args],
|
|
28
|
-
queryFn:
|
|
29
|
-
|
|
30
|
-
invokeLoader({ loaderKey, args }),
|
|
31
|
-
import("./loader-schemas")
|
|
32
|
-
]);
|
|
33
|
-
return schemas.judgemeProductReviewsLoaderOutputSchema.parse(loadedData);
|
|
28
|
+
queryFn: () => {
|
|
29
|
+
return invokeLoader({ loaderKey, args });
|
|
34
30
|
}
|
|
35
31
|
});
|
|
36
32
|
return /* @__PURE__ */ jsx(Fragment, { children: children(data) });
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import type { ReactNode } from "react";
|
|
2
2
|
import type { z } from "zod";
|
|
3
|
+
import type { DATA_LOADER_KEYS } from "./loader-keys";
|
|
4
|
+
import type { LoaderKeyProp } from "./loader-outputs";
|
|
3
5
|
import type { junipProductReviewAggregateLoaderOutputSchema } from "./loader-schemas";
|
|
6
|
+
type LoaderKey = (typeof DATA_LOADER_KEYS)["JUNIP_PRODUCT_REVIEW_AGGREGATE"];
|
|
4
7
|
type JunipReviewAggregateData = z.infer<typeof junipProductReviewAggregateLoaderOutputSchema>;
|
|
5
8
|
type JunipReviewAggregateLoaderProps = {
|
|
6
|
-
loaderKey:
|
|
9
|
+
loaderKey: LoaderKeyProp<LoaderKey>;
|
|
7
10
|
productId: string;
|
|
8
11
|
children: (data: JunipReviewAggregateData) => ReactNode;
|
|
9
12
|
fallback?: ReactNode;
|
|
@@ -11,17 +11,11 @@ function JunipReviewAggregateLoaderInner({
|
|
|
11
11
|
}) {
|
|
12
12
|
const { data } = useSuspenseQuery({
|
|
13
13
|
queryKey: [loaderKey, { productId }],
|
|
14
|
-
queryFn:
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
}),
|
|
20
|
-
import("./loader-schemas")
|
|
21
|
-
]);
|
|
22
|
-
return schemas.junipProductReviewAggregateLoaderOutputSchema.parse(
|
|
23
|
-
loadedData
|
|
24
|
-
);
|
|
14
|
+
queryFn: () => {
|
|
15
|
+
return invokeLoader({
|
|
16
|
+
loaderKey,
|
|
17
|
+
args: { productId }
|
|
18
|
+
});
|
|
25
19
|
}
|
|
26
20
|
});
|
|
27
21
|
return /* @__PURE__ */ jsx(Fragment, { children: children(data) });
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import type { ReactNode } from "react";
|
|
2
2
|
import type { z } from "zod";
|
|
3
|
+
import type { DATA_LOADER_KEYS } from "./loader-keys";
|
|
4
|
+
import type { LoaderKeyProp } from "./loader-outputs";
|
|
3
5
|
import type { junipProductReviewsLoaderOutputSchema } from "./loader-schemas";
|
|
6
|
+
type LoaderKey = (typeof DATA_LOADER_KEYS)["JUNIP_PRODUCT_REVIEWS"];
|
|
4
7
|
type JunipReviewsData = z.infer<typeof junipProductReviewsLoaderOutputSchema>;
|
|
5
8
|
type JunipReviewsLoaderProps = {
|
|
6
|
-
loaderKey:
|
|
9
|
+
loaderKey: LoaderKeyProp<LoaderKey>;
|
|
7
10
|
productId: string;
|
|
8
11
|
perPage?: number;
|
|
9
12
|
children: (data: JunipReviewsData) => ReactNode;
|
|
@@ -19,12 +19,8 @@ function JunipReviewsLoaderInner({
|
|
|
19
19
|
const args = buildReviewsArgs({ productId, perPage });
|
|
20
20
|
const { data } = useSuspenseQuery({
|
|
21
21
|
queryKey: [loaderKey, args],
|
|
22
|
-
queryFn:
|
|
23
|
-
|
|
24
|
-
invokeLoader({ loaderKey, args }),
|
|
25
|
-
import("./loader-schemas")
|
|
26
|
-
]);
|
|
27
|
-
return schemas.junipProductReviewsLoaderOutputSchema.parse(loadedData);
|
|
22
|
+
queryFn: () => {
|
|
23
|
+
return invokeLoader({ loaderKey, args });
|
|
28
24
|
}
|
|
29
25
|
});
|
|
30
26
|
return /* @__PURE__ */ jsx(Fragment, { children: children(data) });
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import type { ReactNode } from "react";
|
|
2
2
|
import type { AddToCartItem } from "../cart/hooks/use-add-to-cart";
|
|
3
|
+
import type { DATA_LOADER_KEYS } from "./loader-keys";
|
|
4
|
+
import type { LoaderKeyProp } from "./loader-outputs";
|
|
5
|
+
type LoaderKey = (typeof DATA_LOADER_KEYS)["SHOPIFY_KACHING_BUNDLES"];
|
|
3
6
|
type KachingBundlesLoaderProps = {
|
|
4
|
-
loaderKey:
|
|
7
|
+
loaderKey: LoaderKeyProp<LoaderKey>;
|
|
5
8
|
productId: string;
|
|
6
9
|
dealBlockId?: string;
|
|
7
10
|
country?: string;
|
|
@@ -15,12 +15,11 @@ function KachingBundlesLoaderInner({
|
|
|
15
15
|
const [lines, setLines] = useState([]);
|
|
16
16
|
const { data } = useSuspenseQuery({
|
|
17
17
|
queryKey: [loaderKey, args],
|
|
18
|
-
queryFn:
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
return schemas.shopifyKachingBundlesLoaderOutputSchema.parse(loadedData);
|
|
18
|
+
queryFn: () => {
|
|
19
|
+
return invokeLoader({
|
|
20
|
+
loaderKey,
|
|
21
|
+
args
|
|
22
|
+
});
|
|
24
23
|
}
|
|
25
24
|
});
|
|
26
25
|
if (data.bundles === null) {
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import type { ReactNode } from "react";
|
|
2
|
+
import type { DATA_LOADER_KEYS } from "./loader-keys";
|
|
3
|
+
import type { LoaderKeyProp } from "./loader-outputs";
|
|
2
4
|
import type { LevantaProductFull } from "./loader-schemas";
|
|
5
|
+
type LoaderKey = (typeof DATA_LOADER_KEYS)["LEVANTA_PRODUCT"];
|
|
3
6
|
type LevantaProductLoaderProps = {
|
|
4
|
-
loaderKey:
|
|
7
|
+
loaderKey: LoaderKeyProp<LoaderKey>;
|
|
5
8
|
asin: string;
|
|
6
9
|
marketplace?: string;
|
|
7
10
|
children: (data: LevantaProductFull) => ReactNode;
|
|
@@ -12,15 +12,11 @@ function LevantaProductLoaderInner({
|
|
|
12
12
|
}) {
|
|
13
13
|
const queryResult = useSuspenseQuery({
|
|
14
14
|
queryKey: [loaderKey, { asin, marketplace }],
|
|
15
|
-
queryFn:
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
}),
|
|
21
|
-
import("./loader-schemas")
|
|
22
|
-
]);
|
|
23
|
-
return schemas.levantaProductFullSchema.parse(loadedData);
|
|
15
|
+
queryFn: () => {
|
|
16
|
+
return invokeLoader({
|
|
17
|
+
loaderKey,
|
|
18
|
+
args: { asin, marketplace }
|
|
19
|
+
});
|
|
24
20
|
}
|
|
25
21
|
});
|
|
26
22
|
return /* @__PURE__ */ jsx(Fragment, { children: children(queryResult.data) });
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { DataLoaderKey } from "./loader-keys";
|
|
2
|
+
import * as z from "zod";
|
|
3
|
+
import { CanopyError } from "../lib/canopy-error";
|
|
4
|
+
/**
|
|
5
|
+
* A loader returned data that does not match its output contract. Carries the
|
|
6
|
+
* unvalidated output so a caller that fails soft can still serve it.
|
|
7
|
+
*/
|
|
8
|
+
export declare class LoaderOutputError extends CanopyError {
|
|
9
|
+
readonly unvalidatedOutput: unknown;
|
|
10
|
+
constructor({ loaderKey, unvalidatedOutput, zodError, }: {
|
|
11
|
+
loaderKey: DataLoaderKey;
|
|
12
|
+
unvalidatedOutput: unknown;
|
|
13
|
+
zodError: z.ZodError;
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Invokes a loader through the canopy-api gateway and validates its output
|
|
18
|
+
* against the loader's contract. The parsed value drops fields the contract
|
|
19
|
+
* does not declare. Output of a loader key the SDK has no contract for passes
|
|
20
|
+
* through unchanged.
|
|
21
|
+
*
|
|
22
|
+
* Malformed output is logged with the loader key and the failing paths, then
|
|
23
|
+
* rejected with a `LoaderOutputError`; callers decide whether to fail soft.
|
|
24
|
+
*/
|
|
25
|
+
export declare function fetchValidatedLoaderOutput({ loaderKey, args, }: {
|
|
26
|
+
loaderKey: string;
|
|
27
|
+
args: Record<string, unknown>;
|
|
28
|
+
}): Promise<unknown>;
|