@forgecart/cli 2.1.1 → 2.202606151453.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/package.json +3 -2
- package/templates/storefront/README.md +1 -1
- package/templates/storefront/next.config.js +19 -0
- package/templates/storefront/package.json +2 -1
- package/templates/storefront/src/app/layout.tsx +2 -0
- package/templates/storefront/src/components/ForgecartDesigner.tsx +43 -0
- package/templates/storefront/src/lib/forgecart.ts +15 -4
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@forgecart/cli",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.202606151453.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "CLI for scaffolding and operating ForgeCart channel storefronts",
|
|
6
6
|
"bin": {
|
|
@@ -26,7 +26,8 @@
|
|
|
26
26
|
"node": ">=18.0.0"
|
|
27
27
|
},
|
|
28
28
|
"publishConfig": {
|
|
29
|
-
"access": "public"
|
|
29
|
+
"access": "public",
|
|
30
|
+
"registry": "https://registry.npmjs.org"
|
|
30
31
|
},
|
|
31
32
|
"keywords": [
|
|
32
33
|
"forgecart",
|
|
@@ -4,6 +4,25 @@ const nextConfig = {
|
|
|
4
4
|
// storefront with `next start` without a full node_modules tree.
|
|
5
5
|
output: 'standalone',
|
|
6
6
|
reactStrictMode: true,
|
|
7
|
+
// Dev-only `data-fc-source` stamping for the ForgeCart visual editor. The
|
|
8
|
+
// loader marks host JSX elements with their source file:line:col so the
|
|
9
|
+
// dashboard can map a sprayed region back to code. It runs under Turbopack
|
|
10
|
+
// before SWC — with no `as` field, Turbopack chains loader -> built-in SWC,
|
|
11
|
+
// so the stamped TSX is still compiled normally.
|
|
12
|
+
//
|
|
13
|
+
// GLOB GOTCHA (Next 15.5): Turbopack matches a rule key by FILENAME unless it
|
|
14
|
+
// contains `/` (then by full project-relative path), and it does NOT expand
|
|
15
|
+
// braces. The earlier `src/**/*.{tsx,jsx}` therefore matched nothing and the
|
|
16
|
+
// loader silently never ran (`data-fc-source` count: 0). Per-extension
|
|
17
|
+
// filename globs are what Turbopack honors. The loader self-gates on
|
|
18
|
+
// NODE_ENV === 'development', so `next build` (webpack, production) is
|
|
19
|
+
// untouched.
|
|
20
|
+
turbopack: {
|
|
21
|
+
rules: {
|
|
22
|
+
'*.tsx': { loaders: ['@forgecart/designer-runtime/turbo-loader'] },
|
|
23
|
+
'*.jsx': { loaders: ['@forgecart/designer-runtime/turbo-loader'] },
|
|
24
|
+
},
|
|
25
|
+
},
|
|
7
26
|
images: {
|
|
8
27
|
// The shop API serves product/asset previews from arbitrary hosts, so
|
|
9
28
|
// allow any remote image. Tighten this to your asset host in production.
|
|
@@ -3,11 +3,12 @@
|
|
|
3
3
|
"version": "0.1.0",
|
|
4
4
|
"private": true,
|
|
5
5
|
"scripts": {
|
|
6
|
-
"dev": "next dev",
|
|
6
|
+
"dev": "next dev --turbopack",
|
|
7
7
|
"build": "next build",
|
|
8
8
|
"start": "next start"
|
|
9
9
|
},
|
|
10
10
|
"dependencies": {
|
|
11
|
+
"@forgecart/designer-runtime": "^1.0.0",
|
|
11
12
|
"@forgecart/sdk": "^1.2.6",
|
|
12
13
|
"next": "^15.1.0",
|
|
13
14
|
"react": "^19.0.0",
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Metadata } from 'next';
|
|
2
2
|
import type { ReactNode } from 'react';
|
|
3
3
|
|
|
4
|
+
import { ForgecartDesigner } from '../components/ForgecartDesigner';
|
|
4
5
|
import { Header } from '../components/Header';
|
|
5
6
|
import { getCart } from '../lib/cart-actions';
|
|
6
7
|
import { CartProvider } from '../lib/cart-context';
|
|
@@ -26,6 +27,7 @@ export default async function RootLayout({ children }: { children: ReactNode })
|
|
|
26
27
|
</div>
|
|
27
28
|
</footer>
|
|
28
29
|
</CartProvider>
|
|
30
|
+
<ForgecartDesigner />
|
|
29
31
|
</body>
|
|
30
32
|
</html>
|
|
31
33
|
);
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useEffect } from 'react';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Mounts the ForgeCart visual-editor guest runtime. Renders nothing.
|
|
7
|
+
*
|
|
8
|
+
* The runtime stays dormant until activated: it registers a single `message`
|
|
9
|
+
* listener and posts a READY beacon, then waits for the dashboard host to
|
|
10
|
+
* drive a nonce-gated handshake over `postMessage` (the activation nonce
|
|
11
|
+
* arrives via the `#fcd=` URL fragment — there is no env switch). On a page
|
|
12
|
+
* that is not embedded in an iframe it never even loads.
|
|
13
|
+
*
|
|
14
|
+
* Production builds ship zero bytes of this: the literal `NODE_ENV` check is
|
|
15
|
+
* inlined by the bundler, so the effect body — including the dynamic import
|
|
16
|
+
* and its chunk — is dead-code-eliminated from `next build` output.
|
|
17
|
+
*/
|
|
18
|
+
export function ForgecartDesigner() {
|
|
19
|
+
useEffect(() => {
|
|
20
|
+
if (process.env.NODE_ENV !== 'development') {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
// Top-level pages have no designer host; skip loading the chunk entirely.
|
|
24
|
+
if (window.parent === window) {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
let cancelled = false;
|
|
28
|
+
let dispose: (() => void) | undefined;
|
|
29
|
+
const install = async () => {
|
|
30
|
+
const mod = await import('@forgecart/designer-runtime');
|
|
31
|
+
if (cancelled) {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
dispose = mod.installDesignerRuntime();
|
|
35
|
+
};
|
|
36
|
+
void install();
|
|
37
|
+
return () => {
|
|
38
|
+
cancelled = true;
|
|
39
|
+
dispose?.();
|
|
40
|
+
};
|
|
41
|
+
}, []);
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
@@ -176,12 +176,23 @@ export function getStartingPrice(product: Product): number | null {
|
|
|
176
176
|
}
|
|
177
177
|
|
|
178
178
|
/**
|
|
179
|
-
* Format a minor-unit price
|
|
180
|
-
*
|
|
179
|
+
* Format a minor-unit price as a currency string. Defaults to USD; pass a
|
|
180
|
+
* different ISO currency code as needed.
|
|
181
|
+
*
|
|
182
|
+
* ForgeCart prices are integers in the currency's smallest denomination, so
|
|
183
|
+
* the divisor depends on the currency's ISO-4217 exponent: 2500 is $25.00
|
|
184
|
+
* (two-decimal cents) but ¥2,500 (zero-decimal yen) and BHD 2.500
|
|
185
|
+
* (three-decimal fils). The exponent is derived from the same
|
|
186
|
+
* `Intl.NumberFormat` instance that renders the price — its
|
|
187
|
+
* `resolvedOptions().maximumFractionDigits` carries the CLDR fraction digits
|
|
188
|
+
* for the currency — so the divisor always agrees with the digits shown,
|
|
189
|
+
* with a defensive fallback of 2 should the formatter resolve none.
|
|
181
190
|
*/
|
|
182
191
|
export function formatPrice(minorUnits: number, currency = 'USD'): string {
|
|
183
|
-
|
|
192
|
+
const formatter = new Intl.NumberFormat('en-US', {
|
|
184
193
|
style: 'currency',
|
|
185
194
|
currency,
|
|
186
|
-
})
|
|
195
|
+
});
|
|
196
|
+
const exponent = formatter.resolvedOptions().maximumFractionDigits ?? 2;
|
|
197
|
+
return formatter.format(minorUnits / 10 ** exponent);
|
|
187
198
|
}
|