@magentrix-corp/magentrix-cli 1.3.16 → 1.3.17
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/LICENSE +25 -25
- package/README.md +1166 -1166
- package/actions/autopublish.old.js +293 -293
- package/actions/config.js +182 -182
- package/actions/create.js +466 -466
- package/actions/help.js +164 -164
- package/actions/iris/buildStage.js +874 -874
- package/actions/iris/delete.js +256 -256
- package/actions/iris/dev.js +391 -391
- package/actions/iris/index.js +6 -6
- package/actions/iris/link.js +375 -375
- package/actions/iris/recover.js +268 -268
- package/actions/main.js +80 -80
- package/actions/publish.js +1420 -1420
- package/actions/pull.js +684 -684
- package/actions/setup.js +148 -148
- package/actions/status.js +17 -17
- package/actions/update.js +248 -248
- package/bin/magentrix.js +393 -393
- package/package.json +55 -55
- package/utils/assetPaths.js +158 -158
- package/utils/autopublishLock.js +77 -77
- package/utils/cacher.js +206 -206
- package/utils/cli/checkInstanceUrl.js +76 -74
- package/utils/cli/helpers/compare.js +282 -282
- package/utils/cli/helpers/ensureApiKey.js +63 -63
- package/utils/cli/helpers/ensureCredentials.js +68 -68
- package/utils/cli/helpers/ensureInstanceUrl.js +75 -75
- package/utils/cli/writeRecords.js +262 -262
- package/utils/compare.js +135 -135
- package/utils/compress.js +17 -17
- package/utils/config.js +527 -527
- package/utils/debug.js +144 -144
- package/utils/diagnostics/testPublishLogic.js +96 -96
- package/utils/diff.js +49 -49
- package/utils/downloadAssets.js +291 -291
- package/utils/filetag.js +115 -115
- package/utils/hash.js +14 -14
- package/utils/iris/backup.js +411 -411
- package/utils/iris/builder.js +541 -541
- package/utils/iris/config-reader.js +664 -664
- package/utils/iris/deleteHelper.js +150 -150
- package/utils/iris/errors.js +537 -537
- package/utils/iris/linker.js +601 -601
- package/utils/iris/lock.js +360 -360
- package/utils/iris/validation.js +360 -360
- package/utils/iris/validator.js +281 -281
- package/utils/iris/zipper.js +248 -248
- package/utils/logger.js +291 -291
- package/utils/magentrix/api/assets.js +220 -220
- package/utils/magentrix/api/auth.js +107 -107
- package/utils/magentrix/api/createEntity.js +61 -61
- package/utils/magentrix/api/deleteEntity.js +55 -55
- package/utils/magentrix/api/iris.js +251 -251
- package/utils/magentrix/api/meqlQuery.js +36 -36
- package/utils/magentrix/api/retrieveEntity.js +86 -86
- package/utils/magentrix/api/updateEntity.js +66 -66
- package/utils/magentrix/fetch.js +168 -168
- package/utils/merge.js +22 -22
- package/utils/permissionError.js +70 -70
- package/utils/preferences.js +40 -40
- package/utils/progress.js +469 -469
- package/utils/spinner.js +43 -43
- package/utils/template.js +52 -52
- package/utils/updateFileBase.js +121 -121
- package/utils/workspaces.js +108 -108
- package/vars/config.js +11 -11
- package/vars/global.js +50 -50
|
@@ -1,86 +1,86 @@
|
|
|
1
|
-
import { fetchMagentrix } from "../fetch.js";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Lists all entities available from the Magentrix API.
|
|
5
|
-
*
|
|
6
|
-
* Makes an authenticated GET request to `/api/3.0/entity` to retrieve metadata
|
|
7
|
-
* about all available entities (objects) in the Magentrix instance.
|
|
8
|
-
*
|
|
9
|
-
* Handles and throws both network errors and API-level errors with detailed messages.
|
|
10
|
-
*
|
|
11
|
-
* @async
|
|
12
|
-
* @param {string} instanceUrl - The base URL of the Magentrix instance.
|
|
13
|
-
* @param {string} token - The OAuth or access token for authentication.
|
|
14
|
-
* @returns {Promise<Object>} Parsed JSON response with entities metadata.
|
|
15
|
-
* @throws {Error} If required arguments are missing, network error occurs,
|
|
16
|
-
* HTTP error is returned, or API-level errors are found in the response.
|
|
17
|
-
*/
|
|
18
|
-
export const listEntities = async (instanceUrl, token) => {
|
|
19
|
-
// --- Validate required input parameters ---
|
|
20
|
-
if (!instanceUrl || !token) {
|
|
21
|
-
throw new Error('Missing required Magentrix instanceUrl or token');
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
const data = await fetchMagentrix({
|
|
25
|
-
instanceUrl,
|
|
26
|
-
token,
|
|
27
|
-
path: '/api/3.0/entity',
|
|
28
|
-
method: "GET"
|
|
29
|
-
})
|
|
30
|
-
|
|
31
|
-
return data;
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Retrieves a specific ActiveClass or ActivePage entity by ID from Magentrix via the REST API.
|
|
36
|
-
*
|
|
37
|
-
* @async
|
|
38
|
-
* @function retrieveEntity
|
|
39
|
-
* @param {string} instanceUrl - The base URL of the Magentrix instance (e.g. "https://your.magentrix.com").
|
|
40
|
-
* @param {string} token - The OAuth2 bearer token for authentication.
|
|
41
|
-
* @param {string} entityName - The Magentrix entity type. Allowed: "ActiveClass" or "ActivePage" (case-insensitive).
|
|
42
|
-
* @param {string} recordId - The unique Magentrix record ID to retrieve.
|
|
43
|
-
* @returns {Promise<Object>} The API response object containing the record data.
|
|
44
|
-
* @throws {Error} If required parameters are missing, entityName is invalid, or recordId is not provided.
|
|
45
|
-
*
|
|
46
|
-
* @example
|
|
47
|
-
* const record = await retrieveEntity(
|
|
48
|
-
* "https://your.magentrix.com",
|
|
49
|
-
* "yourToken",
|
|
50
|
-
* "ActiveClass",
|
|
51
|
-
* "06bdc45e-8222-44f5-9ed2-40f5a7bc6cb3"
|
|
52
|
-
* );
|
|
53
|
-
*/
|
|
54
|
-
export const retrieveEntity = async (instanceUrl, token, entityName, recordId) => {
|
|
55
|
-
// --- Validate required parameters ---
|
|
56
|
-
if (!instanceUrl || typeof instanceUrl !== 'string') {
|
|
57
|
-
throw new Error('Missing or invalid Magentrix instanceUrl');
|
|
58
|
-
}
|
|
59
|
-
if (!token || typeof token !== 'string') {
|
|
60
|
-
throw new Error('Missing or invalid Magentrix token');
|
|
61
|
-
}
|
|
62
|
-
if (!entityName || typeof entityName !== 'string') {
|
|
63
|
-
throw new Error("Missing or invalid 'entityName' (must be 'ActiveClass' or 'ActivePage')");
|
|
64
|
-
}
|
|
65
|
-
if (!recordId || typeof recordId !== 'string') {
|
|
66
|
-
throw new Error("Missing or invalid 'recordId' (must be a Magentrix record GUID string)");
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// --- Validate entity type ---
|
|
70
|
-
const allowedEntities = ['activeclass', 'activepage'];
|
|
71
|
-
const entity = entityName.trim().toLowerCase();
|
|
72
|
-
if (!allowedEntities.includes(entity)) {
|
|
73
|
-
throw new Error("Invalid 'entityName'. Allowed: 'ActiveClass' or 'ActivePage'");
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// --- Make GET request to Magentrix API ---
|
|
77
|
-
const response = await fetchMagentrix({
|
|
78
|
-
instanceUrl,
|
|
79
|
-
token,
|
|
80
|
-
path: `/api/3.0/entity/${entity}/${recordId}`,
|
|
81
|
-
method: "GET",
|
|
82
|
-
returnErrorObject: true
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
return response;
|
|
86
|
-
};
|
|
1
|
+
import { fetchMagentrix } from "../fetch.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Lists all entities available from the Magentrix API.
|
|
5
|
+
*
|
|
6
|
+
* Makes an authenticated GET request to `/api/3.0/entity` to retrieve metadata
|
|
7
|
+
* about all available entities (objects) in the Magentrix instance.
|
|
8
|
+
*
|
|
9
|
+
* Handles and throws both network errors and API-level errors with detailed messages.
|
|
10
|
+
*
|
|
11
|
+
* @async
|
|
12
|
+
* @param {string} instanceUrl - The base URL of the Magentrix instance.
|
|
13
|
+
* @param {string} token - The OAuth or access token for authentication.
|
|
14
|
+
* @returns {Promise<Object>} Parsed JSON response with entities metadata.
|
|
15
|
+
* @throws {Error} If required arguments are missing, network error occurs,
|
|
16
|
+
* HTTP error is returned, or API-level errors are found in the response.
|
|
17
|
+
*/
|
|
18
|
+
export const listEntities = async (instanceUrl, token) => {
|
|
19
|
+
// --- Validate required input parameters ---
|
|
20
|
+
if (!instanceUrl || !token) {
|
|
21
|
+
throw new Error('Missing required Magentrix instanceUrl or token');
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const data = await fetchMagentrix({
|
|
25
|
+
instanceUrl,
|
|
26
|
+
token,
|
|
27
|
+
path: '/api/3.0/entity',
|
|
28
|
+
method: "GET"
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
return data;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Retrieves a specific ActiveClass or ActivePage entity by ID from Magentrix via the REST API.
|
|
36
|
+
*
|
|
37
|
+
* @async
|
|
38
|
+
* @function retrieveEntity
|
|
39
|
+
* @param {string} instanceUrl - The base URL of the Magentrix instance (e.g. "https://your.magentrix.com").
|
|
40
|
+
* @param {string} token - The OAuth2 bearer token for authentication.
|
|
41
|
+
* @param {string} entityName - The Magentrix entity type. Allowed: "ActiveClass" or "ActivePage" (case-insensitive).
|
|
42
|
+
* @param {string} recordId - The unique Magentrix record ID to retrieve.
|
|
43
|
+
* @returns {Promise<Object>} The API response object containing the record data.
|
|
44
|
+
* @throws {Error} If required parameters are missing, entityName is invalid, or recordId is not provided.
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* const record = await retrieveEntity(
|
|
48
|
+
* "https://your.magentrix.com",
|
|
49
|
+
* "yourToken",
|
|
50
|
+
* "ActiveClass",
|
|
51
|
+
* "06bdc45e-8222-44f5-9ed2-40f5a7bc6cb3"
|
|
52
|
+
* );
|
|
53
|
+
*/
|
|
54
|
+
export const retrieveEntity = async (instanceUrl, token, entityName, recordId) => {
|
|
55
|
+
// --- Validate required parameters ---
|
|
56
|
+
if (!instanceUrl || typeof instanceUrl !== 'string') {
|
|
57
|
+
throw new Error('Missing or invalid Magentrix instanceUrl');
|
|
58
|
+
}
|
|
59
|
+
if (!token || typeof token !== 'string') {
|
|
60
|
+
throw new Error('Missing or invalid Magentrix token');
|
|
61
|
+
}
|
|
62
|
+
if (!entityName || typeof entityName !== 'string') {
|
|
63
|
+
throw new Error("Missing or invalid 'entityName' (must be 'ActiveClass' or 'ActivePage')");
|
|
64
|
+
}
|
|
65
|
+
if (!recordId || typeof recordId !== 'string') {
|
|
66
|
+
throw new Error("Missing or invalid 'recordId' (must be a Magentrix record GUID string)");
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// --- Validate entity type ---
|
|
70
|
+
const allowedEntities = ['activeclass', 'activepage'];
|
|
71
|
+
const entity = entityName.trim().toLowerCase();
|
|
72
|
+
if (!allowedEntities.includes(entity)) {
|
|
73
|
+
throw new Error("Invalid 'entityName'. Allowed: 'ActiveClass' or 'ActivePage'");
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// --- Make GET request to Magentrix API ---
|
|
77
|
+
const response = await fetchMagentrix({
|
|
78
|
+
instanceUrl,
|
|
79
|
+
token,
|
|
80
|
+
path: `/api/3.0/entity/${entity}/${recordId}`,
|
|
81
|
+
method: "GET",
|
|
82
|
+
returnErrorObject: true
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
return response;
|
|
86
|
+
};
|
|
@@ -1,66 +1,66 @@
|
|
|
1
|
-
import { fetchMagentrix } from "../fetch.js";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Updates an existing ActiveClass or ActivePage entity in Magentrix via the REST API.
|
|
5
|
-
*
|
|
6
|
-
* @async
|
|
7
|
-
* @function updateEntity
|
|
8
|
-
* @param {string} instanceUrl - The base URL of the Magentrix instance (e.g. "https://your.magentrix.com").
|
|
9
|
-
* @param {string} token - The OAuth2 bearer token for authentication.
|
|
10
|
-
* @param {string} entityName - The Magentrix entity type. Allowed: "ActiveClass" or "ActivePage" (case-insensitive).
|
|
11
|
-
* @param {string} recordId - The unique Magentrix record ID to update.
|
|
12
|
-
* @param {Object} data - The fields to update on the entity. Provide any subset of updatable fields (e.g. Name, Description, Body, Type, etc).
|
|
13
|
-
* @returns {Promise<Object>} The API response object containing updated record data.
|
|
14
|
-
* @throws {Error} If required parameters are missing, entityName is invalid, recordId is not provided, or data is not an object.
|
|
15
|
-
*
|
|
16
|
-
* @example
|
|
17
|
-
* const updated = await updateEntity(
|
|
18
|
-
* "https://your.magentrix.com",
|
|
19
|
-
* "yourToken",
|
|
20
|
-
* "ActiveClass",
|
|
21
|
-
* "06bdc45e-8222-44f5-9ed2-40f5a7bc6cb3",
|
|
22
|
-
* { Name: "RenamedClass", Description: "Updated" }
|
|
23
|
-
* );
|
|
24
|
-
*/
|
|
25
|
-
export const updateEntity = async (instanceUrl, token, entityName, recordId, data) => {
|
|
26
|
-
// --- Validate required parameters ---
|
|
27
|
-
if (!instanceUrl || typeof instanceUrl !== 'string') {
|
|
28
|
-
throw new Error('Missing or invalid Magentrix instanceUrl');
|
|
29
|
-
}
|
|
30
|
-
if (!token || typeof token !== 'string') {
|
|
31
|
-
throw new Error('Missing or invalid Magentrix token');
|
|
32
|
-
}
|
|
33
|
-
if (!entityName || typeof entityName !== 'string') {
|
|
34
|
-
throw new Error("Missing or invalid 'entityName' (must be 'ActiveClass' or 'ActivePage')");
|
|
35
|
-
}
|
|
36
|
-
if (!recordId || typeof recordId !== 'string') {
|
|
37
|
-
throw new Error("Missing or invalid 'recordId' (must be a Magentrix record GUID string)");
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
// --- Validate entity type ---
|
|
41
|
-
const allowedEntities = ['activeclass', 'activepage'];
|
|
42
|
-
const entity = entityName.trim().toLowerCase();
|
|
43
|
-
if (!allowedEntities.includes(entity)) {
|
|
44
|
-
throw new Error("Invalid 'entityName'. Allowed: 'ActiveClass' or 'ActivePage'");
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
// --- Validate update data ---
|
|
48
|
-
if (!data || typeof data !== 'object' || Array.isArray(data)) {
|
|
49
|
-
throw new Error('Missing or invalid data object for entity update');
|
|
50
|
-
}
|
|
51
|
-
if (Object.keys(data).length === 0) {
|
|
52
|
-
throw new Error('No fields provided to update');
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// --- Make PATCH request to Magentrix API ---
|
|
56
|
-
const response = await fetchMagentrix({
|
|
57
|
-
instanceUrl,
|
|
58
|
-
token,
|
|
59
|
-
path: `/api/3.0/entity/${entity}/${recordId}`,
|
|
60
|
-
method: "PATCH",
|
|
61
|
-
body: data,
|
|
62
|
-
returnErrorObject: true
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
return response;
|
|
66
|
-
};
|
|
1
|
+
import { fetchMagentrix } from "../fetch.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Updates an existing ActiveClass or ActivePage entity in Magentrix via the REST API.
|
|
5
|
+
*
|
|
6
|
+
* @async
|
|
7
|
+
* @function updateEntity
|
|
8
|
+
* @param {string} instanceUrl - The base URL of the Magentrix instance (e.g. "https://your.magentrix.com").
|
|
9
|
+
* @param {string} token - The OAuth2 bearer token for authentication.
|
|
10
|
+
* @param {string} entityName - The Magentrix entity type. Allowed: "ActiveClass" or "ActivePage" (case-insensitive).
|
|
11
|
+
* @param {string} recordId - The unique Magentrix record ID to update.
|
|
12
|
+
* @param {Object} data - The fields to update on the entity. Provide any subset of updatable fields (e.g. Name, Description, Body, Type, etc).
|
|
13
|
+
* @returns {Promise<Object>} The API response object containing updated record data.
|
|
14
|
+
* @throws {Error} If required parameters are missing, entityName is invalid, recordId is not provided, or data is not an object.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* const updated = await updateEntity(
|
|
18
|
+
* "https://your.magentrix.com",
|
|
19
|
+
* "yourToken",
|
|
20
|
+
* "ActiveClass",
|
|
21
|
+
* "06bdc45e-8222-44f5-9ed2-40f5a7bc6cb3",
|
|
22
|
+
* { Name: "RenamedClass", Description: "Updated" }
|
|
23
|
+
* );
|
|
24
|
+
*/
|
|
25
|
+
export const updateEntity = async (instanceUrl, token, entityName, recordId, data) => {
|
|
26
|
+
// --- Validate required parameters ---
|
|
27
|
+
if (!instanceUrl || typeof instanceUrl !== 'string') {
|
|
28
|
+
throw new Error('Missing or invalid Magentrix instanceUrl');
|
|
29
|
+
}
|
|
30
|
+
if (!token || typeof token !== 'string') {
|
|
31
|
+
throw new Error('Missing or invalid Magentrix token');
|
|
32
|
+
}
|
|
33
|
+
if (!entityName || typeof entityName !== 'string') {
|
|
34
|
+
throw new Error("Missing or invalid 'entityName' (must be 'ActiveClass' or 'ActivePage')");
|
|
35
|
+
}
|
|
36
|
+
if (!recordId || typeof recordId !== 'string') {
|
|
37
|
+
throw new Error("Missing or invalid 'recordId' (must be a Magentrix record GUID string)");
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// --- Validate entity type ---
|
|
41
|
+
const allowedEntities = ['activeclass', 'activepage'];
|
|
42
|
+
const entity = entityName.trim().toLowerCase();
|
|
43
|
+
if (!allowedEntities.includes(entity)) {
|
|
44
|
+
throw new Error("Invalid 'entityName'. Allowed: 'ActiveClass' or 'ActivePage'");
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// --- Validate update data ---
|
|
48
|
+
if (!data || typeof data !== 'object' || Array.isArray(data)) {
|
|
49
|
+
throw new Error('Missing or invalid data object for entity update');
|
|
50
|
+
}
|
|
51
|
+
if (Object.keys(data).length === 0) {
|
|
52
|
+
throw new Error('No fields provided to update');
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// --- Make PATCH request to Magentrix API ---
|
|
56
|
+
const response = await fetchMagentrix({
|
|
57
|
+
instanceUrl,
|
|
58
|
+
token,
|
|
59
|
+
path: `/api/3.0/entity/${entity}/${recordId}`,
|
|
60
|
+
method: "PATCH",
|
|
61
|
+
body: data,
|
|
62
|
+
returnErrorObject: true
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
return response;
|
|
66
|
+
};
|
package/utils/magentrix/fetch.js
CHANGED
|
@@ -1,168 +1,168 @@
|
|
|
1
|
-
import debug from '../debug.js';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Checks if a request body should be JSON-stringified.
|
|
5
|
-
* Excludes FormData, Blob, ArrayBuffer, URLSearchParams, and typed arrays.
|
|
6
|
-
* @param {any} body
|
|
7
|
-
* @returns {boolean}
|
|
8
|
-
*/
|
|
9
|
-
function isJsonBody(body) {
|
|
10
|
-
return (
|
|
11
|
-
typeof body === 'object' &&
|
|
12
|
-
body !== null &&
|
|
13
|
-
!(body instanceof FormData) &&
|
|
14
|
-
!(body instanceof Blob) &&
|
|
15
|
-
!(body instanceof ArrayBuffer) &&
|
|
16
|
-
!(body instanceof URLSearchParams) &&
|
|
17
|
-
!ArrayBuffer.isView(body) // covers Uint8Array, etc.
|
|
18
|
-
);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Fetch helper for Magentrix API.
|
|
23
|
-
* Handles network, HTTP, and API-level errors with detailed messages or returns error info as JSON object.
|
|
24
|
-
*
|
|
25
|
-
* @async
|
|
26
|
-
* @function fetchMagentrix
|
|
27
|
-
* @param {Object} opts - Fetch options.
|
|
28
|
-
* @param {string} opts.instanceUrl - Magentrix instance base URL (e.g. https://your.magentrix.com).
|
|
29
|
-
* @param {string} [opts.token] - OAuth2 bearer token for authentication (optional for public endpoints).
|
|
30
|
-
* @param {string} opts.path - API path (e.g. '/api/3.0/entity/activeclass').
|
|
31
|
-
* @param {string} [opts.method='GET'] - HTTP method.
|
|
32
|
-
* @param {any} [opts.body] - Request body (object for JSON, or raw for FormData, Blob, string, etc).
|
|
33
|
-
* @param {Object} [opts.headers] - Additional headers to merge with defaults.
|
|
34
|
-
* @param {boolean} [opts.returnErrorObject=false] - If true, errors are returned as JSON objects instead of thrown as Error.
|
|
35
|
-
* @returns {Promise<Object>} Parsed JSON response from the API if successful.
|
|
36
|
-
* @throws {Error|Object} Throws Error (default) or error object if returnErrorObject is true.
|
|
37
|
-
*/
|
|
38
|
-
export const fetchMagentrix = async ({
|
|
39
|
-
instanceUrl,
|
|
40
|
-
token,
|
|
41
|
-
path,
|
|
42
|
-
method = 'GET',
|
|
43
|
-
body,
|
|
44
|
-
headers = {},
|
|
45
|
-
ignoreContentType = false,
|
|
46
|
-
returnErrorObject = false,
|
|
47
|
-
errorConfig = {
|
|
48
|
-
includeStatus: false,
|
|
49
|
-
includeURL: false,
|
|
50
|
-
label: '', // 'Magentrix errors:',
|
|
51
|
-
bullets: false
|
|
52
|
-
},
|
|
53
|
-
}) => {
|
|
54
|
-
if (!instanceUrl || !path) {
|
|
55
|
-
const err = { type: 'client', message: 'Missing required parameter(s): instanceUrl or path' };
|
|
56
|
-
if (returnErrorObject) throw err;
|
|
57
|
-
throw new Error(err.message);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
const finalHeaders = {
|
|
61
|
-
'Accept': 'application/json',
|
|
62
|
-
...headers
|
|
63
|
-
};
|
|
64
|
-
if (isJsonBody(body)) finalHeaders['Content-Type'] = 'application/json';
|
|
65
|
-
if (token) finalHeaders['Authorization'] = `Bearer ${token}`;
|
|
66
|
-
let requestBody;
|
|
67
|
-
if (body === undefined || body === null) {
|
|
68
|
-
requestBody = undefined;
|
|
69
|
-
} else if (isJsonBody(body)) {
|
|
70
|
-
requestBody = JSON.stringify(body);
|
|
71
|
-
} else {
|
|
72
|
-
requestBody = body;
|
|
73
|
-
}
|
|
74
|
-
if (!finalHeaders['Content-Type'] && !ignoreContentType) finalHeaders['Content-Type'] = 'application/json';
|
|
75
|
-
|
|
76
|
-
const fullUrl = `${instanceUrl.replace(/\/$/, '')}${path}`;
|
|
77
|
-
debug.request(method, fullUrl, finalHeaders, body);
|
|
78
|
-
|
|
79
|
-
let response, responseData;
|
|
80
|
-
try {
|
|
81
|
-
response = await fetch(fullUrl, {
|
|
82
|
-
method,
|
|
83
|
-
headers: finalHeaders,
|
|
84
|
-
body: requestBody
|
|
85
|
-
});
|
|
86
|
-
} catch (err) {
|
|
87
|
-
const cause = err.cause || {};
|
|
88
|
-
const rootDetail = cause.code ? `${cause.code}: ${cause.message || ''}` : '';
|
|
89
|
-
debug.log('HTTP-ERR', `Network error: ${err.message}${rootDetail ? ` (${rootDetail})` : ''}`);
|
|
90
|
-
if (cause.code) debug.log('HTTP-ERR', `Error code: ${cause.code}, hostname: ${cause.hostname || 'N/A'}`);
|
|
91
|
-
if (err.stack) debug.log('HTTP-ERR', `Stack: ${err.stack}`);
|
|
92
|
-
const errorObj = {
|
|
93
|
-
type: 'network',
|
|
94
|
-
message: `Network error contacting Magentrix API: ${err.message}`,
|
|
95
|
-
error: err
|
|
96
|
-
};
|
|
97
|
-
if (returnErrorObject) throw errorObj;
|
|
98
|
-
throw new Error(errorObj.message);
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
try {
|
|
102
|
-
responseData = await response.json();
|
|
103
|
-
} catch {
|
|
104
|
-
responseData = null;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
debug.response(response.status, response.statusText, response.headers, responseData);
|
|
108
|
-
|
|
109
|
-
if (!response.ok) {
|
|
110
|
-
const errorObj = {
|
|
111
|
-
type: 'http',
|
|
112
|
-
status: response.status,
|
|
113
|
-
statusText: response.statusText,
|
|
114
|
-
url: response.url,
|
|
115
|
-
response: responseData,
|
|
116
|
-
};
|
|
117
|
-
// Optionally add detailed error message
|
|
118
|
-
let msg = errorConfig?.includeStatus ? `HTTP ${response.status} ${response.statusText}\n` : '';
|
|
119
|
-
if (responseData) {
|
|
120
|
-
const responseErrs = responseData.errors || responseData.Errors;
|
|
121
|
-
|
|
122
|
-
if (Array.isArray(responseErrs) && responseErrs.length) {
|
|
123
|
-
msg += `${errorConfig?.label}${errorConfig?.label ? '\n' : ''}` + responseErrs.map(e => `${errorConfig?.bullets ? " • " : ""}${e.code ? `[${e.code || '500'}] ` : ''}${e.message || e}`).join('\n');
|
|
124
|
-
} else if (responseData.message) {
|
|
125
|
-
msg += `Magentrix message: ${responseData.message}`;
|
|
126
|
-
} else {
|
|
127
|
-
msg += JSON.stringify(responseData);
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
if (errorConfig?.includeURL) msg += `\nURL: ${response.url}`;
|
|
131
|
-
errorObj.message = msg;
|
|
132
|
-
debug.log('HTTP-ERR', `HTTP ${response.status}: ${msg}`);
|
|
133
|
-
if (returnErrorObject) throw errorObj;
|
|
134
|
-
throw new Error(msg);
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
// Handle API-level business logic errors
|
|
138
|
-
if (
|
|
139
|
-
!responseData ||
|
|
140
|
-
responseData.success === false ||
|
|
141
|
-
(Array.isArray(responseData?.errors) && responseData.errors.length > 0) ||
|
|
142
|
-
responseData.error
|
|
143
|
-
) {
|
|
144
|
-
const errorObj = {
|
|
145
|
-
type: 'api',
|
|
146
|
-
url: response.url,
|
|
147
|
-
response: responseData
|
|
148
|
-
};
|
|
149
|
-
let details = '';
|
|
150
|
-
if (Array.isArray(responseData?.errors) && responseData.errors.length) {
|
|
151
|
-
details = responseData.errors
|
|
152
|
-
.map(e => ` • ${e.code ? `[${e.code}] ` : ''}${e.message}`)
|
|
153
|
-
.join('\n');
|
|
154
|
-
} else if (responseData?.message) {
|
|
155
|
-
details = responseData.message;
|
|
156
|
-
} else if (typeof responseData === 'object') {
|
|
157
|
-
details = JSON.stringify(responseData);
|
|
158
|
-
} else {
|
|
159
|
-
details = String(responseData);
|
|
160
|
-
}
|
|
161
|
-
errorObj.message = `Magentrix API error:\n${details}`;
|
|
162
|
-
debug.log('API-ERR', errorObj.message);
|
|
163
|
-
if (returnErrorObject) throw errorObj;
|
|
164
|
-
throw new Error(errorObj.message);
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
return responseData;
|
|
168
|
-
};
|
|
1
|
+
import debug from '../debug.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Checks if a request body should be JSON-stringified.
|
|
5
|
+
* Excludes FormData, Blob, ArrayBuffer, URLSearchParams, and typed arrays.
|
|
6
|
+
* @param {any} body
|
|
7
|
+
* @returns {boolean}
|
|
8
|
+
*/
|
|
9
|
+
function isJsonBody(body) {
|
|
10
|
+
return (
|
|
11
|
+
typeof body === 'object' &&
|
|
12
|
+
body !== null &&
|
|
13
|
+
!(body instanceof FormData) &&
|
|
14
|
+
!(body instanceof Blob) &&
|
|
15
|
+
!(body instanceof ArrayBuffer) &&
|
|
16
|
+
!(body instanceof URLSearchParams) &&
|
|
17
|
+
!ArrayBuffer.isView(body) // covers Uint8Array, etc.
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Fetch helper for Magentrix API.
|
|
23
|
+
* Handles network, HTTP, and API-level errors with detailed messages or returns error info as JSON object.
|
|
24
|
+
*
|
|
25
|
+
* @async
|
|
26
|
+
* @function fetchMagentrix
|
|
27
|
+
* @param {Object} opts - Fetch options.
|
|
28
|
+
* @param {string} opts.instanceUrl - Magentrix instance base URL (e.g. https://your.magentrix.com).
|
|
29
|
+
* @param {string} [opts.token] - OAuth2 bearer token for authentication (optional for public endpoints).
|
|
30
|
+
* @param {string} opts.path - API path (e.g. '/api/3.0/entity/activeclass').
|
|
31
|
+
* @param {string} [opts.method='GET'] - HTTP method.
|
|
32
|
+
* @param {any} [opts.body] - Request body (object for JSON, or raw for FormData, Blob, string, etc).
|
|
33
|
+
* @param {Object} [opts.headers] - Additional headers to merge with defaults.
|
|
34
|
+
* @param {boolean} [opts.returnErrorObject=false] - If true, errors are returned as JSON objects instead of thrown as Error.
|
|
35
|
+
* @returns {Promise<Object>} Parsed JSON response from the API if successful.
|
|
36
|
+
* @throws {Error|Object} Throws Error (default) or error object if returnErrorObject is true.
|
|
37
|
+
*/
|
|
38
|
+
export const fetchMagentrix = async ({
|
|
39
|
+
instanceUrl,
|
|
40
|
+
token,
|
|
41
|
+
path,
|
|
42
|
+
method = 'GET',
|
|
43
|
+
body,
|
|
44
|
+
headers = {},
|
|
45
|
+
ignoreContentType = false,
|
|
46
|
+
returnErrorObject = false,
|
|
47
|
+
errorConfig = {
|
|
48
|
+
includeStatus: false,
|
|
49
|
+
includeURL: false,
|
|
50
|
+
label: '', // 'Magentrix errors:',
|
|
51
|
+
bullets: false
|
|
52
|
+
},
|
|
53
|
+
}) => {
|
|
54
|
+
if (!instanceUrl || !path) {
|
|
55
|
+
const err = { type: 'client', message: 'Missing required parameter(s): instanceUrl or path' };
|
|
56
|
+
if (returnErrorObject) throw err;
|
|
57
|
+
throw new Error(err.message);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const finalHeaders = {
|
|
61
|
+
'Accept': 'application/json',
|
|
62
|
+
...headers
|
|
63
|
+
};
|
|
64
|
+
if (isJsonBody(body)) finalHeaders['Content-Type'] = 'application/json';
|
|
65
|
+
if (token) finalHeaders['Authorization'] = `Bearer ${token}`;
|
|
66
|
+
let requestBody;
|
|
67
|
+
if (body === undefined || body === null) {
|
|
68
|
+
requestBody = undefined;
|
|
69
|
+
} else if (isJsonBody(body)) {
|
|
70
|
+
requestBody = JSON.stringify(body);
|
|
71
|
+
} else {
|
|
72
|
+
requestBody = body;
|
|
73
|
+
}
|
|
74
|
+
if (!finalHeaders['Content-Type'] && !ignoreContentType) finalHeaders['Content-Type'] = 'application/json';
|
|
75
|
+
|
|
76
|
+
const fullUrl = `${instanceUrl.replace(/\/$/, '')}${path}`;
|
|
77
|
+
debug.request(method, fullUrl, finalHeaders, body);
|
|
78
|
+
|
|
79
|
+
let response, responseData;
|
|
80
|
+
try {
|
|
81
|
+
response = await fetch(fullUrl, {
|
|
82
|
+
method,
|
|
83
|
+
headers: finalHeaders,
|
|
84
|
+
body: requestBody
|
|
85
|
+
});
|
|
86
|
+
} catch (err) {
|
|
87
|
+
const cause = err.cause || {};
|
|
88
|
+
const rootDetail = cause.code ? `${cause.code}: ${cause.message || ''}` : '';
|
|
89
|
+
debug.log('HTTP-ERR', `Network error: ${err.message}${rootDetail ? ` (${rootDetail})` : ''}`);
|
|
90
|
+
if (cause.code) debug.log('HTTP-ERR', `Error code: ${cause.code}, hostname: ${cause.hostname || 'N/A'}`);
|
|
91
|
+
if (err.stack) debug.log('HTTP-ERR', `Stack: ${err.stack}`);
|
|
92
|
+
const errorObj = {
|
|
93
|
+
type: 'network',
|
|
94
|
+
message: `Network error contacting Magentrix API: ${err.message}`,
|
|
95
|
+
error: err
|
|
96
|
+
};
|
|
97
|
+
if (returnErrorObject) throw errorObj;
|
|
98
|
+
throw new Error(errorObj.message);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
try {
|
|
102
|
+
responseData = await response.json();
|
|
103
|
+
} catch {
|
|
104
|
+
responseData = null;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
debug.response(response.status, response.statusText, response.headers, responseData);
|
|
108
|
+
|
|
109
|
+
if (!response.ok) {
|
|
110
|
+
const errorObj = {
|
|
111
|
+
type: 'http',
|
|
112
|
+
status: response.status,
|
|
113
|
+
statusText: response.statusText,
|
|
114
|
+
url: response.url,
|
|
115
|
+
response: responseData,
|
|
116
|
+
};
|
|
117
|
+
// Optionally add detailed error message
|
|
118
|
+
let msg = errorConfig?.includeStatus ? `HTTP ${response.status} ${response.statusText}\n` : '';
|
|
119
|
+
if (responseData) {
|
|
120
|
+
const responseErrs = responseData.errors || responseData.Errors;
|
|
121
|
+
|
|
122
|
+
if (Array.isArray(responseErrs) && responseErrs.length) {
|
|
123
|
+
msg += `${errorConfig?.label}${errorConfig?.label ? '\n' : ''}` + responseErrs.map(e => `${errorConfig?.bullets ? " • " : ""}${e.code ? `[${e.code || '500'}] ` : ''}${e.message || e}`).join('\n');
|
|
124
|
+
} else if (responseData.message) {
|
|
125
|
+
msg += `Magentrix message: ${responseData.message}`;
|
|
126
|
+
} else {
|
|
127
|
+
msg += JSON.stringify(responseData);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
if (errorConfig?.includeURL) msg += `\nURL: ${response.url}`;
|
|
131
|
+
errorObj.message = msg;
|
|
132
|
+
debug.log('HTTP-ERR', `HTTP ${response.status}: ${msg}`);
|
|
133
|
+
if (returnErrorObject) throw errorObj;
|
|
134
|
+
throw new Error(msg);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Handle API-level business logic errors
|
|
138
|
+
if (
|
|
139
|
+
!responseData ||
|
|
140
|
+
responseData.success === false ||
|
|
141
|
+
(Array.isArray(responseData?.errors) && responseData.errors.length > 0) ||
|
|
142
|
+
responseData.error
|
|
143
|
+
) {
|
|
144
|
+
const errorObj = {
|
|
145
|
+
type: 'api',
|
|
146
|
+
url: response.url,
|
|
147
|
+
response: responseData
|
|
148
|
+
};
|
|
149
|
+
let details = '';
|
|
150
|
+
if (Array.isArray(responseData?.errors) && responseData.errors.length) {
|
|
151
|
+
details = responseData.errors
|
|
152
|
+
.map(e => ` • ${e.code ? `[${e.code}] ` : ''}${e.message}`)
|
|
153
|
+
.join('\n');
|
|
154
|
+
} else if (responseData?.message) {
|
|
155
|
+
details = responseData.message;
|
|
156
|
+
} else if (typeof responseData === 'object') {
|
|
157
|
+
details = JSON.stringify(responseData);
|
|
158
|
+
} else {
|
|
159
|
+
details = String(responseData);
|
|
160
|
+
}
|
|
161
|
+
errorObj.message = `Magentrix API error:\n${details}`;
|
|
162
|
+
debug.log('API-ERR', errorObj.message);
|
|
163
|
+
if (returnErrorObject) throw errorObj;
|
|
164
|
+
throw new Error(errorObj.message);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
return responseData;
|
|
168
|
+
};
|