@graphcommerce/next-config 8.1.0-canary.9 → 9.0.0-canary.55

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(),
@@ -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.9",
5
+ "version": "9.0.0-canary.55",
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.
@@ -408,6 +432,10 @@ export type MagentoConfigurableVariantValues = {
408
432
  url?: InputMaybe<Scalars['Boolean']['input']>;
409
433
  };
410
434
 
435
+ export type PaginationVariant =
436
+ | 'COMPACT'
437
+ | 'EXTENDED';
438
+
411
439
  export type ProductFiltersLayout =
412
440
  | 'DEFAULT'
413
441
  | 'SIDEBAR';
@@ -444,6 +472,8 @@ export const definedNonNullAnySchema = z.any().refine((v) => isDefinedNonNullAny
444
472
 
445
473
  export const CompareVariantSchema = z.enum(['CHECKBOX', 'ICON']);
446
474
 
475
+ export const PaginationVariantSchema = z.enum(['COMPACT', 'EXTENDED']);
476
+
447
477
  export const ProductFiltersLayoutSchema = z.enum(['DEFAULT', 'SIDEBAR']);
448
478
 
449
479
  export const SidebarGalleryPaginationVariantSchema = z.enum(['DOTS', 'THUMBNAILS_BOTTOM']);
@@ -456,18 +486,21 @@ export function DatalayerConfigSchema(): z.ZodObject<Properties<DatalayerConfig>
456
486
 
457
487
  export function GraphCommerceConfigSchema(): z.ZodObject<Properties<GraphCommerceConfig>> {
458
488
  return z.object({
489
+ breadcrumbs: z.boolean().default(false).nullish(),
459
490
  canonicalBaseUrl: z.string().min(1),
460
491
  cartDisplayPricesInclTax: z.boolean().nullish(),
461
492
  compare: z.boolean().nullish(),
462
- compareVariant: CompareVariantSchema.nullish(),
463
- configurableVariantForSimple: z.boolean().nullish(),
493
+ compareVariant: CompareVariantSchema.default("ICON").nullish(),
494
+ configurableVariantForSimple: z.boolean().default(false).nullish(),
464
495
  configurableVariantValues: MagentoConfigurableVariantValuesSchema().nullish(),
465
- crossSellsHideCartItems: z.boolean().nullish(),
466
- crossSellsRedirectItems: z.boolean().nullish(),
467
- 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(),
468
501
  dataLayer: DatalayerConfigSchema().nullish(),
469
502
  debug: GraphCommerceDebugConfigSchema().nullish(),
470
- demoMode: z.boolean().nullish(),
503
+ demoMode: z.boolean().default(true).nullish(),
471
504
  enableGuestCheckoutLogin: z.boolean().nullish(),
472
505
  googleAnalyticsId: z.string().nullish(),
473
506
  googleRecaptchaKey: z.string().nullish(),
@@ -479,9 +512,11 @@ export function GraphCommerceConfigSchema(): z.ZodObject<Properties<GraphCommerc
479
512
  hygraphWriteAccessToken: z.string().nullish(),
480
513
  limitSsg: z.boolean().nullish(),
481
514
  magentoEndpoint: z.string().min(1),
515
+ magentoVersion: z.number(),
482
516
  previewSecret: z.string().nullish(),
483
- productFiltersLayout: ProductFiltersLayoutSchema.nullish(),
517
+ productFiltersLayout: ProductFiltersLayoutSchema.default("DEFAULT").nullish(),
484
518
  productFiltersPro: z.boolean().nullish(),
519
+ productListPaginationVariant: PaginationVariantSchema.default("COMPACT").nullish(),
485
520
  productRoute: z.string().nullish(),
486
521
  recentlyViewedProducts: RecentlyViewedProductsConfigSchema().nullish(),
487
522
  robotsAllow: z.boolean().nullish(),
@@ -505,6 +540,7 @@ export function GraphCommerceStorefrontConfigSchema(): z.ZodObject<Properties<Gr
505
540
  return z.object({
506
541
  canonicalBaseUrl: z.string().nullish(),
507
542
  cartDisplayPricesInclTax: z.boolean().nullish(),
543
+ customerCompanyFieldsEnable: z.boolean().nullish(),
508
544
  defaultLocale: z.boolean().nullish(),
509
545
  domain: z.string().nullish(),
510
546
  googleAnalyticsId: z.string().nullish(),