@graphcommerce/next-config 8.1.0-canary.8 → 9.0.0-canary.54

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.
@@ -156,3 +156,53 @@ export const AddProductsToCartForm = EnableCrossselsPlugin
156
156
  }
157
157
  `)
158
158
  })
159
+
160
+ it('parses', () => {
161
+ const src = `
162
+ import {
163
+ PaymentMethodContextProviderProps,
164
+ PaymentModule,
165
+ } from '@graphcommerce/magento-cart-payment-method'
166
+ import type { PluginProps } from '@graphcommerce/next-config'
167
+ import { AdyenPaymentActionCard } from '../components/AdyenPaymentActionCard/AdyenPaymentActionCard'
168
+ import { AdyenPaymentHandler } from '../components/AdyenPaymentHandler/AdyenPaymentHandler'
169
+ import { HppOptions } from '../components/AdyenPaymentOptionsAndPlaceOrder/AdyenPaymentOptionsAndPlaceOrder'
170
+ import { adyenHppExpandMethods } from '../hooks/adyenHppExpandMethods'
171
+
172
+ export const adyen_hpp: PaymentModule = {
173
+ PaymentOptions: HppOptions,
174
+ PaymentPlaceOrder: () => null,
175
+ PaymentHandler: AdyenPaymentHandler,
176
+ PaymentActionCard: AdyenPaymentActionCard,
177
+ expandMethods: adyenHppExpandMethods,
178
+ }
179
+
180
+ export const component = 'PaymentMethodContextProvider'
181
+ export const exported = '@graphcommerce/magento-cart-payment-method'
182
+
183
+ function AddAdyenMethods(props: PluginProps<PaymentMethodContextProviderProps>) {
184
+ const { modules, Prev, ...rest } = props
185
+ return <Prev {...rest} modules={{ ...modules, adyen_hpp }} />
186
+ }
187
+
188
+ export const Plugin = AddAdyenMethods
189
+ `
190
+
191
+ const plugins = parseStructure(
192
+ parseSync(src),
193
+ fakeconfig,
194
+ '@graphcommerce/magento-payment-adyen/plugins/AddAdyenMethods.tsx',
195
+ )
196
+ expect(plugins).toHaveLength(1)
197
+ expect(plugins[0]).toMatchInlineSnapshot(`
198
+ {
199
+ "enabled": true,
200
+ "sourceExport": "Plugin",
201
+ "sourceModule": "@graphcommerce/magento-payment-adyen/plugins/AddAdyenMethods.tsx",
202
+ "targetExport": "PaymentMethodContextProvider",
203
+ "targetModule": "@graphcommerce/magento-cart-payment-method",
204
+ "type": "component",
205
+ }
206
+ `)
207
+ expect(plugins[1]).toMatchInlineSnapshot(`undefined`)
208
+ })
@@ -5,6 +5,7 @@ exports.demoConfig = {
5
5
  canonicalBaseUrl: 'https://graphcommerce.vercel.app',
6
6
  hygraphEndpoint: 'https://eu-central-1.cdn.hygraph.com/content/ckhx7xadya6xs01yxdujt8i80/master',
7
7
  magentoEndpoint: 'https://backend.reachdigital.dev/graphql',
8
+ magentoVersion: 246,
8
9
  storefront: [
9
10
  { locale: 'en', magentoStoreCode: 'en_US', defaultLocale: true },
10
11
  {
@@ -35,6 +36,7 @@ exports.demoConfig = {
35
36
  ],
36
37
  productFiltersPro: true,
37
38
  productFiltersLayout: 'DEFAULT',
39
+ productListPaginationVariant: 'COMPACT',
38
40
  compareVariant: 'ICON',
39
41
  robotsAllow: false,
40
42
  demoMode: true,
@@ -44,4 +46,7 @@ exports.demoConfig = {
44
46
  configurableVariantForSimple: true,
45
47
  configurableVariantValues: { url: true, content: true, gallery: true },
46
48
  recentlyViewedProducts: { enabled: true, maxCount: 20 },
49
+ breadcrumbs: false,
50
+ customerDeleteEnabled: true,
51
+ previewSecret: 'SECRET',
47
52
  };
@@ -43,6 +43,8 @@ function configToEnvSchema(schema) {
43
43
  node = node.unwrap();
44
44
  if (node instanceof zod_1.ZodNullable)
45
45
  node = node.unwrap();
46
+ if (node instanceof zod_1.ZodDefault)
47
+ node = node.removeDefault();
46
48
  if (node instanceof zod_1.ZodObject) {
47
49
  if (path.length > 0) {
48
50
  envSchema[(0, exports.toEnvStr)(path)] = zod_1.z
@@ -73,7 +75,12 @@ function configToEnvSchema(schema) {
73
75
  });
74
76
  return;
75
77
  }
76
- if (node instanceof zod_1.ZodString || node instanceof zod_1.ZodNumber || node instanceof zod_1.ZodEnum) {
78
+ if (node instanceof zod_1.ZodNumber) {
79
+ envSchema[(0, exports.toEnvStr)(path)] = zod_1.z.coerce.number().optional();
80
+ envToDot[(0, exports.toEnvStr)(path)] = (0, exports.dotNotation)(path);
81
+ return;
82
+ }
83
+ if (node instanceof zod_1.ZodString || node instanceof zod_1.ZodEnum) {
77
84
  envSchema[(0, exports.toEnvStr)(path)] = node.optional();
78
85
  envToDot[(0, exports.toEnvStr)(path)] = (0, exports.dotNotation)(path);
79
86
  return;
@@ -1,12 +1,13 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.SidebarGalleryConfigSchema = exports.RecentlyViewedProductsConfigSchema = exports.MagentoConfigurableVariantValuesSchema = exports.GraphCommerceStorefrontConfigSchema = exports.GraphCommerceDebugConfigSchema = exports.GraphCommerceConfigSchema = exports.DatalayerConfigSchema = exports.SidebarGalleryPaginationVariantSchema = exports.ProductFiltersLayoutSchema = exports.CompareVariantSchema = exports.definedNonNullAnySchema = exports.isDefinedNonNullAny = void 0;
3
+ exports.SidebarGalleryConfigSchema = exports.RecentlyViewedProductsConfigSchema = exports.MagentoConfigurableVariantValuesSchema = exports.GraphCommerceStorefrontConfigSchema = exports.GraphCommerceDebugConfigSchema = exports.GraphCommerceConfigSchema = exports.DatalayerConfigSchema = exports.SidebarGalleryPaginationVariantSchema = exports.ProductFiltersLayoutSchema = exports.PaginationVariantSchema = exports.CompareVariantSchema = exports.definedNonNullAnySchema = exports.isDefinedNonNullAny = void 0;
4
4
  /* eslint-disable */
5
5
  const zod_1 = require("zod");
6
6
  const isDefinedNonNullAny = (v) => v !== undefined && v !== null;
7
7
  exports.isDefinedNonNullAny = isDefinedNonNullAny;
8
8
  exports.definedNonNullAnySchema = zod_1.z.any().refine((v) => (0, exports.isDefinedNonNullAny)(v));
9
9
  exports.CompareVariantSchema = zod_1.z.enum(['CHECKBOX', 'ICON']);
10
+ exports.PaginationVariantSchema = zod_1.z.enum(['COMPACT', 'EXTENDED']);
10
11
  exports.ProductFiltersLayoutSchema = zod_1.z.enum(['DEFAULT', 'SIDEBAR']);
11
12
  exports.SidebarGalleryPaginationVariantSchema = zod_1.z.enum(['DOTS', 'THUMBNAILS_BOTTOM']);
12
13
  function DatalayerConfigSchema() {
@@ -17,18 +18,21 @@ function DatalayerConfigSchema() {
17
18
  exports.DatalayerConfigSchema = DatalayerConfigSchema;
18
19
  function GraphCommerceConfigSchema() {
19
20
  return zod_1.z.object({
21
+ breadcrumbs: zod_1.z.boolean().default(false).nullish(),
20
22
  canonicalBaseUrl: zod_1.z.string().min(1),
21
23
  cartDisplayPricesInclTax: zod_1.z.boolean().nullish(),
22
24
  compare: zod_1.z.boolean().nullish(),
23
- compareVariant: exports.CompareVariantSchema.nullish(),
24
- configurableVariantForSimple: zod_1.z.boolean().nullish(),
25
+ compareVariant: exports.CompareVariantSchema.default("ICON").nullish(),
26
+ configurableVariantForSimple: zod_1.z.boolean().default(false).nullish(),
25
27
  configurableVariantValues: MagentoConfigurableVariantValuesSchema().nullish(),
26
- crossSellsHideCartItems: zod_1.z.boolean().nullish(),
27
- crossSellsRedirectItems: zod_1.z.boolean().nullish(),
28
- customerRequireEmailConfirmation: zod_1.z.boolean().nullish(),
28
+ crossSellsHideCartItems: zod_1.z.boolean().default(false).nullish(),
29
+ crossSellsRedirectItems: zod_1.z.boolean().default(false).nullish(),
30
+ customerAddressNoteEnable: zod_1.z.boolean().nullish(),
31
+ customerCompanyFieldsEnable: zod_1.z.boolean().nullish(),
32
+ customerDeleteEnabled: zod_1.z.boolean().nullish(),
29
33
  dataLayer: DatalayerConfigSchema().nullish(),
30
34
  debug: GraphCommerceDebugConfigSchema().nullish(),
31
- demoMode: zod_1.z.boolean().nullish(),
35
+ demoMode: zod_1.z.boolean().default(true).nullish(),
32
36
  enableGuestCheckoutLogin: zod_1.z.boolean().nullish(),
33
37
  googleAnalyticsId: zod_1.z.string().nullish(),
34
38
  googleRecaptchaKey: zod_1.z.string().nullish(),
@@ -40,9 +44,11 @@ function GraphCommerceConfigSchema() {
40
44
  hygraphWriteAccessToken: zod_1.z.string().nullish(),
41
45
  limitSsg: zod_1.z.boolean().nullish(),
42
46
  magentoEndpoint: zod_1.z.string().min(1),
47
+ magentoVersion: zod_1.z.number(),
43
48
  previewSecret: zod_1.z.string().nullish(),
44
- productFiltersLayout: exports.ProductFiltersLayoutSchema.nullish(),
49
+ productFiltersLayout: exports.ProductFiltersLayoutSchema.default("DEFAULT").nullish(),
45
50
  productFiltersPro: zod_1.z.boolean().nullish(),
51
+ productListPaginationVariant: exports.PaginationVariantSchema.default("COMPACT").nullish(),
46
52
  productRoute: zod_1.z.string().nullish(),
47
53
  recentlyViewedProducts: RecentlyViewedProductsConfigSchema().nullish(),
48
54
  robotsAllow: zod_1.z.boolean().nullish(),
@@ -66,6 +72,7 @@ function GraphCommerceStorefrontConfigSchema() {
66
72
  return zod_1.z.object({
67
73
  canonicalBaseUrl: zod_1.z.string().nullish(),
68
74
  cartDisplayPricesInclTax: zod_1.z.boolean().nullish(),
75
+ customerCompanyFieldsEnable: zod_1.z.boolean().nullish(),
69
76
  defaultLocale: zod_1.z.boolean().nullish(),
70
77
  domain: zod_1.z.string().nullish(),
71
78
  googleAnalyticsId: zod_1.z.string().nullish(),
@@ -74,7 +81,8 @@ function GraphCommerceStorefrontConfigSchema() {
74
81
  hygraphLocales: zod_1.z.array(zod_1.z.string().min(1)).nullish(),
75
82
  linguiLocale: zod_1.z.string().nullish(),
76
83
  locale: zod_1.z.string().min(1),
77
- magentoStoreCode: zod_1.z.string().min(1)
84
+ magentoStoreCode: zod_1.z.string().min(1),
85
+ robotsAllow: zod_1.z.boolean().nullish()
78
86
  });
79
87
  }
80
88
  exports.GraphCommerceStorefrontConfigSchema = GraphCommerceStorefrontConfigSchema;
@@ -87,9 +87,8 @@ function extractValue(node, path, optional = false) {
87
87
  case 'undefined':
88
88
  return undefined;
89
89
  default:
90
- if (optional)
91
- return exports.RUNTIME_VALUE;
92
- throw new UnsupportedValueError(`Unknown identifier "${node.value}"`, path);
90
+ return exports.RUNTIME_VALUE;
91
+ // throw new UnsupportedValueError(`Unknown identifier "${node.value}"`, path)
93
92
  }
94
93
  }
95
94
  else if (isArrayExpression(node)) {
@@ -100,9 +99,11 @@ function extractValue(node, path, optional = false) {
100
99
  if (elem) {
101
100
  if (elem.spread) {
102
101
  // e.g. [ ...a ]
103
- if (optional)
104
- return exports.RUNTIME_VALUE;
105
- throw new UnsupportedValueError('Unsupported spread operator in the Array Expression', path);
102
+ return exports.RUNTIME_VALUE;
103
+ // throw new UnsupportedValueError(
104
+ // 'Unsupported spread operator in the Array Expression',
105
+ // path,
106
+ // )
106
107
  }
107
108
  arr.push(extractValue(elem.expression, path && [...path, `[${i}]`], optional));
108
109
  }
@@ -120,9 +121,11 @@ function extractValue(node, path, optional = false) {
120
121
  for (const prop of node.properties) {
121
122
  if (!isKeyValueProperty(prop)) {
122
123
  // e.g. { ...a }
123
- if (optional)
124
- return exports.RUNTIME_VALUE;
125
- throw new UnsupportedValueError('Unsupported spread operator in the Object Expression', path);
124
+ return exports.RUNTIME_VALUE;
125
+ // throw new UnsupportedValueError(
126
+ // 'Unsupported spread operator in the Object Expression',
127
+ // path,
128
+ // )
126
129
  }
127
130
  let key;
128
131
  if (isIdentifier(prop.key)) {
@@ -134,9 +137,11 @@ function extractValue(node, path, optional = false) {
134
137
  key = prop.key.value;
135
138
  }
136
139
  else {
137
- if (optional)
138
- return exports.RUNTIME_VALUE;
139
- throw new UnsupportedValueError(`Unsupported key type "${prop.key.type}" in the Object Expression`, path);
140
+ return exports.RUNTIME_VALUE;
141
+ // throw new UnsupportedValueError(
142
+ // `Unsupported key type "${prop.key.type}" in the Object Expression`,
143
+ // path,
144
+ // )
140
145
  }
141
146
  obj[key] = extractValue(prop.value, path && [...path, key]);
142
147
  }
@@ -146,9 +151,8 @@ function extractValue(node, path, optional = false) {
146
151
  // e.g. `abc`
147
152
  if (node.expressions.length !== 0) {
148
153
  // TODO: should we add support for `${'e'}d${'g'}'e'`?
149
- if (optional)
150
- return exports.RUNTIME_VALUE;
151
- throw new UnsupportedValueError('Unsupported template literal with expressions', path);
154
+ return exports.RUNTIME_VALUE;
155
+ // throw new UnsupportedValueError('Unsupported template literal with expressions', path)
152
156
  }
153
157
  // When TemplateLiteral has 0 expressions, the length of quasis is always 1.
154
158
  // Because when parsing TemplateLiteral, the parser yields the first quasi,
@@ -163,9 +167,8 @@ function extractValue(node, path, optional = false) {
163
167
  return cooked ?? raw;
164
168
  }
165
169
  else {
166
- if (optional)
167
- return exports.RUNTIME_VALUE;
168
- throw new UnsupportedValueError(`Unsupported node type "${node.type}"`, path);
170
+ return exports.RUNTIME_VALUE;
171
+ // throw new UnsupportedValueError(`Unsupported node type "${node.type}"`, path)
169
172
  }
170
173
  }
171
174
  function extractExports(module) {
@@ -33,6 +33,22 @@ function parseAndFindExport(resolved, findExport, resolve) {
33
33
  break;
34
34
  }
35
35
  }
36
+ if (node.type === 'ExportNamedDeclaration') {
37
+ for (const specifier of node.specifiers) {
38
+ if (specifier.type === 'ExportSpecifier') {
39
+ if (specifier.exported?.value === findExport)
40
+ return resolved;
41
+ }
42
+ else if (specifier.type === 'ExportDefaultSpecifier') {
43
+ // todo
44
+ }
45
+ else if (specifier.type === 'ExportNamespaceSpecifier') {
46
+ // todo
47
+ }
48
+ }
49
+ }
50
+ // todo: if (node.type === 'ExportDefaultDeclaration') {}
51
+ // todo: if (node.type === 'ExportDefaultExpression') {}
36
52
  }
37
53
  const exports = ast.body
38
54
  .filter((node) => node.type === 'ExportAllDeclaration')
@@ -78,7 +94,7 @@ function findOriginalSource(plug, resolved, resolve) {
78
94
  if (!newResolved) {
79
95
  return {
80
96
  resolved: undefined,
81
- error: new Error(`Can not find ${plug.targetModule}#${plug.sourceExport} for plugin ${plug.sourceModule}`),
97
+ error: new Error(`Plugin target not found ${plug.targetModule}#${plug.sourceExport} for plugin ${plug.sourceModule}#${plug.sourceExport}`),
82
98
  };
83
99
  }
84
100
  // cachedResults.set(cacheKey, newResolved)
@@ -45,7 +45,7 @@ const originalSuffix = 'Original';
45
45
  const sourceSuffix = 'Plugin';
46
46
  const interceptorSuffix = 'Interceptor';
47
47
  const disabledSuffix = 'Disabled';
48
- const name = (plugin) => `${plugin.sourceModule
48
+ const name = (plugin) => `${plugin.sourceExport}${plugin.sourceModule
49
49
  .split('/')[plugin.sourceModule.split('/').length - 1].replace(/[^a-zA-Z0-9]/g, '')}`;
50
50
  const fileName = (plugin) => `${plugin.sourceModule}#${plugin.sourceExport}`;
51
51
  const originalName = (n) => `${n}${originalSuffix}`;
@@ -121,8 +121,7 @@ async function generateInterceptor(interceptor, config, oldInterceptorSource) {
121
121
  .join(' wrapping ');
122
122
  if (isReplacePluginConfig(p)) {
123
123
  new RenameVisitor_1.RenameVisitor([originalName(p.targetExport)], (s) => s.replace(originalSuffix, disabledSuffix)).visitModule(ast);
124
- carryProps.push(interceptorPropsName(name(p)));
125
- result = `type ${interceptorPropsName(name(p))} = React.ComponentProps<typeof ${sourceName(name(p))}>`;
124
+ carryProps.push(`React.ComponentProps<typeof ${sourceName(name(p))}>`);
126
125
  pluginSee.push(`@see {${sourceName(name(p))}} for replacement of the original source (original source not used)`);
127
126
  }
128
127
  if (isReactPluginConfig(p)) {
@@ -154,7 +153,7 @@ async function generateInterceptor(interceptor, config, oldInterceptorSource) {
154
153
  })
155
154
  .filter((v) => !!v)
156
155
  .join('\n');
157
- const isComponent = plugins.every((p) => isReplacePluginConfig(p) || isReactPluginConfig(p));
156
+ const isComponent = plugins.every((p) => isReactPluginConfig(p));
158
157
  if (isComponent && plugins.some((p) => isMethodPluginConfig(p))) {
159
158
  throw new Error(`Cannot mix React and Method plugins for ${base} in ${dependency}.`);
160
159
  }
@@ -27,7 +27,7 @@ function parseStructure(ast, gcConfig, sourceModule) {
27
27
  exportVals.push('Plugin');
28
28
  if (func && !moduleConfig)
29
29
  exportVals.push('plugin');
30
- return exportVals
30
+ const pluginConfigs = exportVals
31
31
  .map((exportVal) => {
32
32
  let config = isObject(moduleConfig) ? moduleConfig : {};
33
33
  if (!moduleConfig && component) {
@@ -41,6 +41,7 @@ function parseStructure(ast, gcConfig, sourceModule) {
41
41
  }
42
42
  else {
43
43
  console.error(`Plugin configuration invalid! See ${sourceModule}`);
44
+ return null;
44
45
  }
45
46
  const parsed = pluginConfigParsed.safeParse(config);
46
47
  if (!parsed.success) {
@@ -67,5 +68,12 @@ function parseStructure(ast, gcConfig, sourceModule) {
67
68
  return val;
68
69
  })
69
70
  .filter(nonNullable);
71
+ const newPluginConfigs = pluginConfigs.reduce((acc, pluginConfig) => {
72
+ if (!acc.find((accPluginConfig) => accPluginConfig.sourceExport === pluginConfig.sourceExport)) {
73
+ acc.push(pluginConfig);
74
+ }
75
+ return acc;
76
+ }, []);
77
+ return newPluginConfigs;
70
78
  }
71
79
  exports.parseStructure = parseStructure;
@@ -17,19 +17,19 @@ function checkFileExists(file) {
17
17
  }
18
18
  async function writeInterceptors(interceptors, cwd = process.cwd()) {
19
19
  const dependencies = (0, resolveDependenciesSync_1.resolveDependenciesSync)(cwd);
20
- const existing = [];
20
+ const existing = new Set();
21
21
  dependencies.forEach((dependency) => {
22
22
  const files = (0, glob_1.sync)([`${dependency}/**/*.interceptor.tsx`, `${dependency}/**/*.interceptor.ts`], { cwd });
23
- existing.push(...files);
23
+ files.forEach((file) => existing.add(file));
24
24
  });
25
25
  const written = Object.entries(interceptors).map(async ([, plugin]) => {
26
26
  const extension = plugin.sourcePath.endsWith('.tsx') ? '.tsx' : '.ts';
27
27
  const relativeFile = `${plugin.fromRoot}.interceptor${extension}`;
28
- if (existing.includes(relativeFile)) {
29
- delete existing[existing.indexOf(relativeFile)];
28
+ if (existing.has(relativeFile)) {
29
+ existing.delete(relativeFile);
30
30
  }
31
- if (existing.includes(`./${relativeFile}`)) {
32
- delete existing[existing.indexOf(`./${relativeFile}`)];
31
+ if (existing.has(`./${relativeFile}`)) {
32
+ existing.delete(`./${relativeFile}`);
33
33
  }
34
34
  const fileToWrite = path_1.default.join(cwd, relativeFile);
35
35
  const isSame = (await checkFileExists(fileToWrite)) &&
@@ -38,7 +38,7 @@ async function writeInterceptors(interceptors, cwd = process.cwd()) {
38
38
  await promises_1.default.writeFile(fileToWrite, plugin.template);
39
39
  });
40
40
  // Cleanup unused interceptors
41
- const cleaned = existing.map(async (file) => (await checkFileExists(file)) && (await promises_1.default.unlink(file)));
41
+ const cleaned = [...existing].map(async (file) => (await checkFileExists(file)) && (await promises_1.default.unlink(file)));
42
42
  await Promise.all(written);
43
43
  await Promise.all(cleaned);
44
44
  }
@@ -94,8 +94,19 @@ function withGraphCommerce(nextConfig, cwd) {
94
94
  },
95
95
  transpilePackages,
96
96
  webpack: (config, options) => {
97
- // Allow importing yml/yaml files for graphql-mesh
98
- config.module?.rules?.push({ test: /\.ya?ml$/, use: 'js-yaml-loader' });
97
+ if (!config.module)
98
+ config.module = { rules: [] };
99
+ config.module = {
100
+ ...config.module,
101
+ rules: [
102
+ ...(config.module.rules ?? []),
103
+ // Allow importing yml/yaml files for graphql-mesh
104
+ { test: /\.ya?ml$/, use: 'js-yaml-loader' },
105
+ // @lingui .po file support
106
+ { test: /\.po/, use: '@lingui/loader' },
107
+ ],
108
+ exprContextCritical: false,
109
+ };
99
110
  if (!config.plugins)
100
111
  config.plugins = [];
101
112
  // Make import.meta.graphCommerce available for usage.
@@ -122,8 +133,6 @@ function withGraphCommerce(nextConfig, cwd) {
122
133
  }));
123
134
  }
124
135
  }
125
- // @lingui .po file support
126
- config.module?.rules?.push({ test: /\.po/, use: '@lingui/loader' });
127
136
  config.snapshot = {
128
137
  ...(config.snapshot ?? {}),
129
138
  managedPaths: [
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@graphcommerce/next-config",
3
3
  "homepage": "https://www.graphcommerce.org/",
4
4
  "repository": "github:graphcommerce-org/graphcommerce",
5
- "version": "8.1.0-canary.8",
5
+ "version": "9.0.0-canary.54",
6
6
  "type": "commonjs",
7
7
  "main": "dist/index.js",
8
8
  "types": "src/index.ts",
@@ -7,6 +7,7 @@ export const demoConfig: PartialDeep<GraphCommerceConfig, { recurseIntoArrays: t
7
7
  canonicalBaseUrl: 'https://graphcommerce.vercel.app',
8
8
  hygraphEndpoint: 'https://eu-central-1.cdn.hygraph.com/content/ckhx7xadya6xs01yxdujt8i80/master',
9
9
  magentoEndpoint: 'https://backend.reachdigital.dev/graphql',
10
+ magentoVersion: 246,
10
11
  storefront: [
11
12
  { locale: 'en', magentoStoreCode: 'en_US', defaultLocale: true },
12
13
  {
@@ -37,6 +38,7 @@ export const demoConfig: PartialDeep<GraphCommerceConfig, { recurseIntoArrays: t
37
38
  ],
38
39
  productFiltersPro: true,
39
40
  productFiltersLayout: 'DEFAULT',
41
+ productListPaginationVariant: 'COMPACT',
40
42
  compareVariant: 'ICON',
41
43
  robotsAllow: false,
42
44
 
@@ -47,4 +49,7 @@ export const demoConfig: PartialDeep<GraphCommerceConfig, { recurseIntoArrays: t
47
49
  configurableVariantForSimple: true,
48
50
  configurableVariantValues: { url: true, content: true, gallery: true },
49
51
  recentlyViewedProducts: { enabled: true, maxCount: 20 },
52
+ breadcrumbs: false,
53
+ customerDeleteEnabled: true,
54
+ previewSecret: 'SECRET',
50
55
  }
@@ -17,6 +17,7 @@ import {
17
17
  ZodEnum,
18
18
  ZodTypeAny,
19
19
  ZodAny,
20
+ ZodDefault,
20
21
  } from 'zod'
21
22
  import diff from './diff'
22
23
 
@@ -61,6 +62,7 @@ export function configToEnvSchema(schema: ZodNode) {
61
62
  if (node instanceof ZodEffects) node = node.innerType()
62
63
  if (node instanceof ZodOptional) node = node.unwrap()
63
64
  if (node instanceof ZodNullable) node = node.unwrap()
65
+ if (node instanceof ZodDefault) node = node.removeDefault()
64
66
 
65
67
  if (node instanceof ZodObject) {
66
68
  if (path.length > 0) {
@@ -99,7 +101,13 @@ export function configToEnvSchema(schema: ZodNode) {
99
101
  return
100
102
  }
101
103
 
102
- if (node instanceof ZodString || node instanceof ZodNumber || node instanceof ZodEnum) {
104
+ if (node instanceof ZodNumber) {
105
+ envSchema[toEnvStr(path)] = z.coerce.number().optional()
106
+ envToDot[toEnvStr(path)] = dotNotation(path)
107
+ return
108
+ }
109
+
110
+ if (node instanceof ZodString || node instanceof ZodEnum) {
103
111
  envSchema[toEnvStr(path)] = node.optional()
104
112
  envToDot[toEnvStr(path)] = dotNotation(path)
105
113
  return
@@ -104,6 +104,8 @@ export type DatalayerConfig = {
104
104
  * Below is a list of all possible configurations that can be set by GraphCommerce.
105
105
  */
106
106
  export type GraphCommerceConfig = {
107
+ /** Configuration for the SidebarGallery component */
108
+ breadcrumbs?: InputMaybe<Scalars['Boolean']['input']>;
107
109
  /**
108
110
  * The canonical base URL is used for SEO purposes.
109
111
  *
@@ -157,14 +159,17 @@ export type GraphCommerceConfig = {
157
159
  * Default: 'false'
158
160
  */
159
161
  crossSellsRedirectItems?: InputMaybe<Scalars['Boolean']['input']>;
162
+ /** Enables the shipping notes field in the checkout */
163
+ customerAddressNoteEnable?: InputMaybe<Scalars['Boolean']['input']>;
160
164
  /**
161
- * Due to a limitation in the GraphQL API of Magento 2, we need to know if the
162
- * customer requires email confirmation.
163
- *
164
- * This value should match Magento 2's configuration value for
165
- * `customer/create_account/confirm` and should be removed once we can query
165
+ * Enables company fields inside the checkout:
166
+ * - Company name
167
+ * - VAT ID
166
168
  */
167
- customerRequireEmailConfirmation?: InputMaybe<Scalars['Boolean']['input']>;
169
+ customerCompanyFieldsEnable?: InputMaybe<Scalars['Boolean']['input']>;
170
+ /** Enable customer account deletion through the account section */
171
+ customerDeleteEnabled?: InputMaybe<Scalars['Boolean']['input']>;
172
+ /** Datalayer config */
168
173
  dataLayer?: InputMaybe<DatalayerConfig>;
169
174
  /** Debug configuration for GraphCommerce */
170
175
  debug?: InputMaybe<GraphCommerceDebugConfig>;
@@ -275,6 +280,12 @@ export type GraphCommerceConfig = {
275
280
  * - https://magento2.test/graphql
276
281
  */
277
282
  magentoEndpoint: Scalars['String']['input'];
283
+ /**
284
+ * Version of the Magento backend.
285
+ *
286
+ * Values: 245, 246, 247 for Magento 2.4.5, 2.4.6, 2.4.7 respectively.
287
+ */
288
+ magentoVersion: Scalars['Int']['input'];
278
289
  /** To enable next.js' preview mode, configure the secret you'd like to use. */
279
290
  previewSecret?: InputMaybe<Scalars['String']['input']>;
280
291
  /**
@@ -285,6 +296,13 @@ export type GraphCommerceConfig = {
285
296
  productFiltersLayout?: InputMaybe<ProductFiltersLayout>;
286
297
  /** Product filters with better UI for mobile and desktop. */
287
298
  productFiltersPro?: InputMaybe<Scalars['Boolean']['input']>;
299
+ /**
300
+ * Pagination variant for the product listings.
301
+ *
302
+ * COMPACT means: "< Page X of Y >"
303
+ * EXTENDED means: "< 1 2 ... 4 [5] 6 ... 10 11 >"
304
+ */
305
+ productListPaginationVariant?: InputMaybe<PaginationVariant>;
288
306
  /**
289
307
  * By default we route products to /p/[url] but you can change this to /product/[url] if you wish.
290
308
  *
@@ -345,6 +363,12 @@ export type GraphCommerceStorefrontConfig = {
345
363
  canonicalBaseUrl?: InputMaybe<Scalars['String']['input']>;
346
364
  /** Due to a limitation of the GraphQL API it is not possible to determine if a cart should be displayed including or excluding tax. */
347
365
  cartDisplayPricesInclTax?: InputMaybe<Scalars['Boolean']['input']>;
366
+ /**
367
+ * Enables company fields inside the checkout:
368
+ * - Company name
369
+ * - VAT ID
370
+ */
371
+ customerCompanyFieldsEnable?: InputMaybe<Scalars['Boolean']['input']>;
348
372
  /**
349
373
  * There can only be one entry with defaultLocale set to true.
350
374
  * - If there are more, the first one is used.
@@ -384,6 +408,11 @@ export type GraphCommerceStorefrontConfig = {
384
408
  * - b2b-us
385
409
  */
386
410
  magentoStoreCode: Scalars['String']['input'];
411
+ /**
412
+ * Allow the site to be indexed by search engines.
413
+ * If false, the robots.txt file will be set to disallow all.
414
+ */
415
+ robotsAllow?: InputMaybe<Scalars['Boolean']['input']>;
387
416
  };
388
417
 
389
418
  /** Options to configure which values will be replaced when a variant is selected on the product page. */
@@ -403,6 +432,10 @@ export type MagentoConfigurableVariantValues = {
403
432
  url?: InputMaybe<Scalars['Boolean']['input']>;
404
433
  };
405
434
 
435
+ export type PaginationVariant =
436
+ | 'COMPACT'
437
+ | 'EXTENDED';
438
+
406
439
  export type ProductFiltersLayout =
407
440
  | 'DEFAULT'
408
441
  | 'SIDEBAR';
@@ -439,6 +472,8 @@ export const definedNonNullAnySchema = z.any().refine((v) => isDefinedNonNullAny
439
472
 
440
473
  export const CompareVariantSchema = z.enum(['CHECKBOX', 'ICON']);
441
474
 
475
+ export const PaginationVariantSchema = z.enum(['COMPACT', 'EXTENDED']);
476
+
442
477
  export const ProductFiltersLayoutSchema = z.enum(['DEFAULT', 'SIDEBAR']);
443
478
 
444
479
  export const SidebarGalleryPaginationVariantSchema = z.enum(['DOTS', 'THUMBNAILS_BOTTOM']);
@@ -451,18 +486,21 @@ export function DatalayerConfigSchema(): z.ZodObject<Properties<DatalayerConfig>
451
486
 
452
487
  export function GraphCommerceConfigSchema(): z.ZodObject<Properties<GraphCommerceConfig>> {
453
488
  return z.object({
489
+ breadcrumbs: z.boolean().default(false).nullish(),
454
490
  canonicalBaseUrl: z.string().min(1),
455
491
  cartDisplayPricesInclTax: z.boolean().nullish(),
456
492
  compare: z.boolean().nullish(),
457
- compareVariant: CompareVariantSchema.nullish(),
458
- configurableVariantForSimple: z.boolean().nullish(),
493
+ compareVariant: CompareVariantSchema.default("ICON").nullish(),
494
+ configurableVariantForSimple: z.boolean().default(false).nullish(),
459
495
  configurableVariantValues: MagentoConfigurableVariantValuesSchema().nullish(),
460
- crossSellsHideCartItems: z.boolean().nullish(),
461
- crossSellsRedirectItems: z.boolean().nullish(),
462
- customerRequireEmailConfirmation: z.boolean().nullish(),
496
+ crossSellsHideCartItems: z.boolean().default(false).nullish(),
497
+ crossSellsRedirectItems: z.boolean().default(false).nullish(),
498
+ customerAddressNoteEnable: z.boolean().nullish(),
499
+ customerCompanyFieldsEnable: z.boolean().nullish(),
500
+ customerDeleteEnabled: z.boolean().nullish(),
463
501
  dataLayer: DatalayerConfigSchema().nullish(),
464
502
  debug: GraphCommerceDebugConfigSchema().nullish(),
465
- demoMode: z.boolean().nullish(),
503
+ demoMode: z.boolean().default(true).nullish(),
466
504
  enableGuestCheckoutLogin: z.boolean().nullish(),
467
505
  googleAnalyticsId: z.string().nullish(),
468
506
  googleRecaptchaKey: z.string().nullish(),
@@ -474,9 +512,11 @@ export function GraphCommerceConfigSchema(): z.ZodObject<Properties<GraphCommerc
474
512
  hygraphWriteAccessToken: z.string().nullish(),
475
513
  limitSsg: z.boolean().nullish(),
476
514
  magentoEndpoint: z.string().min(1),
515
+ magentoVersion: z.number(),
477
516
  previewSecret: z.string().nullish(),
478
- productFiltersLayout: ProductFiltersLayoutSchema.nullish(),
517
+ productFiltersLayout: ProductFiltersLayoutSchema.default("DEFAULT").nullish(),
479
518
  productFiltersPro: z.boolean().nullish(),
519
+ productListPaginationVariant: PaginationVariantSchema.default("COMPACT").nullish(),
480
520
  productRoute: z.string().nullish(),
481
521
  recentlyViewedProducts: RecentlyViewedProductsConfigSchema().nullish(),
482
522
  robotsAllow: z.boolean().nullish(),
@@ -500,6 +540,7 @@ export function GraphCommerceStorefrontConfigSchema(): z.ZodObject<Properties<Gr
500
540
  return z.object({
501
541
  canonicalBaseUrl: z.string().nullish(),
502
542
  cartDisplayPricesInclTax: z.boolean().nullish(),
543
+ customerCompanyFieldsEnable: z.boolean().nullish(),
503
544
  defaultLocale: z.boolean().nullish(),
504
545
  domain: z.string().nullish(),
505
546
  googleAnalyticsId: z.string().nullish(),
@@ -508,7 +549,8 @@ export function GraphCommerceStorefrontConfigSchema(): z.ZodObject<Properties<Gr
508
549
  hygraphLocales: z.array(z.string().min(1)).nullish(),
509
550
  linguiLocale: z.string().nullish(),
510
551
  locale: z.string().min(1),
511
- magentoStoreCode: z.string().min(1)
552
+ magentoStoreCode: z.string().min(1),
553
+ robotsAllow: z.boolean().nullish()
512
554
  })
513
555
  }
514
556