@sixtyninecommerce/create-storefront 0.2.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/README.md ADDED
@@ -0,0 +1,50 @@
1
+ # @sixtyninecommerce/create-storefront
2
+
3
+ Scaffolder for the [sixtynine-commerce storefront template](https://github.com/SIXTYNINE-digital/sixtynine-commerce-storefront-starter).
4
+
5
+ ## Usage
6
+
7
+ ```bash
8
+ npm create @sixtyninecommerce/storefront <project-dir> --store-code <code>
9
+ ```
10
+
11
+ Example:
12
+
13
+ ```bash
14
+ npm create @sixtyninecommerce/storefront my-shop --store-code my-channel
15
+ ```
16
+
17
+ The CLI:
18
+
19
+ 1. Validates the channel exists by calling `client.commerce.getBranding()`.
20
+ 2. Downloads the latest tagged release of the template from GitHub.
21
+ 3. Applies your channel's `BrandingInfo` to the scaffold:
22
+ - Writes `src/theme.config.ts` with the primary color and font identifiers.
23
+ - Drops `logo-light`, `logo-dark`, `favicon`, and `cover` assets into `public/`.
24
+ - Writes `.env.local` so `npm run dev` connects to the right channel.
25
+ - Substitutes `package.json` `name` and `description`.
26
+ 4. Picks the locale shape that matches the channel's `urlLocaleStrategy`.
27
+
28
+ ## Flags
29
+
30
+ | Flag | Default | Notes |
31
+ |---|---|---|
32
+ | `--store-code <code>` | (required) | Channel code from the dashboard |
33
+ | `--cdn-url <url>` | `https://cdn.sixtyninecommerce.com` | Channel CDN base URL |
34
+ | `--cms-url <url>` | SDK production default | Override for self-hosted/local CMS |
35
+ | `--vendure-url <url>` | SDK production default | Override for self-hosted/local Vendure |
36
+ | `--plugins-url <url>` | SDK production default | Override for self-hosted/local plugins service |
37
+ | `--site-url <url>` | `branding.storefront.url` or `http://localhost:6969` | Storefront URL for SEO meta |
38
+ | `--template-ref <ref>` | latest release tag | Tag, branch, or commit SHA |
39
+
40
+ ## Environment
41
+
42
+ - `GITHUB_TOKEN` — set when fetching from a private repo or to avoid GitHub rate limits.
43
+
44
+ ## After scaffolding
45
+
46
+ ```bash
47
+ cd <project-dir>
48
+ npm install
49
+ npm run dev
50
+ ```
package/dist/args.d.ts ADDED
@@ -0,0 +1,14 @@
1
+ export interface CliArgs {
2
+ projectDir?: string;
3
+ storeCode?: string;
4
+ cdnUrl?: string;
5
+ cmsUrl?: string;
6
+ vendureUrl?: string;
7
+ pluginsUrl?: string;
8
+ siteUrl?: string;
9
+ templateRef?: string;
10
+ noInstall: boolean;
11
+ help: boolean;
12
+ }
13
+ export declare function parseArgs(argv: string[]): CliArgs;
14
+ //# sourceMappingURL=args.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"args.d.ts","sourceRoot":"","sources":["../src/args.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,OAAO;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,OAAO,CAAC;IACnB,IAAI,EAAE,OAAO,CAAC;CACf;AAmBD,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CA0CjD"}
package/dist/args.js ADDED
@@ -0,0 +1,49 @@
1
+ const FLAGS = {
2
+ '--store-code': 'storeCode',
3
+ '--cdn-url': 'cdnUrl',
4
+ '--cms-url': 'cmsUrl',
5
+ '--vendure-url': 'vendureUrl',
6
+ '--plugins-url': 'pluginsUrl',
7
+ '--site-url': 'siteUrl',
8
+ '--template-ref': 'templateRef',
9
+ };
10
+ const BOOL_FLAGS = {
11
+ '--no-install': 'noInstall',
12
+ };
13
+ export function parseArgs(argv) {
14
+ const out = { help: false, noInstall: false };
15
+ for (let i = 0; i < argv.length; i++) {
16
+ const token = argv[i] ?? '';
17
+ if (token === '--help' || token === '-h') {
18
+ out.help = true;
19
+ continue;
20
+ }
21
+ if (token in BOOL_FLAGS) {
22
+ const key = BOOL_FLAGS[token];
23
+ out[key] = true;
24
+ continue;
25
+ }
26
+ const eqIndex = token.indexOf('=');
27
+ const flag = (eqIndex >= 0 ? token.slice(0, eqIndex) : token);
28
+ if (flag in FLAGS) {
29
+ const key = FLAGS[flag];
30
+ const value = eqIndex >= 0 ? token.slice(eqIndex + 1) : argv[++i];
31
+ if (value === undefined) {
32
+ throw new Error(`Missing value for ${flag}`);
33
+ }
34
+ out[key] = value;
35
+ continue;
36
+ }
37
+ if (token.startsWith('--')) {
38
+ throw new Error(`Unknown flag: ${token}`);
39
+ }
40
+ if (out.projectDir === undefined) {
41
+ out.projectDir = token;
42
+ }
43
+ else {
44
+ throw new Error(`Unexpected positional argument: ${token}`);
45
+ }
46
+ }
47
+ return out;
48
+ }
49
+ //# sourceMappingURL=args.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"args.js","sourceRoot":"","sources":["../src/args.ts"],"names":[],"mappings":"AAmBA,MAAM,KAAK,GAAG;IACZ,cAAc,EAAE,WAAW;IAC3B,WAAW,EAAE,QAAQ;IACrB,WAAW,EAAE,QAAQ;IACrB,eAAe,EAAE,YAAY;IAC7B,eAAe,EAAE,YAAY;IAC7B,YAAY,EAAE,SAAS;IACvB,gBAAgB,EAAE,aAAa;CACvB,CAAC;AAEX,MAAM,UAAU,GAAG;IACjB,cAAc,EAAE,WAAW;CACnB,CAAC;AAKX,MAAM,UAAU,SAAS,CAAC,IAAc;IACtC,MAAM,GAAG,GAAY,EAAE,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;IAEvD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,MAAM,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAE5B,IAAI,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;YACzC,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC;YAChB,SAAS;QACX,CAAC;QAED,IAAI,KAAK,IAAI,UAAU,EAAE,CAAC;YACxB,MAAM,GAAG,GAAG,UAAU,CAAC,KAAqB,CAAC,CAAC;YAC9C,GAAG,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC;YAChB,SAAS;QACX,CAAC;QAED,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACnC,MAAM,IAAI,GAAG,CAAC,OAAO,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAa,CAAC;QAE1E,IAAI,IAAI,IAAI,KAAK,EAAE,CAAC;YAClB,MAAM,GAAG,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC;YACxB,MAAM,KAAK,GAAG,OAAO,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;YAClE,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;gBACxB,MAAM,IAAI,KAAK,CAAC,qBAAqB,IAAI,EAAE,CAAC,CAAC;YAC/C,CAAC;YACD,GAAG,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;YACjB,SAAS;QACX,CAAC;QAED,IAAI,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;YAC3B,MAAM,IAAI,KAAK,CAAC,iBAAiB,KAAK,EAAE,CAAC,CAAC;QAC5C,CAAC;QAED,IAAI,GAAG,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;YACjC,GAAG,CAAC,UAAU,GAAG,KAAK,CAAC;QACzB,CAAC;aAAM,CAAC;YACN,MAAM,IAAI,KAAK,CAAC,mCAAmC,KAAK,EAAE,CAAC,CAAC;QAC9D,CAAC;IACH,CAAC;IAED,OAAO,GAAG,CAAC;AACb,CAAC"}
@@ -0,0 +1,14 @@
1
+ import type { BrandingInfo } from '@sixtyninecommerce/client';
2
+ export interface ApplyBrandingInput {
3
+ targetDir: string;
4
+ branding: BrandingInfo;
5
+ storeCode: string;
6
+ cdnUrl: string;
7
+ cmsUrl: string | null;
8
+ vendureUrl: string | null;
9
+ pluginsUrl: string | null;
10
+ siteUrl: string | null;
11
+ projectName: string;
12
+ }
13
+ export declare function applyBranding(input: ApplyBrandingInput): Promise<void>;
14
+ //# sourceMappingURL=branding.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"branding.d.ts","sourceRoot":"","sources":["../src/branding.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAoB,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAEhF,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,YAAY,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,wBAAsB,aAAa,CAAC,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAO5E"}
@@ -0,0 +1,139 @@
1
+ import { readFile, writeFile } from 'node:fs/promises';
2
+ import { extname, join } from 'node:path';
3
+ export async function applyBranding(input) {
4
+ const { targetDir, branding } = input;
5
+ await writeThemeConfig(targetDir, branding);
6
+ await downloadAssets(targetDir, branding);
7
+ await writeEnvLocal(targetDir, input);
8
+ await rewritePackageJson(targetDir, input);
9
+ }
10
+ async function writeThemeConfig(targetDir, branding) {
11
+ const primary = branding.theme.primaryColor ?? '#171717';
12
+ const fonts = branding.fonts.map((f) => f.identifier);
13
+ const lines = [
14
+ '/** Auto-generated by @sixtyninecommerce/create-storefront. Edit freely. */',
15
+ '',
16
+ 'export const theme = {',
17
+ ' colors: {',
18
+ ` primary: ${JSON.stringify(primary)},`,
19
+ ' },',
20
+ ' radius: "md" as const,',
21
+ ' fonts: {',
22
+ ` body: ${JSON.stringify(fonts[0] ?? 'sans')},`,
23
+ ` display: ${JSON.stringify(fonts[1] ?? fonts[0] ?? 'sans')},`,
24
+ ' },',
25
+ ' layout: {',
26
+ ' headerVariant: "classic" as const,',
27
+ ' footerVariant: "standard" as const,',
28
+ ' },',
29
+ ' logos: {',
30
+ ` light: ${JSON.stringify(localPathFor(branding.identity.logoLight, '/logo-light'))},`,
31
+ ` dark: ${JSON.stringify(localPathFor(branding.identity.logoDark, '/logo-dark'))},`,
32
+ ` favicon: ${JSON.stringify(localPathFor(branding.identity.favicon, '/favicon'))},`,
33
+ ` cover: ${JSON.stringify(localPathFor(branding.identity.cover, '/cover'))},`,
34
+ ' },',
35
+ '} as const;',
36
+ '',
37
+ 'export type Theme = typeof theme;',
38
+ '',
39
+ ];
40
+ await writeFile(join(targetDir, 'src/theme.config.ts'), lines.join('\n'));
41
+ }
42
+ function localPathFor(asset, fallbackBase) {
43
+ if (!asset)
44
+ return `${fallbackBase}.svg`;
45
+ const ext = extensionFor(asset);
46
+ return `${fallbackBase}${ext}`;
47
+ }
48
+ function extensionFor(asset) {
49
+ const fromMime = asset.mimeType ? mimeExtension(asset.mimeType) : null;
50
+ if (fromMime)
51
+ return fromMime;
52
+ const fromUrl = extname(asset.url.split('?')[0] ?? '');
53
+ return fromUrl || '.png';
54
+ }
55
+ function mimeExtension(mime) {
56
+ switch (mime) {
57
+ case 'image/svg+xml':
58
+ return '.svg';
59
+ case 'image/png':
60
+ return '.png';
61
+ case 'image/jpeg':
62
+ return '.jpg';
63
+ case 'image/webp':
64
+ return '.webp';
65
+ case 'image/x-icon':
66
+ case 'image/vnd.microsoft.icon':
67
+ return '.ico';
68
+ default:
69
+ return null;
70
+ }
71
+ }
72
+ async function downloadAssets(targetDir, branding) {
73
+ const downloads = [];
74
+ const id = branding.identity;
75
+ if (id.logoLight)
76
+ downloads.push(download(id.logoLight, join(targetDir, 'public', `logo-light${extensionFor(id.logoLight)}`)));
77
+ if (id.logoDark)
78
+ downloads.push(download(id.logoDark, join(targetDir, 'public', `logo-dark${extensionFor(id.logoDark)}`)));
79
+ if (id.favicon)
80
+ downloads.push(download(id.favicon, join(targetDir, 'public', `favicon${extensionFor(id.favicon)}`)));
81
+ if (id.cover)
82
+ downloads.push(download(id.cover, join(targetDir, 'public', `cover${extensionFor(id.cover)}`)));
83
+ await Promise.all(downloads);
84
+ }
85
+ async function download(asset, dest) {
86
+ const response = await fetch(asset.url, {
87
+ headers: { 'user-agent': '@sixtyninecommerce/create-storefront' },
88
+ });
89
+ if (!response.ok) {
90
+ throw new Error(`Failed to download ${asset.url}: ${response.status} ${response.statusText}`);
91
+ }
92
+ const buf = Buffer.from(await response.arrayBuffer());
93
+ await writeFile(dest, buf);
94
+ }
95
+ async function writeEnvLocal(targetDir, input) {
96
+ const siteUrl = input.siteUrl ?? input.branding.storefront.url ?? 'http://localhost:6969';
97
+ const lines = [
98
+ `NEXT_PUBLIC_STORE_CODE=${input.storeCode}`,
99
+ `NEXT_PUBLIC_CDN_URL=${input.cdnUrl}`,
100
+ `NEXT_PUBLIC_SITE_URL=${siteUrl}`,
101
+ '',
102
+ '# Dev-only: route platform services through the storefront origin so the',
103
+ '# browser sees same-origin requests (production CORS allowlist usually',
104
+ "# doesn't include localhost). next.config.ts rewrites these to the real",
105
+ '# hosts. Production builds talk to the real domains directly — replace',
106
+ '# these (or override via deploy env) when shipping.',
107
+ ];
108
+ if (input.cmsUrl) {
109
+ lines.push(`NEXT_PUBLIC_CMS_URL=${input.cmsUrl}`);
110
+ }
111
+ else {
112
+ lines.push('NEXT_PUBLIC_CMS_URL=http://localhost:6969/__cms');
113
+ }
114
+ if (input.vendureUrl) {
115
+ lines.push(`NEXT_PUBLIC_VENDURE_URL=${input.vendureUrl}`);
116
+ }
117
+ else {
118
+ lines.push('NEXT_PUBLIC_VENDURE_URL=http://localhost:6969/__vendure');
119
+ }
120
+ if (input.pluginsUrl) {
121
+ lines.push(`NEXT_PUBLIC_PLUGINS_URL=${input.pluginsUrl}`);
122
+ }
123
+ else {
124
+ lines.push('NEXT_PUBLIC_PLUGINS_URL=http://localhost:6969/__plugins');
125
+ }
126
+ lines.push('');
127
+ await writeFile(join(targetDir, '.env.local'), lines.join('\n'));
128
+ }
129
+ async function rewritePackageJson(targetDir, input) {
130
+ const path = join(targetDir, 'package.json');
131
+ const raw = await readFile(path, 'utf8');
132
+ const pkg = JSON.parse(raw);
133
+ pkg.name = input.projectName;
134
+ pkg.description =
135
+ input.branding.identity.businessDescription ??
136
+ `${input.branding.identity.businessName ?? input.storeCode} storefront`;
137
+ await writeFile(path, `${JSON.stringify(pkg, null, 2)}\n`);
138
+ }
139
+ //# sourceMappingURL=branding.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"branding.js","sourceRoot":"","sources":["../src/branding.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ export declare const CLAUDE_MD_BEGIN = "<!-- sixtynine-commerce:begin -->";
2
+ export declare const CLAUDE_MD_END = "<!-- sixtynine-commerce:end -->";
3
+ export interface HandoffInput {
4
+ targetDir: string;
5
+ storeCode: string;
6
+ cdnUrl: string;
7
+ cmsUrl: string | null;
8
+ vendureUrl: string | null;
9
+ pluginsUrl: string | null;
10
+ }
11
+ interface McpServerEntry {
12
+ command: string;
13
+ args: string[];
14
+ env: Record<string, string>;
15
+ }
16
+ export declare function buildCommerceServerEntry(input: HandoffInput): McpServerEntry;
17
+ export declare function mergeMcpJson(existingRaw: string | null, entry: McpServerEntry): string;
18
+ export declare function buildClaudeMdBlock(storeCode: string): string;
19
+ export declare function mergeClaudeMd(existing: string | null, block: string): string;
20
+ export declare function writeHandoff(input: HandoffInput): Promise<void>;
21
+ export {};
22
+ //# sourceMappingURL=handoff.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handoff.d.ts","sourceRoot":"","sources":["../src/handoff.ts"],"names":[],"mappings":"AAcA,eAAO,MAAM,eAAe,sCAAsC,CAAC;AACnE,eAAO,MAAM,aAAa,oCAAoC,CAAC;AAE/D,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,UAAU,cAAc;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC7B;AAED,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,YAAY,GAAG,cAAc,CAS5E;AAGD,wBAAgB,YAAY,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,EAAE,KAAK,EAAE,cAAc,GAAG,MAAM,CAiBtF;AAED,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAc5D;AAGD,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAa5E;AAED,wBAAsB,YAAY,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAUrE"}
@@ -0,0 +1,73 @@
1
+ import { readFile, writeFile } from 'node:fs/promises';
2
+ import { join } from 'node:path';
3
+ export const CLAUDE_MD_BEGIN = '<!-- sixtynine-commerce:begin -->';
4
+ export const CLAUDE_MD_END = '<!-- sixtynine-commerce:end -->';
5
+ export function buildCommerceServerEntry(input) {
6
+ const env = {
7
+ STORE_CODE: input.storeCode,
8
+ CDN_URL: input.cdnUrl,
9
+ };
10
+ if (input.vendureUrl)
11
+ env.VENDURE_URL = input.vendureUrl;
12
+ if (input.cmsUrl)
13
+ env.CMS_URL = input.cmsUrl;
14
+ if (input.pluginsUrl)
15
+ env.PLUGINS_URL = input.pluginsUrl;
16
+ return { command: 'npx', args: ['@sixtyninecommerce/mcp'], env };
17
+ }
18
+ export function mergeMcpJson(existingRaw, entry) {
19
+ let doc = {};
20
+ if (existingRaw && existingRaw.trim() !== '') {
21
+ const parsed = JSON.parse(existingRaw);
22
+ if (typeof parsed === 'object' && parsed !== null && !Array.isArray(parsed)) {
23
+ doc = parsed;
24
+ }
25
+ }
26
+ const existingServers = doc.mcpServers;
27
+ const servers = typeof existingServers === 'object' &&
28
+ existingServers !== null &&
29
+ !Array.isArray(existingServers)
30
+ ? { ...existingServers }
31
+ : {};
32
+ servers.commerce = entry;
33
+ return `${JSON.stringify({ ...doc, mcpServers: servers }, null, 2)}\n`;
34
+ }
35
+ export function buildClaudeMdBlock(storeCode) {
36
+ return `${CLAUDE_MD_BEGIN}
37
+ ## Commerce platform (sixtynine-commerce)
38
+
39
+ This storefront is powered by the sixtynine-commerce platform (store code: \`${storeCode}\`).
40
+
41
+ - Build against \`@sixtyninecommerce/client\` and the **commerce MCP server** (in \`.mcp.json\`).
42
+ - The canonical guidance is served by the MCP as resources — read them instead of guessing:
43
+ - \`storefront://claude-md\` — full storefront conventions (routing, images, cart/checkout, prices, auth).
44
+ - \`storefront://capability-catalog\` — capability → SDK method mapping.
45
+ - \`storefront://guide\` / \`storefront://api\` — integration + API reference.
46
+ - Call the \`get_integration_manifest\` MCP tool for live store config (channel id, languages, branding, asset URLs).
47
+ - To wire up or extend platform features, run the \`/commerce:integrate\` prompt.
48
+ ${CLAUDE_MD_END}`;
49
+ }
50
+ export function mergeClaudeMd(existing, block) {
51
+ if (!existing || existing.trim() === '') {
52
+ return `# CLAUDE.md\n\n${block}\n`;
53
+ }
54
+ const begin = existing.indexOf(CLAUDE_MD_BEGIN);
55
+ const end = existing.indexOf(CLAUDE_MD_END);
56
+ if (begin !== -1 && end !== -1 && end > begin) {
57
+ const before = existing.slice(0, begin);
58
+ const after = existing.slice(end + CLAUDE_MD_END.length);
59
+ return `${before}${block}${after}`;
60
+ }
61
+ const sep = existing.endsWith('\n') ? '\n' : '\n\n';
62
+ return `${existing}${sep}${block}\n`;
63
+ }
64
+ export async function writeHandoff(input) {
65
+ const entry = buildCommerceServerEntry(input);
66
+ const mcpPath = join(input.targetDir, '.mcp.json');
67
+ const existingMcp = await readFile(mcpPath, 'utf8').catch(() => null);
68
+ await writeFile(mcpPath, mergeMcpJson(existingMcp, entry));
69
+ const claudePath = join(input.targetDir, 'CLAUDE.md');
70
+ const existingClaude = await readFile(claudePath, 'utf8').catch(() => null);
71
+ await writeFile(claudePath, mergeClaudeMd(existingClaude, buildClaudeMdBlock(input.storeCode)));
72
+ }
73
+ //# sourceMappingURL=handoff.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handoff.js","sourceRoot":"","sources":["../src/handoff.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js ADDED
@@ -0,0 +1,109 @@
1
+ #!/usr/bin/env node
2
+ import { resolve } from 'node:path';
3
+ import { parseArgs } from './args.js';
4
+ import { applyBranding } from './branding.js';
5
+ import { writeHandoff } from './handoff.js';
6
+ import { runInstall } from './install.js';
7
+ import { resolveLocaleShape } from './locale-shape.js';
8
+ import { promptMissing } from './prompts.js';
9
+ import { fetchAndExtractTemplate } from './template.js';
10
+ import { fetchBranding } from './validate.js';
11
+ async function main() {
12
+ const args = parseArgs(process.argv.slice(2));
13
+ if (args.help) {
14
+ printHelp();
15
+ process.exit(0);
16
+ }
17
+ const filled = await promptMissing(args);
18
+ const targetDir = resolve(process.cwd(), filled.projectDir);
19
+ console.log(`\n→ Validating channel "${filled.storeCode}"…`);
20
+ const snapshot = await fetchBranding({
21
+ storeCode: filled.storeCode,
22
+ cdnUrl: filled.cdnUrl,
23
+ cmsUrl: filled.cmsUrl,
24
+ vendureUrl: filled.vendureUrl,
25
+ pluginsUrl: filled.pluginsUrl,
26
+ });
27
+ const { branding } = snapshot;
28
+ console.log(` ✓ ${branding.identity.businessName ?? filled.storeCode}`);
29
+ console.log(`\n→ Fetching template${filled.templateRef ? ` (${filled.templateRef})` : ''}…`);
30
+ await fetchAndExtractTemplate({
31
+ repo: 'SIXTYNINE-digital/sixtynine-commerce-storefront-starter',
32
+ ref: filled.templateRef,
33
+ targetDir,
34
+ });
35
+ console.log(` ✓ Extracted to ${targetDir}`);
36
+ console.log(`\n→ Applying branding…`);
37
+ await applyBranding({
38
+ targetDir,
39
+ branding,
40
+ storeCode: filled.storeCode,
41
+ cdnUrl: filled.cdnUrl,
42
+ cmsUrl: filled.cmsUrl,
43
+ vendureUrl: filled.vendureUrl,
44
+ pluginsUrl: filled.pluginsUrl,
45
+ siteUrl: filled.siteUrl,
46
+ projectName: filled.projectDir.split('/').pop() ?? filled.storeCode,
47
+ });
48
+ console.log(` ✓ theme.config.ts, .env.local, public/ assets`);
49
+ const strategy = branding.storefront.urlLocaleStrategy;
50
+ console.log(`\n→ Applying locale shape (${strategy})…`);
51
+ await resolveLocaleShape({
52
+ targetDir,
53
+ strategy,
54
+ defaultLanguage: branding.storefront.defaultLanguage,
55
+ availableLanguages: snapshot.availableLanguages,
56
+ prefixDefault: branding.storefront.urlLocalePrefixDefault,
57
+ });
58
+ console.log(` ✓ ${strategy === 'none'
59
+ ? 'No URL changes'
60
+ : strategy === 'subdomain'
61
+ ? 'Wired NEXT_PUBLIC_STORE_LANGUAGE'
62
+ : `Routes wrapped under [locale]/ (${snapshot.availableLanguages.join(', ')})`}`);
63
+ console.log(`\n→ Writing Claude Code handoff…`);
64
+ await writeHandoff({
65
+ targetDir,
66
+ storeCode: filled.storeCode,
67
+ cdnUrl: filled.cdnUrl,
68
+ cmsUrl: filled.cmsUrl,
69
+ vendureUrl: filled.vendureUrl,
70
+ pluginsUrl: filled.pluginsUrl,
71
+ });
72
+ console.log(` ✓ .mcp.json (commerce server) + CLAUDE.md pointer`);
73
+ if (filled.install) {
74
+ console.log(`\n→ Installing dependencies…`);
75
+ await runInstall(targetDir);
76
+ console.log(` ✓ npm install complete`);
77
+ }
78
+ console.log(`\nDone! Next steps:`);
79
+ console.log(` cd ${filled.projectDir}`);
80
+ if (!filled.install)
81
+ console.log(` npm install`);
82
+ console.log(` npm run dev`);
83
+ console.log(`\nThen open Claude Code — the commerce MCP loads from .mcp.json.`);
84
+ console.log(`Run /commerce:integrate to customize or wire up more platform features.\n`);
85
+ }
86
+ function printHelp() {
87
+ console.log(`
88
+ @sixtyninecommerce/create-storefront — scaffold a sixtynine-commerce storefront
89
+
90
+ Usage:
91
+ npm create @sixtyninecommerce/storefront <project-dir> [options]
92
+
93
+ Options:
94
+ --store-code <code> Channel store code (required)
95
+ --cdn-url <url> CDN base URL (default: https://cdn.sixtyninecommerce.com)
96
+ --cms-url <url> CMS service URL (default: SDK production default)
97
+ --vendure-url <url> Vendure service URL (default: SDK production default)
98
+ --plugins-url <url> Plugins service URL (default: SDK production default)
99
+ --site-url <url> Storefront URL (default: from channel.storefrontUrl)
100
+ --template-ref <ref> Template tag, branch, or commit (default: latest release)
101
+ --no-install Skip the npm install step
102
+ --help Show this help
103
+ `);
104
+ }
105
+ main().catch((err) => {
106
+ console.error(`\n✗ ${err instanceof Error ? err.message : err}`);
107
+ process.exit(1);
108
+ });
109
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function runInstall(targetDir: string): Promise<void>;
2
+ //# sourceMappingURL=install.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../src/install.ts"],"names":[],"mappings":"AASA,wBAAsB,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAejE"}
@@ -0,0 +1,19 @@
1
+ import { spawn } from 'node:child_process';
2
+ export async function runInstall(targetDir) {
3
+ await new Promise((resolve, reject) => {
4
+ const npm = process.platform === 'win32' ? 'npm.cmd' : 'npm';
5
+ const child = spawn(npm, ['install'], {
6
+ cwd: targetDir,
7
+ stdio: 'inherit',
8
+ env: process.env,
9
+ });
10
+ child.on('error', reject);
11
+ child.on('exit', (code) => {
12
+ if (code === 0)
13
+ resolve();
14
+ else
15
+ reject(new Error(`npm install exited with code ${code ?? 'null'}`));
16
+ });
17
+ });
18
+ }
19
+ //# sourceMappingURL=install.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install.js","sourceRoot":"","sources":["../src/install.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAE3C,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,SAAiB;IAChD,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QAC1C,MAAM,GAAG,GAAG,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC;QAC7D,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,EAAE;YACpC,GAAG,EAAE,SAAS;YACd,KAAK,EAAE,SAAS;YAChB,GAAG,EAAE,OAAO,CAAC,GAAG;SACjB,CAAC,CAAC;QAEH,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAC1B,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE;YACxB,IAAI,IAAI,KAAK,CAAC;gBAAE,OAAO,EAAE,CAAC;;gBACrB,MAAM,CAAC,IAAI,KAAK,CAAC,gCAAgC,IAAI,IAAI,MAAM,EAAE,CAAC,CAAC,CAAC;QAC3E,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,9 @@
1
+ export interface ResolveLocaleShapeInput {
2
+ targetDir: string;
3
+ strategy: 'none' | 'path-prefix' | 'subdomain';
4
+ defaultLanguage: string;
5
+ availableLanguages: string[];
6
+ prefixDefault?: boolean;
7
+ }
8
+ export declare function resolveLocaleShape(input: ResolveLocaleShapeInput): Promise<void>;
9
+ //# sourceMappingURL=locale-shape.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"locale-shape.d.ts","sourceRoot":"","sources":["../src/locale-shape.ts"],"names":[],"mappings":"AAcA,MAAM,WAAW,uBAAuB;IACtC,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,GAAG,aAAa,GAAG,WAAW,CAAC;IAC/C,eAAe,EAAE,MAAM,CAAC;IACxB,kBAAkB,EAAE,MAAM,EAAE,CAAC;IAO7B,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,wBAAsB,kBAAkB,CAAC,KAAK,EAAE,uBAAuB,GAAG,OAAO,CAAC,IAAI,CAAC,CAetF"}
@@ -0,0 +1,257 @@
1
+ import { mkdir, readdir, readFile, rename, rm, stat, writeFile } from 'node:fs/promises';
2
+ import { join } from 'node:path';
3
+ export async function resolveLocaleShape(input) {
4
+ const shapesDir = join(input.targetDir, 'src/app/_shapes');
5
+ if (await exists(shapesDir)) {
6
+ await rm(shapesDir, { recursive: true, force: true });
7
+ }
8
+ switch (input.strategy) {
9
+ case 'none':
10
+ return;
11
+ case 'subdomain':
12
+ return applySubdomainShape(input);
13
+ case 'path-prefix':
14
+ return applyPathPrefixShape(input);
15
+ }
16
+ }
17
+ function languagesRequiringPrefix(input) {
18
+ const prefixDefault = input.prefixDefault === true;
19
+ return input.availableLanguages.filter((lang) => {
20
+ if (lang === input.defaultLanguage)
21
+ return prefixDefault;
22
+ return true;
23
+ });
24
+ }
25
+ async function applySubdomainShape(input) {
26
+ await appendEnv(input.targetDir, `\n# Subdomain locale strategy: each language is a separate deploy. Set this\n# per-deploy to the language code that subdomain serves.\nNEXT_PUBLIC_STORE_LANGUAGE=${input.defaultLanguage}\n`);
27
+ await patchEnvLib(input.targetDir);
28
+ await patchClientLibForSetLanguage(input.targetDir);
29
+ }
30
+ const RESERVED_DIRS_TO_MOVE = [
31
+ '[...path]',
32
+ 'account',
33
+ 'cart',
34
+ 'checkout',
35
+ 'forgot-password',
36
+ 'register',
37
+ 'reset-password',
38
+ 'sign-in',
39
+ 'verify',
40
+ 'verify-pending',
41
+ ];
42
+ const ROOT_FILES_TO_MOVE = ['page.tsx'];
43
+ async function applyPathPrefixShape(input) {
44
+ const prefixed = languagesRequiringPrefix(input);
45
+ if (prefixed.length === 0) {
46
+ return;
47
+ }
48
+ const prefixDefault = input.prefixDefault === true;
49
+ if (prefixDefault) {
50
+ await moveRoutesUnderLocale(input.targetDir);
51
+ const appDir = join(input.targetDir, 'src/app');
52
+ await writeFile(join(appDir, 'page.tsx'), ROOT_REDIRECT_PAGE(input.defaultLanguage));
53
+ }
54
+ else {
55
+ await mirrorRoutesUnderLocale(input.targetDir, prefixed);
56
+ }
57
+ const appDir = join(input.targetDir, 'src/app');
58
+ const localeDir = join(appDir, '[locale]');
59
+ await writeFile(join(localeDir, 'layout.tsx'), LOCALE_LAYOUT(prefixed));
60
+ await rewriteLinkImports(input.targetDir);
61
+ }
62
+ async function moveRoutesUnderLocale(targetDir) {
63
+ const appDir = join(targetDir, 'src/app');
64
+ const localeDir = join(appDir, '[locale]');
65
+ await mkdir(localeDir, { recursive: true });
66
+ for (const name of RESERVED_DIRS_TO_MOVE) {
67
+ const src = join(appDir, name);
68
+ if (await exists(src)) {
69
+ await rename(src, join(localeDir, name));
70
+ }
71
+ }
72
+ for (const name of ROOT_FILES_TO_MOVE) {
73
+ const src = join(appDir, name);
74
+ if (await exists(src)) {
75
+ await rename(src, join(localeDir, name));
76
+ }
77
+ }
78
+ }
79
+ async function mirrorRoutesUnderLocale(targetDir, _prefixed) {
80
+ const appDir = join(targetDir, 'src/app');
81
+ const localeDir = join(appDir, '[locale]');
82
+ await mkdir(localeDir, { recursive: true });
83
+ for (const name of RESERVED_DIRS_TO_MOVE) {
84
+ const src = join(appDir, name);
85
+ if (!(await exists(src)))
86
+ continue;
87
+ await mirrorTree(src, join(localeDir, name));
88
+ }
89
+ for (const name of ROOT_FILES_TO_MOVE) {
90
+ const src = join(appDir, name);
91
+ if (!(await exists(src)))
92
+ continue;
93
+ await writeFile(join(localeDir, name), `export { default } from '../${name.replace(/\.tsx?$/, '')}';\n`);
94
+ }
95
+ }
96
+ async function mirrorTree(src, dst) {
97
+ const stats = await stat(src);
98
+ if (stats.isDirectory()) {
99
+ await mkdir(dst, { recursive: true });
100
+ const entries = await readdir(src, { withFileTypes: true });
101
+ for (const entry of entries) {
102
+ await mirrorTree(join(src, entry.name), join(dst, entry.name));
103
+ }
104
+ return;
105
+ }
106
+ const rel = relativeImportPath(dst, src);
107
+ const isPage = /\b(page|layout|loading|error|not-found|template)\.tsx?$/.test(src);
108
+ if (isPage) {
109
+ await writeFile(dst, `export { default } from '${rel}';\n`);
110
+ }
111
+ else {
112
+ await writeFile(dst, `export * from '${rel}';\n`);
113
+ }
114
+ }
115
+ function relativeImportPath(from, to) {
116
+ const fromParts = from.split('/').slice(0, -1);
117
+ const toParts = to.split('/');
118
+ let common = 0;
119
+ while (common < fromParts.length &&
120
+ common < toParts.length &&
121
+ fromParts[common] === toParts[common]) {
122
+ common++;
123
+ }
124
+ const ups = fromParts.length - common;
125
+ const down = toParts
126
+ .slice(common)
127
+ .join('/')
128
+ .replace(/\.tsx?$/, '');
129
+ return ups === 0 ? `./${down}` : `${'../'.repeat(ups)}${down}`;
130
+ }
131
+ async function appendEnv(targetDir, contents) {
132
+ const path = join(targetDir, '.env.local');
133
+ const existing = (await exists(path)) ? await readFile(path, 'utf8') : '';
134
+ await writeFile(path, existing + contents);
135
+ }
136
+ async function patchEnvLib(targetDir) {
137
+ const path = join(targetDir, 'src/lib/env.ts');
138
+ if (!(await exists(path)))
139
+ return;
140
+ const source = await readFile(path, 'utf8');
141
+ if (source.includes('storeLanguage'))
142
+ return;
143
+ console.warn(' ⚠ src/lib/env.ts has no `storeLanguage` field — add it to surface NEXT_PUBLIC_STORE_LANGUAGE to the SDK.');
144
+ }
145
+ async function patchClientLibForSetLanguage(targetDir) {
146
+ const path = join(targetDir, 'src/lib/client.ts');
147
+ if (!(await exists(path)))
148
+ return;
149
+ const source = await readFile(path, 'utf8');
150
+ if (source.includes('setLanguage(env.storeLanguage'))
151
+ return;
152
+ const marker = 'return c;';
153
+ if (!source.includes(marker)) {
154
+ console.warn(" ⚠ src/lib/client.ts doesn't match expected shape — please wire `setLanguage(env.storeLanguage)` manually.");
155
+ return;
156
+ }
157
+ const patched = source.replace(marker, 'if (env.storeLanguage) c.setLanguage(env.storeLanguage);\n return c;');
158
+ await writeFile(path, patched);
159
+ }
160
+ async function rewriteLinkImports(targetDir) {
161
+ const roots = [join(targetDir, 'src/app'), join(targetDir, 'src/components')];
162
+ for (const root of roots) {
163
+ if (!(await exists(root)))
164
+ continue;
165
+ for await (const file of walkTsxFiles(root)) {
166
+ if (file.endsWith('LocaleLink.tsx'))
167
+ continue;
168
+ const source = await readFile(file, 'utf8');
169
+ if (!/from\s+['"]next\/link['"]/.test(source))
170
+ continue;
171
+ const patched = source.replace(/from\s+(['"])next\/link\1/g, "from '@/components/LocaleLink'");
172
+ await writeFile(file, patched);
173
+ }
174
+ }
175
+ }
176
+ async function* walkTsxFiles(dir) {
177
+ const entries = await readdir(dir, { withFileTypes: true });
178
+ for (const entry of entries) {
179
+ const full = join(dir, entry.name);
180
+ if (entry.isDirectory()) {
181
+ yield* walkTsxFiles(full);
182
+ }
183
+ else if (entry.isFile() && (entry.name.endsWith('.tsx') || entry.name.endsWith('.ts'))) {
184
+ yield full;
185
+ }
186
+ }
187
+ }
188
+ async function exists(path) {
189
+ try {
190
+ await stat(path);
191
+ return true;
192
+ }
193
+ catch {
194
+ return false;
195
+ }
196
+ }
197
+ function ROOT_REDIRECT_PAGE(defaultLanguage) {
198
+ return `'use client';
199
+
200
+ import { useEffect } from 'react';
201
+
202
+ /**
203
+ * Bare-domain root. Static-export storefronts can't run server-side
204
+ * redirects, so detect a stored locale on the client and replace the URL.
205
+ * The \`<meta http-equiv="refresh">\` fallback handles browsers with JS
206
+ * disabled, and the \`<noscript>\` link is the last-resort manual entry.
207
+ */
208
+ const DEFAULT_LANGUAGE = ${JSON.stringify(defaultLanguage)};
209
+
210
+ export default function RootRedirect() {
211
+ useEffect(() => {
212
+ const stored =
213
+ typeof localStorage !== 'undefined' ? localStorage.getItem('storefront-locale') : null;
214
+ const target = stored && /^[a-z]{2}(-[A-Z]{2})?$/.test(stored) ? stored : DEFAULT_LANGUAGE;
215
+ window.location.replace(\`/\${target}/\`);
216
+ }, []);
217
+
218
+ return (
219
+ <>
220
+ <meta httpEquiv="refresh" content={\`0; url=/\${DEFAULT_LANGUAGE}/\`} />
221
+ <noscript>
222
+ <p>
223
+ <a href={\`/\${DEFAULT_LANGUAGE}/\`}>Continue</a>
224
+ </p>
225
+ </noscript>
226
+ </>
227
+ );
228
+ }
229
+ `;
230
+ }
231
+ function LOCALE_LAYOUT(prefixed) {
232
+ const list = JSON.stringify(prefixed);
233
+ return `import type { ReactNode } from 'react';
234
+
235
+ /**
236
+ * Static-export Next can't accept arbitrary \`[locale]\` values; only the
237
+ * languages listed below get pre-rendered. The default language (when the
238
+ * channel uses \`urlLocalePrefixDefault: false\`) is intentionally absent —
239
+ * those URLs live at root, not under \`/{locale}\`.
240
+ */
241
+ export const dynamicParams = false;
242
+
243
+ export function generateStaticParams() {
244
+ return ${list}.map((locale) => ({ locale }));
245
+ }
246
+
247
+ interface LayoutProps {
248
+ children: ReactNode;
249
+ params: Promise<{ locale: string }>;
250
+ }
251
+
252
+ export default async function LocaleLayout({ children }: LayoutProps) {
253
+ return <>{children}</>;
254
+ }
255
+ `;
256
+ }
257
+ //# sourceMappingURL=locale-shape.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"locale-shape.js","sourceRoot":"","sources":["../src/locale-shape.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACzF,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAgBjC,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,KAA8B;IAErE,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,EAAE,iBAAiB,CAAC,CAAC;IAC3D,IAAI,MAAM,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC;QAC5B,MAAM,EAAE,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACxD,CAAC;IAED,QAAQ,KAAK,CAAC,QAAQ,EAAE,CAAC;QACvB,KAAK,MAAM;YACT,OAAO;QACT,KAAK,WAAW;YACd,OAAO,mBAAmB,CAAC,KAAK,CAAC,CAAC;QACpC,KAAK,aAAa;YAChB,OAAO,oBAAoB,CAAC,KAAK,CAAC,CAAC;IACvC,CAAC;AACH,CAAC;AAUD,SAAS,wBAAwB,CAAC,KAA8B;IAC9D,MAAM,aAAa,GAAG,KAAK,CAAC,aAAa,KAAK,IAAI,CAAC;IACnD,OAAO,KAAK,CAAC,kBAAkB,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE;QAC9C,IAAI,IAAI,KAAK,KAAK,CAAC,eAAe;YAAE,OAAO,aAAa,CAAC;QACzD,OAAO,IAAI,CAAC;IACd,CAAC,CAAC,CAAC;AACL,CAAC;AAID,KAAK,UAAU,mBAAmB,CAAC,KAA8B;IAC/D,MAAM,SAAS,CACb,KAAK,CAAC,SAAS,EACf,qKAAqK,KAAK,CAAC,eAAe,IAAI,CAC/L,CAAC;IAEF,MAAM,WAAW,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IACnC,MAAM,4BAA4B,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;AACtD,CAAC;AAID,MAAM,qBAAqB,GAAG;IAC5B,WAAW;IACX,SAAS;IACT,MAAM;IACN,UAAU;IACV,iBAAiB;IACjB,UAAU;IACV,gBAAgB;IAChB,SAAS;IACT,QAAQ;IACR,gBAAgB;CACjB,CAAC;AAEF,MAAM,kBAAkB,GAAG,CAAC,UAAU,CAAC,CAAC;AAExC,KAAK,UAAU,oBAAoB,CAAC,KAA8B;IAChE,MAAM,QAAQ,GAAG,wBAAwB,CAAC,KAAK,CAAC,CAAC;IACjD,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAI1B,OAAO;IACT,CAAC;IAED,MAAM,aAAa,GAAG,KAAK,CAAC,aAAa,KAAK,IAAI,CAAC;IAEnD,IAAI,aAAa,EAAE,CAAC;QAIlB,MAAM,qBAAqB,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;QAC7C,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;QAChD,MAAM,SAAS,CAAC,IAAI,CAAC,MAAM,EAAE,UAAU,CAAC,EAAE,kBAAkB,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC,CAAC;IACvF,CAAC;SAAM,CAAC;QAMN,MAAM,uBAAuB,CAAC,KAAK,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;IAC3D,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;IAChD,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAC3C,MAAM,SAAS,CAAC,IAAI,CAAC,SAAS,EAAE,YAAY,CAAC,EAAE,aAAa,CAAC,QAAQ,CAAC,CAAC,CAAC;IAExE,MAAM,kBAAkB,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;AAC5C,CAAC;AAED,KAAK,UAAU,qBAAqB,CAAC,SAAiB;IACpD,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;IAC1C,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAC3C,MAAM,KAAK,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAE5C,KAAK,MAAM,IAAI,IAAI,qBAAqB,EAAE,CAAC;QACzC,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QAC/B,IAAI,MAAM,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;YACtB,MAAM,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC;QAC3C,CAAC;IACH,CAAC;IACD,KAAK,MAAM,IAAI,IAAI,kBAAkB,EAAE,CAAC;QACtC,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QAC/B,IAAI,MAAM,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;YACtB,MAAM,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC;QAC3C,CAAC;IACH,CAAC;AACH,CAAC;AAED,KAAK,UAAU,uBAAuB,CAAC,SAAiB,EAAE,SAAmB;IAC3E,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;IAC1C,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAC3C,MAAM,KAAK,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAE5C,KAAK,MAAM,IAAI,IAAI,qBAAqB,EAAE,CAAC;QACzC,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QAC/B,IAAI,CAAC,CAAC,MAAM,MAAM,CAAC,GAAG,CAAC,CAAC;YAAE,SAAS;QACnC,MAAM,UAAU,CAAC,GAAG,EAAE,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC;IAC/C,CAAC;IACD,KAAK,MAAM,IAAI,IAAI,kBAAkB,EAAE,CAAC;QACtC,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QAC/B,IAAI,CAAC,CAAC,MAAM,MAAM,CAAC,GAAG,CAAC,CAAC;YAAE,SAAS;QAEnC,MAAM,SAAS,CACb,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,EACrB,+BAA+B,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,MAAM,CACjE,CAAC;IACJ,CAAC;AACH,CAAC;AAED,KAAK,UAAU,UAAU,CAAC,GAAW,EAAE,GAAW;IAChD,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,CAAC;IAC9B,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;QACxB,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACtC,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;QAC5D,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC5B,MAAM,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;QACjE,CAAC;QACD,OAAO;IACT,CAAC;IAID,MAAM,GAAG,GAAG,kBAAkB,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IACzC,MAAM,MAAM,GAAG,yDAAyD,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACnF,IAAI,MAAM,EAAE,CAAC;QACX,MAAM,SAAS,CAAC,GAAG,EAAE,4BAA4B,GAAG,MAAM,CAAC,CAAC;IAC9D,CAAC;SAAM,CAAC;QACN,MAAM,SAAS,CAAC,GAAG,EAAE,kBAAkB,GAAG,MAAM,CAAC,CAAC;IACpD,CAAC;AACH,CAAC;AAED,SAAS,kBAAkB,CAAC,IAAY,EAAE,EAAU;IAElD,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAC/C,MAAM,OAAO,GAAG,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC9B,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,OACE,MAAM,GAAG,SAAS,CAAC,MAAM;QACzB,MAAM,GAAG,OAAO,CAAC,MAAM;QACvB,SAAS,CAAC,MAAM,CAAC,KAAK,OAAO,CAAC,MAAM,CAAC,EACrC,CAAC;QACD,MAAM,EAAE,CAAC;IACX,CAAC;IACD,MAAM,GAAG,GAAG,SAAS,CAAC,MAAM,GAAG,MAAM,CAAC;IACtC,MAAM,IAAI,GAAG,OAAO;SACjB,KAAK,CAAC,MAAM,CAAC;SACb,IAAI,CAAC,GAAG,CAAC;SACT,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;IAC1B,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,IAAI,EAAE,CAAC;AACjE,CAAC;AAID,KAAK,UAAU,SAAS,CAAC,SAAiB,EAAE,QAAgB;IAC1D,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC;IAC3C,MAAM,QAAQ,GAAG,CAAC,MAAM,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAC1E,MAAM,SAAS,CAAC,IAAI,EAAE,QAAQ,GAAG,QAAQ,CAAC,CAAC;AAC7C,CAAC;AAQD,KAAK,UAAU,WAAW,CAAC,SAAiB;IAC1C,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,EAAE,gBAAgB,CAAC,CAAC;IAC/C,IAAI,CAAC,CAAC,MAAM,MAAM,CAAC,IAAI,CAAC,CAAC;QAAE,OAAO;IAClC,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAC5C,IAAI,MAAM,CAAC,QAAQ,CAAC,eAAe,CAAC;QAAE,OAAO;IAI7C,OAAO,CAAC,IAAI,CACV,4GAA4G,CAC7G,CAAC;AACJ,CAAC;AAOD,KAAK,UAAU,4BAA4B,CAAC,SAAiB;IAC3D,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,EAAE,mBAAmB,CAAC,CAAC;IAClD,IAAI,CAAC,CAAC,MAAM,MAAM,CAAC,IAAI,CAAC,CAAC;QAAE,OAAO;IAClC,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAC5C,IAAI,MAAM,CAAC,QAAQ,CAAC,+BAA+B,CAAC;QAAE,OAAO;IAE7D,MAAM,MAAM,GAAG,WAAW,CAAC;IAC3B,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;QAC7B,OAAO,CAAC,IAAI,CACV,6GAA6G,CAC9G,CAAC;QACF,OAAO;IACT,CAAC;IAED,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAC5B,MAAM,EACN,2EAA2E,CAC5E,CAAC;IACF,MAAM,SAAS,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;AACjC,CAAC;AAMD,KAAK,UAAU,kBAAkB,CAAC,SAAiB;IACjD,MAAM,KAAK,GAAG,CAAC,IAAI,CAAC,SAAS,EAAE,SAAS,CAAC,EAAE,IAAI,CAAC,SAAS,EAAE,gBAAgB,CAAC,CAAC,CAAC;IAC9E,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,CAAC,CAAC,MAAM,MAAM,CAAC,IAAI,CAAC,CAAC;YAAE,SAAS;QACpC,IAAI,KAAK,EAAE,MAAM,IAAI,IAAI,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC;YAE5C,IAAI,IAAI,CAAC,QAAQ,CAAC,gBAAgB,CAAC;gBAAE,SAAS;YAC9C,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;YAC5C,IAAI,CAAC,2BAA2B,CAAC,IAAI,CAAC,MAAM,CAAC;gBAAE,SAAS;YACxD,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAC5B,4BAA4B,EAC5B,gCAAgC,CACjC,CAAC;YACF,MAAM,SAAS,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QACjC,CAAC;IACH,CAAC;AACH,CAAC;AAED,KAAK,SAAS,CAAC,CAAC,YAAY,CAAC,GAAW;IACtC,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IAC5D,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QACnC,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;YACxB,KAAK,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;QAC5B,CAAC;aAAM,IAAI,KAAK,CAAC,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;YACzF,MAAM,IAAI,CAAC;QACb,CAAC;IACH,CAAC;AACH,CAAC;AAED,KAAK,UAAU,MAAM,CAAC,IAAY;IAChC,IAAI,CAAC;QACH,MAAM,IAAI,CAAC,IAAI,CAAC,CAAC;QACjB,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAID,SAAS,kBAAkB,CAAC,eAAuB;IACjD,OAAO;;;;;;;;;;2BAUkB,IAAI,CAAC,SAAS,CAAC,eAAe,CAAC;;;;;;;;;;;;;;;;;;;;;CAqBzD,CAAC;AACF,CAAC;AAED,SAAS,aAAa,CAAC,QAAkB;IACvC,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;IACtC,OAAO;;;;;;;;;;;WAWE,IAAI;;;;;;;;;;;CAWd,CAAC;AACF,CAAC"}
@@ -0,0 +1,14 @@
1
+ import type { CliArgs } from './args.js';
2
+ export interface FilledArgs {
3
+ projectDir: string;
4
+ storeCode: string;
5
+ cdnUrl: string;
6
+ cmsUrl: string | null;
7
+ vendureUrl: string | null;
8
+ pluginsUrl: string | null;
9
+ siteUrl: string | null;
10
+ templateRef: string | null;
11
+ install: boolean;
12
+ }
13
+ export declare function promptMissing(args: CliArgs): Promise<FilledArgs>;
14
+ //# sourceMappingURL=prompts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../src/prompts.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEzC,MAAM,WAAW,UAAU;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,OAAO,EAAE,OAAO,CAAC;CAClB;AAID,wBAAsB,aAAa,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,UAAU,CAAC,CAwBtE"}
@@ -0,0 +1,38 @@
1
+ import { stdin, stdout } from 'node:process';
2
+ import { createInterface } from 'node:readline/promises';
3
+ const DEFAULT_CDN_URL = 'https://cdn.sixtyninecommerce.com';
4
+ export async function promptMissing(args) {
5
+ const rl = createInterface({ input: stdin, output: stdout });
6
+ try {
7
+ const projectDir = args.projectDir ?? (await ask(rl, 'Project directory', 'my-storefront'));
8
+ const storeCode = args.storeCode ?? (await ask(rl, 'Store code', null));
9
+ if (!storeCode) {
10
+ throw new Error('Store code is required');
11
+ }
12
+ const cdnUrl = args.cdnUrl ?? DEFAULT_CDN_URL;
13
+ return {
14
+ projectDir,
15
+ storeCode,
16
+ cdnUrl,
17
+ cmsUrl: args.cmsUrl ?? null,
18
+ vendureUrl: args.vendureUrl ?? null,
19
+ pluginsUrl: args.pluginsUrl ?? null,
20
+ siteUrl: args.siteUrl ?? null,
21
+ templateRef: args.templateRef ?? null,
22
+ install: !args.noInstall,
23
+ };
24
+ }
25
+ finally {
26
+ rl.close();
27
+ }
28
+ }
29
+ async function ask(rl, label, fallback) {
30
+ const suffix = fallback === null ? '' : ` (${fallback})`;
31
+ const answer = (await rl.question(`${label}${suffix}: `)).trim();
32
+ if (answer)
33
+ return answer;
34
+ if (fallback !== null)
35
+ return fallback;
36
+ return '';
37
+ }
38
+ //# sourceMappingURL=prompts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompts.js","sourceRoot":"","sources":["../src/prompts.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAezD,MAAM,eAAe,GAAG,mCAAmC,CAAC;AAE5D,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,IAAa;IAC/C,MAAM,EAAE,GAAG,eAAe,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IAC7D,IAAI,CAAC;QACH,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,EAAE,mBAAmB,EAAE,eAAe,CAAC,CAAC,CAAC;QAC5F,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,EAAE,YAAY,EAAE,IAAI,CAAC,CAAC,CAAC;QACxE,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;QAC5C,CAAC;QACD,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,eAAe,CAAC;QAE9C,OAAO;YACL,UAAU;YACV,SAAS;YACT,MAAM;YACN,MAAM,EAAE,IAAI,CAAC,MAAM,IAAI,IAAI;YAC3B,UAAU,EAAE,IAAI,CAAC,UAAU,IAAI,IAAI;YACnC,UAAU,EAAE,IAAI,CAAC,UAAU,IAAI,IAAI;YACnC,OAAO,EAAE,IAAI,CAAC,OAAO,IAAI,IAAI;YAC7B,WAAW,EAAE,IAAI,CAAC,WAAW,IAAI,IAAI;YACrC,OAAO,EAAE,CAAC,IAAI,CAAC,SAAS;SACzB,CAAC;IACJ,CAAC;YAAS,CAAC;QACT,EAAE,CAAC,KAAK,EAAE,CAAC;IACb,CAAC;AACH,CAAC;AAED,KAAK,UAAU,GAAG,CAChB,EAAsC,EACtC,KAAa,EACb,QAAuB;IAEvB,MAAM,MAAM,GAAG,QAAQ,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,QAAQ,GAAG,CAAC;IACzD,MAAM,MAAM,GAAG,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,GAAG,KAAK,GAAG,MAAM,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IACjE,IAAI,MAAM;QAAE,OAAO,MAAM,CAAC;IAC1B,IAAI,QAAQ,KAAK,IAAI;QAAE,OAAO,QAAQ,CAAC;IACvC,OAAO,EAAE,CAAC;AACZ,CAAC"}
@@ -0,0 +1,7 @@
1
+ export interface FetchTemplateInput {
2
+ repo: string;
3
+ ref: string | null;
4
+ targetDir: string;
5
+ }
6
+ export declare function fetchAndExtractTemplate(input: FetchTemplateInput): Promise<void>;
7
+ //# sourceMappingURL=template.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template.d.ts","sourceRoot":"","sources":["../src/template.ts"],"names":[],"mappings":"AAiBA,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,wBAAsB,uBAAuB,CAAC,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CA6BtF"}
@@ -0,0 +1,71 @@
1
+ import { mkdir, readdir } from 'node:fs/promises';
2
+ import { Readable } from 'node:stream';
3
+ import { pipeline } from 'node:stream/promises';
4
+ import { extract } from 'tar';
5
+ export async function fetchAndExtractTemplate(input) {
6
+ const ref = input.ref ?? (await resolveLatestRef(input.repo));
7
+ await mkdir(input.targetDir, { recursive: true });
8
+ const existing = await readdir(input.targetDir);
9
+ if (existing.length > 0) {
10
+ throw new Error(`Target directory is not empty: ${input.targetDir}`);
11
+ }
12
+ const token = process.env.GITHUB_TOKEN ?? null;
13
+ const { url, headers } = token
14
+ ? apiTarball(input.repo, ref, token)
15
+ : { url: await publicTarballUrl(input.repo, ref), headers: defaultHeaders() };
16
+ const response = await fetch(url, { redirect: 'follow', headers });
17
+ if (!response.ok || !response.body) {
18
+ throw new Error(`Failed to download template: ${response.status} ${response.statusText} (${url})`);
19
+ }
20
+ await pipeline(Readable.fromWeb(response.body), extract({ cwd: input.targetDir, strip: 1 }));
21
+ }
22
+ function apiTarball(repo, ref, token) {
23
+ return {
24
+ url: `https://api.github.com/repos/${repo}/tarball/${ref}`,
25
+ headers: {
26
+ ...defaultHeaders(),
27
+ authorization: `Bearer ${token}`,
28
+ accept: 'application/vnd.github+json',
29
+ },
30
+ };
31
+ }
32
+ function defaultHeaders() {
33
+ return { 'user-agent': '@sixtyninecommerce/create-storefront' };
34
+ }
35
+ async function resolveLatestRef(repo) {
36
+ const url = `https://api.github.com/repos/${repo}/releases/latest`;
37
+ const token = process.env.GITHUB_TOKEN;
38
+ const headers = {
39
+ 'user-agent': '@sixtyninecommerce/create-storefront',
40
+ accept: 'application/vnd.github+json',
41
+ };
42
+ if (token)
43
+ headers.authorization = `Bearer ${token}`;
44
+ const response = await fetch(url, { headers });
45
+ if (response.status === 404) {
46
+ return 'main';
47
+ }
48
+ if (!response.ok) {
49
+ throw new Error(`Failed to resolve latest release: ${response.status} ${response.statusText}`);
50
+ }
51
+ const body = (await response.json());
52
+ if (!body.tag_name) {
53
+ throw new Error('Latest release has no tag_name');
54
+ }
55
+ return body.tag_name;
56
+ }
57
+ async function publicTarballUrl(repo, ref) {
58
+ if (/^[0-9a-f]{7,40}$/i.test(ref)) {
59
+ return `https://github.com/${repo}/archive/${ref}.tar.gz`;
60
+ }
61
+ const tagUrl = `https://github.com/${repo}/archive/refs/tags/${ref}.tar.gz`;
62
+ const tagHead = await fetch(tagUrl, {
63
+ method: 'HEAD',
64
+ redirect: 'follow',
65
+ headers: { 'user-agent': '@sixtyninecommerce/create-storefront' },
66
+ });
67
+ if (tagHead.ok)
68
+ return tagUrl;
69
+ return `https://github.com/${repo}/archive/refs/heads/${ref}.tar.gz`;
70
+ }
71
+ //# sourceMappingURL=template.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template.js","sourceRoot":"","sources":["../src/template.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import type { BrandingInfo } from '@sixtyninecommerce/client';
2
+ export interface FetchBrandingInput {
3
+ storeCode: string;
4
+ cdnUrl: string;
5
+ cmsUrl: string | null;
6
+ vendureUrl: string | null;
7
+ pluginsUrl: string | null;
8
+ }
9
+ export interface ChannelSnapshot {
10
+ branding: BrandingInfo;
11
+ availableLanguages: string[];
12
+ }
13
+ export declare function fetchBranding(input: FetchBrandingInput): Promise<ChannelSnapshot>;
14
+ //# sourceMappingURL=validate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../src/validate.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAG9D,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,YAAY,CAAC;IAGvB,kBAAkB,EAAE,MAAM,EAAE,CAAC;CAC9B;AAED,wBAAsB,aAAa,CAAC,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAAC,eAAe,CAAC,CAavF"}
@@ -0,0 +1,16 @@
1
+ import { createStorefrontClient } from '@sixtyninecommerce/client';
2
+ export async function fetchBranding(input) {
3
+ const client = await createStorefrontClient({
4
+ storeCode: input.storeCode,
5
+ cdnUrl: input.cdnUrl,
6
+ ...(input.cmsUrl ? { cmsUrl: input.cmsUrl } : {}),
7
+ ...(input.vendureUrl ? { vendureUrl: input.vendureUrl } : {}),
8
+ ...(input.pluginsUrl ? { pluginsUrl: input.pluginsUrl } : {}),
9
+ });
10
+ const [branding, channel] = await Promise.all([
11
+ client.commerce.getBranding(),
12
+ client.commerce.getActiveChannel(),
13
+ ]);
14
+ return { branding, availableLanguages: channel.availableLanguageCodes };
15
+ }
16
+ //# sourceMappingURL=validate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.js","sourceRoot":"","sources":["../src/validate.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;AAiBnE,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,KAAyB;IAC3D,MAAM,MAAM,GAAG,MAAM,sBAAsB,CAAC;QAC1C,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACjD,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,KAAK,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC7D,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,KAAK,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC9D,CAAC,CAAC;IACH,MAAM,CAAC,QAAQ,EAAE,OAAO,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QAC5C,MAAM,CAAC,QAAQ,CAAC,WAAW,EAAE;QAC7B,MAAM,CAAC,QAAQ,CAAC,gBAAgB,EAAE;KACnC,CAAC,CAAC;IACH,OAAO,EAAE,QAAQ,EAAE,kBAAkB,EAAE,OAAO,CAAC,sBAAsB,EAAE,CAAC;AAC1E,CAAC"}
package/package.json ADDED
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "@sixtyninecommerce/create-storefront",
3
+ "version": "0.2.0",
4
+ "description": "Scaffold a sixtynine-commerce storefront from the official template",
5
+ "license": "MIT",
6
+ "homepage": "https://github.com/SIXTYNINE-digital/sixtynine-commerce-engine/tree/main/packages/create-storefront#readme",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/SIXTYNINE-digital/sixtynine-commerce-engine.git",
10
+ "directory": "packages/create-storefront"
11
+ },
12
+ "bugs": "https://github.com/SIXTYNINE-digital/sixtynine-commerce-engine/issues",
13
+ "keywords": [
14
+ "ecommerce",
15
+ "storefront",
16
+ "vendure",
17
+ "scaffold",
18
+ "create",
19
+ "starter"
20
+ ],
21
+ "type": "module",
22
+ "bin": {
23
+ "create-sixtynine-storefront": "./dist/index.js"
24
+ },
25
+ "files": [
26
+ "dist"
27
+ ],
28
+ "publishConfig": {
29
+ "access": "public"
30
+ },
31
+ "dependencies": {
32
+ "tar": "7.5.15",
33
+ "zod": "4.4.3",
34
+ "@sixtyninecommerce/client": "0.7.0"
35
+ },
36
+ "devDependencies": {
37
+ "@types/node": "22.19.7",
38
+ "@types/tar": "6.1.13",
39
+ "typescript": "5.9.3",
40
+ "vitest": "4.1.6"
41
+ },
42
+ "scripts": {
43
+ "build": "tsc -p tsconfig.build.json && chmod +x dist/index.js",
44
+ "dev": "tsc -p tsconfig.build.json --watch",
45
+ "typecheck": "tsc --noEmit",
46
+ "test": "vitest run",
47
+ "test:watch": "vitest",
48
+ "test:unit": "vitest run",
49
+ "release:publish": "pnpm pack && npm publish *.tgz --access public"
50
+ }
51
+ }