catalyst-relay 0.6.1 → 0.6.3

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 CHANGED
@@ -599,17 +599,25 @@ interface SearchOptions {
599
599
  type ClassIncludeType = 'definitions' | 'implementations' | 'macros' | 'testclasses';
600
600
 
601
601
  /**
602
- * Create Transport — Create a new transport request for a package
602
+ * Create Transport — create a new transport request.
603
+ *
604
+ * Uses the transport-organizer endpoint, which allows choosing the request
605
+ * type (Workbench vs Customizing). The target is taken from the caller, or
606
+ * resolved from the target value-help when unambiguous.
603
607
  */
604
608
 
605
- /**
606
- * Configuration for creating a transport
607
- */
609
+ declare const TRANSPORT_TYPE_CODES: {
610
+ readonly workbench: "K";
611
+ readonly customizing: "W";
612
+ };
613
+ type TransportType = keyof typeof TRANSPORT_TYPE_CODES;
608
614
  interface TransportConfig {
609
- /** Package name (DEVCLASS) */
610
- package: string;
611
615
  /** Transport description/text */
612
616
  description: string;
617
+ /** Request type — 'workbench' (default) or 'customizing' */
618
+ type?: TransportType;
619
+ /** Transport target. If omitted, resolved from the value-help (fails when ambiguous). */
620
+ target?: string;
613
621
  }
614
622
 
615
623
  /**
@@ -742,6 +750,7 @@ interface ADTClient {
742
750
  read(objects: ObjectRef[]): AsyncResult<ObjectWithContent[]>;
743
751
  create(object: ObjectContent, packageName: string, transport?: string): AsyncResult<void>;
744
752
  update(object: ObjectContent, transport?: string): AsyncResult<void>;
753
+ readClassInclude(className: string, includeType: ClassIncludeType): AsyncResult<string>;
745
754
  writeClassInclude(className: string, includeType: ClassIncludeType, source: string, transport?: string): AsyncResult<void>;
746
755
  upsert(objects: ObjectContent[], packageName: string, transport?: string): AsyncResult<UpsertResult[]>;
747
756
  activate(objects: ObjectRef[]): AsyncResult<ActivationResult[]>;
@@ -791,4 +800,4 @@ declare function activateLogging(): void;
791
800
  */
792
801
  declare function deactivateLogging(): void;
793
802
 
794
- export { type ADTClient, type ActivationMessage, type ActivationReference, type ActivationResult, type Aggregation, type ApiResponse, type AsyncResult, type AuthConfig, type AuthType, type BasicAuthConfig, type BasicFilter, BehaviorImplementationType, type BetweenFilter, type CheckResult, type ClassIncludeType, type ClientConfig, type ColumnInfo, type CreateServiceBindingOptions, type DataFrame, type DataPreviewQuery, type DeleteResult, type Dependency, type DiffHunk, type DiffResult, type DistinctResult, type ErrorCode, type ErrorResponse, type ExportableSessionState, type ExternalReference, ExternalReferencesError, type FolderNode, type GetPackagesOptions, type InactiveEntry, type InactiveObject, type InactiveRef, type InactiveTransport, type ListFilter, type ModifiedDiffHunk, type ObjectConfig, type ObjectContent, type ObjectMetadata, type ObjectNode, type ObjectRef, type ObjectWithContent, type Package, type PackageNode, type Parameter, type PreviewSQL, type QueryFilter, type Result, type SamlAuthConfig, type SearchOptions, type SearchResult, type ServiceBindingResult, type ServiceBindingType, type ServiceBindingVersion, type Session, type SimpleDiffHunk, type Sorting, type SsoAuthConfig, type SuccessResponse, type TaskContents, type Transport, type TransportConfig, type TransportObject, type TreeQuery, type TreeResponse, type UpsertResult, activateLogging, buildSQLQuery, createClient, deactivateLogging, err, ok };
803
+ export { type ADTClient, type ActivationMessage, type ActivationReference, type ActivationResult, type Aggregation, type ApiResponse, type AsyncResult, type AuthConfig, type AuthType, type BasicAuthConfig, type BasicFilter, BehaviorImplementationType, type BetweenFilter, type CheckResult, type ClassIncludeType, type ClientConfig, type ColumnInfo, type CreateServiceBindingOptions, type DataFrame, type DataPreviewQuery, type DeleteResult, type Dependency, type DiffHunk, type DiffResult, type DistinctResult, type ErrorCode, type ErrorResponse, type ExportableSessionState, type ExternalReference, ExternalReferencesError, type FolderNode, type GetPackagesOptions, type InactiveEntry, type InactiveObject, type InactiveRef, type InactiveTransport, type ListFilter, type ModifiedDiffHunk, type ObjectConfig, type ObjectContent, type ObjectMetadata, type ObjectNode, type ObjectRef, type ObjectWithContent, type Package, type PackageNode, type Parameter, type PreviewSQL, type QueryFilter, type Result, type SamlAuthConfig, type SearchOptions, type SearchResult, type ServiceBindingResult, type ServiceBindingType, type ServiceBindingVersion, type Session, type SimpleDiffHunk, type Sorting, type SsoAuthConfig, type SuccessResponse, type TaskContents, type Transport, type TransportConfig, type TransportObject, type TransportType, type TreeQuery, type TreeResponse, type UpsertResult, activateLogging, buildSQLQuery, createClient, deactivateLogging, err, ok };
package/dist/index.d.ts CHANGED
@@ -599,17 +599,25 @@ interface SearchOptions {
599
599
  type ClassIncludeType = 'definitions' | 'implementations' | 'macros' | 'testclasses';
600
600
 
601
601
  /**
602
- * Create Transport — Create a new transport request for a package
602
+ * Create Transport — create a new transport request.
603
+ *
604
+ * Uses the transport-organizer endpoint, which allows choosing the request
605
+ * type (Workbench vs Customizing). The target is taken from the caller, or
606
+ * resolved from the target value-help when unambiguous.
603
607
  */
604
608
 
605
- /**
606
- * Configuration for creating a transport
607
- */
609
+ declare const TRANSPORT_TYPE_CODES: {
610
+ readonly workbench: "K";
611
+ readonly customizing: "W";
612
+ };
613
+ type TransportType = keyof typeof TRANSPORT_TYPE_CODES;
608
614
  interface TransportConfig {
609
- /** Package name (DEVCLASS) */
610
- package: string;
611
615
  /** Transport description/text */
612
616
  description: string;
617
+ /** Request type — 'workbench' (default) or 'customizing' */
618
+ type?: TransportType;
619
+ /** Transport target. If omitted, resolved from the value-help (fails when ambiguous). */
620
+ target?: string;
613
621
  }
614
622
 
615
623
  /**
@@ -742,6 +750,7 @@ interface ADTClient {
742
750
  read(objects: ObjectRef[]): AsyncResult<ObjectWithContent[]>;
743
751
  create(object: ObjectContent, packageName: string, transport?: string): AsyncResult<void>;
744
752
  update(object: ObjectContent, transport?: string): AsyncResult<void>;
753
+ readClassInclude(className: string, includeType: ClassIncludeType): AsyncResult<string>;
745
754
  writeClassInclude(className: string, includeType: ClassIncludeType, source: string, transport?: string): AsyncResult<void>;
746
755
  upsert(objects: ObjectContent[], packageName: string, transport?: string): AsyncResult<UpsertResult[]>;
747
756
  activate(objects: ObjectRef[]): AsyncResult<ActivationResult[]>;
@@ -791,4 +800,4 @@ declare function activateLogging(): void;
791
800
  */
792
801
  declare function deactivateLogging(): void;
793
802
 
794
- export { type ADTClient, type ActivationMessage, type ActivationReference, type ActivationResult, type Aggregation, type ApiResponse, type AsyncResult, type AuthConfig, type AuthType, type BasicAuthConfig, type BasicFilter, BehaviorImplementationType, type BetweenFilter, type CheckResult, type ClassIncludeType, type ClientConfig, type ColumnInfo, type CreateServiceBindingOptions, type DataFrame, type DataPreviewQuery, type DeleteResult, type Dependency, type DiffHunk, type DiffResult, type DistinctResult, type ErrorCode, type ErrorResponse, type ExportableSessionState, type ExternalReference, ExternalReferencesError, type FolderNode, type GetPackagesOptions, type InactiveEntry, type InactiveObject, type InactiveRef, type InactiveTransport, type ListFilter, type ModifiedDiffHunk, type ObjectConfig, type ObjectContent, type ObjectMetadata, type ObjectNode, type ObjectRef, type ObjectWithContent, type Package, type PackageNode, type Parameter, type PreviewSQL, type QueryFilter, type Result, type SamlAuthConfig, type SearchOptions, type SearchResult, type ServiceBindingResult, type ServiceBindingType, type ServiceBindingVersion, type Session, type SimpleDiffHunk, type Sorting, type SsoAuthConfig, type SuccessResponse, type TaskContents, type Transport, type TransportConfig, type TransportObject, type TreeQuery, type TreeResponse, type UpsertResult, activateLogging, buildSQLQuery, createClient, deactivateLogging, err, ok };
803
+ export { type ADTClient, type ActivationMessage, type ActivationReference, type ActivationResult, type Aggregation, type ApiResponse, type AsyncResult, type AuthConfig, type AuthType, type BasicAuthConfig, type BasicFilter, BehaviorImplementationType, type BetweenFilter, type CheckResult, type ClassIncludeType, type ClientConfig, type ColumnInfo, type CreateServiceBindingOptions, type DataFrame, type DataPreviewQuery, type DeleteResult, type Dependency, type DiffHunk, type DiffResult, type DistinctResult, type ErrorCode, type ErrorResponse, type ExportableSessionState, type ExternalReference, ExternalReferencesError, type FolderNode, type GetPackagesOptions, type InactiveEntry, type InactiveObject, type InactiveRef, type InactiveTransport, type ListFilter, type ModifiedDiffHunk, type ObjectConfig, type ObjectContent, type ObjectMetadata, type ObjectNode, type ObjectRef, type ObjectWithContent, type Package, type PackageNode, type Parameter, type PreviewSQL, type QueryFilter, type Result, type SamlAuthConfig, type SearchOptions, type SearchResult, type ServiceBindingResult, type ServiceBindingType, type ServiceBindingVersion, type Session, type SimpleDiffHunk, type Sorting, type SsoAuthConfig, type SuccessResponse, type TaskContents, type Transport, type TransportConfig, type TransportObject, type TransportType, type TreeQuery, type TreeResponse, type UpsertResult, activateLogging, buildSQLQuery, createClient, deactivateLogging, err, ok };
package/dist/index.js CHANGED
@@ -1061,22 +1061,6 @@ function escapeXml(str) {
1061
1061
  }
1062
1062
  return str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
1063
1063
  }
1064
- function dictToAbapXml(data, root = "DATA") {
1065
- const innerElements = Object.entries(data).map(([key, value]) => {
1066
- if (value) {
1067
- return `<${key}>${escapeXml(value)}</${key}>`;
1068
- }
1069
- return `<${key}/>`;
1070
- }).join("\n ");
1071
- return `<?xml version="1.0" encoding="UTF-8"?>
1072
- <asx:abap xmlns:asx="http://www.sap.com/abapxml" version="1.0">
1073
- <asx:values>
1074
- <${root}>
1075
- ${innerElements}
1076
- </${root}>
1077
- </asx:values>
1078
- </asx:abap>`;
1079
- }
1080
1064
 
1081
1065
  // src/core/utils/csrf.ts
1082
1066
  var FETCH_CSRF_TOKEN = "fetch";
@@ -1904,6 +1888,23 @@ async function updateObject(client, object, lockHandle, transport) {
1904
1888
  }
1905
1889
 
1906
1890
  // src/core/adt/craud/classInclude.ts
1891
+ async function readClassInclude(client, className, includeType) {
1892
+ const [config, configErr] = requireConfig("aclass");
1893
+ if (configErr) return err(configErr);
1894
+ debug(`Read class include ${className}/${includeType}`);
1895
+ const [response, requestErr] = await client.request({
1896
+ method: "GET",
1897
+ path: `/sap/bc/adt/${config.endpoint}/${className.toLowerCase()}/includes/${includeType}`,
1898
+ headers: { "Accept": "text/plain" }
1899
+ });
1900
+ const [content, checkErr] = await checkResponse(
1901
+ response,
1902
+ requestErr,
1903
+ `Failed to read ${includeType} include of class ${className}`
1904
+ );
1905
+ if (checkErr) return err(checkErr);
1906
+ return ok(content);
1907
+ }
1907
1908
  async function updateClassInclude(client, className, includeType, source, lockHandle, transport) {
1908
1909
  const [config, configErr] = requireConfig("aclass");
1909
1910
  if (configErr) return err(configErr);
@@ -3081,35 +3082,102 @@ function parseSearchResults(xml) {
3081
3082
  return ok(results);
3082
3083
  }
3083
3084
 
3084
- // src/core/adt/transports/createTransport.ts
3085
- async function createTransport(client, config) {
3086
- const body = dictToAbapXml({
3087
- DEVCLASS: config.package,
3088
- REQUEST_TEXT: config.description,
3089
- REF: "",
3090
- OPERATION: "I"
3085
+ // src/core/adt/transports/getTransportTargets.ts
3086
+ var TARGET_VALUEHELP_PATH = "/sap/bc/adt/cts/transportrequests/valuehelp/target?name=*";
3087
+ var NAMEDITEM_CONTENT_TYPE = "application/vnd.sap.adt.nameditems.v1+xml";
3088
+ var NAMEDITEM_NS = "http://www.sap.com/adt/nameditem";
3089
+ async function getTransportTargets(client) {
3090
+ const [response, requestErr] = await client.request({
3091
+ method: "GET",
3092
+ path: TARGET_VALUEHELP_PATH,
3093
+ headers: { Accept: NAMEDITEM_CONTENT_TYPE }
3091
3094
  });
3095
+ if (requestErr) return err(requestErr);
3096
+ if (!response.ok) {
3097
+ const text2 = await response.text();
3098
+ return err(new Error(`Failed to fetch transport targets: ${extractError(text2)}`));
3099
+ }
3100
+ const text = await response.text();
3101
+ const [targets, parseErr] = extractTargets(text);
3102
+ if (parseErr) return err(parseErr);
3103
+ return ok(targets);
3104
+ }
3105
+ function extractTargets(xml) {
3106
+ const [doc, parseErr] = safeParseXml(xml);
3107
+ if (parseErr) return err(parseErr);
3108
+ const targets = [];
3109
+ const items = doc.getElementsByTagNameNS(NAMEDITEM_NS, "namedItem");
3110
+ for (let i = 0; i < items.length; i++) {
3111
+ const item = items[i];
3112
+ if (!item) continue;
3113
+ const name = item.getElementsByTagNameNS(NAMEDITEM_NS, "name")[0]?.textContent;
3114
+ if (!name || !name.trim()) continue;
3115
+ const description = item.getElementsByTagNameNS(NAMEDITEM_NS, "description")[0]?.textContent;
3116
+ targets.push({ name: name.trim(), description: (description ?? "").trim() });
3117
+ }
3118
+ return ok(targets);
3119
+ }
3120
+
3121
+ // src/core/adt/transports/createTransport.ts
3122
+ var TRANSPORTREQUESTS_PATH = "/sap/bc/adt/cts/transportrequests";
3123
+ var TM_CONTENT_TYPE = "application/vnd.sap.adt.transportorganizer.v1+xml";
3124
+ var TM_NS = "http://www.sap.com/cts/adt/tm";
3125
+ var TRANSPORT_TYPE_CODES = {
3126
+ workbench: "K",
3127
+ customizing: "W"
3128
+ };
3129
+ async function createTransport(client, config, owner) {
3130
+ const [target, targetErr] = await resolveTarget(client, config.target);
3131
+ if (targetErr) return err(targetErr);
3132
+ const typeCode = TRANSPORT_TYPE_CODES[config.type ?? "workbench"];
3133
+ const body = `<?xml version="1.0" encoding="UTF-8"?>
3134
+ <tm:root xmlns:tm="${TM_NS}" tm:useraction="newrequest">
3135
+ <tm:request tm:desc="${escapeXml(config.description)}" tm:type="${typeCode}" tm:target="${escapeXml(target)}" tm:cts_project="">
3136
+ <tm:task tm:owner="${escapeXml(owner)}"/>
3137
+ </tm:request>
3138
+ </tm:root>`;
3092
3139
  const [response, requestErr] = await client.request({
3093
3140
  method: "POST",
3094
- path: "/sap/bc/adt/cts/transports",
3141
+ path: TRANSPORTREQUESTS_PATH,
3095
3142
  headers: {
3096
- "Content-Type": "application/vnd.sap.as+xml; charset=UTF-8; dataname=com.sap.adt.CreateCorrectionRequest",
3097
- "Accept": "text/plain"
3143
+ "Content-Type": TM_CONTENT_TYPE,
3144
+ "Accept": TM_CONTENT_TYPE
3098
3145
  },
3099
3146
  body
3100
3147
  });
3101
3148
  if (requestErr) return err(requestErr);
3102
3149
  if (!response.ok) {
3103
3150
  const text2 = await response.text();
3104
- const errorMsg = extractError(text2);
3105
- return err(new Error(`Failed to create transport for ${config.package}: ${errorMsg}`));
3151
+ return err(new Error(`Failed to create transport: ${extractError(text2)}`));
3106
3152
  }
3107
3153
  const text = await response.text();
3108
- const transportId = text.trim().split("/").pop();
3109
- if (!transportId) {
3110
- return err(new Error("Failed to parse transport ID from response"));
3154
+ return extractTransportNumber(text);
3155
+ }
3156
+ async function resolveTarget(client, explicit) {
3157
+ if (explicit) return ok(explicit);
3158
+ const [targets, targetsErr] = await getTransportTargets(client);
3159
+ if (targetsErr) return err(targetsErr);
3160
+ if (targets.length === 0) {
3161
+ return err(new Error("No transport targets available; pass an explicit target."));
3162
+ }
3163
+ if (targets.length === 1) {
3164
+ return ok(targets[0].name);
3111
3165
  }
3112
- return ok(transportId);
3166
+ const options = targets.map((t) => `${t.name} (${t.description})`).join(", ");
3167
+ return err(new Error(
3168
+ `Multiple transport targets available; pass an explicit target. Options: ${options}`
3169
+ ));
3170
+ }
3171
+ function extractTransportNumber(xml) {
3172
+ const [doc, parseErr] = safeParseXml(xml);
3173
+ if (parseErr) return err(parseErr);
3174
+ const request4 = doc.getElementsByTagNameNS(TM_NS, "request")[0];
3175
+ if (!request4) return err(new Error("Failed to parse transport number from response"));
3176
+ const number = request4.getAttributeNS(TM_NS, "number") || request4.getAttribute("tm:number");
3177
+ if (!number || !number.trim()) {
3178
+ return err(new Error("Failed to parse transport number from response"));
3179
+ }
3180
+ return ok(number.trim());
3113
3181
  }
3114
3182
 
3115
3183
  // src/core/adt/transports/parseTransportTasks.ts
@@ -3620,6 +3688,12 @@ async function update(state, requestor, object, transport) {
3620
3688
  return ok(void 0);
3621
3689
  }
3622
3690
 
3691
+ // src/client/methods/craud/specialcases/classes/readClassInclude.ts
3692
+ async function readClassInclude2(state, requestor, className, includeType) {
3693
+ if (!state.session) return err(new Error("Not logged in"));
3694
+ return readClassInclude(requestor, className, includeType);
3695
+ }
3696
+
3623
3697
  // src/client/methods/craud/specialcases/classes/writeClassInclude.ts
3624
3698
  async function writeClassInclude(state, requestor, className, includeType, source, transport) {
3625
3699
  if (!state.session) return err(new Error("Not logged in"));
@@ -3770,7 +3844,7 @@ async function whereUsed(state, requestor, object) {
3770
3844
  // src/client/methods/transport/createTransport.ts
3771
3845
  async function createTransport2(state, requestor, transportConfig) {
3772
3846
  if (!state.session) return err(new Error("Not logged in"));
3773
- return createTransport(requestor, transportConfig);
3847
+ return createTransport(requestor, transportConfig, state.session.username);
3774
3848
  }
3775
3849
 
3776
3850
  // src/client/methods/transport/deleteTransport.ts
@@ -4156,6 +4230,9 @@ var ADTClientImpl = class {
4156
4230
  async update(object, transport) {
4157
4231
  return update(this.state, this.requestor, object, transport);
4158
4232
  }
4233
+ async readClassInclude(className, includeType) {
4234
+ return readClassInclude2(this.state, this.requestor, className, includeType);
4235
+ }
4159
4236
  async writeClassInclude(className, includeType, source, transport) {
4160
4237
  return writeClassInclude(this.state, this.requestor, className, includeType, source, transport);
4161
4238
  }