@sitecore-jss/sitecore-jss-dev-tools 22.5.0-beta.1 → 22.5.0-beta.10

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.
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.fetchBearerToken = exports.DEFAULT_SITECORE_AUTH_AUDIENCE = exports.DEFAULT_SITECORE_AUTH_ENDPOINT = void 0;
16
+ const chalk_1 = __importDefault(require("chalk"));
17
+ exports.DEFAULT_SITECORE_AUTH_ENDPOINT = 'https://auth.sitecorecloud.io/oauth/token';
18
+ exports.DEFAULT_SITECORE_AUTH_AUDIENCE = 'https://api.sitecorecloud.io';
19
+ /**
20
+ * Connects to M2M endpoint and fetches the bearer token
21
+ * Uses client_id and client_secret from environment variables
22
+ * @returns {string} bearer token string
23
+ */
24
+ const fetchBearerToken = () => __awaiter(void 0, void 0, void 0, function* () {
25
+ const audience = process.env.SITECORE_AUTH_AUDIENCE || exports.DEFAULT_SITECORE_AUTH_AUDIENCE;
26
+ const m2mEndpoint = process.env.SITECORE_AUTH_ENDPOINT || exports.DEFAULT_SITECORE_AUTH_ENDPOINT;
27
+ try {
28
+ // TODO:adjust when M2M endpoint is live
29
+ const authenticateResponse = yield fetch(m2mEndpoint, {
30
+ method: 'POST',
31
+ headers: {
32
+ 'Content-Type': 'application/json',
33
+ },
34
+ body: JSON.stringify({
35
+ client_id: process.env.SITECORE_AUTH_CLIENT_ID,
36
+ client_secret: process.env.SITECORE_AUTH_CLIENT_SECRET,
37
+ audience: audience,
38
+ grant_type: 'client_credentials',
39
+ }),
40
+ });
41
+ const jsonResponse = yield authenticateResponse.json();
42
+ return jsonResponse.access_token;
43
+ }
44
+ catch (error) {
45
+ console.error(chalk_1.default.red('Error authenticating with Sitecore Auth endpoint:', error));
46
+ console.log(chalk_1.default.yellow('Please ensure your SITECORE_AUTH_CLIENT_ID and SITECORE_AUTH_CLIENT_SECRET environment variables are set correctly.'));
47
+ return null;
48
+ }
49
+ });
50
+ exports.fetchBearerToken = fetchBearerToken;
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.extractComponents = extractComponents;
16
+ const utils_1 = require("./utils");
17
+ const fetch_bearer_token_1 = require("../auth/fetch-bearer-token");
18
+ const chalk_1 = __importDefault(require("chalk"));
19
+ /**
20
+ * Handler for the extract-component API command
21
+ * Reads imports from the componentBuilder.ts file and posts the code to the mesh endpoint
22
+ * @param {ExtractComponentOptions} [args] - The options for code extraction
23
+ * @returns {Promise<void>} void
24
+ */
25
+ function extractComponents() {
26
+ return __awaiter(this, arguments, void 0, function* (args = {}) {
27
+ if (!validateDeployContext()) {
28
+ console.log(chalk_1.default.yellow('Skipping code extraction, not in deploy context'));
29
+ return;
30
+ }
31
+ // TODO: add alternative consent procedure when refining later
32
+ if (!process.env.EXTRACT_CONSENT) {
33
+ console.log(chalk_1.default.yellow('Skipping code extraction, EXTRACT_CONSENT is not set'));
34
+ return;
35
+ }
36
+ const basePath = process.cwd();
37
+ try {
38
+ const bearer = yield (0, fetch_bearer_token_1.fetchBearerToken)();
39
+ if (!bearer) {
40
+ console.error(chalk_1.default.red('Failed to get bearer token, aborting code extraction'));
41
+ return;
42
+ }
43
+ const componentPaths = yield (0, utils_1.resolveComponentImportFiles)(basePath, args.componentBuilderPath);
44
+ const codeDispatches = Array.from(componentPaths, (mapEntry) => (0, utils_1.sendCode)({
45
+ name: mapEntry[0],
46
+ path: mapEntry[1],
47
+ type: utils_1.ExtractedFileType.Component,
48
+ }, bearer));
49
+ yield Promise.all(codeDispatches);
50
+ }
51
+ catch (error) {
52
+ console.error(chalk_1.default.red('Error during component extraction:', error));
53
+ }
54
+ });
55
+ }
56
+ const validateDeployContext = () => {
57
+ if (process.env.NETLIFY && process.env.BUILD_ID) {
58
+ return true;
59
+ }
60
+ // workaround, Vercel does not have variables that are only accessible at build time
61
+ if (process.env.VERCEL && !process.env.VERCEL_REGION) {
62
+ return true;
63
+ }
64
+ if (process.env.SITECORE && process.env.BuildMetadata_BuildId) {
65
+ return true;
66
+ }
67
+ return false;
68
+ };
@@ -0,0 +1,175 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
26
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
27
+ return new (P || (P = Promise))(function (resolve, reject) {
28
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
29
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
30
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
31
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
32
+ });
33
+ };
34
+ var __importDefault = (this && this.__importDefault) || function (mod) {
35
+ return (mod && mod.__esModule) ? mod : { "default": mod };
36
+ };
37
+ Object.defineProperty(exports, "__esModule", { value: true });
38
+ exports.sendCode = exports.resolveComponentImportFiles = exports.ExtractedFileType = void 0;
39
+ const chalk_1 = __importDefault(require("chalk"));
40
+ const path_1 = __importDefault(require("path"));
41
+ const fs_1 = __importDefault(require("fs"));
42
+ const ts = __importStar(require("typescript"));
43
+ const sitecore_jss_1 = require("@sitecore-jss/sitecore-jss");
44
+ // TODO:adjust when mesh endpoint is live
45
+ const meshEndpoint = `${process.env.SITECORE_EDGE_URL ||
46
+ sitecore_jss_1.constants.SITECORE_EDGE_URL_DEFAULT}/api/v1/mesh`;
47
+ /**
48
+ * Type of file to be sent to the mesh endpoint
49
+ */
50
+ var ExtractedFileType;
51
+ (function (ExtractedFileType) {
52
+ ExtractedFileType["Component"] = "component";
53
+ ExtractedFileType["Json"] = "json";
54
+ ExtractedFileType["Package"] = "package.json";
55
+ })(ExtractedFileType || (exports.ExtractedFileType = ExtractedFileType = {}));
56
+ /**
57
+ * Parses the componentBuilder.ts file and returns a map of component names
58
+ * and their respective import strings
59
+ * @param {string} appPath path to the JSS app root
60
+ * @param {string} componentBuilderPath path to the app's component builder file. Default: 'src/temp/componentBuilder.ts'
61
+ * @returns map of component names and their respective import strings
62
+ */
63
+ const resolveComponentImportFiles = (appPath, componentBuilderPath = './src/temp/componentBuilder.ts') => {
64
+ appPath = path_1.default.isAbsolute(appPath) ? appPath : path_1.default.resolve(process.cwd(), appPath);
65
+ const tsConfig = ts.readConfigFile(path_1.default.resolve(appPath, 'tsconfig.json'), ts.sys.readFile);
66
+ if (tsConfig.error) {
67
+ throw new Error(`Error reading tsconfig.json from JSS app root: ${tsConfig.error.messageText}`);
68
+ }
69
+ const tsOptions = Object.assign(Object.assign({}, tsConfig.config.compilerOptions), { baseUrl: appPath });
70
+ const componentBuilderFullPath = path_1.default.isAbsolute(componentBuilderPath)
71
+ ? componentBuilderPath
72
+ : path_1.default.resolve(appPath, componentBuilderPath);
73
+ // compiler host to process the componentBuilder.ts file and component sources
74
+ const tsHost = ts.createCompilerHost(tsOptions, true);
75
+ const builderSourceFile = tsHost.getSourceFile(componentBuilderFullPath, ts.ScriptTarget.Latest, (msg) => {
76
+ throw new Error(`Failed to parse ${componentBuilderFullPath}: ${msg}`);
77
+ });
78
+ if (!builderSourceFile)
79
+ throw ReferenceError(`Failed to find file ${componentBuilderFullPath}`);
80
+ // this map matches all raw import strings (i.e. * as component) to import strings
81
+ const importStringsMap = {};
82
+ // this map will match component names only to full resolved source file paths
83
+ const componentImportsMap = new Map();
84
+ // name of the export from componentBuilder.ts
85
+ let mapExportName = '';
86
+ // all map.set() assignments in file
87
+ const mapAssignments = [];
88
+ // step 1: get all import statements and map assignments (map.set) from componentBuilder file
89
+ ts.forEachChild(builderSourceFile, (childNode) => {
90
+ var _a;
91
+ // first, all import statements are parsed
92
+ if (ts.isImportDeclaration(childNode) && childNode.importClause) {
93
+ // import path is extracted
94
+ const moduleName = childNode.moduleSpecifier.getText().replace(/['"]/g, '');
95
+ // unless the import is a nodeJS one, or points to dependency package, resolve full path to the imported source file
96
+ if (moduleName.startsWith('node:') || moduleName.indexOf('/node_modules') > -1) {
97
+ return;
98
+ }
99
+ const resolvedModule = ts.nodeModuleNameResolver(moduleName, componentBuilderFullPath, tsOptions, tsHost);
100
+ const resolvedFile = (_a = resolvedModule === null || resolvedModule === void 0 ? void 0 : resolvedModule.resolvedModule) === null || _a === void 0 ? void 0 : _a.resolvedFileName;
101
+ // module imports paths will be resolved to /node_modules location - we don't support that yet
102
+ if (resolvedFile && resolvedFile.indexOf('node_modules') === -1) {
103
+ importStringsMap[childNode.importClause.getText()] = path_1.default.resolve(resolvedFile);
104
+ }
105
+ }
106
+ else if (ts.isExpressionStatement(childNode)) {
107
+ // parse map assignments (map.set(..)) to get registered components
108
+ ts.forEachChild(childNode, (expressionNode) => {
109
+ if (ts.isCallExpression(expressionNode) &&
110
+ expressionNode.expression.getText().indexOf('set') !== -1) {
111
+ // get map.set assignments
112
+ mapAssignments.push(expressionNode);
113
+ }
114
+ });
115
+ }
116
+ else if (ts.isExportAssignment(childNode)) {
117
+ // get component map export variable
118
+ // In case there are multiple assignment statements a file, we need to only pick ones that related to exported map
119
+ mapExportName = childNode.expression.getText();
120
+ }
121
+ });
122
+ // step 2: parse mapAssignments and retrieve import paths
123
+ // only for components registered into component map
124
+ for (const mapAssignment of mapAssignments) {
125
+ // only consider the map variable that is exported
126
+ if (mapAssignment.getText().startsWith(mapExportName)) {
127
+ const componentKey = mapAssignment.arguments[1].getText();
128
+ const componentImport = Object.keys(importStringsMap).find((importStatement) => {
129
+ const matcher = new RegExp(`\\b(${componentKey})\\b`);
130
+ return importStatement.match(matcher) !== null;
131
+ });
132
+ if (componentImport) {
133
+ const componentValue = importStringsMap[componentImport];
134
+ componentImportsMap.set(componentKey, componentValue);
135
+ }
136
+ }
137
+ }
138
+ return componentImportsMap;
139
+ };
140
+ exports.resolveComponentImportFiles = resolveComponentImportFiles;
141
+ /**
142
+ * Sends extracted component code to mesh endpoint
143
+ * @param {ExcractedFile} file properties of the file to be sent
144
+ * @param {string} token bearer token for authentication into mesh endpoint
145
+ */
146
+ const sendCode = (file, token) => __awaiter(void 0, void 0, void 0, function* () {
147
+ if (!fs_1.default.existsSync(file.path)) {
148
+ console.error(chalk_1.default.red(`File planned for code extraction not found: ${file.path}`));
149
+ return;
150
+ }
151
+ const code = fs_1.default.readFileSync(file.path);
152
+ const response = yield fetch(meshEndpoint, {
153
+ method: 'POST',
154
+ headers: {
155
+ Authorization: `Bearer ${token}`,
156
+ 'Content-Type': 'application/json',
157
+ },
158
+ body: JSON.stringify({
159
+ name: file.name,
160
+ content: code.toString(),
161
+ labels: {
162
+ properties: {
163
+ type: file.type,
164
+ },
165
+ },
166
+ }),
167
+ });
168
+ if (!response.ok) {
169
+ console.error(chalk_1.default.red(`Failed to send extracted code from ${file.path}: ${response.statusText}`));
170
+ }
171
+ else {
172
+ console.log(chalk_1.default.green(`Code from ${file.path} extracted and sent to mesh endpoint`));
173
+ }
174
+ });
175
+ exports.sendCode = sendCode;
package/dist/cjs/index.js CHANGED
@@ -14,7 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
- exports.resolveScJssConfig = exports.createDefaultDisconnectedServer = exports.createDefaultDocumentMiddleware = exports.createDisconnectedDictionaryService = exports.createDisconnectedLayoutService = exports.createDisconnectedAssetMiddleware = exports.packageGenerate = exports.packageDeploy = exports.clean = exports.deploy = exports.mergeFs = exports.verifySetup = exports.userConfigPath = exports.setup = exports.replaceConfigTokens = void 0;
17
+ exports.extractComponents = exports.fetchBearerToken = exports.constants = exports.resolveScJssConfig = exports.createDefaultDisconnectedServer = exports.createDefaultDocumentMiddleware = exports.createDisconnectedDictionaryService = exports.createDisconnectedLayoutService = exports.createDisconnectedAssetMiddleware = exports.packageGenerate = exports.packageDeploy = exports.clean = exports.deploy = exports.mergeFs = exports.verifySetup = exports.userConfigPath = exports.setup = exports.replaceConfigTokens = void 0;
18
18
  var jss_config_1 = require("./setup/jss-config");
19
19
  Object.defineProperty(exports, "replaceConfigTokens", { enumerable: true, get: function () { return jss_config_1.replaceConfigTokens; } });
20
20
  var setup_1 = require("./setup/setup");
@@ -44,6 +44,12 @@ var create_default_disconnected_server_1 = require("./disconnected-server/create
44
44
  Object.defineProperty(exports, "createDefaultDisconnectedServer", { enumerable: true, get: function () { return create_default_disconnected_server_1.createDefaultDisconnectedServer; } });
45
45
  var resolve_scjssconfig_1 = require("./resolve-scjssconfig");
46
46
  Object.defineProperty(exports, "resolveScJssConfig", { enumerable: true, get: function () { return resolve_scjssconfig_1.resolveScJssConfig; } });
47
+ var sitecore_jss_1 = require("@sitecore-jss/sitecore-jss");
48
+ Object.defineProperty(exports, "constants", { enumerable: true, get: function () { return sitecore_jss_1.constants; } });
49
+ var fetch_bearer_token_1 = require("./auth/fetch-bearer-token");
50
+ Object.defineProperty(exports, "fetchBearerToken", { enumerable: true, get: function () { return fetch_bearer_token_1.fetchBearerToken; } });
51
+ var extract_components_1 = require("./codegen/extract-components");
52
+ Object.defineProperty(exports, "extractComponents", { enumerable: true, get: function () { return extract_components_1.extractComponents; } });
47
53
  __exportStar(require("./templating"), exports);
48
54
  __exportStar(require("./manifest"), exports);
49
55
  __exportStar(require("./pipelines"), exports);
@@ -0,0 +1,43 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import chalk from 'chalk';
11
+ export const DEFAULT_SITECORE_AUTH_ENDPOINT = 'https://auth.sitecorecloud.io/oauth/token';
12
+ export const DEFAULT_SITECORE_AUTH_AUDIENCE = 'https://api.sitecorecloud.io';
13
+ /**
14
+ * Connects to M2M endpoint and fetches the bearer token
15
+ * Uses client_id and client_secret from environment variables
16
+ * @returns {string} bearer token string
17
+ */
18
+ export const fetchBearerToken = () => __awaiter(void 0, void 0, void 0, function* () {
19
+ const audience = process.env.SITECORE_AUTH_AUDIENCE || DEFAULT_SITECORE_AUTH_AUDIENCE;
20
+ const m2mEndpoint = process.env.SITECORE_AUTH_ENDPOINT || DEFAULT_SITECORE_AUTH_ENDPOINT;
21
+ try {
22
+ // TODO:adjust when M2M endpoint is live
23
+ const authenticateResponse = yield fetch(m2mEndpoint, {
24
+ method: 'POST',
25
+ headers: {
26
+ 'Content-Type': 'application/json',
27
+ },
28
+ body: JSON.stringify({
29
+ client_id: process.env.SITECORE_AUTH_CLIENT_ID,
30
+ client_secret: process.env.SITECORE_AUTH_CLIENT_SECRET,
31
+ audience: audience,
32
+ grant_type: 'client_credentials',
33
+ }),
34
+ });
35
+ const jsonResponse = yield authenticateResponse.json();
36
+ return jsonResponse.access_token;
37
+ }
38
+ catch (error) {
39
+ console.error(chalk.red('Error authenticating with Sitecore Auth endpoint:', error));
40
+ console.log(chalk.yellow('Please ensure your SITECORE_AUTH_CLIENT_ID and SITECORE_AUTH_CLIENT_SECRET environment variables are set correctly.'));
41
+ return null;
42
+ }
43
+ });
@@ -0,0 +1,62 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import { ExtractedFileType, resolveComponentImportFiles, sendCode } from './utils';
11
+ import { fetchBearerToken } from '../auth/fetch-bearer-token';
12
+ import chalk from 'chalk';
13
+ /**
14
+ * Handler for the extract-component API command
15
+ * Reads imports from the componentBuilder.ts file and posts the code to the mesh endpoint
16
+ * @param {ExtractComponentOptions} [args] - The options for code extraction
17
+ * @returns {Promise<void>} void
18
+ */
19
+ export function extractComponents() {
20
+ return __awaiter(this, arguments, void 0, function* (args = {}) {
21
+ if (!validateDeployContext()) {
22
+ console.log(chalk.yellow('Skipping code extraction, not in deploy context'));
23
+ return;
24
+ }
25
+ // TODO: add alternative consent procedure when refining later
26
+ if (!process.env.EXTRACT_CONSENT) {
27
+ console.log(chalk.yellow('Skipping code extraction, EXTRACT_CONSENT is not set'));
28
+ return;
29
+ }
30
+ const basePath = process.cwd();
31
+ try {
32
+ const bearer = yield fetchBearerToken();
33
+ if (!bearer) {
34
+ console.error(chalk.red('Failed to get bearer token, aborting code extraction'));
35
+ return;
36
+ }
37
+ const componentPaths = yield resolveComponentImportFiles(basePath, args.componentBuilderPath);
38
+ const codeDispatches = Array.from(componentPaths, (mapEntry) => sendCode({
39
+ name: mapEntry[0],
40
+ path: mapEntry[1],
41
+ type: ExtractedFileType.Component,
42
+ }, bearer));
43
+ yield Promise.all(codeDispatches);
44
+ }
45
+ catch (error) {
46
+ console.error(chalk.red('Error during component extraction:', error));
47
+ }
48
+ });
49
+ }
50
+ const validateDeployContext = () => {
51
+ if (process.env.NETLIFY && process.env.BUILD_ID) {
52
+ return true;
53
+ }
54
+ // workaround, Vercel does not have variables that are only accessible at build time
55
+ if (process.env.VERCEL && !process.env.VERCEL_REGION) {
56
+ return true;
57
+ }
58
+ if (process.env.SITECORE && process.env.BuildMetadata_BuildId) {
59
+ return true;
60
+ }
61
+ return false;
62
+ };
@@ -0,0 +1,144 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import chalk from 'chalk';
11
+ import path from 'path';
12
+ import fs from 'fs';
13
+ import * as ts from 'typescript';
14
+ import { constants } from '@sitecore-jss/sitecore-jss';
15
+ // TODO:adjust when mesh endpoint is live
16
+ const meshEndpoint = `${process.env.SITECORE_EDGE_URL ||
17
+ constants.SITECORE_EDGE_URL_DEFAULT}/api/v1/mesh`;
18
+ /**
19
+ * Type of file to be sent to the mesh endpoint
20
+ */
21
+ export var ExtractedFileType;
22
+ (function (ExtractedFileType) {
23
+ ExtractedFileType["Component"] = "component";
24
+ ExtractedFileType["Json"] = "json";
25
+ ExtractedFileType["Package"] = "package.json";
26
+ })(ExtractedFileType || (ExtractedFileType = {}));
27
+ /**
28
+ * Parses the componentBuilder.ts file and returns a map of component names
29
+ * and their respective import strings
30
+ * @param {string} appPath path to the JSS app root
31
+ * @param {string} componentBuilderPath path to the app's component builder file. Default: 'src/temp/componentBuilder.ts'
32
+ * @returns map of component names and their respective import strings
33
+ */
34
+ export const resolveComponentImportFiles = (appPath, componentBuilderPath = './src/temp/componentBuilder.ts') => {
35
+ appPath = path.isAbsolute(appPath) ? appPath : path.resolve(process.cwd(), appPath);
36
+ const tsConfig = ts.readConfigFile(path.resolve(appPath, 'tsconfig.json'), ts.sys.readFile);
37
+ if (tsConfig.error) {
38
+ throw new Error(`Error reading tsconfig.json from JSS app root: ${tsConfig.error.messageText}`);
39
+ }
40
+ const tsOptions = Object.assign(Object.assign({}, tsConfig.config.compilerOptions), { baseUrl: appPath });
41
+ const componentBuilderFullPath = path.isAbsolute(componentBuilderPath)
42
+ ? componentBuilderPath
43
+ : path.resolve(appPath, componentBuilderPath);
44
+ // compiler host to process the componentBuilder.ts file and component sources
45
+ const tsHost = ts.createCompilerHost(tsOptions, true);
46
+ const builderSourceFile = tsHost.getSourceFile(componentBuilderFullPath, ts.ScriptTarget.Latest, (msg) => {
47
+ throw new Error(`Failed to parse ${componentBuilderFullPath}: ${msg}`);
48
+ });
49
+ if (!builderSourceFile)
50
+ throw ReferenceError(`Failed to find file ${componentBuilderFullPath}`);
51
+ // this map matches all raw import strings (i.e. * as component) to import strings
52
+ const importStringsMap = {};
53
+ // this map will match component names only to full resolved source file paths
54
+ const componentImportsMap = new Map();
55
+ // name of the export from componentBuilder.ts
56
+ let mapExportName = '';
57
+ // all map.set() assignments in file
58
+ const mapAssignments = [];
59
+ // step 1: get all import statements and map assignments (map.set) from componentBuilder file
60
+ ts.forEachChild(builderSourceFile, (childNode) => {
61
+ var _a;
62
+ // first, all import statements are parsed
63
+ if (ts.isImportDeclaration(childNode) && childNode.importClause) {
64
+ // import path is extracted
65
+ const moduleName = childNode.moduleSpecifier.getText().replace(/['"]/g, '');
66
+ // unless the import is a nodeJS one, or points to dependency package, resolve full path to the imported source file
67
+ if (moduleName.startsWith('node:') || moduleName.indexOf('/node_modules') > -1) {
68
+ return;
69
+ }
70
+ const resolvedModule = ts.nodeModuleNameResolver(moduleName, componentBuilderFullPath, tsOptions, tsHost);
71
+ const resolvedFile = (_a = resolvedModule === null || resolvedModule === void 0 ? void 0 : resolvedModule.resolvedModule) === null || _a === void 0 ? void 0 : _a.resolvedFileName;
72
+ // module imports paths will be resolved to /node_modules location - we don't support that yet
73
+ if (resolvedFile && resolvedFile.indexOf('node_modules') === -1) {
74
+ importStringsMap[childNode.importClause.getText()] = path.resolve(resolvedFile);
75
+ }
76
+ }
77
+ else if (ts.isExpressionStatement(childNode)) {
78
+ // parse map assignments (map.set(..)) to get registered components
79
+ ts.forEachChild(childNode, (expressionNode) => {
80
+ if (ts.isCallExpression(expressionNode) &&
81
+ expressionNode.expression.getText().indexOf('set') !== -1) {
82
+ // get map.set assignments
83
+ mapAssignments.push(expressionNode);
84
+ }
85
+ });
86
+ }
87
+ else if (ts.isExportAssignment(childNode)) {
88
+ // get component map export variable
89
+ // In case there are multiple assignment statements a file, we need to only pick ones that related to exported map
90
+ mapExportName = childNode.expression.getText();
91
+ }
92
+ });
93
+ // step 2: parse mapAssignments and retrieve import paths
94
+ // only for components registered into component map
95
+ for (const mapAssignment of mapAssignments) {
96
+ // only consider the map variable that is exported
97
+ if (mapAssignment.getText().startsWith(mapExportName)) {
98
+ const componentKey = mapAssignment.arguments[1].getText();
99
+ const componentImport = Object.keys(importStringsMap).find((importStatement) => {
100
+ const matcher = new RegExp(`\\b(${componentKey})\\b`);
101
+ return importStatement.match(matcher) !== null;
102
+ });
103
+ if (componentImport) {
104
+ const componentValue = importStringsMap[componentImport];
105
+ componentImportsMap.set(componentKey, componentValue);
106
+ }
107
+ }
108
+ }
109
+ return componentImportsMap;
110
+ };
111
+ /**
112
+ * Sends extracted component code to mesh endpoint
113
+ * @param {ExcractedFile} file properties of the file to be sent
114
+ * @param {string} token bearer token for authentication into mesh endpoint
115
+ */
116
+ export const sendCode = (file, token) => __awaiter(void 0, void 0, void 0, function* () {
117
+ if (!fs.existsSync(file.path)) {
118
+ console.error(chalk.red(`File planned for code extraction not found: ${file.path}`));
119
+ return;
120
+ }
121
+ const code = fs.readFileSync(file.path);
122
+ const response = yield fetch(meshEndpoint, {
123
+ method: 'POST',
124
+ headers: {
125
+ Authorization: `Bearer ${token}`,
126
+ 'Content-Type': 'application/json',
127
+ },
128
+ body: JSON.stringify({
129
+ name: file.name,
130
+ content: code.toString(),
131
+ labels: {
132
+ properties: {
133
+ type: file.type,
134
+ },
135
+ },
136
+ }),
137
+ });
138
+ if (!response.ok) {
139
+ console.error(chalk.red(`Failed to send extracted code from ${file.path}: ${response.statusText}`));
140
+ }
141
+ else {
142
+ console.log(chalk.green(`Code from ${file.path} extracted and sent to mesh endpoint`));
143
+ }
144
+ });
package/dist/esm/index.js CHANGED
@@ -12,6 +12,9 @@ export { createDisconnectedDictionaryService, } from './disconnected-server/dict
12
12
  export { createDefaultDocumentMiddleware, } from './disconnected-server/default-document';
13
13
  export { createDefaultDisconnectedServer, } from './disconnected-server/create-default-disconnected-server';
14
14
  export { resolveScJssConfig } from './resolve-scjssconfig';
15
+ export { constants } from '@sitecore-jss/sitecore-jss';
16
+ export { fetchBearerToken } from './auth/fetch-bearer-token';
17
+ export { extractComponents } from './codegen/extract-components';
15
18
  export * from './templating';
16
19
  export * from './manifest';
17
20
  export * from './pipelines';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sitecore-jss/sitecore-jss-dev-tools",
3
- "version": "22.5.0-beta.1",
3
+ "version": "22.5.0-beta.10",
4
4
  "description": "Utilities to assist in the development and deployment of Sitecore JSS apps.",
5
5
  "main": "dist/cjs/index.js",
6
6
  "module": "dist/esm/index.js",
@@ -33,7 +33,7 @@
33
33
  },
34
34
  "dependencies": {
35
35
  "@babel/parser": "^7.24.0",
36
- "@sitecore-jss/sitecore-jss": "^22.5.0-beta.1",
36
+ "@sitecore-jss/sitecore-jss": "22.5.0-beta.10",
37
37
  "chalk": "^4.1.2",
38
38
  "chokidar": "^3.6.0",
39
39
  "del": "^6.0.0",
@@ -77,7 +77,7 @@
77
77
  "del-cli": "^5.0.0",
78
78
  "eslint": "^8.56.0",
79
79
  "mocha": "^10.2.0",
80
- "nock": "^13.3.0",
80
+ "nock": "14.0.0-beta.7",
81
81
  "nyc": "^15.1.0",
82
82
  "sinon": "^15.0.1",
83
83
  "ts-node": "^10.9.1",
@@ -85,7 +85,7 @@
85
85
  "typescript": "~5.6.3"
86
86
  },
87
87
  "types": "types/index.d.ts",
88
- "gitHead": "e080916b354c36e63f29f01fbcb87688d7f2b4cd",
88
+ "gitHead": "5219803dfd700b1e2967c02e1b17db07f6f31b45",
89
89
  "files": [
90
90
  "dist",
91
91
  "types",
@@ -0,0 +1,8 @@
1
+ export declare const DEFAULT_SITECORE_AUTH_ENDPOINT = "https://auth.sitecorecloud.io/oauth/token";
2
+ export declare const DEFAULT_SITECORE_AUTH_AUDIENCE = "https://api.sitecorecloud.io";
3
+ /**
4
+ * Connects to M2M endpoint and fetches the bearer token
5
+ * Uses client_id and client_secret from environment variables
6
+ * @returns {string} bearer token string
7
+ */
8
+ export declare const fetchBearerToken: () => Promise<any>;
@@ -0,0 +1,11 @@
1
+ type ExtractComponentOptions = {
2
+ componentBuilderPath?: string;
3
+ };
4
+ /**
5
+ * Handler for the extract-component API command
6
+ * Reads imports from the componentBuilder.ts file and posts the code to the mesh endpoint
7
+ * @param {ExtractComponentOptions} [args] - The options for code extraction
8
+ * @returns {Promise<void>} void
9
+ */
10
+ export declare function extractComponents(args?: ExtractComponentOptions): Promise<void>;
11
+ export {};
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Description properties for the files sent to the mesh endpoint
3
+ */
4
+ export type ExtractedFile = {
5
+ name: string;
6
+ path: string;
7
+ type: ExtractedFileType;
8
+ };
9
+ /**
10
+ * Type of file to be sent to the mesh endpoint
11
+ */
12
+ export declare enum ExtractedFileType {
13
+ Component = "component",
14
+ Json = "json",
15
+ Package = "package.json"
16
+ }
17
+ /**
18
+ * Parses the componentBuilder.ts file and returns a map of component names
19
+ * and their respective import strings
20
+ * @param {string} appPath path to the JSS app root
21
+ * @param {string} componentBuilderPath path to the app's component builder file. Default: 'src/temp/componentBuilder.ts'
22
+ * @returns map of component names and their respective import strings
23
+ */
24
+ export declare const resolveComponentImportFiles: (appPath: string, componentBuilderPath?: string) => Map<string, string>;
25
+ /**
26
+ * Sends extracted component code to mesh endpoint
27
+ * @param {ExcractedFile} file properties of the file to be sent
28
+ * @param {string} token bearer token for authentication into mesh endpoint
29
+ */
30
+ export declare const sendCode: (file: ExtractedFile, token: string) => Promise<void>;
package/types/index.d.ts CHANGED
@@ -14,6 +14,9 @@ export { createDefaultDocumentMiddleware, DefaultDocumentMiddlewareOptions, } fr
14
14
  export { createDefaultDisconnectedServer, DisconnectedServerOptions, } from './disconnected-server/create-default-disconnected-server';
15
15
  export { ScJssConfig, JssConfiguration, resolveScJssConfig } from './resolve-scjssconfig';
16
16
  export { Metadata } from '@sitecore-jss/sitecore-jss/editing';
17
+ export { constants } from '@sitecore-jss/sitecore-jss';
18
+ export { fetchBearerToken } from './auth/fetch-bearer-token';
19
+ export { extractComponents } from './codegen/extract-components';
17
20
  export * from './templating';
18
21
  export * from './manifest';
19
22
  export * from './pipelines';