diff --git a/components/Session.tsx b/components/Session.tsx index a03ecaa5..26c486a6 100644 --- a/components/Session.tsx +++ b/components/Session.tsx @@ -9,9 +9,52 @@ import Drawer from "./ui/Drawer.tsx"; import UserProvider from "./user/Provider.tsx"; import WishlistProvider, { type Wishlist } from "./wishlist/Provider.tsx"; import { useScript } from "@deco/deco/hooks"; +import type { Manifest } from "../manifest.gen.ts"; + +export type FetchKeys = keyof Manifest["loaders"] | keyof Manifest["actions"]; + +type AppsManifest = { + [K in keyof Manifest["apps"]]: ReturnType["manifest"]; +}; +type LoaderProps = { + [K in keyof T]: { + // @ts-ignore Because I know we have loaders + [Loader in keyof T[K]["loaders"]]: Parameters[0]; + } & { + // @ts-ignore Because I know we have actions + [Action in keyof T[K]["actions"]]: Parameters[0]; + }; +}; + +type MergeLoaderProps = { + [K in keyof T]: LoaderProps[K]; +}; + +// Now flatten the merged loader props into a single object +type FlattenLoaderProps = MergeLoaderProps[keyof T] extends infer U + ? { [K in keyof U]: U[K] } + : never; + +type InvokableProps = FlattenLoaderProps; + +// deno-lint-ignore no-explicit-any +type ExtractKeys = T extends { [key: string]: any } ? keyof T : never; +type InvokableKeys = ExtractKeys + +type InvokablePropType = + // deno-lint-ignore no-explicit-any + K extends keyof (Extract) + // deno-lint-ignore no-explicit-any + ? Extract[K] + : never; + declare global { interface Window { STOREFRONT: SDK; + invoke: ( + key: T, + props: InvokablePropType, + ) => Promise; } } export interface Cart { @@ -222,11 +265,38 @@ const sdk = () => { return sdk; }; createAnalyticsSDK(); + + const createInvoke = () => + async ( + key: K, + props: InvokablePropType + ) => { + const response = await fetch("/live/invoke", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + key, + props, + }), + }); + + if (!response.ok) { + throw new Error( + `Failed to invoke function ${key}: ${response.statusText}`, + ); + } + + return response.json(); + }; + window.STOREFRONT = { CART: createCartSDK(), USER: createUserSDK(), WISHLIST: createWishlistSDK(), }; + window.invoke = createInvoke() }; export const action = async ( _props: unknown,