medusa-storefront-core 1.1.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/dist/edge.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ export { medusaListRegions, medusaMergeCarts } from 'medusa-services';
2
+ export type { MedusaMiddlewareClientOptions } from 'medusa-services';
@@ -0,0 +1,15 @@
1
+ import { default as React, Component, ReactNode } from 'react';
2
+
3
+ type Props = {
4
+ children: ReactNode;
5
+ fallback?: ReactNode | ((error: Error) => ReactNode);
6
+ };
7
+ type State = {
8
+ error: Error | null;
9
+ };
10
+ export declare class StorefrontErrorBoundary extends Component<Props, State> {
11
+ state: State;
12
+ static getDerivedStateFromError(error: Error): State;
13
+ render(): string | number | bigint | boolean | Iterable<React.ReactNode> | Promise<React.AwaitedReactNode> | import("react/jsx-runtime").JSX.Element | null | undefined;
14
+ }
15
+ export {};
@@ -0,0 +1,2 @@
1
+ export declare function parseMedusaStoreError(response: Response): Promise<string>;
2
+ export declare function getErrorMessage(error: unknown, fallback?: string): string;
@@ -0,0 +1,6 @@
1
+ export * from './types';
2
+ export * from './errors';
3
+ export * from './provider';
4
+ export * from './use-storefront-action';
5
+ export * from './site-config';
6
+ export { StorefrontErrorBoundary } from './error-boundary';
@@ -0,0 +1,21 @@
1
+ import { default as React } from 'react';
2
+ import { StorefrontCompanyConfig } from './site-config';
3
+
4
+ export type MedusaSiteContextValue = {
5
+ countryCode?: string;
6
+ regionId?: string;
7
+ publishableKey?: string;
8
+ backendUrl?: string;
9
+ company?: StorefrontCompanyConfig;
10
+ };
11
+ export type MedusaSiteProviderProps = {
12
+ children: React.ReactNode;
13
+ value?: MedusaSiteContextValue;
14
+ countryCode?: string;
15
+ regionId?: string;
16
+ company?: StorefrontCompanyConfig;
17
+ };
18
+ export declare function MedusaSiteProvider({ children, value, countryCode, regionId, company, }: MedusaSiteProviderProps): import("react/jsx-runtime").JSX.Element;
19
+ export declare function useMedusaSite(): MedusaSiteContextValue;
20
+ /** Shorthand for company details from site config. */
21
+ export declare function useSiteCompany(): StorefrontCompanyConfig;
@@ -0,0 +1,52 @@
1
+ import { Metadata } from 'next';
2
+
3
+ /** Company / brand details passed from each storefront — never hardcode in libraries. */
4
+ export type StorefrontCompanyConfig = {
5
+ name: string;
6
+ brandName?: string;
7
+ customerLabel?: string;
8
+ contactEmail?: string;
9
+ phone?: string;
10
+ description?: string;
11
+ helpTagline?: string;
12
+ mapTitle?: string;
13
+ whyChooseUsTitle?: string;
14
+ termsSubtitle?: string;
15
+ privacySubtitle?: string;
16
+ };
17
+ /** Site-specific values passed from each storefront project. */
18
+ export type StorefrontSiteConfig = {
19
+ siteName: string;
20
+ siteUrl: string;
21
+ company?: StorefrontCompanyConfig;
22
+ gtmId?: string;
23
+ locale?: string;
24
+ htmlLang?: string;
25
+ icons?: {
26
+ icon?: string;
27
+ apple?: string;
28
+ };
29
+ seo: {
30
+ titleTemplate: string;
31
+ defaultTitle: string;
32
+ description: string;
33
+ openGraph?: {
34
+ title?: string;
35
+ description?: string;
36
+ image?: string;
37
+ imageAlt?: string;
38
+ locale?: string;
39
+ };
40
+ twitter?: {
41
+ title?: string;
42
+ description?: string;
43
+ image?: string;
44
+ };
45
+ };
46
+ features?: {
47
+ cookieConsent?: boolean;
48
+ metaPixelGuard?: boolean;
49
+ gtm?: boolean;
50
+ };
51
+ };
52
+ export declare function buildSiteMetadata(config: StorefrontSiteConfig, metadataBase: URL): Metadata;
@@ -0,0 +1,12 @@
1
+ export type StorefrontErrorCode = "UNKNOWN" | "NETWORK" | "UNAUTHORIZED" | "NOT_FOUND" | "VALIDATION" | "CONFIG";
2
+ export type StorefrontResult<T> = {
3
+ ok: true;
4
+ data: T;
5
+ } | {
6
+ ok: false;
7
+ code: StorefrontErrorCode;
8
+ message: string;
9
+ };
10
+ export declare function ok<T>(data: T): StorefrontResult<T>;
11
+ export declare function err<T = never>(message: string, code?: StorefrontErrorCode): StorefrontResult<T>;
12
+ export declare function fromCaught(error: unknown, fallback?: string): StorefrontResult<never>;
@@ -0,0 +1,144 @@
1
+ var g = Object.defineProperty;
2
+ var h = (e, t, r) => t in e ? g(e, t, { enumerable: !0, configurable: !0, writable: !0, value: r }) : e[t] = r;
3
+ var p = (e, t, r) => h(e, typeof t != "symbol" ? t + "" : t, r);
4
+ import { parseStoreErrorMessage as y } from "medusa-services";
5
+ import { jsx as f } from "react/jsx-runtime";
6
+ import { useMemo as U, useContext as S, createContext as C, useTransition as _, useState as l, useCallback as b, Component as N } from "react";
7
+ function L(e) {
8
+ return { ok: !0, data: e };
9
+ }
10
+ function M(e, t = "UNKNOWN") {
11
+ return { ok: !1, code: t, message: e };
12
+ }
13
+ function k(e, t = "Something went wrong") {
14
+ const r = e instanceof Error ? e.message : t;
15
+ return M(r);
16
+ }
17
+ async function P(e) {
18
+ return y(e);
19
+ }
20
+ function B(e, t = "Something went wrong") {
21
+ return e instanceof Error ? e.message : typeof e == "string" ? e : t;
22
+ }
23
+ const m = {
24
+ name: "Store",
25
+ brandName: "Store",
26
+ customerLabel: "Customer"
27
+ }, d = C({
28
+ company: m
29
+ });
30
+ function K({
31
+ children: e,
32
+ value: t,
33
+ countryCode: r,
34
+ regionId: s,
35
+ company: i
36
+ }) {
37
+ const a = U(
38
+ () => ({
39
+ countryCode: (t == null ? void 0 : t.countryCode) ?? r,
40
+ regionId: (t == null ? void 0 : t.regionId) ?? s,
41
+ publishableKey: (t == null ? void 0 : t.publishableKey) ?? process.env.NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY,
42
+ backendUrl: (t == null ? void 0 : t.backendUrl) ?? process.env.NEXT_PUBLIC_MEDUSA_BACKEND_URL ?? process.env.MEDUSA_BACKEND_URL,
43
+ company: (t == null ? void 0 : t.company) ?? i ?? m
44
+ }),
45
+ [t, r, s, i]
46
+ );
47
+ return /* @__PURE__ */ f(d.Provider, { value: a, children: e });
48
+ }
49
+ function I() {
50
+ return S(d);
51
+ }
52
+ function j() {
53
+ return S(d).company ?? m;
54
+ }
55
+ function F(e) {
56
+ const [t, r] = _(), [s, i] = l(null), [a, u] = l(null);
57
+ return { run: b(
58
+ (...E) => (i(null), new Promise((c) => {
59
+ r(() => {
60
+ (async () => {
61
+ try {
62
+ const n = await e(...E);
63
+ if (n && typeof n == "object" && "ok" in n) {
64
+ const o = n;
65
+ o.ok ? u(o.data) : i(o.message), c(o);
66
+ } else
67
+ u(n), c({ ok: !0, data: n });
68
+ } catch (n) {
69
+ const o = k(n);
70
+ o.ok || i(o.message), c(o);
71
+ }
72
+ })();
73
+ });
74
+ })),
75
+ [e]
76
+ ), isPending: t, error: s, data: a, clearError: () => i(null) };
77
+ }
78
+ function G(e, t) {
79
+ const r = e.seo.openGraph ?? {}, s = e.seo.twitter ?? {};
80
+ return {
81
+ metadataBase: t,
82
+ title: {
83
+ template: e.seo.titleTemplate,
84
+ default: e.seo.defaultTitle
85
+ },
86
+ description: e.seo.description,
87
+ openGraph: {
88
+ title: r.title ?? e.seo.defaultTitle,
89
+ description: r.description ?? e.seo.description,
90
+ url: e.siteUrl,
91
+ siteName: e.siteName,
92
+ images: r.image ? [
93
+ {
94
+ url: r.image,
95
+ width: 1200,
96
+ height: 630,
97
+ alt: r.imageAlt ?? e.siteName
98
+ }
99
+ ] : void 0,
100
+ locale: r.locale ?? e.locale ?? "en_US",
101
+ type: "website"
102
+ },
103
+ twitter: {
104
+ card: "summary_large_image",
105
+ title: s.title ?? e.seo.defaultTitle,
106
+ description: s.description ?? e.seo.description,
107
+ images: s.image ? [s.image] : r.image ? [r.image] : void 0
108
+ },
109
+ icons: e.icons,
110
+ alternates: {
111
+ canonical: e.siteUrl
112
+ }
113
+ };
114
+ }
115
+ class O extends N {
116
+ constructor() {
117
+ super(...arguments);
118
+ p(this, "state", { error: null });
119
+ }
120
+ static getDerivedStateFromError(r) {
121
+ return { error: r };
122
+ }
123
+ render() {
124
+ const { error: r } = this.state;
125
+ if (r) {
126
+ const { fallback: s } = this.props;
127
+ return typeof s == "function" ? s(r) : s || /* @__PURE__ */ f("div", { role: "alert", className: "p-4 text-sm text-red-700", children: r.message });
128
+ }
129
+ return this.props.children;
130
+ }
131
+ }
132
+ export {
133
+ K as MedusaSiteProvider,
134
+ O as StorefrontErrorBoundary,
135
+ G as buildSiteMetadata,
136
+ M as err,
137
+ k as fromCaught,
138
+ B as getErrorMessage,
139
+ L as ok,
140
+ P as parseMedusaStoreError,
141
+ I as useMedusaSite,
142
+ j as useSiteCompany,
143
+ F as useStorefrontAction
144
+ };
@@ -0,0 +1 @@
1
+ (function(r,o){typeof exports=="object"&&typeof module<"u"?o(exports,require("medusa-services"),require("react/jsx-runtime"),require("react")):typeof define=="function"&&define.amd?define(["exports","medusa-services","react/jsx-runtime","react"],o):(r=typeof globalThis<"u"?globalThis:r||self,o(r.MedusaStorefrontCore={},r.MedusaServices,r.jsxRuntime,r.React))})(this,function(r,o,d,i){"use strict";var A=Object.defineProperty;var P=(r,o,d)=>o in r?A(r,o,{enumerable:!0,configurable:!0,writable:!0,value:d}):r[o]=d;var g=(r,o,d)=>P(r,typeof o!="symbol"?o+"":o,d);function h(e){return{ok:!0,data:e}}function S(e,t="UNKNOWN"){return{ok:!1,code:t,message:e}}function y(e,t="Something went wrong"){const n=e instanceof Error?e.message:t;return S(n)}async function M(e){return o.parseStoreErrorMessage(e)}function C(e,t="Something went wrong"){return e instanceof Error?e.message:typeof e=="string"?e:t}const m={name:"Store",brandName:"Store",customerLabel:"Customer"},l=i.createContext({company:m});function U({children:e,value:t,countryCode:n,regionId:s,company:c}){const f=i.useMemo(()=>({countryCode:(t==null?void 0:t.countryCode)??n,regionId:(t==null?void 0:t.regionId)??s,publishableKey:(t==null?void 0:t.publishableKey)??process.env.NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY,backendUrl:(t==null?void 0:t.backendUrl)??process.env.NEXT_PUBLIC_MEDUSA_BACKEND_URL??process.env.MEDUSA_BACKEND_URL,company:(t==null?void 0:t.company)??c??m}),[t,n,s,c]);return d.jsx(l.Provider,{value:f,children:e})}function b(){return i.useContext(l)}function _(){return i.useContext(l).company??m}function N(e){const[t,n]=i.useTransition(),[s,c]=i.useState(null),[f,E]=i.useState(null);return{run:i.useCallback((...w)=>(c(null),new Promise(p=>{n(()=>{(async()=>{try{const a=await e(...w);if(a&&typeof a=="object"&&"ok"in a){const u=a;u.ok?E(u.data):c(u.message),p(u)}else E(a),p({ok:!0,data:a})}catch(a){const u=y(a);u.ok||c(u.message),p(u)}})()})})),[e]),isPending:t,error:s,data:f,clearError:()=>c(null)}}function k(e,t){const n=e.seo.openGraph??{},s=e.seo.twitter??{};return{metadataBase:t,title:{template:e.seo.titleTemplate,default:e.seo.defaultTitle},description:e.seo.description,openGraph:{title:n.title??e.seo.defaultTitle,description:n.description??e.seo.description,url:e.siteUrl,siteName:e.siteName,images:n.image?[{url:n.image,width:1200,height:630,alt:n.imageAlt??e.siteName}]:void 0,locale:n.locale??e.locale??"en_US",type:"website"},twitter:{card:"summary_large_image",title:s.title??e.seo.defaultTitle,description:s.description??e.seo.description,images:s.image?[s.image]:n.image?[n.image]:void 0},icons:e.icons,alternates:{canonical:e.siteUrl}}}class T extends i.Component{constructor(){super(...arguments);g(this,"state",{error:null})}static getDerivedStateFromError(n){return{error:n}}render(){const{error:n}=this.state;if(n){const{fallback:s}=this.props;return typeof s=="function"?s(n):s||d.jsx("div",{role:"alert",className:"p-4 text-sm text-red-700",children:n.message})}return this.props.children}}r.MedusaSiteProvider=U,r.StorefrontErrorBoundary=T,r.buildSiteMetadata=k,r.err=S,r.fromCaught=y,r.getErrorMessage=C,r.ok=h,r.parseMedusaStoreError=M,r.useMedusaSite=b,r.useSiteCompany=_,r.useStorefrontAction=N,Object.defineProperty(r,Symbol.toStringTag,{value:"Module"})});
@@ -0,0 +1,9 @@
1
+ import { StorefrontResult } from './types';
2
+
3
+ export declare function useStorefrontAction<TArgs extends unknown[], TData>(action: (...args: TArgs) => Promise<StorefrontResult<TData> | TData>): {
4
+ run: (...args: TArgs) => Promise<StorefrontResult<TData>>;
5
+ isPending: boolean;
6
+ error: string | null;
7
+ data: TData | null;
8
+ clearError: () => void;
9
+ };
package/package.json ADDED
@@ -0,0 +1,60 @@
1
+ {
2
+ "name": "medusa-storefront-core",
3
+ "version": "1.1.0",
4
+ "description": "Core types, providers, and error handling for Medusa storefronts.",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "publishConfig": {
8
+ "access": "public"
9
+ },
10
+ "sideEffects": false,
11
+ "exports": {
12
+ ".": {
13
+ "types": "./dist/index.d.ts",
14
+ "import": "./dist/ui-library.js",
15
+ "require": "./dist/ui-library.umd.cjs",
16
+ "default": "./dist/ui-library.js"
17
+ },
18
+ "./edge": {
19
+ "types": "./src/edge.ts",
20
+ "import": "./src/edge.ts",
21
+ "default": "./src/edge.ts"
22
+ },
23
+ "./site-config": {
24
+ "types": "./src/site-config.ts",
25
+ "import": "./src/site-config.ts",
26
+ "default": "./src/site-config.ts"
27
+ }
28
+ },
29
+ "files": [
30
+ "dist",
31
+ "src/edge.ts",
32
+ "src/site-config.ts"
33
+ ],
34
+ "scripts": {
35
+ "build": "tsc && vite build",
36
+ "clean": "rm -rf dist"
37
+ },
38
+ "peerDependencies": {
39
+ "react": "^18.0.0 || ^19.0.0",
40
+ "react-dom": "^18.0.0 || ^19.0.0",
41
+ "next": ">=14.0.0",
42
+ "medusa-services": "^1.1.0"
43
+ },
44
+ "peerDependenciesMeta": {
45
+ "next": {
46
+ "optional": true
47
+ }
48
+ },
49
+ "devDependencies": {
50
+ "@types/react": "^19.0.0",
51
+ "@types/react-dom": "^19.0.0",
52
+ "@vitejs/plugin-react": "^4.0.0",
53
+ "medusa-services": "workspace:*",
54
+ "react": "^19.0.0",
55
+ "react-dom": "^19.0.0",
56
+ "typescript": "^5.6.0",
57
+ "vite": "^5.0.0",
58
+ "vite-plugin-dts": "^3.0.0"
59
+ }
60
+ }
package/src/edge.ts ADDED
@@ -0,0 +1,2 @@
1
+ export { medusaListRegions, medusaMergeCarts } from "medusa-services";
2
+ export type { MedusaMiddlewareClientOptions } from "medusa-services";
@@ -0,0 +1,97 @@
1
+ import type { Metadata } from "next"
2
+
3
+ /** Company / brand details passed from each storefront — never hardcode in libraries. */
4
+ export type StorefrontCompanyConfig = {
5
+ name: string
6
+ brandName?: string
7
+ customerLabel?: string
8
+ contactEmail?: string
9
+ phone?: string
10
+ description?: string
11
+ helpTagline?: string
12
+ mapTitle?: string
13
+ whyChooseUsTitle?: string
14
+ termsSubtitle?: string
15
+ privacySubtitle?: string
16
+ }
17
+
18
+ /** Site-specific values passed from each storefront project. */
19
+ export type StorefrontSiteConfig = {
20
+ siteName: string
21
+ siteUrl: string
22
+ company?: StorefrontCompanyConfig
23
+ gtmId?: string
24
+ locale?: string
25
+ htmlLang?: string
26
+ icons?: {
27
+ icon?: string
28
+ apple?: string
29
+ }
30
+ seo: {
31
+ titleTemplate: string
32
+ defaultTitle: string
33
+ description: string
34
+ openGraph?: {
35
+ title?: string
36
+ description?: string
37
+ image?: string
38
+ imageAlt?: string
39
+ locale?: string
40
+ }
41
+ twitter?: {
42
+ title?: string
43
+ description?: string
44
+ image?: string
45
+ }
46
+ }
47
+ features?: {
48
+ cookieConsent?: boolean
49
+ metaPixelGuard?: boolean
50
+ gtm?: boolean
51
+ }
52
+ }
53
+
54
+ export function buildSiteMetadata(
55
+ config: StorefrontSiteConfig,
56
+ metadataBase: URL
57
+ ): Metadata {
58
+ const og = config.seo.openGraph ?? {}
59
+ const tw = config.seo.twitter ?? {}
60
+
61
+ return {
62
+ metadataBase,
63
+ title: {
64
+ template: config.seo.titleTemplate,
65
+ default: config.seo.defaultTitle,
66
+ },
67
+ description: config.seo.description,
68
+ openGraph: {
69
+ title: og.title ?? config.seo.defaultTitle,
70
+ description: og.description ?? config.seo.description,
71
+ url: config.siteUrl,
72
+ siteName: config.siteName,
73
+ images: og.image
74
+ ? [
75
+ {
76
+ url: og.image,
77
+ width: 1200,
78
+ height: 630,
79
+ alt: og.imageAlt ?? config.siteName,
80
+ },
81
+ ]
82
+ : undefined,
83
+ locale: og.locale ?? config.locale ?? "en_US",
84
+ type: "website",
85
+ },
86
+ twitter: {
87
+ card: "summary_large_image",
88
+ title: tw.title ?? config.seo.defaultTitle,
89
+ description: tw.description ?? config.seo.description,
90
+ images: tw.image ? [tw.image] : og.image ? [og.image] : undefined,
91
+ },
92
+ icons: config.icons,
93
+ alternates: {
94
+ canonical: config.siteUrl,
95
+ },
96
+ }
97
+ }