@sitecore-jss/sitecore-jss-dev-tools 22.5.0-beta.7 → 22.5.0-beta.9
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/dist/cjs/auth/fetch-bearer-token.js +50 -0
- package/dist/cjs/codegen/extract-components.js +68 -0
- package/dist/cjs/codegen/utils.js +175 -0
- package/dist/cjs/index.js +7 -1
- package/dist/esm/auth/fetch-bearer-token.js +43 -0
- package/dist/esm/codegen/extract-components.js +62 -0
- package/dist/esm/codegen/utils.js +144 -0
- package/dist/esm/index.js +3 -0
- package/package.json +4 -4
- package/types/auth/fetch-bearer-token.d.ts +8 -0
- package/types/codegen/extract-components.d.ts +11 -0
- package/types/codegen/utils.d.ts +30 -0
- package/types/index.d.ts +3 -0
|
@@ -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.
|
|
3
|
+
"version": "22.5.0-beta.9",
|
|
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.
|
|
36
|
+
"@sitecore-jss/sitecore-jss": "22.5.0-beta.9",
|
|
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": "
|
|
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": "
|
|
88
|
+
"gitHead": "5ff649ad7266eb6d4ccdda4ff4aa3d2395071eed",
|
|
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';
|