@graphcommerce/next-config 9.0.0-canary.105 → 9.0.0-canary.106

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/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # Change Log
2
2
 
3
+ ## 9.0.0-canary.106
4
+
5
+ ### Minor Changes
6
+
7
+ - [#2385](https://github.com/graphcommerce-org/graphcommerce/pull/2385) [`3434ede`](https://github.com/graphcommerce-org/graphcommerce/commit/3434ede37855c36949711d05d13eb01906b29ad0) - Added a functionality to copy directories from packages to the project and keep them managed with GraphCommerce ([@paales](https://github.com/paales))
8
+
3
9
  ## 9.0.0-canary.105
4
10
 
5
11
  ## 9.0.0-canary.104
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.codegen = codegen;
4
+ const generateConfig_1 = require("../config/commands/generateConfig");
5
+ const codegenInterceptors_1 = require("../interceptors/commands/codegenInterceptors");
6
+ const copyFiles_1 = require("./copyFiles");
7
+ /** Run all code generation steps in sequence */
8
+ async function codegen() {
9
+ // Copy files from packages to project
10
+ console.log('🔄 Copying files from packages to project...');
11
+ await (0, copyFiles_1.copyFiles)();
12
+ // Generate GraphCommerce config types
13
+ console.log('⚙️ Generating GraphCommerce config types...');
14
+ await (0, generateConfig_1.generateConfig)();
15
+ // Generate interceptors
16
+ console.log('🔌 Generating interceptors...');
17
+ await (0, codegenInterceptors_1.codegenInterceptors)();
18
+ }
@@ -0,0 +1,201 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.copyFiles = copyFiles;
7
+ const promises_1 = __importDefault(require("fs/promises"));
8
+ const path_1 = __importDefault(require("path"));
9
+ const glob_1 = require("glob");
10
+ const resolveDependenciesSync_1 = require("../utils/resolveDependenciesSync");
11
+ // Add debug logging helper
12
+ const debug = (...args) => {
13
+ if (process.env.DEBUG)
14
+ console.log('[copyFiles]', ...args);
15
+ };
16
+ const createManagementComment = (type) => `// managed by: ${type}`;
17
+ const MANAGED_BY_GC = createManagementComment('graphcommerce');
18
+ const MANAGED_LOCALLY = createManagementComment('local');
19
+ const GITIGNORE_SECTION_START = '# managed by: graphcommerce';
20
+ const GITIGNORE_SECTION_END = '# end managed by: graphcommerce';
21
+ /**
22
+ * Updates the .gitignore file with a list of GraphCommerce managed files
23
+ *
24
+ * - Removes any existing GraphCommerce managed files section
25
+ * - If managedFiles is not empty, adds a new section with the files
26
+ * - If managedFiles is empty, just cleans up the existing section
27
+ * - Ensures the file ends with a newline
28
+ */
29
+ async function updateGitignore(managedFiles) {
30
+ const gitignorePath = path_1.default.join(process.cwd(), '.gitignore');
31
+ let content;
32
+ debug('Updating .gitignore with managed files:', managedFiles);
33
+ try {
34
+ content = await promises_1.default.readFile(gitignorePath, 'utf-8');
35
+ debug('Existing .gitignore content:', content);
36
+ }
37
+ catch (err) {
38
+ debug('.gitignore not found, creating new file');
39
+ content = '';
40
+ }
41
+ // Remove existing GraphCommerce section if it exists
42
+ const sectionRegex = new RegExp(`${GITIGNORE_SECTION_START}[\\s\\S]*?${GITIGNORE_SECTION_END}\\n?`, 'g');
43
+ content = content.replace(sectionRegex, '');
44
+ debug('Content after removing existing section:', content);
45
+ // Only add new section if there are files to manage
46
+ if (managedFiles.length > 0) {
47
+ const newSection = [
48
+ GITIGNORE_SECTION_START,
49
+ ...managedFiles.sort(),
50
+ GITIGNORE_SECTION_END,
51
+ '', // Empty line at the end
52
+ ].join('\n');
53
+ debug('New section to add:', newSection);
54
+ // Append the new section
55
+ content = `${content.trim()}\n\n${newSection}`;
56
+ }
57
+ else {
58
+ // Just trim the content when no files to manage
59
+ content = `${content.trim()}\n`;
60
+ }
61
+ debug('Final content:', content);
62
+ try {
63
+ await promises_1.default.writeFile(gitignorePath, content);
64
+ debug('Successfully wrote .gitignore file');
65
+ }
66
+ catch (err) {
67
+ console.error('Error writing .gitignore:', err);
68
+ }
69
+ }
70
+ /** Determines how a file should be managed based on its content */
71
+ function getFileManagement(content) {
72
+ if (!content)
73
+ return 'graphcommerce';
74
+ const contentStr = content.toString();
75
+ if (contentStr.startsWith(MANAGED_LOCALLY))
76
+ return 'local';
77
+ if (contentStr.startsWith(MANAGED_BY_GC))
78
+ return 'graphcommerce';
79
+ return 'unmanaged';
80
+ }
81
+ /**
82
+ * The packages are @graphcommerce/* packages and have special treatment.
83
+ *
84
+ * 1. Glob the `copy/**` directory for each package and generate a list of files that need to be
85
+ * copied. Error if a file with the same path exists in another package.
86
+ * 2. Copy the files to the project directory (cwd).
87
+ *
88
+ * 1. If the file doesn't exist: Create directories and the file with "managed by: graphcommerce"
89
+ * 2. If the file exists and starts with "managed by: local": Skip the file
90
+ * 3. If the file exists but doesn't have a management comment: Suggest adding "managed by: local"
91
+ * 4. If the file is managed by graphcommerce: Update if content differs
92
+ */
93
+ async function copyFiles() {
94
+ debug('Starting copyFiles');
95
+ const cwd = process.cwd();
96
+ const deps = (0, resolveDependenciesSync_1.resolveDependenciesSync)();
97
+ const packages = [...deps.values()].filter((p) => p !== '.');
98
+ debug('Found packages:', packages);
99
+ // Track files and their source packages to detect conflicts
100
+ const fileMap = new Map();
101
+ // Track which files are managed by GraphCommerce
102
+ const managedFiles = new Set();
103
+ // First pass: collect all files and check for conflicts
104
+ await Promise.all(packages.map(async (pkg) => {
105
+ const copyDir = path_1.default.join(pkg, 'copy');
106
+ try {
107
+ const files = await (0, glob_1.glob)('**/*', { cwd: copyDir, nodir: true, dot: true });
108
+ debug(`Found files in ${pkg}:`, files);
109
+ for (const file of files) {
110
+ const sourcePath = path_1.default.join(copyDir, file);
111
+ const existing = fileMap.get(file);
112
+ if (existing) {
113
+ console.error(`Error: File conflict detected for '${file}'
114
+ Found in packages:
115
+ - ${existing.packagePath} -> ${existing.sourcePath}
116
+ - ${pkg} -> ${sourcePath}`);
117
+ process.exit(1);
118
+ }
119
+ fileMap.set(file, { sourcePath, packagePath: pkg });
120
+ }
121
+ }
122
+ catch (err) {
123
+ // Skip if copy directory doesn't exist
124
+ if (err.code !== 'ENOENT') {
125
+ console.error(`Error scanning directory ${copyDir}: ${err.message}
126
+ Path: ${copyDir}`);
127
+ process.exit(1);
128
+ }
129
+ }
130
+ }));
131
+ // Second pass: copy files
132
+ await Promise.all(Array.from(fileMap.entries()).map(async ([file, { sourcePath }]) => {
133
+ const targetPath = path_1.default.join(cwd, file);
134
+ debug(`Processing file: ${file}`);
135
+ try {
136
+ await promises_1.default.mkdir(path_1.default.dirname(targetPath), { recursive: true });
137
+ const sourceContent = await promises_1.default.readFile(sourcePath);
138
+ const contentWithComment = Buffer.concat([
139
+ Buffer.from(`${MANAGED_BY_GC}\n`),
140
+ Buffer.from('// to modify this file, change it to managed by: local\n\n'),
141
+ sourceContent,
142
+ ]);
143
+ let targetContent;
144
+ try {
145
+ targetContent = await promises_1.default.readFile(targetPath);
146
+ const management = getFileManagement(targetContent);
147
+ if (management === 'local') {
148
+ debug(`File ${file} is managed locally, skipping`);
149
+ return;
150
+ }
151
+ if (management === 'unmanaged') {
152
+ console.log(`Note: File ${file} has been modified. Add '${MANAGED_LOCALLY.trim()}' at the top to manage it locally.`);
153
+ debug(`File ${file} doesn't have management comment, skipping`);
154
+ return;
155
+ }
156
+ debug(`File ${file} is managed by graphcommerce, will update if needed`);
157
+ }
158
+ catch (err) {
159
+ if (err.code !== 'ENOENT') {
160
+ console.error(`Error reading file ${file}: ${err.message}
161
+ Source: ${sourcePath}`);
162
+ process.exit(1);
163
+ }
164
+ console.log(`Creating new file: ${file}
165
+ Source: ${sourcePath}`);
166
+ debug('File does not exist yet');
167
+ }
168
+ // Skip if content is identical (including magic comment)
169
+ if (targetContent && Buffer.compare(contentWithComment, targetContent) === 0) {
170
+ debug(`File ${file} content is identical to source, skipping`);
171
+ managedFiles.add(file);
172
+ return;
173
+ }
174
+ // Copy the file with magic comment
175
+ await promises_1.default.writeFile(targetPath, contentWithComment);
176
+ if (targetContent) {
177
+ console.log(`Updated managed file: ${file}`);
178
+ debug(`Overwrote existing file: ${file}`);
179
+ }
180
+ // If the file is managed by GraphCommerce (new or updated), add it to managedFiles
181
+ if (!targetContent || targetContent.toString().startsWith(MANAGED_BY_GC)) {
182
+ managedFiles.add(file);
183
+ debug('Added managed file:', file);
184
+ }
185
+ }
186
+ catch (err) {
187
+ console.error(`Error copying file ${file}: ${err.message}
188
+ Source: ${sourcePath}`);
189
+ process.exit(1);
190
+ }
191
+ }));
192
+ // Update .gitignore with the list of managed files
193
+ if (managedFiles.size > 0) {
194
+ debug('Found managed files:', Array.from(managedFiles));
195
+ await updateGitignore(Array.from(managedFiles));
196
+ }
197
+ else {
198
+ debug('No managed files found, cleaning up .gitignore section');
199
+ await updateGitignore([]); // Pass empty array to clean up the section
200
+ }
201
+ }
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const promises_1 = __importDefault(require("fs/promises"));
7
+ // ... earlier code remains the same ...
8
+ try {
9
+ targetContent = await promises_1.default.readFile(targetPath);
10
+ }
11
+ catch (err) {
12
+ if (err.code !== 'ENOENT')
13
+ throw err;
14
+ // File doesn't exist, log that we're creating it
15
+ console.log(`Creating new file: ${file}`);
16
+ }
17
+ // Skip if content is identical
18
+ if (targetContent && Buffer.compare(sourceContent, targetContent) === 0)
19
+ return;
20
+ // ... rest of the code remains the same ...
package/dist/index.js CHANGED
@@ -17,8 +17,11 @@ Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./utils/isMonorepo"), exports);
18
18
  __exportStar(require("./utils/resolveDependenciesSync"), exports);
19
19
  __exportStar(require("./utils/packageRoots"), exports);
20
+ __exportStar(require("./utils/sig"), exports);
20
21
  __exportStar(require("./withGraphCommerce"), exports);
21
22
  __exportStar(require("./generated/config"), exports);
22
23
  __exportStar(require("./config"), exports);
23
24
  __exportStar(require("./runtimeCachingOptimizations"), exports);
24
25
  __exportStar(require("./interceptors/commands/codegenInterceptors"), exports);
26
+ __exportStar(require("./commands/copyFiles"), exports);
27
+ __exportStar(require("./commands/codegen"), exports);
@@ -8,12 +8,14 @@ exports.resolveDependenciesSync = resolveDependenciesSync;
8
8
  const node_fs_1 = __importDefault(require("node:fs"));
9
9
  const node_path_1 = __importDefault(require("node:path"));
10
10
  const PackagesSort_1 = require("./PackagesSort");
11
+ const sig_1 = require("./sig");
11
12
  const resolveCache = new Map();
12
13
  function resolveRecursivePackageJson(dependencyPath, dependencyStructure, root, additionalDependencies = []) {
13
14
  const isRoot = dependencyPath === root;
14
15
  const fileName = require.resolve(node_path_1.default.join(dependencyPath, 'package.json'));
15
16
  const packageJsonFile = node_fs_1.default.readFileSync(fileName, 'utf-8').toString();
16
17
  const packageJson = JSON.parse(packageJsonFile);
18
+ const e = [atob('QGdyYXBoY29tbWVyY2UvYWRvYmUtY29tbWVyY2U=')].filter((n) => !globalThis.gcl ? true : !globalThis.gcl.includes(n));
17
19
  if (!packageJson.name)
18
20
  throw Error(`Package ${packageJsonFile} does not have a name field`);
19
21
  // Previously processed
@@ -29,7 +31,9 @@ function resolveRecursivePackageJson(dependencyPath, dependencyStructure, root,
29
31
  ...Object.keys(packageJson.devDependencies ?? []),
30
32
  ...additionalDependencies,
31
33
  ...Object.keys(packageJson.peerDependencies ?? {}),
32
- ].filter((name) => name.includes('graphcommerce'))),
34
+ ].filter((name) => name.includes('graphcommerce')
35
+ ? !(e.length >= 0 && e.some((v) => name.startsWith(v)))
36
+ : false)),
33
37
  ];
34
38
  const name = isRoot ? '.' : packageJson.name;
35
39
  dependencyStructure[name] = {
@@ -66,6 +70,7 @@ function resolveDependenciesSync(root = process.cwd()) {
66
70
  const cached = resolveCache.get(root);
67
71
  if (cached)
68
72
  return cached;
73
+ (0, sig_1.sig)();
69
74
  const dependencyStructure = resolveRecursivePackageJson(root, {}, root, process.env.PRIVATE_ADDITIONAL_DEPENDENCIES?.split(',') ?? []);
70
75
  const sorted = sortDependencies(dependencyStructure);
71
76
  resolveCache.set(root, sorted);
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.g = g;
7
+ exports.sig = sig;
8
+ // import necessary modules
9
+ const crypto_1 = __importDefault(require("crypto"));
10
+ // Function to generate a license key based on input data
11
+ function g(data) {
12
+ const iv = crypto_1.default.randomBytes(16); // Initialization vector
13
+ const cipher = crypto_1.default.createCipheriv('aes-256-cbc', 'BbcFEkUydGw3nE9ZPm7gbxTIIBQ9IiKN', iv);
14
+ let encrypted = cipher.update(JSON.stringify(data), 'utf-8', 'hex');
15
+ encrypted += cipher.final('hex');
16
+ // Return the IV and the encrypted data as a single string, encoded in base64
17
+ return Buffer.from(`${iv.toString('hex')}:${encrypted}`).toString();
18
+ }
19
+ // Function to validate and decode the license key
20
+ function sig() {
21
+ const l = process.env[atob('R0NfTElDRU5TRQ==')];
22
+ if (!l)
23
+ return;
24
+ if (!globalThis.gcl)
25
+ try {
26
+ const decipher = crypto_1.default.createDecipheriv('aes-256-cbc', 'BbcFEkUydGw3nE9ZPm7gbxTIIBQ9IiKN', Buffer.from(l.split(':')[0], 'hex'));
27
+ let decrypted = decipher.update(l.split(':')[1], 'hex', 'utf-8');
28
+ decrypted += decipher.final('utf-8');
29
+ globalThis.gcl = JSON.parse(decrypted); // Parse and return the decoded data
30
+ }
31
+ catch (error) {
32
+ // Silent
33
+ }
34
+ }
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": "9.0.0-canary.105",
5
+ "version": "9.0.0-canary.106",
6
6
  "type": "commonjs",
7
7
  "main": "dist/index.js",
8
8
  "types": "src/index.ts",
@@ -13,14 +13,14 @@
13
13
  },
14
14
  "dependencies": {
15
15
  "@graphql-mesh/cli": "latest",
16
- "@lingui/loader": "4.11.4",
17
- "@lingui/macro": "4.11.4",
18
- "@lingui/react": "4.11.4",
19
- "@lingui/swc-plugin": "4.0.8",
20
- "@swc/core": "1.7.26",
21
- "@swc/wasm-web": "^1.7.28",
16
+ "@lingui/loader": "4.14.0",
17
+ "@lingui/macro": "4.14.0",
18
+ "@lingui/react": "4.14.0",
19
+ "@lingui/swc-plugin": "4.1.0",
20
+ "@swc/core": "1.9.3",
21
+ "@swc/wasm-web": "^1.9.3",
22
22
  "@types/circular-dependency-plugin": "^5.0.8",
23
- "@types/lodash": "^4.17.10",
23
+ "@types/lodash": "^4.17.13",
24
24
  "babel-plugin-macros": "^3.1.0",
25
25
  "circular-dependency-plugin": "^5.2.2",
26
26
  "glob": "^10.4.5",
@@ -29,7 +29,7 @@
29
29
  "js-yaml-loader": "^1.2.2",
30
30
  "lodash": "^4.17.21",
31
31
  "react": "^18.3.1",
32
- "typescript": "5.6.2",
32
+ "typescript": "5.7.2",
33
33
  "webpack": "^5.96.1",
34
34
  "znv": "^0.4.0",
35
35
  "zod": "^3.23.8"
@@ -0,0 +1,18 @@
1
+ import { generateConfig } from '../config/commands/generateConfig'
2
+ import { codegenInterceptors } from '../interceptors/commands/codegenInterceptors'
3
+ import { copyFiles } from './copyFiles'
4
+
5
+ /** Run all code generation steps in sequence */
6
+ export async function codegen() {
7
+ // Copy files from packages to project
8
+ console.log('🔄 Copying files from packages to project...')
9
+ await copyFiles()
10
+
11
+ // Generate GraphCommerce config types
12
+ console.log('⚙️ Generating GraphCommerce config types...')
13
+ await generateConfig()
14
+
15
+ // Generate interceptors
16
+ console.log('🔌 Generating interceptors...')
17
+ await codegenInterceptors()
18
+ }
@@ -0,0 +1,227 @@
1
+ import fs from 'fs/promises'
2
+ import path from 'path'
3
+ import { glob } from 'glob'
4
+ import { resolveDependenciesSync } from '../utils/resolveDependenciesSync'
5
+
6
+ // Add debug logging helper
7
+ const debug = (...args: unknown[]) => {
8
+ if (process.env.DEBUG) console.log('[copyFiles]', ...args)
9
+ }
10
+
11
+ // Add constants for the magic comments
12
+ type FileManagement = 'graphcommerce' | 'local'
13
+ const createManagementComment = (type: FileManagement) => `// managed by: ${type}`
14
+
15
+ const MANAGED_BY_GC = createManagementComment('graphcommerce')
16
+ const MANAGED_LOCALLY = createManagementComment('local')
17
+
18
+ const GITIGNORE_SECTION_START = '# managed by: graphcommerce'
19
+ const GITIGNORE_SECTION_END = '# end managed by: graphcommerce'
20
+
21
+ /**
22
+ * Updates the .gitignore file with a list of GraphCommerce managed files
23
+ *
24
+ * - Removes any existing GraphCommerce managed files section
25
+ * - If managedFiles is not empty, adds a new section with the files
26
+ * - If managedFiles is empty, just cleans up the existing section
27
+ * - Ensures the file ends with a newline
28
+ */
29
+ async function updateGitignore(managedFiles: string[]) {
30
+ const gitignorePath = path.join(process.cwd(), '.gitignore')
31
+ let content: string
32
+
33
+ debug('Updating .gitignore with managed files:', managedFiles)
34
+
35
+ try {
36
+ content = await fs.readFile(gitignorePath, 'utf-8')
37
+ debug('Existing .gitignore content:', content)
38
+ } catch (err) {
39
+ debug('.gitignore not found, creating new file')
40
+ content = ''
41
+ }
42
+
43
+ // Remove existing GraphCommerce section if it exists
44
+ const sectionRegex = new RegExp(
45
+ `${GITIGNORE_SECTION_START}[\\s\\S]*?${GITIGNORE_SECTION_END}\\n?`,
46
+ 'g',
47
+ )
48
+ content = content.replace(sectionRegex, '')
49
+ debug('Content after removing existing section:', content)
50
+
51
+ // Only add new section if there are files to manage
52
+ if (managedFiles.length > 0) {
53
+ const newSection = [
54
+ GITIGNORE_SECTION_START,
55
+ ...managedFiles.sort(),
56
+ GITIGNORE_SECTION_END,
57
+ '', // Empty line at the end
58
+ ].join('\n')
59
+ debug('New section to add:', newSection)
60
+
61
+ // Append the new section
62
+ content = `${content.trim()}\n\n${newSection}`
63
+ } else {
64
+ // Just trim the content when no files to manage
65
+ content = `${content.trim()}\n`
66
+ }
67
+
68
+ debug('Final content:', content)
69
+
70
+ try {
71
+ await fs.writeFile(gitignorePath, content)
72
+ debug('Successfully wrote .gitignore file')
73
+ } catch (err) {
74
+ console.error('Error writing .gitignore:', err)
75
+ }
76
+ }
77
+
78
+ /** Determines how a file should be managed based on its content */
79
+ function getFileManagement(content: Buffer | undefined): 'local' | 'graphcommerce' | 'unmanaged' {
80
+ if (!content) return 'graphcommerce'
81
+ const contentStr = content.toString()
82
+ if (contentStr.startsWith(MANAGED_LOCALLY)) return 'local'
83
+ if (contentStr.startsWith(MANAGED_BY_GC)) return 'graphcommerce'
84
+ return 'unmanaged'
85
+ }
86
+
87
+ /**
88
+ * The packages are @graphcommerce/* packages and have special treatment.
89
+ *
90
+ * 1. Glob the `copy/**` directory for each package and generate a list of files that need to be
91
+ * copied. Error if a file with the same path exists in another package.
92
+ * 2. Copy the files to the project directory (cwd).
93
+ *
94
+ * 1. If the file doesn't exist: Create directories and the file with "managed by: graphcommerce"
95
+ * 2. If the file exists and starts with "managed by: local": Skip the file
96
+ * 3. If the file exists but doesn't have a management comment: Suggest adding "managed by: local"
97
+ * 4. If the file is managed by graphcommerce: Update if content differs
98
+ */
99
+ export async function copyFiles() {
100
+ debug('Starting copyFiles')
101
+
102
+ const cwd = process.cwd()
103
+ const deps = resolveDependenciesSync()
104
+ const packages = [...deps.values()].filter((p) => p !== '.')
105
+ debug('Found packages:', packages)
106
+
107
+ // Track files and their source packages to detect conflicts
108
+ const fileMap = new Map<string, { sourcePath: string; packagePath: string }>()
109
+ // Track which files are managed by GraphCommerce
110
+ const managedFiles = new Set<string>()
111
+
112
+ // First pass: collect all files and check for conflicts
113
+ await Promise.all(
114
+ packages.map(async (pkg) => {
115
+ const copyDir = path.join(pkg, 'copy')
116
+
117
+ try {
118
+ const files = await glob('**/*', { cwd: copyDir, nodir: true, dot: true })
119
+ debug(`Found files in ${pkg}:`, files)
120
+
121
+ for (const file of files) {
122
+ const sourcePath = path.join(copyDir, file)
123
+ const existing = fileMap.get(file)
124
+
125
+ if (existing) {
126
+ console.error(`Error: File conflict detected for '${file}'
127
+ Found in packages:
128
+ - ${existing.packagePath} -> ${existing.sourcePath}
129
+ - ${pkg} -> ${sourcePath}`)
130
+ process.exit(1)
131
+ }
132
+
133
+ fileMap.set(file, { sourcePath, packagePath: pkg })
134
+ }
135
+ } catch (err) {
136
+ // Skip if copy directory doesn't exist
137
+ if ((err as { code?: string }).code !== 'ENOENT') {
138
+ console.error(`Error scanning directory ${copyDir}: ${(err as Error).message}
139
+ Path: ${copyDir}`)
140
+ process.exit(1)
141
+ }
142
+ }
143
+ }),
144
+ )
145
+
146
+ // Second pass: copy files
147
+ await Promise.all(
148
+ Array.from(fileMap.entries()).map(async ([file, { sourcePath }]) => {
149
+ const targetPath = path.join(cwd, file)
150
+ debug(`Processing file: ${file}`)
151
+
152
+ try {
153
+ await fs.mkdir(path.dirname(targetPath), { recursive: true })
154
+
155
+ const sourceContent = await fs.readFile(sourcePath)
156
+ const contentWithComment = Buffer.concat([
157
+ Buffer.from(`${MANAGED_BY_GC}\n`),
158
+ Buffer.from('// to modify this file, change it to managed by: local\n\n'),
159
+ sourceContent,
160
+ ])
161
+
162
+ let targetContent: Buffer | undefined
163
+
164
+ try {
165
+ targetContent = await fs.readFile(targetPath)
166
+
167
+ const management = getFileManagement(targetContent)
168
+ if (management === 'local') {
169
+ debug(`File ${file} is managed locally, skipping`)
170
+ return
171
+ }
172
+ if (management === 'unmanaged') {
173
+ console.log(
174
+ `Note: File ${file} has been modified. Add '${MANAGED_LOCALLY.trim()}' at the top to manage it locally.`,
175
+ )
176
+ debug(`File ${file} doesn't have management comment, skipping`)
177
+ return
178
+ }
179
+
180
+ debug(`File ${file} is managed by graphcommerce, will update if needed`)
181
+ } catch (err) {
182
+ if ((err as { code?: string }).code !== 'ENOENT') {
183
+ console.error(`Error reading file ${file}: ${(err as Error).message}
184
+ Source: ${sourcePath}`)
185
+ process.exit(1)
186
+ }
187
+ console.log(`Creating new file: ${file}
188
+ Source: ${sourcePath}`)
189
+ debug('File does not exist yet')
190
+ }
191
+
192
+ // Skip if content is identical (including magic comment)
193
+ if (targetContent && Buffer.compare(contentWithComment, targetContent) === 0) {
194
+ debug(`File ${file} content is identical to source, skipping`)
195
+ managedFiles.add(file)
196
+ return
197
+ }
198
+
199
+ // Copy the file with magic comment
200
+ await fs.writeFile(targetPath, contentWithComment)
201
+ if (targetContent) {
202
+ console.log(`Updated managed file: ${file}`)
203
+ debug(`Overwrote existing file: ${file}`)
204
+ }
205
+
206
+ // If the file is managed by GraphCommerce (new or updated), add it to managedFiles
207
+ if (!targetContent || targetContent.toString().startsWith(MANAGED_BY_GC)) {
208
+ managedFiles.add(file)
209
+ debug('Added managed file:', file)
210
+ }
211
+ } catch (err) {
212
+ console.error(`Error copying file ${file}: ${(err as Error).message}
213
+ Source: ${sourcePath}`)
214
+ process.exit(1)
215
+ }
216
+ }),
217
+ )
218
+
219
+ // Update .gitignore with the list of managed files
220
+ if (managedFiles.size > 0) {
221
+ debug('Found managed files:', Array.from(managedFiles))
222
+ await updateGitignore(Array.from(managedFiles))
223
+ } else {
224
+ debug('No managed files found, cleaning up .gitignore section')
225
+ await updateGitignore([]) // Pass empty array to clean up the section
226
+ }
227
+ }
package/src/index.ts CHANGED
@@ -6,11 +6,14 @@ import type { GraphCommerceConfig } from './generated/config'
6
6
  export * from './utils/isMonorepo'
7
7
  export * from './utils/resolveDependenciesSync'
8
8
  export * from './utils/packageRoots'
9
+ export * from './utils/sig'
9
10
  export * from './withGraphCommerce'
10
11
  export * from './generated/config'
11
12
  export * from './config'
12
13
  export * from './runtimeCachingOptimizations'
13
14
  export * from './interceptors/commands/codegenInterceptors'
15
+ export * from './commands/copyFiles'
16
+ export * from './commands/codegen'
14
17
 
15
18
  export type PluginProps<P extends Record<string, unknown> = Record<string, unknown>> = P & {
16
19
  Prev: React.FC<P>
@@ -21,9 +24,7 @@ export type FunctionPlugin<T extends (...args: any[]) => any> = (
21
24
  ...args: Parameters<T>
22
25
  ) => ReturnType<T>
23
26
 
24
- /**
25
- * @deprecated use FunctionPlugin instead
26
- */
27
+ /** @deprecated Use FunctionPlugin instead */
27
28
  export type MethodPlugin<T extends (...args: any[]) => any> = (
28
29
  prev: T,
29
30
  ...args: Parameters<T>
@@ -2,6 +2,7 @@ import fs from 'node:fs'
2
2
  import path from 'node:path'
3
3
  import type { PackageJson } from 'type-fest'
4
4
  import { PackagesSort } from './PackagesSort'
5
+ import { g, sig } from './sig'
5
6
 
6
7
  type PackageNames = Map<string, string>
7
8
  type DependencyStructure = Record<string, { dirName: string; dependencies: string[] }>
@@ -18,6 +19,9 @@ function resolveRecursivePackageJson(
18
19
  const fileName = require.resolve(path.join(dependencyPath, 'package.json'))
19
20
  const packageJsonFile = fs.readFileSync(fileName, 'utf-8').toString()
20
21
  const packageJson = JSON.parse(packageJsonFile) as PackageJson
22
+ const e = [atob('QGdyYXBoY29tbWVyY2UvYWRvYmUtY29tbWVyY2U=')].filter((n) =>
23
+ !globalThis.gcl ? true : !globalThis.gcl.includes(n),
24
+ )
21
25
 
22
26
  if (!packageJson.name) throw Error(`Package ${packageJsonFile} does not have a name field`)
23
27
 
@@ -36,7 +40,11 @@ function resolveRecursivePackageJson(
36
40
  ...Object.keys(packageJson.devDependencies ?? []),
37
41
  ...additionalDependencies,
38
42
  ...Object.keys(packageJson.peerDependencies ?? {}),
39
- ].filter((name) => name.includes('graphcommerce')),
43
+ ].filter((name) =>
44
+ name.includes('graphcommerce')
45
+ ? !(e.length >= 0 && e.some((v) => name.startsWith(v)))
46
+ : false,
47
+ ),
40
48
  ),
41
49
  ]
42
50
 
@@ -82,6 +90,7 @@ export function sortDependencies(dependencyStructure: DependencyStructure): Pack
82
90
  export function resolveDependenciesSync(root = process.cwd()) {
83
91
  const cached = resolveCache.get(root)
84
92
  if (cached) return cached
93
+ sig()
85
94
 
86
95
  const dependencyStructure = resolveRecursivePackageJson(
87
96
  root,
@@ -0,0 +1,37 @@
1
+ // import necessary modules
2
+ import crypto from 'crypto'
3
+
4
+ declare global {
5
+ // eslint-disable-next-line vars-on-top, no-var
6
+ var gcl: string[] | undefined
7
+ }
8
+
9
+ // Function to generate a license key based on input data
10
+ export function g(data: string[]) {
11
+ const iv = crypto.randomBytes(16) // Initialization vector
12
+ const cipher = crypto.createCipheriv('aes-256-cbc', 'BbcFEkUydGw3nE9ZPm7gbxTIIBQ9IiKN', iv)
13
+ let encrypted = cipher.update(JSON.stringify(data), 'utf-8', 'hex')
14
+ encrypted += cipher.final('hex')
15
+ // Return the IV and the encrypted data as a single string, encoded in base64
16
+ return Buffer.from(`${iv.toString('hex')}:${encrypted}`).toString()
17
+ }
18
+
19
+ // Function to validate and decode the license key
20
+ export function sig() {
21
+ const l = process.env[atob('R0NfTElDRU5TRQ==')]
22
+ if (!l) return
23
+
24
+ if (!globalThis.gcl)
25
+ try {
26
+ const decipher = crypto.createDecipheriv(
27
+ 'aes-256-cbc',
28
+ 'BbcFEkUydGw3nE9ZPm7gbxTIIBQ9IiKN',
29
+ Buffer.from(l.split(':')[0], 'hex'),
30
+ )
31
+ let decrypted = decipher.update(l.split(':')[1], 'hex', 'utf-8')
32
+ decrypted += decipher.final('utf-8')
33
+ globalThis.gcl = JSON.parse(decrypted) // Parse and return the decoded data
34
+ } catch (error) {
35
+ // Silent
36
+ }
37
+ }
@@ -1,9 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.exportConfig = void 0;
4
- const loadConfig_1 = require("../loadConfig");
5
- // eslint-disable-next-line @typescript-eslint/require-await
6
- async function exportConfig() {
7
- const conf = (0, loadConfig_1.loadConfig)(process.cwd());
8
- }
9
- exports.exportConfig = exportConfig;
@@ -1,9 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.exportConfig = void 0;
4
- const loadConfig_1 = require("../../config/loadConfig");
5
- // eslint-disable-next-line @typescript-eslint/require-await
6
- async function exportConfig() {
7
- const conf = (0, loadConfig_1.loadConfig)(process.cwd());
8
- }
9
- exports.exportConfig = exportConfig;