@kaena1/ecomm-remote-utils 1.0.0-f-EC-4239.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.
@@ -0,0 +1,71 @@
1
+ import { GetServerSideProps } from 'next';
2
+
3
+ declare interface ComponentManifest {
4
+ bundleUrl: string;
5
+ styleUrl?: string;
6
+ /** Rollup chunk files that the entry imports. Pre-declared so consumers can add
7
+ * modulepreload hints before the entry is evaluated, eliminating cascade fetches. */
8
+ chunkUrls?: string[];
9
+ skeletonSpec?: SkeletonSpec;
10
+ }
11
+
12
+ export declare const getRemoteComponentsData: ({ NEXT_PUBLIC_ENVIRONMENT, }: {
13
+ NEXT_PUBLIC_ENVIRONMENT: string;
14
+ }) => Promise<{
15
+ remoteManifest: RemoteManifest;
16
+ }>;
17
+
18
+ export declare const ImportMapScripts: ({ mmUiComponentsExports, }?: ImportMapScriptsProps) => JSX.Element;
19
+
20
+ declare interface ImportMapScriptsProps {
21
+ /**
22
+ * Names of the exports to bridge from window.mmUiComponents into the
23
+ * '@kaena1/mm-ui-components' import map specifier.
24
+ * Must match what remote components import from that package.
25
+ *
26
+ * These are plain strings — safe to pass from a Server Component.
27
+ * Pass the actual module object to `<RemoteComponentsProvider>` instead.
28
+ *
29
+ * @example
30
+ * <ImportMapScripts mmUiComponentsExports={['ThemeProvider', 'ConfigProvider', 'Text', 'Link']} />
31
+ */
32
+ mmUiComponentsExports?: string[];
33
+ }
34
+
35
+ declare type RemoteComponentsEnvVars = {
36
+ NEXT_PUBLIC_SITE_URL: string;
37
+ NEXT_PUBLIC_ENVIRONMENT: string;
38
+ ECOMM_API_URL: string;
39
+ ECOMM_API_STANDALONE_DEVICE_CREDS: string;
40
+ };
41
+
42
+ export declare const RemoteLinks: ({ manifest }: RemoteLinksProps) => JSX.Element;
43
+
44
+ declare interface RemoteLinksProps {
45
+ manifest: ComponentManifest;
46
+ }
47
+
48
+ declare interface RemoteManifest {
49
+ components: Record<string, ComponentManifest>;
50
+ version: string;
51
+ generatedAt: string;
52
+ }
53
+
54
+ declare interface SkeletonSpec {
55
+ shimmerStyle: string;
56
+ componentStyle: string;
57
+ containerClass: string;
58
+ minHeight: string;
59
+ barWidth: string;
60
+ barHeight: number;
61
+ }
62
+
63
+ /**
64
+ * HOF that composes a getServerSideProps function for fetching remote components data (manifest and component props) with an optional getServerSideProps function from the page.
65
+ * @param envVars All environment variables needed
66
+ * @param pageGSSP An optional getServerSideProps function from the page that will be composed with the remote components data fetching. If not provided, only remote components data will be fetched and returned as props.
67
+ * @returns A new getServerSideProps function.
68
+ */
69
+ export declare function withRemoteComponentsGSSP(envVars: RemoteComponentsEnvVars, pageGSSP?: GetServerSideProps): GetServerSideProps;
70
+
71
+ export { }
package/dist/server.js ADDED
@@ -0,0 +1,10 @@
1
+ import { ImportMapScripts as e } from "./components/ImportMapScripts.js";
2
+ import { RemoteLinks as r } from "./components/RemoteLinks.js";
3
+ import { withRemoteComponentsGSSP as n } from "./lib/utils/withRemoteComponentsGSSP.js";
4
+ import { getRemoteComponentsData as s } from "./lib/utils/getRemoteComponentsData.js";
5
+ export {
6
+ e as ImportMapScripts,
7
+ r as RemoteLinks,
8
+ s as getRemoteComponentsData,
9
+ n as withRemoteComponentsGSSP
10
+ };
@@ -0,0 +1,49 @@
1
+ const a = () => `data:text/javascript;charset=utf-8,
2
+ const React = window.React;
3
+ export default React;
4
+ export const {
5
+ Children, Component, PureComponent, createContext, useContext, useState, useEffect,
6
+ useCallback, useMemo, useReducer, useRef, useImperativeHandle, forwardRef, createElement,
7
+ createRef, Fragment, memo, lazy, Suspense, useLayoutEffect, useInsertionEffect, useId,
8
+ isValidElement, cloneElement
9
+ } = React;`, n = () => `data:text/javascript;charset=utf-8,
10
+ const ReactDOM = window.ReactDOM;
11
+ export default ReactDOM;
12
+ export const { createPortal, flushSync, findDOMNode, unmountComponentAtNode } = ReactDOM;`, c = () => `data:text/javascript;charset=utf-8,
13
+ const ReactDOM = window.ReactDOM;
14
+ export const { createRoot, hydrateRoot } = ReactDOM;`, o = () => `data:text/javascript;charset=utf-8,
15
+ const React = window.React;
16
+ export const Fragment = React.Fragment;
17
+ export function jsx(type, props, key) {
18
+ const { children, ...restProps } = props || {};
19
+ return React.createElement(type, key !== undefined ? { ...restProps, key } : restProps, children);
20
+ }
21
+ export function jsxs(type, props, key) {
22
+ const { children, ...restProps } = props || {};
23
+ return React.createElement(type, key !== undefined ? { ...restProps, key } : restProps, ...(Array.isArray(children) ? children : [children]));
24
+ }`, s = "@kaena1/mm-ui-components", u = "mmUiComponents", i = (t) => `data:text/javascript;charset=utf-8,const m = window.${u};export default m;export const { ${t.join(", ")} } = m;`, d = (t = {}, e) => {
25
+ const r = o();
26
+ return {
27
+ imports: {
28
+ react: a(),
29
+ "react/jsx-runtime": r,
30
+ "react/jsx-dev-runtime": r,
31
+ // Some bundlers emit ".js" suffixed bare specifiers; map those too
32
+ "react/jsx-runtime.js": r,
33
+ "react/jsx-dev-runtime.js": r,
34
+ // Use window.ReactDOM (set by the host app) to avoid a CDN fetch on
35
+ // first load, which was causing intermittent timeout errors.
36
+ "react-dom": n(),
37
+ "react-dom/client": c(),
38
+ ...(e == null ? void 0 : e.length) && {
39
+ [s]: i(
40
+ e
41
+ )
42
+ }
43
+ }
44
+ };
45
+ }, p = (t, e) => JSON.stringify(d(t, e));
46
+ export {
47
+ d as generateImportMap,
48
+ p as generateImportMapJson
49
+ };
@@ -0,0 +1,26 @@
1
+ async function n(e) {
2
+ try {
3
+ const o = await fetch(e, {
4
+ headers: {
5
+ "Content-Type": "application/json"
6
+ }
7
+ });
8
+ if (!o.ok)
9
+ throw new Error(
10
+ `Failed to fetch manifest: ${o.status} ${o.statusText}`
11
+ );
12
+ const t = await o.json();
13
+ if (!t || typeof t != "object" || !t.components || typeof t.components != "object")
14
+ throw new Error("Invalid manifest: missing 'components' object");
15
+ return t;
16
+ } catch (o) {
17
+ throw o instanceof Error ? new Error(
18
+ `Manifest loading failed from ${e}: ${o.message}`
19
+ ) : new Error(
20
+ `Manifest loading failed from ${e}: Unknown error`
21
+ );
22
+ }
23
+ }
24
+ export {
25
+ n as fetchManifest
26
+ };
@@ -0,0 +1,139 @@
1
+ var l = Object.defineProperty;
2
+ var u = (r, e, t) => e in r ? l(r, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : r[e] = t;
3
+ var d = (r, e, t) => u(r, typeof e != "symbol" ? e + "" : e, t);
4
+ import p from "react";
5
+ import m from "react-dom";
6
+ import { getModulePreloadKey as w } from "../lib/utils/getModulePreloadKey.js";
7
+ typeof window < "u" && (window.React || (window.React = p), window.ReactDOM || (window.ReactDOM = m));
8
+ class h {
9
+ constructor() {
10
+ d(this, "loadedModules", /* @__PURE__ */ new Map());
11
+ d(this, "importMapInjected", !1);
12
+ d(this, "mmUiComponents");
13
+ }
14
+ /**
15
+ * Register the mm-ui-components module to expose on `window` before any
16
+ * remote component is loaded. Call this once at app startup, before the
17
+ * first render. Must match the `mmUiComponents` prop passed to `ImportMapScripts`.
18
+ */
19
+ configure(e) {
20
+ this.mmUiComponents = e;
21
+ }
22
+ prepareGlobalDependencies() {
23
+ window.React || (window.React = p), window.ReactDOM || (window.ReactDOM = m), this.mmUiComponents && !window.mmUiComponents && (window.mmUiComponents = this.mmUiComponents);
24
+ }
25
+ /**
26
+ * Ensure import map is injected before loading any modules
27
+ * Import maps MUST be added before any module scripts
28
+ */
29
+ ensureImportMap() {
30
+ if (typeof window > "u" || this.importMapInjected) return;
31
+ if (document.querySelector(
32
+ 'script[type="importmap"], script[type="importmap-shim"]'
33
+ )) {
34
+ this.importMapInjected = !0;
35
+ return;
36
+ }
37
+ console.warn(
38
+ `Import map not found. Ensure an import map is included early in:
39
+
40
+ - pages router: the document head (e.g. in pages/_document.tsx).
41
+
42
+ - app router: the root layout head (e.g. in app/layout.tsx).`
43
+ ), this.importMapInjected = !0;
44
+ }
45
+ /**
46
+ * Load remote React component from ES module URL
47
+ *
48
+ * @param options - Configuration object with bundleUrl and componentName
49
+ * @returns Promise that resolves to the loaded React component
50
+ * @throws Error if component loading fails or times out (10s)
51
+ */
52
+ async loadComponent(e) {
53
+ const { bundleUrl: t, componentName: i } = e;
54
+ if (this.loadedModules.has(t)) {
55
+ const o = this.loadedModules.get(t), n = (o == null ? void 0 : o[i]) || (o == null ? void 0 : o.default);
56
+ if (n) return n;
57
+ }
58
+ this.prepareGlobalDependencies(), this.ensureImportMap();
59
+ try {
60
+ const o = await this.loadModuleViaScript(t), n = o[i] || o.default;
61
+ if (!n)
62
+ throw new Error(`Component ${i} not found in module`);
63
+ return this.loadedModules.set(t, o), n;
64
+ } catch (o) {
65
+ throw console.error("Failed to load component:", o), o;
66
+ }
67
+ }
68
+ /**
69
+ * Load ES module from external URL using dynamic script injection
70
+ * This bypasses Webpack's module resolution and works with import maps
71
+ */
72
+ loadModuleViaScript(e) {
73
+ return new Promise((t, i) => {
74
+ const o = w(e);
75
+ if (window[o]) {
76
+ t(window[o]);
77
+ return;
78
+ }
79
+ const n = document.createElement("script"), a = () => {
80
+ try {
81
+ delete window[o];
82
+ } catch {
83
+ }
84
+ n.parentNode && document.head.removeChild(n);
85
+ };
86
+ Object.defineProperty(window, o, {
87
+ set(s) {
88
+ a(), t(s);
89
+ },
90
+ configurable: !0
91
+ });
92
+ const c = `
93
+ import * as loadedModule from '${e}';
94
+ window['${o}'] = loadedModule;
95
+ `;
96
+ n.type = "module-shim", n.textContent = c, n.onerror = (s) => {
97
+ a(), i(new Error(`Failed to load module from ${e}`));
98
+ }, document.head.appendChild(n);
99
+ });
100
+ }
101
+ /**
102
+ * Preload a module without extracting components
103
+ * Useful for warming up cache
104
+ *
105
+ * @param bundleUrl - URL of the module to preload
106
+ */
107
+ async preloadModule(e) {
108
+ if (!this.loadedModules.has(e)) {
109
+ this.ensureImportMap();
110
+ try {
111
+ const t = await this.loadModuleViaScript(e);
112
+ this.loadedModules.set(e, t);
113
+ } catch (t) {
114
+ console.error(`Failed to preload module ${e}:`, t);
115
+ }
116
+ }
117
+ }
118
+ /**
119
+ * Check if a module has already been loaded
120
+ *
121
+ * @param bundleUrl - URL of the module to check
122
+ * @returns true if module is already loaded, false otherwise
123
+ */
124
+ isLoaded(e) {
125
+ return this.loadedModules.has(e);
126
+ }
127
+ /**
128
+ * Clear all loaded modules from cache
129
+ * Useful for development/testing
130
+ */
131
+ clearCache() {
132
+ this.loadedModules.clear();
133
+ }
134
+ }
135
+ const g = new h();
136
+ export {
137
+ h as ModuleLoader,
138
+ g as moduleLoader
139
+ };
@@ -0,0 +1,7 @@
1
+ const o = ["develop", "development", "staging", "qa1"], t = ["production"], N = [...o, ...t];
2
+ function e(n) {
3
+ return !!n && N.includes(n);
4
+ }
5
+ export {
6
+ e as isEnvironment
7
+ };
@@ -0,0 +1,68 @@
1
+ export declare interface ComponentManifest {
2
+ bundleUrl: string;
3
+ styleUrl?: string;
4
+ /** Rollup chunk files that the entry imports. Pre-declared so consumers can add
5
+ * modulepreload hints before the entry is evaluated, eliminating cascade fetches. */
6
+ chunkUrls?: string[];
7
+ skeletonSpec?: SkeletonSpec;
8
+ }
9
+
10
+ export declare type Environment = (typeof ENVIRONMENTS)[number];
11
+
12
+ declare const ENVIRONMENTS: readonly ["develop", "development", "staging", "qa1", "production"];
13
+
14
+ export declare interface ImportMapConfig {
15
+ reactVersion?: string;
16
+ reactDomVersion?: string;
17
+ }
18
+
19
+ export declare interface ModuleLoadOptions {
20
+ bundleUrl: string;
21
+ componentName: string;
22
+ }
23
+
24
+ export declare type RemoteComponentsEnvVars = {
25
+ NEXT_PUBLIC_SITE_URL: string;
26
+ NEXT_PUBLIC_ENVIRONMENT: string;
27
+ ECOMM_API_URL: string;
28
+ ECOMM_API_STANDALONE_DEVICE_CREDS: string;
29
+ };
30
+
31
+ export declare interface RemoteComponentState {
32
+ component: RemoteComponentType | null;
33
+ manifest: ComponentManifest | null;
34
+ loading: boolean;
35
+ error: string | null;
36
+ loaded: boolean;
37
+ }
38
+
39
+ export declare type RemoteComponentType = React.ComponentType<any>;
40
+
41
+ export declare interface RemoteManifest {
42
+ components: Record<string, ComponentManifest>;
43
+ version: string;
44
+ generatedAt: string;
45
+ }
46
+
47
+ declare interface SkeletonSpec {
48
+ shimmerStyle: string;
49
+ componentStyle: string;
50
+ containerClass: string;
51
+ minHeight: string;
52
+ barWidth: string;
53
+ barHeight: number;
54
+ }
55
+
56
+ export declare interface UseRemoteComponentOptions {
57
+ manifest: ComponentManifest;
58
+ componentName: string;
59
+ autoLoad?: boolean;
60
+ }
61
+
62
+ export declare interface UseRemoteComponentReturn extends RemoteComponentState {
63
+ loadComponent: () => Promise<void>;
64
+ reload: () => Promise<void>;
65
+ clearError: () => void;
66
+ }
67
+
68
+ export { }
package/dist/types.js ADDED
@@ -0,0 +1 @@
1
+
package/package.json ADDED
@@ -0,0 +1,81 @@
1
+ {
2
+ "name": "@kaena1/ecomm-remote-utils",
3
+ "version": "1.0.0-f-EC-4239.1",
4
+ "description": "Shared utilities for loading remote React components in Mint Mobile microfrontends",
5
+ "type": "module",
6
+ "exports": {
7
+ "./server": {
8
+ "types": "./dist/server.d.ts",
9
+ "import": "./dist/server.js"
10
+ },
11
+ "./client": {
12
+ "types": "./dist/client.d.ts",
13
+ "import": "./dist/client.js"
14
+ },
15
+ "./types": {
16
+ "types": "./dist/types.d.ts",
17
+ "import": "./dist/types.js"
18
+ },
19
+ "./styles.css": "./dist/styles.css",
20
+ "./dist/styles.css": "./dist/styles.css"
21
+ },
22
+ "files": [
23
+ "dist"
24
+ ],
25
+ "publishConfig": {
26
+ "access": "public"
27
+ },
28
+ "scripts": {
29
+ "dev": "vite build --watch",
30
+ "build": "vite build",
31
+ "build:debug": "vite build --debug",
32
+ "test": "echo \"Error: no test specified\" && exit 1",
33
+ "typecheck": "tsc --noEmit",
34
+ "lint": "eslint ./src",
35
+ "release": "semantic-release -e ./release.config.cjs"
36
+ },
37
+ "keywords": [
38
+ "mint",
39
+ "remote-components",
40
+ "microfrontends",
41
+ "ecomm-remote-utils"
42
+ ],
43
+ "author": "",
44
+ "license": "ISC",
45
+ "peerDependencies": {
46
+ "next": "^15.3.3 || ^16.1.6",
47
+ "react": "^18.3.1 || ^19.0.0",
48
+ "react-dom": "^18.3.1 || ^19.0.0"
49
+ },
50
+ "devDependencies": {
51
+ "@semantic-release/changelog": "^6.0.3",
52
+ "@semantic-release/commit-analyzer": "^13.0.0",
53
+ "@semantic-release/exec": "^6.0.3",
54
+ "@semantic-release/git": "^10.0.1",
55
+ "@semantic-release/npm": "^12.0.0",
56
+ "@semantic-release/release-notes-generator": "^14.0.0",
57
+ "@types/react": "^18.3.18",
58
+ "@types/react-dom": "^18.3.5",
59
+ "@typescript-eslint/eslint-plugin": "^8.53.0",
60
+ "@typescript-eslint/parser": "^8.53.0",
61
+ "conventional-changelog-conventionalcommits": "^8.0.0",
62
+ "eslint": "^9.39.2",
63
+ "next": "^15.5.9",
64
+ "react": "^18.3.1",
65
+ "react-dom": "^18.3.1",
66
+ "read-pkg-up": "^11.0.0",
67
+ "rollup-preserve-directives": "^1.1.3",
68
+ "semantic-release": "^24.2.9",
69
+ "semantic-release-slack-bot": "^4.0.2",
70
+ "typescript": "^5.0.0",
71
+ "vite": "^5.4.14",
72
+ "vite-plugin-dts": "^3.9.1",
73
+ "vite-plugin-externalize-deps": "^0.9.0"
74
+ },
75
+ "dependencies": {
76
+ "clsx": "^2.1.1",
77
+ "es-module-shims": "^2.8.0",
78
+ "just-debounce-it": "^3.2.0",
79
+ "just-throttle": "^4.2.0"
80
+ }
81
+ }