catalyst-relay 0.6.4 → 0.6.6
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/index.d.mts +64 -1
- package/dist/index.d.ts +64 -1
- package/dist/index.js +220 -3
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +220 -3
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -2052,6 +2052,192 @@ function extractActivationErrors(objects, xml) {
|
|
|
2052
2052
|
return ok(results);
|
|
2053
2053
|
}
|
|
2054
2054
|
|
|
2055
|
+
// src/core/adt/craud/apirelease/helpers.ts
|
|
2056
|
+
var DDLS_ENDPOINT = "ddic/ddl/sources";
|
|
2057
|
+
var CONTRACT_PATH = "c1";
|
|
2058
|
+
var CONTRACT_ELEMENT = "ars:c1Release";
|
|
2059
|
+
var APIRELEASE_MEDIA_TYPE = "application/vnd.sap.adt.apirelease.v10+xml";
|
|
2060
|
+
var APIRELEASE_VALIDATION_CONTENT_TYPE = "application/vnd.sap.adt.apireleasecontractvalidation+xml";
|
|
2061
|
+
var APIRELEASE_VALIDATION_ACCEPT = "application/vnd.sap.adt.apireleasecontractvalidation+xml, application/vnd.sap.adt.apireleasecontractvalidation.v2+xml";
|
|
2062
|
+
function buildReleasableUri(name) {
|
|
2063
|
+
return `/sap/bc/adt/${DDLS_ENDPOINT}/${name.toLowerCase()}`;
|
|
2064
|
+
}
|
|
2065
|
+
function buildApiReleasePath(name) {
|
|
2066
|
+
return `/sap/bc/adt/apireleases/${encodeURIComponent(buildReleasableUri(name))}`;
|
|
2067
|
+
}
|
|
2068
|
+
function buildContractPath(name) {
|
|
2069
|
+
return `${buildApiReleasePath(name)}/${CONTRACT_PATH}`;
|
|
2070
|
+
}
|
|
2071
|
+
function buildValidationRunPath(name) {
|
|
2072
|
+
return `${buildContractPath(name)}/validationrun`;
|
|
2073
|
+
}
|
|
2074
|
+
function buildC1ReleaseBody(status) {
|
|
2075
|
+
return `<?xml version="1.0" encoding="UTF-8"?><ars:apiRelease xmlns:ars="http://www.sap.com/adt/ars">
|
|
2076
|
+
<ars:c1Release ars:comment="" ars:contract="C1" ars:createAuthValues="false" ars:featureToggle="" ars:useInKeyUserApps="true" ars:useInSAPCloudPlatform="true">
|
|
2077
|
+
<ars:status ars:state="${status}"/>
|
|
2078
|
+
<ars:useConceptAsSuccessor>false</ars:useConceptAsSuccessor>
|
|
2079
|
+
<ars:successors/>
|
|
2080
|
+
<ars:successorConceptName/>
|
|
2081
|
+
</ars:c1Release>
|
|
2082
|
+
<ars:apiCatalogData ars:isAnyAssignmentPossible="false" ars:isAnyContractReleased="false">
|
|
2083
|
+
<ars:ApiCatalogs/>
|
|
2084
|
+
</ars:apiCatalogData>
|
|
2085
|
+
</ars:apiRelease>`;
|
|
2086
|
+
}
|
|
2087
|
+
function toStatus(state) {
|
|
2088
|
+
return state;
|
|
2089
|
+
}
|
|
2090
|
+
function findContractElement(doc) {
|
|
2091
|
+
const candidates = doc.getElementsByTagName(CONTRACT_ELEMENT);
|
|
2092
|
+
for (let i = 0; i < candidates.length; i++) {
|
|
2093
|
+
const el = candidates[i];
|
|
2094
|
+
if (!el) continue;
|
|
2095
|
+
if (el.getElementsByTagName("ars:status").length === 0) continue;
|
|
2096
|
+
return el;
|
|
2097
|
+
}
|
|
2098
|
+
return null;
|
|
2099
|
+
}
|
|
2100
|
+
function parseReleaseState(xml, fallbackName) {
|
|
2101
|
+
const [doc, parseErr] = safeParseXml(xml);
|
|
2102
|
+
if (parseErr) return err(parseErr);
|
|
2103
|
+
const contract = findContractElement(doc);
|
|
2104
|
+
if (!contract) return err(new Error("apiRelease response missing C1 contract element"));
|
|
2105
|
+
const statusEl = contract.getElementsByTagName("ars:status")[0];
|
|
2106
|
+
const state = statusEl?.getAttribute("ars:state");
|
|
2107
|
+
if (!state) return err(new Error("apiRelease response missing C1 status"));
|
|
2108
|
+
const statusDescription = statusEl?.getAttribute("ars:stateDescription") ?? "";
|
|
2109
|
+
const allowedTransitions = [];
|
|
2110
|
+
const transitionsEl = contract.getElementsByTagName("ars:stateTransitions")[0];
|
|
2111
|
+
if (transitionsEl) {
|
|
2112
|
+
const transitionStatuses = transitionsEl.getElementsByTagName("ars:status");
|
|
2113
|
+
for (let i = 0; i < transitionStatuses.length; i++) {
|
|
2114
|
+
const transitionState = transitionStatuses[i]?.getAttribute("ars:state");
|
|
2115
|
+
if (transitionState) allowedTransitions.push(toStatus(transitionState));
|
|
2116
|
+
}
|
|
2117
|
+
}
|
|
2118
|
+
const releasable = doc.getElementsByTagName("ars:releasableObject")[0];
|
|
2119
|
+
const name = releasable?.getAttribute("adtcore:name") ?? fallbackName;
|
|
2120
|
+
const uri = releasable?.getAttribute("adtcore:uri") ?? buildReleasableUri(fallbackName);
|
|
2121
|
+
const result = {
|
|
2122
|
+
name,
|
|
2123
|
+
uri,
|
|
2124
|
+
status: toStatus(state),
|
|
2125
|
+
statusDescription,
|
|
2126
|
+
released: state === "RELEASED",
|
|
2127
|
+
allowedTransitions
|
|
2128
|
+
};
|
|
2129
|
+
const changedBy = contract.getAttribute("adtcore:changedBy");
|
|
2130
|
+
if (changedBy) result.changedBy = changedBy;
|
|
2131
|
+
const changedAt = contract.getAttribute("adtcore:changedAt");
|
|
2132
|
+
if (changedAt) result.changedAt = changedAt;
|
|
2133
|
+
return ok(result);
|
|
2134
|
+
}
|
|
2135
|
+
function parseValidationMessages(xml) {
|
|
2136
|
+
const [doc, parseErr] = safeParseXml(xml);
|
|
2137
|
+
if (parseErr) return [];
|
|
2138
|
+
const messages = [];
|
|
2139
|
+
const elements = doc.getElementsByTagName("ars:validationMessage");
|
|
2140
|
+
for (let i = 0; i < elements.length; i++) {
|
|
2141
|
+
const el = elements[i];
|
|
2142
|
+
if (!el) continue;
|
|
2143
|
+
const text = el.getAttribute("text");
|
|
2144
|
+
if (!text) continue;
|
|
2145
|
+
const message = {
|
|
2146
|
+
severity: mapSeverity(el.getAttribute("type")),
|
|
2147
|
+
text
|
|
2148
|
+
};
|
|
2149
|
+
const msgid = el.getAttribute("msgid");
|
|
2150
|
+
if (msgid) message.msgid = msgid;
|
|
2151
|
+
const msgno = el.getAttribute("msgno");
|
|
2152
|
+
if (msgno) message.msgno = msgno;
|
|
2153
|
+
messages.push(message);
|
|
2154
|
+
}
|
|
2155
|
+
return messages;
|
|
2156
|
+
}
|
|
2157
|
+
function collectErrors(messages) {
|
|
2158
|
+
return messages.filter((m) => m.severity === "error");
|
|
2159
|
+
}
|
|
2160
|
+
function mapSeverity(type) {
|
|
2161
|
+
if (type === "E" || type === "A" || type === "X") return "error";
|
|
2162
|
+
if (type === "W") return "warning";
|
|
2163
|
+
return "info";
|
|
2164
|
+
}
|
|
2165
|
+
|
|
2166
|
+
// src/core/adt/craud/apirelease/getState.ts
|
|
2167
|
+
async function getApiReleaseState(client, objectName) {
|
|
2168
|
+
const [response, requestErr] = await client.request({
|
|
2169
|
+
method: "GET",
|
|
2170
|
+
path: buildApiReleasePath(objectName),
|
|
2171
|
+
headers: { "Accept": APIRELEASE_MEDIA_TYPE }
|
|
2172
|
+
});
|
|
2173
|
+
const [text, checkErr] = await checkResponse(
|
|
2174
|
+
response,
|
|
2175
|
+
requestErr,
|
|
2176
|
+
`Failed to read API release state for ${objectName}`
|
|
2177
|
+
);
|
|
2178
|
+
if (checkErr) return err(checkErr);
|
|
2179
|
+
const [state, parseErr] = parseReleaseState(text, objectName);
|
|
2180
|
+
if (parseErr) return err(parseErr);
|
|
2181
|
+
return ok(state);
|
|
2182
|
+
}
|
|
2183
|
+
|
|
2184
|
+
// src/core/adt/craud/apirelease/release.ts
|
|
2185
|
+
async function releaseApi(client, objectName, transport) {
|
|
2186
|
+
return setApiReleaseState(client, objectName, "RELEASED", transport);
|
|
2187
|
+
}
|
|
2188
|
+
async function unreleaseApi(client, objectName, transport) {
|
|
2189
|
+
return setApiReleaseState(client, objectName, "NOT_RELEASED", transport);
|
|
2190
|
+
}
|
|
2191
|
+
async function setApiReleaseState(client, objectName, status, transport) {
|
|
2192
|
+
const body = buildC1ReleaseBody(status);
|
|
2193
|
+
const [validationRes, validationReqErr] = await client.request({
|
|
2194
|
+
method: "POST",
|
|
2195
|
+
path: buildValidationRunPath(objectName),
|
|
2196
|
+
headers: {
|
|
2197
|
+
"Content-Type": APIRELEASE_VALIDATION_CONTENT_TYPE,
|
|
2198
|
+
"Accept": APIRELEASE_VALIDATION_ACCEPT
|
|
2199
|
+
},
|
|
2200
|
+
body
|
|
2201
|
+
});
|
|
2202
|
+
const [validationText, validationCheckErr] = await checkResponse(
|
|
2203
|
+
validationRes,
|
|
2204
|
+
validationReqErr,
|
|
2205
|
+
`API release validation failed for ${objectName}`
|
|
2206
|
+
);
|
|
2207
|
+
if (validationCheckErr) return err(validationCheckErr);
|
|
2208
|
+
const messages = parseValidationMessages(validationText);
|
|
2209
|
+
const errors = collectErrors(messages);
|
|
2210
|
+
if (errors.length > 0) {
|
|
2211
|
+
const detail = errors.map((e) => e.text).join("; ");
|
|
2212
|
+
return err(new Error(`API release validation failed for ${objectName}: ${detail}`));
|
|
2213
|
+
}
|
|
2214
|
+
const params = {};
|
|
2215
|
+
if (transport) params["request"] = transport;
|
|
2216
|
+
const [putRes, putReqErr] = await client.request({
|
|
2217
|
+
method: "PUT",
|
|
2218
|
+
path: buildContractPath(objectName),
|
|
2219
|
+
params,
|
|
2220
|
+
headers: {
|
|
2221
|
+
"Content-Type": APIRELEASE_MEDIA_TYPE,
|
|
2222
|
+
"Accept": APIRELEASE_MEDIA_TYPE
|
|
2223
|
+
},
|
|
2224
|
+
body
|
|
2225
|
+
});
|
|
2226
|
+
const [putText, putCheckErr] = await checkResponse(
|
|
2227
|
+
putRes,
|
|
2228
|
+
putReqErr,
|
|
2229
|
+
`Failed to set API release state for ${objectName}`
|
|
2230
|
+
);
|
|
2231
|
+
if (putCheckErr) return err(putCheckErr);
|
|
2232
|
+
const [state, parseErr] = parseReleaseState(putText, objectName);
|
|
2233
|
+
if (parseErr) return err(parseErr);
|
|
2234
|
+
return ok({
|
|
2235
|
+
name: state.name,
|
|
2236
|
+
status: state.status,
|
|
2237
|
+
messages
|
|
2238
|
+
});
|
|
2239
|
+
}
|
|
2240
|
+
|
|
2055
2241
|
// src/core/adt/craud/syntaxCheck.ts
|
|
2056
2242
|
async function checkSyntax(client, objects) {
|
|
2057
2243
|
if (objects.length === 0) {
|
|
@@ -3884,6 +4070,24 @@ async function deleteServiceBinding2(state, requestor, bindingName, transport) {
|
|
|
3884
4070
|
return deleteServiceBinding(requestor, bindingName, transport);
|
|
3885
4071
|
}
|
|
3886
4072
|
|
|
4073
|
+
// src/client/methods/apirelease/getApiReleaseState.ts
|
|
4074
|
+
async function getApiReleaseState2(state, requestor, objectName) {
|
|
4075
|
+
if (!state.session) return err(new Error("Not logged in"));
|
|
4076
|
+
return getApiReleaseState(requestor, objectName);
|
|
4077
|
+
}
|
|
4078
|
+
|
|
4079
|
+
// src/client/methods/apirelease/releaseApi.ts
|
|
4080
|
+
async function releaseApi2(state, requestor, objectName, transport) {
|
|
4081
|
+
if (!state.session) return err(new Error("Not logged in"));
|
|
4082
|
+
return releaseApi(requestor, objectName, transport);
|
|
4083
|
+
}
|
|
4084
|
+
|
|
4085
|
+
// src/client/methods/apirelease/unreleaseApi.ts
|
|
4086
|
+
async function unreleaseApi2(state, requestor, objectName, transport) {
|
|
4087
|
+
if (!state.session) return err(new Error("Not logged in"));
|
|
4088
|
+
return unreleaseApi(requestor, objectName, transport);
|
|
4089
|
+
}
|
|
4090
|
+
|
|
3887
4091
|
// src/client/methods/internal/cookies.ts
|
|
3888
4092
|
function storeCookies(cookies, response) {
|
|
3889
4093
|
const setCookieHeader = response.headers.get("set-cookie");
|
|
@@ -4076,9 +4280,12 @@ async function executeRequest(deps, options, selfRequest) {
|
|
|
4076
4280
|
}
|
|
4077
4281
|
if (response.status === 500) {
|
|
4078
4282
|
const text = await response.text();
|
|
4079
|
-
const
|
|
4080
|
-
if (
|
|
4081
|
-
|
|
4283
|
+
const isSessionError = /session/i.test(text) && /(timed out|expired|no longer exists|not found)/i.test(text);
|
|
4284
|
+
if (isSessionError && config.auth.type !== "saml") {
|
|
4285
|
+
const [, resetErr] = await sessionReset(state, selfRequest);
|
|
4286
|
+
if (resetErr) {
|
|
4287
|
+
debugError(`Session reset after 500 failed: ${resetErr.message}`);
|
|
4288
|
+
}
|
|
4082
4289
|
}
|
|
4083
4290
|
return ok(new Response(text, {
|
|
4084
4291
|
status: response.status,
|
|
@@ -4274,6 +4481,16 @@ var ADTClientImpl = class {
|
|
|
4274
4481
|
async deleteServiceBinding(bindingName, transport) {
|
|
4275
4482
|
return deleteServiceBinding2(this.state, this.requestor, bindingName, transport);
|
|
4276
4483
|
}
|
|
4484
|
+
// --- API Release ---
|
|
4485
|
+
async getApiReleaseState(objectName) {
|
|
4486
|
+
return getApiReleaseState2(this.state, this.requestor, objectName);
|
|
4487
|
+
}
|
|
4488
|
+
async releaseApi(objectName, transport) {
|
|
4489
|
+
return releaseApi2(this.state, this.requestor, objectName, transport);
|
|
4490
|
+
}
|
|
4491
|
+
async unreleaseApi(objectName, transport) {
|
|
4492
|
+
return unreleaseApi2(this.state, this.requestor, objectName, transport);
|
|
4493
|
+
}
|
|
4277
4494
|
// --- Configuration ---
|
|
4278
4495
|
getObjectConfig() {
|
|
4279
4496
|
return getObjectConfig();
|