@commercetools-frontend/mc-scripts 25.0.0 → 25.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.
Files changed (84) hide show
  1. package/application-runtime/dist/commercetools-frontend-mc-scripts-application-runtime.cjs.dev.js +1 -1
  2. package/application-runtime/dist/commercetools-frontend-mc-scripts-application-runtime.cjs.prod.js +1 -1
  3. package/application-runtime/dist/commercetools-frontend-mc-scripts-application-runtime.esm.js +1 -1
  4. package/cli/dist/commercetools-frontend-mc-scripts-cli.cjs.dev.js +28 -14
  5. package/cli/dist/commercetools-frontend-mc-scripts-cli.cjs.prod.js +28 -14
  6. package/cli/dist/commercetools-frontend-mc-scripts-cli.esm.js +28 -14
  7. package/dist/{build-50f29fb0.cjs.prod.js → build-182a099c.cjs.prod.js} +7 -7
  8. package/dist/{build-0b4c6b04.esm.js → build-220a1658.esm.js} +7 -7
  9. package/dist/{build-1baf8a00.cjs.dev.js → build-519d246d.cjs.dev.js} +7 -7
  10. package/dist/{build-vite-e26f6c9f.cjs.dev.js → build-vite-837e7c94.cjs.dev.js} +64 -43
  11. package/dist/{build-vite-85211835.esm.js → build-vite-8cae71a0.esm.js} +61 -24
  12. package/dist/{build-vite-4a6c90c2.cjs.prod.js → build-vite-b007241b.cjs.prod.js} +64 -43
  13. package/dist/commercetools-frontend-mc-scripts.cjs.dev.js +1 -1
  14. package/dist/commercetools-frontend-mc-scripts.cjs.prod.js +1 -1
  15. package/dist/commercetools-frontend-mc-scripts.esm.js +1 -1
  16. package/dist/{compile-html-adfef598.esm.js → compile-html-025cd493.esm.js} +2 -4
  17. package/dist/{compile-html-b80f9651.cjs.prod.js → compile-html-50fd05ec.cjs.prod.js} +2 -5
  18. package/dist/{compile-html-8679f721.cjs.dev.js → compile-html-f4ac88cc.cjs.dev.js} +2 -5
  19. package/dist/config-sync-0b96d430.esm.js +255 -0
  20. package/dist/config-sync-b3072939.cjs.prod.js +265 -0
  21. package/dist/config-sync-ci-4a09aa00.cjs.prod.js +305 -0
  22. package/dist/config-sync-ci-85e3fec2.esm.js +294 -0
  23. package/dist/config-sync-ci-eadb8bfc.cjs.dev.js +305 -0
  24. package/dist/config-sync-f8fca39f.cjs.dev.js +265 -0
  25. package/dist/{config-sync-87ba9f28.cjs.prod.js → config-sync-helpers-11fc328f.cjs.prod.js} +193 -326
  26. package/dist/{config-sync-27ca0c93.cjs.dev.js → config-sync-helpers-dab59ed9.cjs.dev.js} +195 -328
  27. package/dist/{config-sync-ff4b1e5b.esm.js → config-sync-helpers-fe6ea729.esm.js} +186 -323
  28. package/dist/{create-postcss-config-34bab342.cjs.prod.js → create-postcss-config-56b74a34.cjs.prod.js} +1 -1
  29. package/dist/{create-postcss-config-0e833724.cjs.dev.js → create-postcss-config-78879a12.cjs.dev.js} +1 -1
  30. package/dist/{create-postcss-config-e6dfba3f.esm.js → create-postcss-config-95f9bf62.esm.js} +1 -1
  31. package/dist/{create-webpack-config-for-development-fe0945ce.cjs.prod.js → create-webpack-config-for-development-3eb1b365.cjs.prod.js} +7 -7
  32. package/dist/{create-webpack-config-for-development-2ac1d86f.cjs.dev.js → create-webpack-config-for-development-62b89920.cjs.dev.js} +7 -7
  33. package/dist/{create-webpack-config-for-development-be2722d6.esm.js → create-webpack-config-for-development-a28736fa.esm.js} +7 -7
  34. package/dist/{create-webpack-config-for-production-66c77849.esm.js → create-webpack-config-for-production-21ea561f.esm.js} +8 -8
  35. package/dist/{create-webpack-config-for-production-2200e554.cjs.prod.js → create-webpack-config-for-production-3b6599db.cjs.prod.js} +8 -8
  36. package/dist/{create-webpack-config-for-production-d2c41a9d.cjs.dev.js → create-webpack-config-for-production-e5ed8805.cjs.dev.js} +8 -8
  37. package/dist/{credentials-storage-381abf27.cjs.prod.js → credentials-storage-6d592cd6.cjs.prod.js} +21 -3
  38. package/dist/{credentials-storage-de220814.cjs.dev.js → credentials-storage-c4c5980e.cjs.dev.js} +21 -3
  39. package/dist/{credentials-storage-7285d7b4.esm.js → credentials-storage-fcc77fb6.esm.js} +21 -3
  40. package/dist/declarations/src/types.d.ts +4 -0
  41. package/dist/{deployment-previews-set-7f9fbfe5.esm.js → deployment-previews-set-7d49e7df.esm.js} +22 -27
  42. package/dist/{deployment-previews-set-3697be5e.cjs.dev.js → deployment-previews-set-8d6a1e99.cjs.dev.js} +22 -28
  43. package/dist/{deployment-previews-set-e92403f7.cjs.prod.js → deployment-previews-set-f8ce3db7.cjs.prod.js} +22 -28
  44. package/dist/{graphql-requests-bab5fcc3.cjs.dev.js → graphql-requests-b57fca4c.cjs.prod.js} +5 -8
  45. package/dist/{graphql-requests-d8bc2292.esm.js → graphql-requests-d2fa2ca7.esm.js} +6 -9
  46. package/dist/{graphql-requests-8ef89149.cjs.prod.js → graphql-requests-da194989.cjs.dev.js} +5 -8
  47. package/dist/{i18n-message-complilation-8aec9d1b.esm.js → i18n-message-complilation-21d3b0aa.esm.js} +1 -1
  48. package/dist/{i18n-message-complilation-3f80e8d6.cjs.dev.js → i18n-message-complilation-7311cb29.cjs.dev.js} +1 -1
  49. package/dist/{i18n-message-complilation-393d344a.cjs.prod.js → i18n-message-complilation-7762da61.cjs.prod.js} +1 -1
  50. package/dist/{login-5fd67aac.cjs.prod.js → login-9774c9cc.cjs.prod.js} +154 -38
  51. package/dist/login-abb38213.esm.js +337 -0
  52. package/dist/{login-9fac9eee.cjs.dev.js → login-f4550251.cjs.dev.js} +154 -38
  53. package/dist/{optimizations-ea21b802.cjs.prod.js → optimizations-7789145e.cjs.dev.js} +5 -8
  54. package/dist/{optimizations-ea71a24a.esm.js → optimizations-bf991634.esm.js} +5 -7
  55. package/dist/{optimizations-ebbeaf88.cjs.dev.js → optimizations-fb93514f.cjs.prod.js} +5 -8
  56. package/dist/{package-ff04bcf7.cjs.dev.js → package-0eebca1b.cjs.dev.js} +21 -11
  57. package/dist/{package-4bdd2ccf.esm.js → package-9e6910b8.esm.js} +21 -11
  58. package/dist/{package-428d5001.cjs.prod.js → package-b9298ce3.cjs.prod.js} +21 -11
  59. package/dist/{paths-7bf7e88e.esm.js → paths-39f22b8b.esm.js} +4 -9
  60. package/dist/{paths-af1a725a.cjs.prod.js → paths-7768b440.cjs.prod.js} +4 -10
  61. package/dist/{paths-ec3e3a7d.cjs.dev.js → paths-b76fc753.cjs.dev.js} +4 -10
  62. package/dist/{serve-04a03d5f.cjs.dev.js → serve-38456e1b.cjs.dev.js} +7 -6
  63. package/dist/{serve-fb1a0f5a.esm.js → serve-be1f9439.esm.js} +6 -6
  64. package/dist/{serve-2a863026.cjs.prod.js → serve-cc4a766d.cjs.prod.js} +7 -6
  65. package/dist/{start-643a55bb.esm.js → start-109f9462.esm.js} +8 -9
  66. package/dist/{start-47ea5e04.cjs.dev.js → start-7765f44c.cjs.dev.js} +8 -9
  67. package/dist/{start-84cdf12b.cjs.prod.js → start-e014127c.cjs.prod.js} +8 -9
  68. package/dist/{start-vite-eea72ba9.cjs.dev.js → start-vite-068e9f73.cjs.dev.js} +3 -4
  69. package/dist/{start-vite-d548c121.cjs.prod.js → start-vite-29078b3a.cjs.prod.js} +3 -4
  70. package/dist/{start-vite-d649d1f3.esm.js → start-vite-7d1161e8.esm.js} +3 -4
  71. package/dist/{vite-plugin-svgr-53ef97c7.cjs.dev.js → vite-plugin-svgr-4034a834.cjs.prod.js} +4 -4
  72. package/dist/{vite-plugin-svgr-5de1cad9.cjs.prod.js → vite-plugin-svgr-7d06f400.cjs.dev.js} +4 -4
  73. package/dist/{vite-plugin-svgr-22c8d518.esm.js → vite-plugin-svgr-de6ee7da.esm.js} +4 -4
  74. package/package.json +21 -11
  75. package/postcss/dist/commercetools-frontend-mc-scripts-postcss.cjs.dev.js +2 -2
  76. package/postcss/dist/commercetools-frontend-mc-scripts-postcss.cjs.prod.js +2 -2
  77. package/postcss/dist/commercetools-frontend-mc-scripts-postcss.esm.js +2 -2
  78. package/webpack/dist/commercetools-frontend-mc-scripts-webpack.cjs.dev.js +6 -6
  79. package/webpack/dist/commercetools-frontend-mc-scripts-webpack.cjs.prod.js +6 -6
  80. package/webpack/dist/commercetools-frontend-mc-scripts-webpack.esm.js +6 -6
  81. package/webpack-loaders/i18n-message-compilation-loader/dist/commercetools-frontend-mc-scripts-webpack-loaders-i18n-message-compilation-loader.cjs.dev.js +1 -1
  82. package/webpack-loaders/i18n-message-compilation-loader/dist/commercetools-frontend-mc-scripts-webpack-loaders-i18n-message-compilation-loader.cjs.prod.js +1 -1
  83. package/webpack-loaders/i18n-message-compilation-loader/dist/commercetools-frontend-mc-scripts-webpack-loaders-i18n-message-compilation-loader.esm.js +1 -1
  84. package/dist/login-9ee43381.esm.js +0 -223
@@ -0,0 +1,337 @@
1
+ import _Promise from '@babel/runtime-corejs3/core-js-stable/promise';
2
+ import _mapInstanceProperty from '@babel/runtime-corejs3/core-js-stable/instance/map';
3
+ import _startsWithInstanceProperty from '@babel/runtime-corejs3/core-js-stable/instance/starts-with';
4
+ import _bindInstanceProperty from '@babel/runtime-corejs3/core-js-stable/instance/bind';
5
+ import _trimInstanceProperty from '@babel/runtime-corejs3/core-js-stable/instance/trim';
6
+ import _flatMapInstanceProperty from '@babel/runtime-corejs3/core-js-stable/instance/flat-map';
7
+ import _setTimeout from '@babel/runtime-corejs3/core-js-stable/set-timeout';
8
+ import _Date$now from '@babel/runtime-corejs3/core-js-stable/date/now';
9
+ import _includesInstanceProperty from '@babel/runtime-corejs3/core-js-stable/instance/includes';
10
+ import _forEachInstanceProperty from '@babel/runtime-corejs3/core-js-stable/instance/for-each';
11
+ import _URL from '@babel/runtime-corejs3/core-js-stable/url';
12
+ import crypto from 'node:crypto';
13
+ import process, { exit } from 'node:process';
14
+ import chalk from 'chalk';
15
+ import { processConfig } from '@commercetools-frontend/application-config';
16
+ import { p as pkgJson } from './package-9e6910b8.esm.js';
17
+ import http from 'node:http';
18
+ import jwtDecode from 'jwt-decode';
19
+ import { C as CredentialsStorage } from './credentials-storage-fcc77fb6.esm.js';
20
+ import '@babel/runtime-corejs3/helpers/classCallCheck';
21
+ import '@babel/runtime-corejs3/helpers/createClass';
22
+ import '@babel/runtime-corejs3/core-js-stable/json/stringify';
23
+ import 'node:fs';
24
+ import 'node:os';
25
+ import 'node:path';
26
+ import './does-file-exist-32618334.esm.js';
27
+
28
+ function createAuthCallbackServer(options) {
29
+ const server = http.createServer(async (request, response) => {
30
+ try {
31
+ var _context, _context2;
32
+ if (((_context = request.url) == null ? void 0 : _bindInstanceProperty(_context2 = Function.call).call(_context2, _includesInstanceProperty(_context), _context))?.(`/${options.clientIdentifier}/oidc/callback`)) {
33
+ const incomingUrl = new _URL(request.url, 'http://localhost');
34
+ const sessionToken = incomingUrl.searchParams.get('sessionToken');
35
+ const requestedState = incomingUrl.searchParams.get('state');
36
+ if (!sessionToken) {
37
+ throw new Error('Invalid authentication flow (missing sessionToken)');
38
+ }
39
+ const decodedSessionToken = jwtDecode(sessionToken);
40
+ if (decodedSessionToken?.nonce !== options.nonce) {
41
+ throw new Error('Invalid authentication flow (nonce mismatch)');
42
+ }
43
+ if (requestedState !== options.state) {
44
+ throw new Error('Invalid authentication flow (state mismatch)');
45
+ }
46
+ options.onSuccess({
47
+ token: sessionToken,
48
+ expiresAt: decodedSessionToken.exp
49
+ });
50
+ response.setHeader('content-type', 'text/html');
51
+ response.end('Success!');
52
+ server.close(() => {
53
+ exit();
54
+ });
55
+ }
56
+ } catch (error) {
57
+ response.setHeader('content-type', 'text/html');
58
+ if (error instanceof Error) {
59
+ console.error(error.message);
60
+ response.end(error.message);
61
+ } else {
62
+ console.error(error);
63
+ response.end(`Invalid authentication flow.`);
64
+ }
65
+ server.close(() => {
66
+ exit();
67
+ });
68
+ }
69
+ });
70
+ return server;
71
+ }
72
+
73
+ const credentialsStorage = new CredentialsStorage();
74
+ const port = 3001;
75
+ const clientIdentifier = `mc-scripts-${pkgJson.version}`;
76
+ const isServerError = error => {
77
+ return error instanceof Error && 'code' in error;
78
+ };
79
+ const startServer = server => new _Promise((resolve, reject) => {
80
+ server.listen(port, 'localhost').on('listening', resolve).on('error', error => {
81
+ if (isServerError(error) && error.code === 'EADDRINUSE') {
82
+ return reject(new Error(`The address "localhost:${port}" is already in use. Are you running a Merchant Center application in other process? Please stop that and try again.`, {
83
+ cause: error
84
+ }));
85
+ }
86
+ return reject(new Error('Problem starting server', {
87
+ cause: error
88
+ }));
89
+ }).on('close', () => {
90
+ process.exit();
91
+ });
92
+ });
93
+ const resolveMcApiUrl = async options => {
94
+ if (options.mcApiUrl) {
95
+ return options.mcApiUrl;
96
+ }
97
+
98
+ // We first check whether the user has set the MC_API_URL environment variable
99
+ if (process.env.MC_API_URL) {
100
+ return process.env.MC_API_URL;
101
+ }
102
+
103
+ // If not, we parse the configuration and check if it's defined over there
104
+ const applicationConfig = await processConfig();
105
+ const mcApiUrl = applicationConfig.env.mcApiUrl;
106
+ return mcApiUrl;
107
+ };
108
+ const resolveProjectKey = async options => {
109
+ if (options.projectKey) {
110
+ return options.projectKey;
111
+ }
112
+
113
+ // We first check whether the user has set the CTP_PROJECT_KEY environment variable
114
+ if (process.env.CTP_PROJECT_KEY) {
115
+ return process.env.CTP_PROJECT_KEY;
116
+ }
117
+ try {
118
+ const applicationConfig = await processConfig();
119
+ return applicationConfig.env.__DEVELOPMENT__?.oidc?.initialProjectKey;
120
+ } catch (error) {
121
+ // It's ok if there's not application config file or if it does not contain the initialProjectKey
122
+ return;
123
+ }
124
+ };
125
+ const mapOAuthScopesToClaims = scopes => {
126
+ return _mapInstanceProperty(scopes).call(scopes, scope => {
127
+ if (_startsWithInstanceProperty(scope).call(scope, 'view_')) {
128
+ return `view:${scope}`;
129
+ }
130
+ if (_startsWithInstanceProperty(scope).call(scope, 'manage_')) {
131
+ return `manage:${scope}`;
132
+ }
133
+ return scope;
134
+ });
135
+ };
136
+ const mapAdditionalOAuthScopesToClaims = (name, scopes) => {
137
+ return _mapInstanceProperty(scopes).call(scopes, scope => {
138
+ if (_startsWithInstanceProperty(scope).call(scope, 'view_')) {
139
+ return `view/${name}:${scope}`;
140
+ }
141
+ if (_startsWithInstanceProperty(scope).call(scope, 'manage_')) {
142
+ return `manage/${name}:${scope}`;
143
+ }
144
+ return scope;
145
+ });
146
+ };
147
+ const resolveOAuthScopes = async options => {
148
+ if (options.oauthScope) {
149
+ return mapOAuthScopesToClaims(options.oauthScope);
150
+ }
151
+
152
+ // We first check whether the user has set the CTP_OAUTH_SCOPES environment variable
153
+ if (process.env.CTP_OAUTH_SCOPES) {
154
+ var _context, _context2;
155
+ return mapOAuthScopesToClaims(((_context = process.env.CTP_OAUTH_SCOPES?.split(',')) == null ? void 0 : _bindInstanceProperty(_context2 = Function.call).call(_context2, _mapInstanceProperty(_context), _context))?.(scope => _trimInstanceProperty(scope).call(scope)) ?? []);
156
+ }
157
+ try {
158
+ var _context3, _context4, _context5, _context6;
159
+ const applicationConfig = await processConfig();
160
+ const configuredOAuthScopes = applicationConfig.env.__DEVELOPMENT__?.oidc?.oAuthScopes;
161
+ const configuredAdditionalOAuthScopes = applicationConfig.env.__DEVELOPMENT__?.oidc?.additionalOAuthScopes;
162
+ return [...mapOAuthScopesToClaims(configuredOAuthScopes?.view ?? []), ...mapOAuthScopesToClaims(configuredOAuthScopes?.manage ?? []), ...(((_context3 = configuredAdditionalOAuthScopes) == null ? void 0 : _bindInstanceProperty(_context4 = Function.call).call(_context4, _flatMapInstanceProperty(_context3), _context3))?.(scope => mapAdditionalOAuthScopesToClaims(scope.name, scope.view)) ?? []), ...(((_context5 = configuredAdditionalOAuthScopes) == null ? void 0 : _bindInstanceProperty(_context6 = Function.call).call(_context6, _flatMapInstanceProperty(_context5), _context5))?.(scope => mapAdditionalOAuthScopesToClaims(scope.name, scope.manage)) ?? [])];
163
+ } catch (error) {
164
+ // It's ok if there's not application config file or if it does not contain the initialProjectKey
165
+ return [];
166
+ }
167
+ };
168
+ const generateRandomHash = function () {
169
+ let length = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 16;
170
+ return crypto.randomBytes(length).toString('hex');
171
+ };
172
+
173
+ /**
174
+ * Performs headless login using Puppeteer.
175
+ * Requires IDENTITY_EMAIL and IDENTITY_PASSWORD environment variables.
176
+ */
177
+ async function runHeadlessLogin(authUrl) {
178
+ const email = process.env.IDENTITY_EMAIL;
179
+ const password = process.env.IDENTITY_PASSWORD;
180
+ if (!email || !password) {
181
+ throw new Error('Headless login requires IDENTITY_EMAIL and IDENTITY_PASSWORD environment variables');
182
+ }
183
+ let puppeteer;
184
+ try {
185
+ puppeteer = await import('puppeteer');
186
+ } catch {
187
+ throw new Error('Puppeteer is required for headless login. Install it with: npm install puppeteer');
188
+ }
189
+ const browser = await puppeteer.default.launch({
190
+ headless: 'new',
191
+ args: ['--no-sandbox', '--disable-setuid-sandbox']
192
+ });
193
+ try {
194
+ const page = await browser.newPage();
195
+ await page.goto(authUrl.toString(), {
196
+ waitUntil: 'networkidle2'
197
+ });
198
+
199
+ // Wait for the login page to load
200
+ await page.waitForSelector('input[name="identifier"]', {
201
+ timeout: 30000
202
+ });
203
+
204
+ // Dismiss cookie banner if present
205
+ // Note: Using string-based evaluate to avoid bundler transforming Array.from
206
+ try {
207
+ await page.evaluate(`
208
+ (function() {
209
+ var buttons = Array.from(document.querySelectorAll('button'));
210
+ var acceptBtn = buttons.find(function(btn) {
211
+ return btn.textContent && btn.textContent.includes('Accept all cookies');
212
+ });
213
+ if (acceptBtn) acceptBtn.click();
214
+ })()
215
+ `);
216
+ await new _Promise(resolve => _setTimeout(resolve, 500));
217
+ } catch {
218
+ // Cookie banner not found or already dismissed
219
+ }
220
+
221
+ // Fill in email
222
+ await page.type('input[name="identifier"]', email);
223
+ await new _Promise(resolve => _setTimeout(resolve, 500));
224
+
225
+ // Click "Next" button
226
+ await page.evaluate(`
227
+ (function() {
228
+ var buttons = Array.from(document.querySelectorAll('button'));
229
+ var nextBtn = buttons.find(function(btn) {
230
+ return btn.textContent && btn.textContent.toLowerCase().includes('next');
231
+ });
232
+ if (nextBtn) nextBtn.click();
233
+ })()
234
+ `);
235
+
236
+ // Wait for password field
237
+ await page.waitForSelector('input[name="password"]', {
238
+ visible: true,
239
+ timeout: 30000
240
+ });
241
+
242
+ // Fill in password
243
+ await page.type('input[name="password"]', password);
244
+ await new _Promise(resolve => _setTimeout(resolve, 500));
245
+
246
+ // Click "Submit" button
247
+ await page.evaluate(`
248
+ (function() {
249
+ var buttons = Array.from(document.querySelectorAll('button'));
250
+ var submitBtn = buttons.find(function(btn) {
251
+ return btn.textContent && btn.textContent.toLowerCase().includes('submit');
252
+ });
253
+ if (submitBtn) submitBtn.click();
254
+ })()
255
+ `);
256
+
257
+ // Wait for the callback to be processed (the server will close and exit)
258
+ // We just need to keep the browser alive until the redirect happens
259
+ const startTime = _Date$now();
260
+ const timeout = 60000;
261
+ while (_Date$now() - startTime < timeout) {
262
+ await new _Promise(resolve => _setTimeout(resolve, 500));
263
+ const currentUrl = page.url();
264
+ if (_includesInstanceProperty(currentUrl).call(currentUrl, 'sessionToken=')) {
265
+ // Token was captured by the callback server, we can exit
266
+ break;
267
+ }
268
+ const pageContent = await page.content();
269
+ if (_includesInstanceProperty(pageContent).call(pageContent, 'Invalid credentials') || _includesInstanceProperty(pageContent).call(pageContent, 'invalid_grant')) {
270
+ throw new Error('Invalid credentials');
271
+ }
272
+
273
+ // Check if page shows success (callback server response)
274
+ if (_includesInstanceProperty(pageContent).call(pageContent, 'Success!')) {
275
+ break;
276
+ }
277
+ }
278
+ } finally {
279
+ await browser.close();
280
+ }
281
+ }
282
+ async function run(options) {
283
+ const mcApiUrl = await resolveMcApiUrl(options);
284
+ if (!mcApiUrl) {
285
+ throw new Error('No Merchant Center API URL found. Aborting.');
286
+ }
287
+ console.log(`Using Merchant Center environment "${chalk.green(mcApiUrl)}".`);
288
+ console.log();
289
+ if (!options.force && credentialsStorage.isSessionValid(mcApiUrl)) {
290
+ console.log(`You already have a valid session.`);
291
+ return;
292
+ }
293
+ const projectKey = await resolveProjectKey(options);
294
+ const oauthScopes = await resolveOAuthScopes(options);
295
+ const scopes = ['openid'];
296
+ if (projectKey) {
297
+ scopes.push(`project_key:${projectKey}`);
298
+ _forEachInstanceProperty(oauthScopes).call(oauthScopes, scope => {
299
+ scopes.push(scope);
300
+ });
301
+ }
302
+ const state = generateRandomHash();
303
+ const nonce = generateRandomHash();
304
+ const authUrl = new _URL('/login/authorize', mcApiUrl);
305
+ authUrl.searchParams.set('response_type', 'id_token');
306
+ authUrl.searchParams.set('response_mode', 'query');
307
+ authUrl.searchParams.set('client_id', `__local:${clientIdentifier}`);
308
+ authUrl.searchParams.set('scope', scopes.join(' '));
309
+ authUrl.searchParams.set('state', state);
310
+ authUrl.searchParams.set('nonce', nonce);
311
+ const server = createAuthCallbackServer({
312
+ clientIdentifier,
313
+ state,
314
+ nonce,
315
+ onSuccess: tokenContext => {
316
+ credentialsStorage.setToken(mcApiUrl, tokenContext);
317
+ console.log();
318
+ console.log(chalk.green(`Login successful.`));
319
+ console.log();
320
+ }
321
+ });
322
+ await startServer(server);
323
+ if (options.headless) {
324
+ console.log(`Initiating headless authentication flow using Puppeteer...`);
325
+ console.log();
326
+ await runHeadlessLogin(authUrl);
327
+ } else {
328
+ console.log(`Initiating the OIDC authentication flow, opening the login page in your browser...`);
329
+ console.log(` ${authUrl}`);
330
+ console.log();
331
+ const open = await import('open');
332
+ await open.default(authUrl.toString());
333
+ console.log('Waiting for the OIDC authentication to complete...');
334
+ }
335
+ }
336
+
337
+ export { run as default };
@@ -3,24 +3,25 @@
3
3
  var _Promise = require('@babel/runtime-corejs3/core-js-stable/promise');
4
4
  var _mapInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/map');
5
5
  var _startsWithInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/starts-with');
6
- var _concatInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/concat');
6
+ var _bindInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/bind');
7
7
  var _trimInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/trim');
8
8
  var _flatMapInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/flat-map');
9
+ var _setTimeout = require('@babel/runtime-corejs3/core-js-stable/set-timeout');
10
+ var _Date$now = require('@babel/runtime-corejs3/core-js-stable/date/now');
11
+ var _includesInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/includes');
9
12
  var _forEachInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/for-each');
10
13
  var _URL = require('@babel/runtime-corejs3/core-js-stable/url');
11
14
  var crypto = require('node:crypto');
12
15
  var process = require('node:process');
13
16
  var chalk = require('chalk');
14
17
  var applicationConfig = require('@commercetools-frontend/application-config');
15
- var _package = require('./package-ff04bcf7.cjs.dev.js');
16
- var _includesInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/includes');
18
+ var _package = require('./package-0eebca1b.cjs.dev.js');
17
19
  var http = require('node:http');
18
20
  var jwtDecode = require('jwt-decode');
19
- var credentialsStorage$1 = require('./credentials-storage-de220814.cjs.dev.js');
21
+ var credentialsStorage$1 = require('./credentials-storage-c4c5980e.cjs.dev.js');
20
22
  require('@babel/runtime-corejs3/helpers/classCallCheck');
21
23
  require('@babel/runtime-corejs3/helpers/createClass');
22
24
  require('@babel/runtime-corejs3/core-js-stable/json/stringify');
23
- require('@babel/runtime-corejs3/core-js-stable/date/now');
24
25
  require('node:fs');
25
26
  require('node:os');
26
27
  require('node:path');
@@ -49,23 +50,25 @@ function _interopNamespace(e) {
49
50
  var _Promise__default = /*#__PURE__*/_interopDefault(_Promise);
50
51
  var _mapInstanceProperty__default = /*#__PURE__*/_interopDefault(_mapInstanceProperty);
51
52
  var _startsWithInstanceProperty__default = /*#__PURE__*/_interopDefault(_startsWithInstanceProperty);
52
- var _concatInstanceProperty__default = /*#__PURE__*/_interopDefault(_concatInstanceProperty);
53
+ var _bindInstanceProperty__default = /*#__PURE__*/_interopDefault(_bindInstanceProperty);
53
54
  var _trimInstanceProperty__default = /*#__PURE__*/_interopDefault(_trimInstanceProperty);
54
55
  var _flatMapInstanceProperty__default = /*#__PURE__*/_interopDefault(_flatMapInstanceProperty);
56
+ var _setTimeout__default = /*#__PURE__*/_interopDefault(_setTimeout);
57
+ var _Date$now__default = /*#__PURE__*/_interopDefault(_Date$now);
58
+ var _includesInstanceProperty__default = /*#__PURE__*/_interopDefault(_includesInstanceProperty);
55
59
  var _forEachInstanceProperty__default = /*#__PURE__*/_interopDefault(_forEachInstanceProperty);
56
60
  var _URL__default = /*#__PURE__*/_interopDefault(_URL);
57
61
  var crypto__default = /*#__PURE__*/_interopDefault(crypto);
58
62
  var process__default = /*#__PURE__*/_interopDefault(process);
59
63
  var chalk__default = /*#__PURE__*/_interopDefault(chalk);
60
- var _includesInstanceProperty__default = /*#__PURE__*/_interopDefault(_includesInstanceProperty);
61
64
  var http__default = /*#__PURE__*/_interopDefault(http);
62
65
  var jwtDecode__default = /*#__PURE__*/_interopDefault(jwtDecode);
63
66
 
64
67
  function createAuthCallbackServer(options) {
65
68
  const server = http__default["default"].createServer(async (request, response) => {
66
69
  try {
67
- var _request$url;
68
- if ((_request$url = request.url) !== null && _request$url !== void 0 && _includesInstanceProperty__default["default"](_request$url).call(_request$url, "/".concat(options.clientIdentifier, "/oidc/callback"))) {
70
+ var _context, _context2;
71
+ if (((_context = request.url) == null ? void 0 : _bindInstanceProperty__default["default"](_context2 = Function.call).call(_context2, _includesInstanceProperty__default["default"](_context), _context))?.(`/${options.clientIdentifier}/oidc/callback`)) {
69
72
  const incomingUrl = new _URL__default["default"](request.url, 'http://localhost');
70
73
  const sessionToken = incomingUrl.searchParams.get('sessionToken');
71
74
  const requestedState = incomingUrl.searchParams.get('state');
@@ -73,7 +76,7 @@ function createAuthCallbackServer(options) {
73
76
  throw new Error('Invalid authentication flow (missing sessionToken)');
74
77
  }
75
78
  const decodedSessionToken = jwtDecode__default["default"](sessionToken);
76
- if ((decodedSessionToken === null || decodedSessionToken === void 0 ? void 0 : decodedSessionToken.nonce) !== options.nonce) {
79
+ if (decodedSessionToken?.nonce !== options.nonce) {
77
80
  throw new Error('Invalid authentication flow (nonce mismatch)');
78
81
  }
79
82
  if (requestedState !== options.state) {
@@ -96,7 +99,7 @@ function createAuthCallbackServer(options) {
96
99
  response.end(error.message);
97
100
  } else {
98
101
  console.error(error);
99
- response.end("Invalid authentication flow.");
102
+ response.end(`Invalid authentication flow.`);
100
103
  }
101
104
  server.close(() => {
102
105
  process.exit();
@@ -108,14 +111,14 @@ function createAuthCallbackServer(options) {
108
111
 
109
112
  const credentialsStorage = new credentialsStorage$1.CredentialsStorage();
110
113
  const port = 3001;
111
- const clientIdentifier = "mc-scripts-".concat(_package.pkgJson.version);
114
+ const clientIdentifier = `mc-scripts-${_package.pkgJson.version}`;
112
115
  const isServerError = error => {
113
116
  return error instanceof Error && 'code' in error;
114
117
  };
115
118
  const startServer = server => new _Promise__default["default"]((resolve, reject) => {
116
119
  server.listen(port, 'localhost').on('listening', resolve).on('error', error => {
117
120
  if (isServerError(error) && error.code === 'EADDRINUSE') {
118
- return reject(new Error("The address \"localhost:".concat(port, "\" is already in use. Are you running a Merchant Center application in other process? Please stop that and try again."), {
121
+ return reject(new Error(`The address "localhost:${port}" is already in use. Are you running a Merchant Center application in other process? Please stop that and try again.`, {
119
122
  cause: error
120
123
  }));
121
124
  }
@@ -151,9 +154,8 @@ const resolveProjectKey = async options => {
151
154
  return process__default["default"].env.CTP_PROJECT_KEY;
152
155
  }
153
156
  try {
154
- var _applicationConfig$en;
155
157
  const applicationConfig$1 = await applicationConfig.processConfig();
156
- return (_applicationConfig$en = applicationConfig$1.env.__DEVELOPMENT__) === null || _applicationConfig$en === void 0 || (_applicationConfig$en = _applicationConfig$en.oidc) === null || _applicationConfig$en === void 0 ? void 0 : _applicationConfig$en.initialProjectKey;
158
+ return applicationConfig$1.env.__DEVELOPMENT__?.oidc?.initialProjectKey;
157
159
  } catch (error) {
158
160
  // It's ok if there's not application config file or if it does not contain the initialProjectKey
159
161
  return;
@@ -162,10 +164,10 @@ const resolveProjectKey = async options => {
162
164
  const mapOAuthScopesToClaims = scopes => {
163
165
  return _mapInstanceProperty__default["default"](scopes).call(scopes, scope => {
164
166
  if (_startsWithInstanceProperty__default["default"](scope).call(scope, 'view_')) {
165
- return "view:".concat(scope);
167
+ return `view:${scope}`;
166
168
  }
167
169
  if (_startsWithInstanceProperty__default["default"](scope).call(scope, 'manage_')) {
168
- return "manage:".concat(scope);
170
+ return `manage:${scope}`;
169
171
  }
170
172
  return scope;
171
173
  });
@@ -173,12 +175,10 @@ const mapOAuthScopesToClaims = scopes => {
173
175
  const mapAdditionalOAuthScopesToClaims = (name, scopes) => {
174
176
  return _mapInstanceProperty__default["default"](scopes).call(scopes, scope => {
175
177
  if (_startsWithInstanceProperty__default["default"](scope).call(scope, 'view_')) {
176
- var _context;
177
- return _concatInstanceProperty__default["default"](_context = "view/".concat(name, ":")).call(_context, scope);
178
+ return `view/${name}:${scope}`;
178
179
  }
179
180
  if (_startsWithInstanceProperty__default["default"](scope).call(scope, 'manage_')) {
180
- var _context2;
181
- return _concatInstanceProperty__default["default"](_context2 = "manage/".concat(name, ":")).call(_context2, scope);
181
+ return `manage/${name}:${scope}`;
182
182
  }
183
183
  return scope;
184
184
  });
@@ -190,15 +190,15 @@ const resolveOAuthScopes = async options => {
190
190
 
191
191
  // We first check whether the user has set the CTP_OAUTH_SCOPES environment variable
192
192
  if (process__default["default"].env.CTP_OAUTH_SCOPES) {
193
- var _process$env$CTP_OAUT, _process$env$CTP_OAUT2, _context3;
194
- return mapOAuthScopesToClaims((_process$env$CTP_OAUT = (_process$env$CTP_OAUT2 = process__default["default"].env.CTP_OAUTH_SCOPES) === null || _process$env$CTP_OAUT2 === void 0 ? void 0 : _mapInstanceProperty__default["default"](_context3 = _process$env$CTP_OAUT2.split(',')).call(_context3, scope => _trimInstanceProperty__default["default"](scope).call(scope))) !== null && _process$env$CTP_OAUT !== void 0 ? _process$env$CTP_OAUT : []);
193
+ var _context, _context2;
194
+ return mapOAuthScopesToClaims(((_context = process__default["default"].env.CTP_OAUTH_SCOPES?.split(',')) == null ? void 0 : _bindInstanceProperty__default["default"](_context2 = Function.call).call(_context2, _mapInstanceProperty__default["default"](_context), _context))?.(scope => _trimInstanceProperty__default["default"](scope).call(scope)) ?? []);
195
195
  }
196
196
  try {
197
- var _applicationConfig$en2, _applicationConfig$en3, _configuredOAuthScope, _configuredOAuthScope2, _configuredAdditional, _configuredAdditional2;
197
+ var _context3, _context4, _context5, _context6;
198
198
  const applicationConfig$1 = await applicationConfig.processConfig();
199
- const configuredOAuthScopes = (_applicationConfig$en2 = applicationConfig$1.env.__DEVELOPMENT__) === null || _applicationConfig$en2 === void 0 || (_applicationConfig$en2 = _applicationConfig$en2.oidc) === null || _applicationConfig$en2 === void 0 ? void 0 : _applicationConfig$en2.oAuthScopes;
200
- const configuredAdditionalOAuthScopes = (_applicationConfig$en3 = applicationConfig$1.env.__DEVELOPMENT__) === null || _applicationConfig$en3 === void 0 || (_applicationConfig$en3 = _applicationConfig$en3.oidc) === null || _applicationConfig$en3 === void 0 ? void 0 : _applicationConfig$en3.additionalOAuthScopes;
201
- return [...mapOAuthScopesToClaims((_configuredOAuthScope = configuredOAuthScopes === null || configuredOAuthScopes === void 0 ? void 0 : configuredOAuthScopes.view) !== null && _configuredOAuthScope !== void 0 ? _configuredOAuthScope : []), ...mapOAuthScopesToClaims((_configuredOAuthScope2 = configuredOAuthScopes === null || configuredOAuthScopes === void 0 ? void 0 : configuredOAuthScopes.manage) !== null && _configuredOAuthScope2 !== void 0 ? _configuredOAuthScope2 : []), ...((_configuredAdditional = configuredAdditionalOAuthScopes === null || configuredAdditionalOAuthScopes === void 0 ? void 0 : _flatMapInstanceProperty__default["default"](configuredAdditionalOAuthScopes).call(configuredAdditionalOAuthScopes, scope => mapAdditionalOAuthScopesToClaims(scope.name, scope.view))) !== null && _configuredAdditional !== void 0 ? _configuredAdditional : []), ...((_configuredAdditional2 = configuredAdditionalOAuthScopes === null || configuredAdditionalOAuthScopes === void 0 ? void 0 : _flatMapInstanceProperty__default["default"](configuredAdditionalOAuthScopes).call(configuredAdditionalOAuthScopes, scope => mapAdditionalOAuthScopesToClaims(scope.name, scope.manage))) !== null && _configuredAdditional2 !== void 0 ? _configuredAdditional2 : [])];
199
+ const configuredOAuthScopes = applicationConfig$1.env.__DEVELOPMENT__?.oidc?.oAuthScopes;
200
+ const configuredAdditionalOAuthScopes = applicationConfig$1.env.__DEVELOPMENT__?.oidc?.additionalOAuthScopes;
201
+ return [...mapOAuthScopesToClaims(configuredOAuthScopes?.view ?? []), ...mapOAuthScopesToClaims(configuredOAuthScopes?.manage ?? []), ...(((_context3 = configuredAdditionalOAuthScopes) == null ? void 0 : _bindInstanceProperty__default["default"](_context4 = Function.call).call(_context4, _flatMapInstanceProperty__default["default"](_context3), _context3))?.(scope => mapAdditionalOAuthScopesToClaims(scope.name, scope.view)) ?? []), ...(((_context5 = configuredAdditionalOAuthScopes) == null ? void 0 : _bindInstanceProperty__default["default"](_context6 = Function.call).call(_context6, _flatMapInstanceProperty__default["default"](_context5), _context5))?.(scope => mapAdditionalOAuthScopesToClaims(scope.name, scope.manage)) ?? [])];
202
202
  } catch (error) {
203
203
  // It's ok if there's not application config file or if it does not contain the initialProjectKey
204
204
  return [];
@@ -208,22 +208,132 @@ const generateRandomHash = function () {
208
208
  let length = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 16;
209
209
  return crypto__default["default"].randomBytes(length).toString('hex');
210
210
  };
211
+
212
+ /**
213
+ * Performs headless login using Puppeteer.
214
+ * Requires IDENTITY_EMAIL and IDENTITY_PASSWORD environment variables.
215
+ */
216
+ async function runHeadlessLogin(authUrl) {
217
+ const email = process__default["default"].env.IDENTITY_EMAIL;
218
+ const password = process__default["default"].env.IDENTITY_PASSWORD;
219
+ if (!email || !password) {
220
+ throw new Error('Headless login requires IDENTITY_EMAIL and IDENTITY_PASSWORD environment variables');
221
+ }
222
+ let puppeteer;
223
+ try {
224
+ puppeteer = await Promise.resolve().then(function () { return /*#__PURE__*/_interopNamespace(require('puppeteer')); });
225
+ } catch {
226
+ throw new Error('Puppeteer is required for headless login. Install it with: npm install puppeteer');
227
+ }
228
+ const browser = await puppeteer.default.launch({
229
+ headless: 'new',
230
+ args: ['--no-sandbox', '--disable-setuid-sandbox']
231
+ });
232
+ try {
233
+ const page = await browser.newPage();
234
+ await page.goto(authUrl.toString(), {
235
+ waitUntil: 'networkidle2'
236
+ });
237
+
238
+ // Wait for the login page to load
239
+ await page.waitForSelector('input[name="identifier"]', {
240
+ timeout: 30000
241
+ });
242
+
243
+ // Dismiss cookie banner if present
244
+ // Note: Using string-based evaluate to avoid bundler transforming Array.from
245
+ try {
246
+ await page.evaluate(`
247
+ (function() {
248
+ var buttons = Array.from(document.querySelectorAll('button'));
249
+ var acceptBtn = buttons.find(function(btn) {
250
+ return btn.textContent && btn.textContent.includes('Accept all cookies');
251
+ });
252
+ if (acceptBtn) acceptBtn.click();
253
+ })()
254
+ `);
255
+ await new _Promise__default["default"](resolve => _setTimeout__default["default"](resolve, 500));
256
+ } catch {
257
+ // Cookie banner not found or already dismissed
258
+ }
259
+
260
+ // Fill in email
261
+ await page.type('input[name="identifier"]', email);
262
+ await new _Promise__default["default"](resolve => _setTimeout__default["default"](resolve, 500));
263
+
264
+ // Click "Next" button
265
+ await page.evaluate(`
266
+ (function() {
267
+ var buttons = Array.from(document.querySelectorAll('button'));
268
+ var nextBtn = buttons.find(function(btn) {
269
+ return btn.textContent && btn.textContent.toLowerCase().includes('next');
270
+ });
271
+ if (nextBtn) nextBtn.click();
272
+ })()
273
+ `);
274
+
275
+ // Wait for password field
276
+ await page.waitForSelector('input[name="password"]', {
277
+ visible: true,
278
+ timeout: 30000
279
+ });
280
+
281
+ // Fill in password
282
+ await page.type('input[name="password"]', password);
283
+ await new _Promise__default["default"](resolve => _setTimeout__default["default"](resolve, 500));
284
+
285
+ // Click "Submit" button
286
+ await page.evaluate(`
287
+ (function() {
288
+ var buttons = Array.from(document.querySelectorAll('button'));
289
+ var submitBtn = buttons.find(function(btn) {
290
+ return btn.textContent && btn.textContent.toLowerCase().includes('submit');
291
+ });
292
+ if (submitBtn) submitBtn.click();
293
+ })()
294
+ `);
295
+
296
+ // Wait for the callback to be processed (the server will close and exit)
297
+ // We just need to keep the browser alive until the redirect happens
298
+ const startTime = _Date$now__default["default"]();
299
+ const timeout = 60000;
300
+ while (_Date$now__default["default"]() - startTime < timeout) {
301
+ await new _Promise__default["default"](resolve => _setTimeout__default["default"](resolve, 500));
302
+ const currentUrl = page.url();
303
+ if (_includesInstanceProperty__default["default"](currentUrl).call(currentUrl, 'sessionToken=')) {
304
+ // Token was captured by the callback server, we can exit
305
+ break;
306
+ }
307
+ const pageContent = await page.content();
308
+ if (_includesInstanceProperty__default["default"](pageContent).call(pageContent, 'Invalid credentials') || _includesInstanceProperty__default["default"](pageContent).call(pageContent, 'invalid_grant')) {
309
+ throw new Error('Invalid credentials');
310
+ }
311
+
312
+ // Check if page shows success (callback server response)
313
+ if (_includesInstanceProperty__default["default"](pageContent).call(pageContent, 'Success!')) {
314
+ break;
315
+ }
316
+ }
317
+ } finally {
318
+ await browser.close();
319
+ }
320
+ }
211
321
  async function run(options) {
212
322
  const mcApiUrl = await resolveMcApiUrl(options);
213
323
  if (!mcApiUrl) {
214
324
  throw new Error('No Merchant Center API URL found. Aborting.');
215
325
  }
216
- console.log("Using Merchant Center environment \"".concat(chalk__default["default"].green(mcApiUrl), "\"."));
326
+ console.log(`Using Merchant Center environment "${chalk__default["default"].green(mcApiUrl)}".`);
217
327
  console.log();
218
328
  if (!options.force && credentialsStorage.isSessionValid(mcApiUrl)) {
219
- console.log("You already have a valid session.");
329
+ console.log(`You already have a valid session.`);
220
330
  return;
221
331
  }
222
332
  const projectKey = await resolveProjectKey(options);
223
333
  const oauthScopes = await resolveOAuthScopes(options);
224
334
  const scopes = ['openid'];
225
335
  if (projectKey) {
226
- scopes.push("project_key:".concat(projectKey));
336
+ scopes.push(`project_key:${projectKey}`);
227
337
  _forEachInstanceProperty__default["default"](oauthScopes).call(oauthScopes, scope => {
228
338
  scopes.push(scope);
229
339
  });
@@ -233,7 +343,7 @@ async function run(options) {
233
343
  const authUrl = new _URL__default["default"]('/login/authorize', mcApiUrl);
234
344
  authUrl.searchParams.set('response_type', 'id_token');
235
345
  authUrl.searchParams.set('response_mode', 'query');
236
- authUrl.searchParams.set('client_id', "__local:".concat(clientIdentifier));
346
+ authUrl.searchParams.set('client_id', `__local:${clientIdentifier}`);
237
347
  authUrl.searchParams.set('scope', scopes.join(' '));
238
348
  authUrl.searchParams.set('state', state);
239
349
  authUrl.searchParams.set('nonce', nonce);
@@ -244,17 +354,23 @@ async function run(options) {
244
354
  onSuccess: tokenContext => {
245
355
  credentialsStorage.setToken(mcApiUrl, tokenContext);
246
356
  console.log();
247
- console.log(chalk__default["default"].green("Login successful."));
357
+ console.log(chalk__default["default"].green(`Login successful.`));
248
358
  console.log();
249
359
  }
250
360
  });
251
361
  await startServer(server);
252
- console.log("Initiating the OIDC authentication flow, opening the login page in your browser...");
253
- console.log(" ".concat(authUrl));
254
- console.log();
255
- const open = await Promise.resolve().then(function () { return /*#__PURE__*/_interopNamespace(require('open')); });
256
- await open.default(authUrl.toString());
257
- console.log('Waiting for the OIDC authentication to complete...');
362
+ if (options.headless) {
363
+ console.log(`Initiating headless authentication flow using Puppeteer...`);
364
+ console.log();
365
+ await runHeadlessLogin(authUrl);
366
+ } else {
367
+ console.log(`Initiating the OIDC authentication flow, opening the login page in your browser...`);
368
+ console.log(` ${authUrl}`);
369
+ console.log();
370
+ const open = await Promise.resolve().then(function () { return /*#__PURE__*/_interopNamespace(require('open')); });
371
+ await open.default(authUrl.toString());
372
+ console.log('Waiting for the OIDC authentication to complete...');
373
+ }
258
374
  }
259
375
 
260
376
  exports["default"] = run;