@abapify/adk 0.3.6 → 0.4.1

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.mjs ADDED
@@ -0,0 +1,4300 @@
1
+ import { A as Package, C as Domain, D as Include, E as FunctionModule, F as TransportRequest, I as TransportTask, M as Structure, N as Table, O as Interface, P as TableType, S as DataElement, T as FunctionGroup, _ as parseAdtType, a as parseXmlIdentity, b as resolveType, c as getKindForType, d as getObjectUri, f as getRegisteredKinds, g as normalizeObjectName, h as isTypeRegistered, j as Program, k as MessageClass, l as getMainType, m as getTypeForKind, n as createAdk, o as ADT_TYPE_MAPPINGS, p as getRegisteredTypes, r as createAdkFactory, s as getEndpointForType, t as AdkGenericObject, u as getObjectRootUri, v as registerObjectType, w as EnhancementSpot, x as Class, y as resolveKind } from "./factory-DtyrTGlN.mjs";
2
+ import { createLockService, createLockService as createLockService$1 } from "@abapify/adt-locks";
3
+
4
+ //#region src/base/fetch-utils.ts
5
+ /**
6
+ * Utility for handling v2 client fetch responses.
7
+ *
8
+ * The v2 ADT client's `fetch()` returns parsed data directly (a string for
9
+ * text/plain content), not a standard `Response` object. This helper
10
+ * normalises both cases so ADK objects work with both client versions.
11
+ */
12
+ /**
13
+ * Convert a fetch result to a text string.
14
+ *
15
+ * - If the result is already a string (v2 client), return it as-is.
16
+ * - If the result is a Response-like object (v1 / standard fetch), call `.text()`.
17
+ */
18
+ async function toText(result) {
19
+ if (typeof result === "string") return result;
20
+ if (result && typeof result === "object" && "text" in result && typeof result.text === "function") return result.text();
21
+ if (result === null || result === void 0) return "";
22
+ if (typeof result === "object") try {
23
+ return JSON.stringify(result);
24
+ } catch {
25
+ return String(result);
26
+ }
27
+ return String(result);
28
+ }
29
+
30
+ //#endregion
31
+ //#region src/base/model.ts
32
+ /**
33
+ * Base class for all ADK objects
34
+ *
35
+ * All ADK objects (AdkPackage, AdkTransportRequest, etc.) extend this.
36
+ * Supports deferred loading - create with just a name, then call load().
37
+ *
38
+ * Note: Uses loose type constraint for D to allow schema-inferred types
39
+ * from contracts which may have different shapes. The getters safely
40
+ * handle missing properties with defaults.
41
+ *
42
+ * @typeParam K - The object kind (from AdkKind)
43
+ * @typeParam D - The internal data type (typically schema-inferred from contract)
44
+ */
45
+ var AdkObject = class {
46
+ /**
47
+ * ADT collection URI - base path for creating new objects.
48
+ * Example: `/sap/bc/adt/oo/classes`
49
+ * Default: derived from objectUri by removing the object name
50
+ */
51
+ get collectionUri() {
52
+ const uri = this.objectUri;
53
+ const lastSlash = uri.lastIndexOf("/");
54
+ return lastSlash > 0 ? uri.substring(0, lastSlash) : uri;
55
+ }
56
+ ctx;
57
+ /** Public access to the ADT client for plugins and external code */
58
+ get client() {
59
+ return this.ctx.client;
60
+ }
61
+ _data;
62
+ _name;
63
+ cache = /* @__PURE__ */ new Map();
64
+ dirty = /* @__PURE__ */ new Set();
65
+ _lockHandle;
66
+ /** Set by save() when all pending changes are identical to SAP state */
67
+ _unchanged = false;
68
+ /**
69
+ * Create ADK object
70
+ * @param ctx - ADK context
71
+ * @param dataOrName - Full data object OR just the object name for deferred loading
72
+ */
73
+ constructor(ctx, dataOrName) {
74
+ this.ctx = ctx;
75
+ if (typeof dataOrName === "string") this._name = dataOrName;
76
+ else {
77
+ this._data = dataOrName;
78
+ this._name = dataOrName.name;
79
+ }
80
+ }
81
+ /**
82
+ * Adopt a richer context (merge services into existing context).
83
+ *
84
+ * Used by AdkObjectSet to propagate lockService / lockStore
85
+ * to objects created by plugins that only have { client }.
86
+ * Keeps the original client reference intact.
87
+ */
88
+ adoptContext(ctx) {
89
+ this.ctx = {
90
+ ...this.ctx,
91
+ ...ctx
92
+ };
93
+ }
94
+ /**
95
+ * Load object data from SAP
96
+ *
97
+ * Default implementation uses crudContract.get() and unwraps with wrapperKey.
98
+ * Objects without crudContract must override this.
99
+ *
100
+ * @returns this (for chaining)
101
+ */
102
+ async load() {
103
+ const contract = this.crudContract;
104
+ const wrapperKey = this.wrapperKey;
105
+ if (!contract || !wrapperKey) throw new Error(`Load not implemented for ${this.kind}. Override load() or provide crudContract/wrapperKey.`);
106
+ const response = await contract.get(this.name);
107
+ if (!response || !(wrapperKey in response)) throw new Error(`${this.kind} '${this.name}' not found or returned empty response`);
108
+ this.setData(response[wrapperKey]);
109
+ return this;
110
+ }
111
+ /** Whether data has been loaded */
112
+ get isLoaded() {
113
+ return !!this._data;
114
+ }
115
+ /**
116
+ * Get data - auto-loads if not already loaded
117
+ * @returns Promise that resolves to the data
118
+ */
119
+ async data() {
120
+ if (!this._data) await this.load();
121
+ return this._data;
122
+ }
123
+ /**
124
+ * Get data synchronously - throws if not loaded
125
+ * Use when you know data is already loaded
126
+ */
127
+ get dataSync() {
128
+ if (!this._data) throw new Error(`${this.kind} '${this._name}' not loaded. Call load() or use data() instead.`);
129
+ return this._data;
130
+ }
131
+ /** Set data (for subclasses to use after loading) */
132
+ setData(data) {
133
+ this._data = data;
134
+ this._name = data.name;
135
+ }
136
+ /** Helper to access data with AdkObjectData properties */
137
+ get coreData() {
138
+ return this.dataSync;
139
+ }
140
+ /** ADT object name (adtcore:name) - available even before load() */
141
+ get name() {
142
+ return this._name;
143
+ }
144
+ /** ADT object type (adtcore:type, e.g. 'RQRQ', 'DEVC/K') - requires load() */
145
+ get type() {
146
+ return this.coreData.type;
147
+ }
148
+ /** Description text (adtcore:description) */
149
+ get description() {
150
+ return this.coreData.description ?? "";
151
+ }
152
+ /** Version state (adtcore:version) - active, inactive, etc. */
153
+ get version() {
154
+ return this.coreData.version ?? "";
155
+ }
156
+ /** Current language (adtcore:language) */
157
+ get language() {
158
+ return this.coreData.language ?? "";
159
+ }
160
+ /** User who last modified (adtcore:changedBy) */
161
+ get changedBy() {
162
+ return this.coreData.changedBy ?? "";
163
+ }
164
+ /** Last modification timestamp (adtcore:changedAt) */
165
+ get changedAt() {
166
+ const val = this.coreData.changedAt;
167
+ return val instanceof Date ? val : val ? new Date(val) : /* @__PURE__ */ new Date(0);
168
+ }
169
+ /** User who created (adtcore:createdBy) */
170
+ get createdBy() {
171
+ return this.coreData.createdBy ?? "";
172
+ }
173
+ /** Creation timestamp (adtcore:createdAt) */
174
+ get createdAt() {
175
+ const val = this.coreData.createdAt;
176
+ return val instanceof Date ? val : val ? new Date(val) : /* @__PURE__ */ new Date(0);
177
+ }
178
+ /** All atom:link elements */
179
+ get links() {
180
+ return this.coreData.links ?? [];
181
+ }
182
+ /** Find link by rel attribute */
183
+ getLink(rel) {
184
+ return this.links.find((l) => l.rel === rel);
185
+ }
186
+ /** Get link href by rel, or undefined */
187
+ getLinkHref(rel) {
188
+ return this.getLink(rel)?.href;
189
+ }
190
+ /** Container reference (adtcore:containerRef) */
191
+ get containerRef() {
192
+ return this.coreData.containerRef;
193
+ }
194
+ /** Check if object is currently locked */
195
+ get isLocked() {
196
+ return !!this._lockHandle;
197
+ }
198
+ /** Get current lock handle */
199
+ get lockHandle() {
200
+ return this._lockHandle;
201
+ }
202
+ /**
203
+ * Lock the object for modification
204
+ *
205
+ * Delegates to the lock service (single lock mechanism).
206
+ *
207
+ * The lock response contains:
208
+ * - LOCK_HANDLE: Required for subsequent PUT/unlock operations
209
+ * - CORRNR: Transport request assigned to this object (use for PUT if no explicit transport)
210
+ * - CORRUSER: User who owns the transport
211
+ *
212
+ * @param transport - Optional transport request to use for locking.
213
+ * Required when object is already in a transport.
214
+ */
215
+ async lock(transport) {
216
+ if (this._lockHandle) return this._lockHandle;
217
+ const lockService = this.ctx.lockService;
218
+ if (!lockService) throw new Error(`Lock not available: no lockService in context. Did you call initializeAdk()?`);
219
+ this._lockHandle = await lockService.lock(this.objectUri, {
220
+ transport,
221
+ objectName: this.name,
222
+ objectType: this.kind
223
+ });
224
+ return this._lockHandle;
225
+ }
226
+ /**
227
+ * Unlock the object
228
+ *
229
+ * Delegates to the lock service (single lock mechanism).
230
+ */
231
+ async unlock() {
232
+ if (!this._lockHandle) return;
233
+ const lockService = this.ctx.lockService;
234
+ if (!lockService) throw new Error(`Unlock not available: no lockService in context. Did you call initializeAdk()?`);
235
+ await lockService.unlock(this.objectUri, { lockHandle: this._lockHandle.handle });
236
+ this._lockHandle = void 0;
237
+ }
238
+ /**
239
+ * Set lock handle (for subclasses that need custom lock logic)
240
+ */
241
+ setLockHandle(handle) {
242
+ this._lockHandle = handle;
243
+ }
244
+ /**
245
+ * Save the object to SAP
246
+ *
247
+ * Generic implementation that handles:
248
+ * - Lock/unlock lifecycle
249
+ * - Mode switching (create/update/upsert)
250
+ * - Error handling
251
+ *
252
+ * Subclasses implement `saveViaContract()` to provide the typed contract call.
253
+ *
254
+ * Modes:
255
+ * - 'update' (default): PUT to existing object
256
+ * - 'create': POST skeleton, then lock → PUT/source → unlock (Eclipse ADT pattern)
257
+ * - 'upsert': Check existence, create if needed, then update
258
+ *
259
+ * @param options - Save options
260
+ * @returns this (for chaining)
261
+ */
262
+ async save(options = {}) {
263
+ const { transport, mode = "update" } = options;
264
+ this._unchanged = false;
265
+ if (mode === "create") {
266
+ if (!await this.checkObjectExists()) await this.saveViaContract("create", { transport });
267
+ return this.save({
268
+ ...options,
269
+ mode: "update"
270
+ });
271
+ }
272
+ const hasPendingSources = this.hasPendingSources();
273
+ if (hasPendingSources) {
274
+ await this.checkPendingSourcesUnchanged();
275
+ if (this._unchanged) return this;
276
+ }
277
+ if (!hasPendingSources) {
278
+ await this.checkMetadataUnchanged();
279
+ if (this._unchanged) return this;
280
+ }
281
+ let confirmedExists = false;
282
+ if (mode === "upsert") {
283
+ confirmedExists = await this.checkObjectExists();
284
+ if (!confirmedExists) return this.fallbackToCreate(options);
285
+ }
286
+ const wasLocked = this.isLocked;
287
+ if (!wasLocked) try {
288
+ await this.lock(transport);
289
+ } catch (e) {
290
+ if (mode === "upsert" && !confirmedExists && this.shouldFallbackToCreate(e)) return this.fallbackToCreate(options);
291
+ throw e;
292
+ }
293
+ try {
294
+ const effectiveTransport = transport ?? this._lockHandle?.correlationNumber;
295
+ if (!wasLocked) await this.refreshETagsAfterLock();
296
+ if (hasPendingSources) await this.savePendingSources({
297
+ lockHandle: this._lockHandle?.handle,
298
+ transport: effectiveTransport
299
+ });
300
+ else {
301
+ const effectiveMode = mode === "upsert" ? "update" : mode;
302
+ await this.saveViaContract(effectiveMode, {
303
+ transport: effectiveTransport,
304
+ lockHandle: this._lockHandle?.handle
305
+ });
306
+ }
307
+ this.dirty.clear();
308
+ return this;
309
+ } catch (e) {
310
+ if (mode === "upsert" && this.shouldFallbackToCreate(e)) {
311
+ if (!wasLocked) try {
312
+ await this.unlock();
313
+ } catch {}
314
+ return this.fallbackToCreate(options);
315
+ }
316
+ if (mode === "upsert" && this.isAlreadyExistsError(e)) {
317
+ this._unchanged = true;
318
+ return this;
319
+ }
320
+ throw e;
321
+ } finally {
322
+ if (!wasLocked) await this.unlock();
323
+ }
324
+ }
325
+ /**
326
+ * Wrapper key for the data in contract requests/responses
327
+ *
328
+ * Contracts wrap data like { abapClass: ... } or { abapInterface: ... }.
329
+ * Subclasses that support save override this.
330
+ */
331
+ get wrapperKey() {}
332
+ /**
333
+ * CRUD contract for this object type
334
+ *
335
+ * Subclasses that support save override this to return their contract.
336
+ */
337
+ get crudContract() {}
338
+ /**
339
+ * Execute the typed contract call for save
340
+ *
341
+ * Generic implementation using wrapperKey and crudContract.
342
+ * Objects that don't support save leave wrapperKey/crudContract undefined.
343
+ *
344
+ * For 'create' mode: POSTs skeleton data (minimal fields).
345
+ * For 'update' mode: PUTs full data (all fields except abapLanguageVersion).
346
+ *
347
+ * @param mode - 'create' (POST skeleton) or 'update' (PUT full)
348
+ * @param options - Contract options (transport, lockHandle)
349
+ */
350
+ async saveViaContract(mode, options) {
351
+ const wrapperKey = this.wrapperKey;
352
+ const contract = this.crudContract;
353
+ if (!wrapperKey || !contract) throw new Error(`Save not supported for ${this.kind}.`);
354
+ if (mode === "create") {
355
+ const skeleton = await this.getSkeletonData();
356
+ const data = { [wrapperKey]: skeleton };
357
+ await contract.post({ corrNr: options.transport }, data);
358
+ } else {
359
+ const { abapLanguageVersion: _, ...rest } = await this.data();
360
+ const saveData = rest;
361
+ const data = { [wrapperKey]: saveData };
362
+ if (contract.get) try {
363
+ await contract.get(this.name);
364
+ } catch {
365
+ this.ctx.client.clearETag();
366
+ }
367
+ await contract.put(this.name, {
368
+ corrNr: options.transport,
369
+ lockHandle: options.lockHandle
370
+ }, data);
371
+ }
372
+ }
373
+ /**
374
+ * Get skeleton data for object creation (POST).
375
+ *
376
+ * Returns only the minimal fields needed to create the object on SAP.
377
+ * SAP creates the object structure (includes, etc.) from these fields.
378
+ * Full metadata and source code are sent via PUT in the update step.
379
+ *
380
+ * Override in subclasses that need different skeleton fields.
381
+ */
382
+ async getSkeletonData() {
383
+ const d = await this.data();
384
+ return {
385
+ name: d.name,
386
+ type: d.type,
387
+ description: d.description ?? "",
388
+ language: d.language ?? "EN",
389
+ masterLanguage: d.masterLanguage ?? "EN",
390
+ packageRef: d.packageRef
391
+ };
392
+ }
393
+ /**
394
+ * Check if the object exists on the SAP system.
395
+ *
396
+ * Used by upsert mode to decide between update and create paths upfront.
397
+ * On BTP, locking a non-existent DDIC object creates a draft that persists
398
+ * even after unlock, blocking subsequent POST (create) attempts. Checking
399
+ * existence first with GET avoids this problem entirely.
400
+ */
401
+ async checkObjectExists() {
402
+ const contract = this.crudContract;
403
+ if (!contract?.get) return true;
404
+ try {
405
+ await contract.get(this.name);
406
+ return true;
407
+ } catch (e) {
408
+ if (this.shouldFallbackToCreate(e)) return false;
409
+ throw e;
410
+ }
411
+ }
412
+ /**
413
+ * Check if error is a 404 Not Found
414
+ */
415
+ isNotFoundError(e) {
416
+ if (e instanceof Error) return e.message.includes("404") || e.message.includes("Not Found");
417
+ return false;
418
+ }
419
+ /**
420
+ * Upsert fallback: try POST (create), treat 422 "already exists" as unchanged.
421
+ * Extracted to avoid duplication in lock-catch and saveViaContract-catch paths.
422
+ */
423
+ async fallbackToCreate(options) {
424
+ try {
425
+ return await this.save({
426
+ ...options,
427
+ mode: "create"
428
+ });
429
+ } catch (createErr) {
430
+ if (this.isAlreadyExistsError(createErr)) {
431
+ this._unchanged = true;
432
+ return this;
433
+ }
434
+ throw createErr;
435
+ }
436
+ }
437
+ /**
438
+ * Check if error suggests the object doesn't exist or the operation
439
+ * is not supported for the current state.
440
+ *
441
+ * Some SAP DDIC endpoints (TABL, TTYP) return 405 Method Not Allowed
442
+ * instead of 404 when attempting to lock or PUT a non-existent object.
443
+ * In upsert mode, both should trigger a fallback to POST (create).
444
+ */
445
+ shouldFallbackToCreate(e) {
446
+ if (this.isNotFoundError(e)) return true;
447
+ if (e instanceof Error) {
448
+ const msg = e.message;
449
+ if (msg.includes("405") || msg.includes("Method Not Allowed")) return true;
450
+ if (msg.includes("403") && msg.includes("S_ABPLNGVS")) return true;
451
+ }
452
+ return false;
453
+ }
454
+ /**
455
+ * Check if error is a 422 "already exists" from a POST create attempt
456
+ */
457
+ isAlreadyExistsError(e) {
458
+ const msg = e instanceof Error ? e.message.toLowerCase() : "";
459
+ return (msg.includes("422") || msg.includes("unprocessable")) && msg.includes("already exists");
460
+ }
461
+ /**
462
+ * Check if object has pending sources to save
463
+ * Subclasses with source code (classes, interfaces) override this
464
+ */
465
+ hasPendingSources() {
466
+ const self = this;
467
+ return !!(self._pendingSources || self._pendingSource);
468
+ }
469
+ /**
470
+ * Normalize source code for comparison.
471
+ * Trims trailing whitespace/newlines so minor formatting differences
472
+ * don't trigger unnecessary saves.
473
+ */
474
+ normalizeSource(source) {
475
+ return source.split("\n").map((line) => line.trimEnd()).join("\n").trimEnd();
476
+ }
477
+ /**
478
+ * Check if pending sources are unchanged vs SAP (pre-lock comparison).
479
+ * Sets _unchanged = true if nothing needs saving.
480
+ *
481
+ * Default handles single-source objects (_pendingSource) by fetching
482
+ * GET {objectUri}/source/main and comparing.
483
+ * AdkClass overrides this for multi-include logic.
484
+ */
485
+ async checkPendingSourcesUnchanged() {
486
+ const self = this;
487
+ if (!self._pendingSource) return;
488
+ try {
489
+ const currentSource = await toText(await this.ctx.client.fetch(`${this.objectUri}/source/main`, {
490
+ method: "GET",
491
+ headers: { Accept: "text/plain" }
492
+ }));
493
+ if (this.normalizeSource(currentSource) === this.normalizeSource(self._pendingSource)) {
494
+ this._unchanged = true;
495
+ delete self._pendingSource;
496
+ }
497
+ } catch {}
498
+ }
499
+ /**
500
+ * Check if metadata-only objects are unchanged on SAP.
501
+ *
502
+ * For objects without source code (DDIC types like DOMA, DTEL, TABL, TTYP),
503
+ * fetches the current SAP state and compares only the fields present in
504
+ * the local data. SAP returns extra volatile fields (timestamps, links,
505
+ * version, etc.) that are ignored — only semantic fields matter.
506
+ */
507
+ async checkMetadataUnchanged() {
508
+ const contract = this.crudContract;
509
+ const wrapperKey = this.wrapperKey;
510
+ if (!contract?.get || !wrapperKey) return;
511
+ try {
512
+ const sapData = (await contract.get(this.name))?.[wrapperKey];
513
+ if (!sapData) return;
514
+ const localData = await this.data();
515
+ const isEmpty = (v) => v == null || v === "" || Array.isArray(v) && v.length === 0 || typeof v === "object" && v !== null && Object.keys(v).length === 0;
516
+ const isSubsetMatch = (local, sap) => {
517
+ if (local === sap) return true;
518
+ if (isEmpty(local) && isEmpty(sap)) return true;
519
+ if (isEmpty(local) && sap != null) return true;
520
+ if (local == null || sap == null) return false;
521
+ if (typeof local !== typeof sap) return false;
522
+ if (Array.isArray(local)) {
523
+ if (!Array.isArray(sap)) return false;
524
+ if (local.length !== sap.length) return false;
525
+ return local.every((item, i) => isSubsetMatch(item, sap[i]));
526
+ }
527
+ if (typeof local === "object") {
528
+ const localObj = local;
529
+ const sapObj = sap;
530
+ return Object.keys(localObj).every((key) => {
531
+ if (key === "abapLanguageVersion") return true;
532
+ return isSubsetMatch(localObj[key], sapObj[key]);
533
+ });
534
+ }
535
+ return local === sap;
536
+ };
537
+ if (isSubsetMatch(localData, sapData)) this._unchanged = true;
538
+ } catch {}
539
+ }
540
+ /**
541
+ * Refresh cached ETags after acquiring a lock.
542
+ *
543
+ * SAP changes the object's internal version when a lock is acquired,
544
+ * which invalidates any cached ETags. Without refreshing, the next
545
+ * PUT sends a stale If-Match header and SAP returns HTTP 412.
546
+ *
547
+ * For objects with pending sources: re-GET {objectUri}/source/main
548
+ * For metadata-only objects: re-GET via crudContract.get()
549
+ *
550
+ * Subclasses with multiple source endpoints (e.g., AdkClass with includes)
551
+ * should override this to refresh all relevant endpoints.
552
+ */
553
+ async refreshETagsAfterLock() {
554
+ if (this.hasPendingSources()) {
555
+ const sourceUrl = `${this.objectUri}/source/main`;
556
+ try {
557
+ await this.ctx.client.fetch(sourceUrl, {
558
+ method: "GET",
559
+ headers: { Accept: "text/plain" }
560
+ });
561
+ } catch {
562
+ this.ctx.client.clearETag(sourceUrl);
563
+ }
564
+ } else {
565
+ const contract = this.crudContract;
566
+ if (contract?.get) try {
567
+ await contract.get(this.name);
568
+ } catch {
569
+ this.ctx.client.clearETag();
570
+ }
571
+ }
572
+ }
573
+ /**
574
+ * Save pending sources to SAP.
575
+ *
576
+ * Default handles single-source objects (_pendingSource) by PUTting
577
+ * to {objectUri}/source/main.
578
+ * AdkClass overrides this for multi-include logic.
579
+ */
580
+ async savePendingSources(options) {
581
+ const self = this;
582
+ if (!self._pendingSource) return;
583
+ const sourceUrl = `${this.objectUri}/source/main`;
584
+ try {
585
+ await this.ctx.client.fetch(sourceUrl, {
586
+ method: "GET",
587
+ headers: { Accept: "text/plain" }
588
+ });
589
+ } catch {
590
+ this.ctx.client.clearETag(sourceUrl);
591
+ }
592
+ const params = new URLSearchParams();
593
+ if (options?.lockHandle) params.set("lockHandle", options.lockHandle);
594
+ if (options?.transport) params.set("corrNr", options.transport);
595
+ const qs = params.toString();
596
+ await this.ctx.client.fetch(`${sourceUrl}${qs ? "?" + qs : ""}`, {
597
+ method: "PUT",
598
+ headers: { "Content-Type": "text/plain" },
599
+ body: self._pendingSource
600
+ });
601
+ delete self._pendingSource;
602
+ }
603
+ /**
604
+ * Set source content for a source-based object
605
+ *
606
+ * Generic implementation for objects with source code (classes, includes, etc.)
607
+ * Subclasses should override if they need custom source handling.
608
+ *
609
+ * @param sourcePath - Relative path to source (e.g., '/source/main')
610
+ * @param content - Source code content
611
+ * @param options - Save options
612
+ */
613
+ async setSource(sourcePath, content, options = {}) {
614
+ const { transport } = options;
615
+ const wasLocked = this.isLocked;
616
+ if (!wasLocked) await this.lock();
617
+ try {
618
+ const params = new URLSearchParams();
619
+ if (transport) params.set("corrNr", transport);
620
+ if (this._lockHandle) params.set("lockHandle", this._lockHandle.handle);
621
+ const fullPath = `${this.objectUri}${sourcePath}`;
622
+ const url = params.toString() ? `${fullPath}?${params.toString()}` : fullPath;
623
+ await this.ctx.client.fetch(url, {
624
+ method: "PUT",
625
+ headers: { "Content-Type": "text/plain; charset=utf-8" },
626
+ body: content
627
+ });
628
+ } finally {
629
+ if (!wasLocked) await this.unlock();
630
+ }
631
+ }
632
+ /**
633
+ * Activate this object
634
+ *
635
+ * Activates a single object. For bulk activation of multiple objects,
636
+ * use `AdkObjectSet.activateAll()`.
637
+ *
638
+ * @returns this (for chaining)
639
+ */
640
+ async activate() {
641
+ const activationXml = `<?xml version="1.0" encoding="UTF-8"?>
642
+ <adtcore:objectReferences xmlns:adtcore="http://www.sap.com/adt/core">
643
+ <adtcore:objectReference adtcore:uri="${this.objectUri}" adtcore:type="${this.type}" adtcore:name="${this.name}"/>
644
+ </adtcore:objectReferences>`;
645
+ await this.ctx.client.fetch("/sap/bc/adt/activation?method=activate&preauditRequested=true", {
646
+ method: "POST",
647
+ headers: {
648
+ "Content-Type": "application/xml",
649
+ Accept: "application/xml"
650
+ },
651
+ body: activationXml
652
+ });
653
+ return this;
654
+ }
655
+ /** Lazy load a segment (async) - fetches only once, then cached */
656
+ async lazy(key, loader) {
657
+ if (!this.cache.has(key)) this.cache.set(key, await loader());
658
+ return this.cache.get(key);
659
+ }
660
+ /** Lazy compute a segment (sync) - computes only once, then cached */
661
+ cached(key, compute) {
662
+ if (!this.cache.has(key)) this.cache.set(key, compute());
663
+ return this.cache.get(key);
664
+ }
665
+ /** Set a cached value directly (for local/generated data) */
666
+ set(key, value) {
667
+ this.cache.set(key, value);
668
+ }
669
+ /** Mark a segment as dirty (modified locally) */
670
+ markDirty(key) {
671
+ this.dirty.add(key);
672
+ }
673
+ /** Check if any segment (or specific segment) is dirty */
674
+ isDirty(segment) {
675
+ return segment ? this.dirty.has(segment) : this.dirty.size > 0;
676
+ }
677
+ /** Clear cache for a segment (force reload on next access) */
678
+ invalidate(key) {
679
+ this.cache.delete(key);
680
+ this.dirty.delete(key);
681
+ }
682
+ /**
683
+ * Fetch a text resource from an ADT endpoint.
684
+ * Delegates to the underlying ADT client's fetch.
685
+ *
686
+ * @param url - ADT endpoint path (e.g., '/sap/bc/adt/ddic/dataelements/spras')
687
+ * @param headers - Optional HTTP headers (defaults to no Accept header, letting server choose)
688
+ * @returns Response content as text, or undefined if 404
689
+ */
690
+ async fetchText(url, headers) {
691
+ try {
692
+ return toText(await this.ctx.client.fetch(url, {
693
+ method: "GET",
694
+ headers: headers ?? {}
695
+ }));
696
+ } catch {
697
+ return;
698
+ }
699
+ }
700
+ };
701
+ /**
702
+ * Base class for main development objects (AdtMainObject)
703
+ *
704
+ * Extends AdkObject with package reference, responsible user, and master language.
705
+ * Used for repository objects like classes, interfaces, packages, etc.
706
+ *
707
+ * Note: Uses type assertions internally because schema-inferred types from
708
+ * contracts may have different shapes than AdkMainObjectData. The getters
709
+ * safely handle missing properties with defaults.
710
+ *
711
+ * @typeParam K - The object kind (from AdkKind)
712
+ * @typeParam D - The internal data type (typically schema-inferred from contract)
713
+ */
714
+ var AdkMainObject = class extends AdkObject {
715
+ get mainData() {
716
+ return this.dataSync;
717
+ }
718
+ /** Package reference (adtcore:packageRef) */
719
+ get packageRef() {
720
+ return this.mainData.packageRef;
721
+ }
722
+ /** Package name (convenience getter) */
723
+ get package() {
724
+ return this.mainData.packageRef?.name ?? "";
725
+ }
726
+ /** Master system (adtcore:masterSystem) */
727
+ get masterSystem() {
728
+ return this.mainData.masterSystem ?? "";
729
+ }
730
+ /** Master language (adtcore:masterLanguage) */
731
+ get masterLanguage() {
732
+ return this.mainData.masterLanguage ?? "";
733
+ }
734
+ /** Responsible user (adtcore:responsible) */
735
+ get responsible() {
736
+ return this.mainData.responsible ?? "";
737
+ }
738
+ /** ABAP language version (adtcore:abapLanguageVersion) */
739
+ get abapLanguageVersion() {
740
+ return this.mainData.abapLanguageVersion ?? "";
741
+ }
742
+ /**
743
+ * Save main source code to SAP.
744
+ * Requires the object to be locked before calling.
745
+ * Subclasses may override to add additional behavior (e.g. cache invalidation).
746
+ */
747
+ async saveMainSource(source, options) {
748
+ const params = new URLSearchParams();
749
+ if (options?.lockHandle) params.set("lockHandle", options.lockHandle);
750
+ if (options?.transport) params.set("corrNr", options.transport);
751
+ const qs = params.toString();
752
+ await this.ctx.client.fetch(`${this.objectUri}/source/main${qs ? "?" + qs : ""}`, {
753
+ method: "PUT",
754
+ headers: { "Content-Type": "text/plain" },
755
+ body: source
756
+ });
757
+ }
758
+ };
759
+
760
+ //#endregion
761
+ //#region src/base/object-set.ts
762
+ /**
763
+ * ADK Object Set - Collection of objects with bulk operations
764
+ *
765
+ * A semantic layer for managing collections of ADK objects and
766
+ * performing bulk operations like save and activate.
767
+ */
768
+ var AdkObjectSet = class AdkObjectSet {
769
+ ctx;
770
+ objects = [];
771
+ constructor(ctx) {
772
+ this.ctx = ctx;
773
+ }
774
+ /**
775
+ * Add a single object to the set
776
+ *
777
+ * Propagates the set's context (lockService, lockStore) to the object
778
+ * so that objects created by plugins with a bare { client } context
779
+ * inherit the services configured on the set.
780
+ */
781
+ add(object) {
782
+ if (!this.objects.includes(object)) {
783
+ object.adoptContext(this.ctx);
784
+ this.objects.push(object);
785
+ }
786
+ return this;
787
+ }
788
+ /**
789
+ * Add multiple objects to the set
790
+ */
791
+ addAll(objects) {
792
+ for (const obj of objects) this.add(obj);
793
+ return this;
794
+ }
795
+ /**
796
+ * Remove an object from the set
797
+ */
798
+ remove(object) {
799
+ const index = this.objects.indexOf(object);
800
+ if (index !== -1) this.objects.splice(index, 1);
801
+ return this;
802
+ }
803
+ /**
804
+ * Clear all objects from the set
805
+ */
806
+ clear() {
807
+ this.objects.length = 0;
808
+ return this;
809
+ }
810
+ /**
811
+ * Get all objects in the set
812
+ */
813
+ getAll() {
814
+ return [...this.objects];
815
+ }
816
+ /**
817
+ * Get number of objects in the set
818
+ */
819
+ get size() {
820
+ return this.objects.length;
821
+ }
822
+ /**
823
+ * Check if set is empty
824
+ */
825
+ get isEmpty() {
826
+ return this.objects.length === 0;
827
+ }
828
+ /**
829
+ * Filter objects by type
830
+ */
831
+ filterByType(type) {
832
+ return this.objects.filter((obj) => obj.type === type);
833
+ }
834
+ /**
835
+ * Filter objects by kind
836
+ */
837
+ filterByKind(kind) {
838
+ return this.objects.filter((obj) => obj.kind === kind);
839
+ }
840
+ /**
841
+ * Iterate over objects
842
+ */
843
+ [Symbol.iterator]() {
844
+ return this.objects[Symbol.iterator]();
845
+ }
846
+ /**
847
+ * Save all objects in the set
848
+ *
849
+ * Saves each object individually, handling lock/unlock per object.
850
+ * By default continues on error to save as many objects as possible.
851
+ *
852
+ * @param options - Save options (transport, inactive, continueOnError)
853
+ * @returns Result with success/failure counts and details
854
+ */
855
+ async saveAll(options = {}) {
856
+ const { continueOnError = true, onProgress, ...saveOptions } = options;
857
+ const result = {
858
+ success: 0,
859
+ failed: 0,
860
+ unchanged: 0,
861
+ results: []
862
+ };
863
+ const total = this.objects.length;
864
+ let _saved = 0;
865
+ let processed = 0;
866
+ for (const obj of this.objects) {
867
+ try {
868
+ await obj.save(saveOptions);
869
+ if (obj._unchanged) {
870
+ result.unchanged++;
871
+ result.results.push({
872
+ object: obj,
873
+ success: true,
874
+ unchanged: true
875
+ });
876
+ } else {
877
+ _saved++;
878
+ result.success++;
879
+ result.results.push({
880
+ object: obj,
881
+ success: true
882
+ });
883
+ }
884
+ } catch (error) {
885
+ result.failed++;
886
+ result.results.push({
887
+ object: obj,
888
+ success: false,
889
+ error: error instanceof Error ? error.message : String(error)
890
+ });
891
+ if (!continueOnError) {
892
+ processed++;
893
+ onProgress?.(processed, total, obj);
894
+ break;
895
+ }
896
+ }
897
+ processed++;
898
+ onProgress?.(processed, total, obj);
899
+ }
900
+ return result;
901
+ }
902
+ /**
903
+ * Activate all objects in the set (bulk activation)
904
+ *
905
+ * Uses SAP's bulk activation endpoint for efficiency.
906
+ * All objects are activated in a single request.
907
+ *
908
+ * @param options - Activation options
909
+ * @returns Activation result with success/failure counts
910
+ */
911
+ async activateAll(options = {}) {
912
+ const { onProgress } = options;
913
+ if (this.objects.length === 0) return {
914
+ success: 0,
915
+ failed: 0,
916
+ messages: []
917
+ };
918
+ onProgress?.(`Activating ${this.objects.length} objects...`);
919
+ const activationXml = `<?xml version="1.0" encoding="UTF-8"?>
920
+ <adtcore:objectReferences xmlns:adtcore="http://www.sap.com/adt/core">
921
+ ${this.objects.map((obj) => `<adtcore:objectReference adtcore:uri="${obj.objectUri}" adtcore:type="${obj.type}" adtcore:name="${obj.name}"/>`).join("\n ")}
922
+ </adtcore:objectReferences>`;
923
+ try {
924
+ const response = await this.ctx.client.fetch("/sap/bc/adt/activation?method=activate&preauditRequested=true", {
925
+ method: "POST",
926
+ headers: {
927
+ "Content-Type": "application/xml",
928
+ Accept: "application/xml"
929
+ },
930
+ body: activationXml
931
+ });
932
+ return {
933
+ success: this.objects.length,
934
+ failed: 0,
935
+ messages: [],
936
+ response: String(response)
937
+ };
938
+ } catch (error) {
939
+ return {
940
+ success: 0,
941
+ failed: this.objects.length,
942
+ messages: [error instanceof Error ? error.message : String(error)]
943
+ };
944
+ }
945
+ }
946
+ /**
947
+ * Save all objects as inactive, then bulk activate, then unlock
948
+ *
949
+ * This is the recommended pattern for deploying multiple objects:
950
+ * 1. Save all objects as inactive (handles dependencies)
951
+ * 2. Bulk activate all saved objects
952
+ * 3. Unlock all objects
953
+ *
954
+ * @param options - Save options (transport required)
955
+ * @returns Combined result of save and activation
956
+ */
957
+ async deploy(options) {
958
+ const { activate = true, ...saveOptions } = options;
959
+ try {
960
+ const saveResult = await this.saveAll({
961
+ ...saveOptions,
962
+ inactive: true
963
+ });
964
+ let activationResult;
965
+ if (activate && saveResult.success > 0) {
966
+ const savedSet = new AdkObjectSet(this.ctx);
967
+ for (const r of saveResult.results) if (r.success) savedSet.add(r.object);
968
+ activationResult = await savedSet.activateAll();
969
+ for (const r of saveResult.results) {
970
+ if (!r.success) continue;
971
+ const obj = r.object;
972
+ const deferred = obj._deferredSources;
973
+ if (deferred && deferred.length > 0) try {
974
+ const lock = await r.object.lock();
975
+ for (const [key, source] of deferred) await obj.saveIncludeSource(key, source, {
976
+ lockHandle: lock.handle,
977
+ transport: saveOptions.transport
978
+ });
979
+ delete obj._deferredSources;
980
+ const deferredSet = new AdkObjectSet(this.ctx);
981
+ deferredSet.add(r.object);
982
+ await deferredSet.activateAll();
983
+ } catch {} finally {
984
+ try {
985
+ await r.object.unlock();
986
+ } catch {}
987
+ }
988
+ }
989
+ }
990
+ return {
991
+ save: saveResult,
992
+ activation: activationResult
993
+ };
994
+ } finally {
995
+ await this.unlockAll();
996
+ }
997
+ }
998
+ /**
999
+ * Lock all objects in the set
1000
+ *
1001
+ * @returns Array of lock handles
1002
+ */
1003
+ async lockAll() {
1004
+ const handles = [];
1005
+ for (const obj of this.objects) {
1006
+ const handle = await obj.lock();
1007
+ handles.push(handle);
1008
+ }
1009
+ return handles;
1010
+ }
1011
+ /**
1012
+ * Unlock all objects in the set
1013
+ */
1014
+ async unlockAll() {
1015
+ for (const obj of this.objects) try {
1016
+ await obj.unlock();
1017
+ } catch {}
1018
+ }
1019
+ /**
1020
+ * Load all objects (fetch data from SAP)
1021
+ *
1022
+ * @param options - Load options
1023
+ * @returns This set (for chaining)
1024
+ */
1025
+ async loadAll(options = {}) {
1026
+ const { parallel = false } = options;
1027
+ if (parallel) await Promise.all(this.objects.map((obj) => obj.load()));
1028
+ else for (const obj of this.objects) await obj.load();
1029
+ return this;
1030
+ }
1031
+ /**
1032
+ * Create an object set from an array of objects
1033
+ */
1034
+ static from(objects, ctx) {
1035
+ const set = new AdkObjectSet(ctx);
1036
+ set.addAll(objects);
1037
+ return set;
1038
+ }
1039
+ /**
1040
+ * Create an object set by collecting from an async generator
1041
+ *
1042
+ * Collects all objects yielded by the generator into the set.
1043
+ * Useful for collecting objects from format plugin export generators.
1044
+ *
1045
+ * @param generator - Async generator yielding AdkObject instances
1046
+ * @param ctx - ADK context for the set
1047
+ * @param options - Collection options
1048
+ * @returns Promise resolving to populated AdkObjectSet
1049
+ */
1050
+ static async fromGenerator(generator, ctx, options = {}) {
1051
+ const { filter, onObject } = options;
1052
+ const set = new AdkObjectSet(ctx);
1053
+ for await (const obj of generator) {
1054
+ if (filter && !filter(obj)) continue;
1055
+ set.add(obj);
1056
+ onObject?.(obj);
1057
+ }
1058
+ return set;
1059
+ }
1060
+ };
1061
+
1062
+ //#endregion
1063
+ //#region src/base/adt.ts
1064
+ /**
1065
+ * Create ADK contract from ADT client
1066
+ *
1067
+ * @param client - ADT client instance from createAdtClient()
1068
+ * @returns ADK contract proxy
1069
+ */
1070
+ function createAdkContract(client) {
1071
+ return {
1072
+ oo: client.adt.oo,
1073
+ packages: client.adt.packages,
1074
+ cts: client.adt.cts,
1075
+ core: client.adt.core,
1076
+ repository: client.adt.repository,
1077
+ programs: client.adt.programs,
1078
+ functions: client.adt.functions,
1079
+ ddic: client.adt.ddic,
1080
+ bo: client.adt.bo
1081
+ };
1082
+ }
1083
+
1084
+ //#endregion
1085
+ //#region src/base/global-context.ts
1086
+ let globalContext = null;
1087
+ /**
1088
+ * Initialize the global ADK context from an ADT client.
1089
+ *
1090
+ * Call this once during application bootstrap (e.g., in CLI initialization).
1091
+ * After initialization, ADK objects can be used without passing context.
1092
+ *
1093
+ * @param client - ADT client v2 instance
1094
+ * @throws Error if client is not provided
1095
+ *
1096
+ * @example
1097
+ * ```ts
1098
+ * import { initializeAdk } from '@abapify/adk';
1099
+ * import { createAdtClient } from '@abapify/adt-client';
1100
+ *
1101
+ * const client = createAdtClient({ ... });
1102
+ * initializeAdk(client);
1103
+ *
1104
+ * // Now ADK objects work without context
1105
+ * const transport = await AdkTransportRequest.get('S0DK900001');
1106
+ * ```
1107
+ */
1108
+ function initializeAdk(client, options) {
1109
+ if (!client) throw new Error("ADK initialization failed: client is required");
1110
+ const lockStore = options?.lockStore;
1111
+ globalContext = {
1112
+ client,
1113
+ lockStore,
1114
+ lockService: options?.lockService ?? createLockService$1(client, { store: lockStore })
1115
+ };
1116
+ }
1117
+ /**
1118
+ * Get the global ADK context.
1119
+ *
1120
+ * Used internally by ADK objects when no explicit context is provided.
1121
+ *
1122
+ * @returns The global ADK context
1123
+ * @throws Error if ADK has not been initialized
1124
+ *
1125
+ * @example
1126
+ * ```ts
1127
+ * // Internal usage in ADK objects:
1128
+ * static async get(number: string, ctx?: AdkContext): Promise<AdkTransportRequest> {
1129
+ * const context = ctx ?? getGlobalContext();
1130
+ * // ...
1131
+ * }
1132
+ * ```
1133
+ */
1134
+ function getGlobalContext() {
1135
+ if (!globalContext) throw new Error("ADK not initialized. Call initializeAdk(client) before using ADK objects.\nExample:\n import { initializeAdk } from '@abapify/adk';\n initializeAdk(client);");
1136
+ return globalContext;
1137
+ }
1138
+ /**
1139
+ * Check if ADK has been initialized.
1140
+ *
1141
+ * Useful for conditional logic or error handling.
1142
+ *
1143
+ * @returns true if initializeAdk() has been called
1144
+ */
1145
+ function isAdkInitialized() {
1146
+ return globalContext !== null;
1147
+ }
1148
+ /**
1149
+ * Reset the global ADK context.
1150
+ *
1151
+ * Primarily for testing purposes. Clears the global context.
1152
+ */
1153
+ function resetAdk() {
1154
+ globalContext = null;
1155
+ }
1156
+ /**
1157
+ * Get the global context or return undefined if not initialized.
1158
+ *
1159
+ * Unlike getGlobalContext(), this doesn't throw - useful when you want
1160
+ * to check if context exists before using it.
1161
+ *
1162
+ * @returns The global context or undefined
1163
+ */
1164
+ function tryGetGlobalContext() {
1165
+ return globalContext ?? void 0;
1166
+ }
1167
+
1168
+ //#endregion
1169
+ //#region src/objects/repository/devc/devc.model.ts
1170
+ /**
1171
+ * DEVC - ABAP Package
1172
+ *
1173
+ * ADK object for ABAP packages (DEVC).
1174
+ */
1175
+ /**
1176
+ * ADK Package object
1177
+ *
1178
+ * Inherits from AdkMainObject which provides:
1179
+ * - AdkObject: name, type, description, version, language, changedBy/At, createdBy/At, links
1180
+ * - AdkMainObject: packageRef, responsible, masterLanguage, masterSystem, abapLanguageVersion
1181
+ *
1182
+ * Note: For packages, the parent package is stored in `superPackage` not `packageRef`.
1183
+ * The `package` getter is overridden to return the super package name.
1184
+ */
1185
+ var AdkPackage = class AdkPackage extends AdkMainObject {
1186
+ static kind = Package;
1187
+ kind = AdkPackage.kind;
1188
+ get objectUri() {
1189
+ return `/sap/bc/adt/packages/${encodeURIComponent(this.name)}`;
1190
+ }
1191
+ get package() {
1192
+ return this.dataSync.superPackage?.name ?? "";
1193
+ }
1194
+ get attributes() {
1195
+ const attrs = this.dataSync.attributes;
1196
+ return {
1197
+ packageType: attrs?.packageType ?? "development",
1198
+ isEncapsulated: attrs?.isEncapsulated ?? false,
1199
+ isAddingObjectsAllowed: attrs?.isAddingObjectsAllowed ?? true,
1200
+ recordChanges: attrs?.recordChanges ?? false,
1201
+ languageVersion: attrs?.languageVersion ?? ""
1202
+ };
1203
+ }
1204
+ get superPackage() {
1205
+ const sp = this.dataSync.superPackage;
1206
+ if (!sp?.name) return void 0;
1207
+ return {
1208
+ uri: sp.uri ?? "",
1209
+ type: sp.type ?? "DEVC/K",
1210
+ name: sp.name,
1211
+ description: sp.description
1212
+ };
1213
+ }
1214
+ get applicationComponent() {
1215
+ const ac = this.dataSync.applicationComponent;
1216
+ if (!ac?.name) return void 0;
1217
+ return {
1218
+ name: ac.name,
1219
+ description: ac.description ?? ""
1220
+ };
1221
+ }
1222
+ get transport() {
1223
+ const t = this.dataSync.transport;
1224
+ if (!t) return void 0;
1225
+ return {
1226
+ softwareComponent: t.softwareComponent?.name ? {
1227
+ name: t.softwareComponent.name,
1228
+ description: t.softwareComponent.description ?? ""
1229
+ } : void 0,
1230
+ transportLayer: t.transportLayer?.name ? {
1231
+ name: t.transportLayer.name,
1232
+ description: t.transportLayer.description ?? ""
1233
+ } : void 0
1234
+ };
1235
+ }
1236
+ async getSubpackages() {
1237
+ return this.lazy("subpackages", async () => {
1238
+ const response = await this.ctx.client.adt.repository.informationsystem.search.quickSearch({
1239
+ query: "*",
1240
+ packageName: this.name,
1241
+ objectType: "DEVC",
1242
+ maxResults: 1e3
1243
+ });
1244
+ const refs = "objectReferences" in response ? response.objectReferences?.objectReference ?? [] : [];
1245
+ const subpkgRefs = (Array.isArray(refs) ? refs : [refs]).filter((ref) => !!ref.name && ref.type === "DEVC/K" && ref.name !== this.name);
1246
+ return (await Promise.all(subpkgRefs.map(async (ref) => {
1247
+ const pkg = new AdkPackage(this.ctx, ref.name);
1248
+ await pkg.load();
1249
+ return pkg;
1250
+ }))).filter((pkg) => pkg.superPackage?.name?.toUpperCase() === this.name.toUpperCase());
1251
+ });
1252
+ }
1253
+ async getObjects() {
1254
+ return this.lazy("objects", async () => {
1255
+ const response = await this.ctx.client.adt.repository.informationsystem.search.quickSearch({
1256
+ query: "*",
1257
+ packageName: this.name,
1258
+ maxResults: 1e3
1259
+ });
1260
+ const refs = "objectReferences" in response ? response.objectReferences?.objectReference ?? [] : [];
1261
+ return (Array.isArray(refs) ? refs : [refs]).filter((ref) => !!ref.name && ref.type !== "DEVC/K" && ref.packageName?.toUpperCase() === this.name.toUpperCase()).map((ref) => ({
1262
+ kind: ref.type ?? "",
1263
+ type: ref.type ?? "",
1264
+ name: ref.name,
1265
+ description: ref.description ?? "",
1266
+ package: ref.packageName ?? ""
1267
+ }));
1268
+ });
1269
+ }
1270
+ async getAllObjects() {
1271
+ return this.lazy("allObjects", async () => {
1272
+ const direct = await this.getObjects();
1273
+ const subpackages = await this.getSubpackages();
1274
+ const nested = await Promise.all(subpackages.map((pkg) => pkg.getAllObjects()));
1275
+ const seen = /* @__PURE__ */ new Set();
1276
+ return [...direct, ...nested.flat()].filter((obj) => {
1277
+ const key = `${obj.type}:${obj.name}`;
1278
+ if (seen.has(key)) return false;
1279
+ seen.add(key);
1280
+ return true;
1281
+ });
1282
+ });
1283
+ }
1284
+ async load() {
1285
+ const response = await this.ctx.client.adt.packages.get(this.name);
1286
+ if (!response || !("package" in response) || !response.package) throw new Error(`Package '${this.name}' not found or returned empty response`);
1287
+ this.setData(response.package);
1288
+ return this;
1289
+ }
1290
+ get wrapperKey() {
1291
+ return "package";
1292
+ }
1293
+ get crudContract() {
1294
+ return this.ctx.client.adt.packages;
1295
+ }
1296
+ /**
1297
+ * Get skeleton data for package creation (POST).
1298
+ *
1299
+ * SAP requires ALL elements in the Package xs:sequence, even if empty.
1300
+ * The sequence order is: attributes, superPackage, extensionAlias, switch,
1301
+ * applicationComponent, transport, translation, useAccesses,
1302
+ * packageInterfaces, subPackages.
1303
+ * Missing elements cause "System expected the element ..." 400 errors.
1304
+ */
1305
+ async getSkeletonData() {
1306
+ const d = await this.data();
1307
+ return {
1308
+ name: d.name,
1309
+ type: d.type ?? "DEVC/K",
1310
+ description: d.description ?? "",
1311
+ language: d.language ?? "EN",
1312
+ masterLanguage: d.masterLanguage ?? "EN",
1313
+ responsible: d.responsible ?? "",
1314
+ attributes: d.attributes ?? { packageType: "development" },
1315
+ superPackage: d.superPackage ?? {},
1316
+ extensionAlias: d.extensionAlias ?? {},
1317
+ switch: d.switch ?? {},
1318
+ applicationComponent: d.applicationComponent ?? {},
1319
+ transport: d.transport ?? {},
1320
+ translation: d.translation ?? {},
1321
+ useAccesses: d.useAccesses ?? {},
1322
+ packageInterfaces: d.packageInterfaces ?? {},
1323
+ subPackages: d.subPackages ?? {}
1324
+ };
1325
+ }
1326
+ /**
1327
+ * Get a package by name
1328
+ *
1329
+ * @param name - Package name (e.g., '$TMP', 'ZPACKAGE')
1330
+ * @param ctx - Optional ADK context (uses global context if not provided)
1331
+ */
1332
+ static async get(name, ctx) {
1333
+ const pkg = new AdkPackage(ctx ?? getGlobalContext(), name);
1334
+ await pkg.load();
1335
+ return pkg;
1336
+ }
1337
+ /**
1338
+ * Check if a package exists on SAP
1339
+ *
1340
+ * @param name - Package name
1341
+ * @param ctx - Optional ADK context (uses global context if not provided)
1342
+ * @returns true if package exists, false otherwise
1343
+ */
1344
+ static async exists(name, ctx) {
1345
+ try {
1346
+ await new AdkPackage(ctx ?? getGlobalContext(), name).load();
1347
+ return true;
1348
+ } catch {
1349
+ return false;
1350
+ }
1351
+ }
1352
+ /**
1353
+ * Create a new package on SAP
1354
+ *
1355
+ * Builds an AdkPackage with the given data and saves it in 'create' mode.
1356
+ *
1357
+ * @param name - Package name (e.g., 'ZABAPGIT_EXAMPLES_CLAS')
1358
+ * @param data - Package data (superPackage, attributes, transport, etc.)
1359
+ * @param options - Save options (transport request)
1360
+ * @param ctx - Optional ADK context (uses global context if not provided)
1361
+ */
1362
+ static async create(name, data, options, ctx) {
1363
+ const pkg = new AdkPackage(ctx ?? getGlobalContext(), name);
1364
+ pkg.setData({
1365
+ name,
1366
+ type: "DEVC/K",
1367
+ description: data.description ?? name,
1368
+ responsible: data.responsible ?? "",
1369
+ attributes: {
1370
+ packageType: "development",
1371
+ ...data.attributes
1372
+ },
1373
+ superPackage: data.superPackage ?? {},
1374
+ extensionAlias: data.extensionAlias ?? {},
1375
+ switch: data.switch ?? {},
1376
+ applicationComponent: data.applicationComponent ?? {},
1377
+ transport: data.transport ?? {},
1378
+ translation: data.translation ?? {},
1379
+ useAccesses: data.useAccesses ?? {},
1380
+ packageInterfaces: data.packageInterfaces ?? {},
1381
+ subPackages: data.subPackages ?? {},
1382
+ ...data
1383
+ });
1384
+ await pkg.save({
1385
+ transport: options?.transport,
1386
+ mode: "create"
1387
+ });
1388
+ return pkg;
1389
+ }
1390
+ /**
1391
+ * Delete an ABAP package from SAP
1392
+ *
1393
+ * @param name - Package name
1394
+ * @param options - Delete options (transport, lockHandle)
1395
+ * @param ctx - Optional ADK context (uses global context if not provided)
1396
+ */
1397
+ static async delete(name, options, ctx) {
1398
+ await new AdkPackage(ctx ?? getGlobalContext(), name.toUpperCase()).crudContract.delete(name.toUpperCase(), {
1399
+ ...options?.transport && { corrNr: options.transport },
1400
+ ...options?.lockHandle && { lockHandle: options.lockHandle }
1401
+ });
1402
+ }
1403
+ };
1404
+ registerObjectType("DEVC", Package, AdkPackage, {
1405
+ endpoint: "packages",
1406
+ nameTransform: "preserve"
1407
+ });
1408
+
1409
+ //#endregion
1410
+ //#region src/decorators/lockable.ts
1411
+ /**
1412
+ * @requiresLock - Method decorator
1413
+ *
1414
+ * Automatically acquires lock before method execution
1415
+ * and releases it after (unless keep: true).
1416
+ *
1417
+ * @param options - Lock options
1418
+ * @param options.keep - If true, keep lock after method completes
1419
+ *
1420
+ * @example
1421
+ * ```typescript
1422
+ * @requiresLock()
1423
+ * async update(data: UpdateData): Promise<void> {
1424
+ * // Lock is acquired before this runs
1425
+ * // Lock is released after this completes
1426
+ * }
1427
+ *
1428
+ * @requiresLock({ keep: true })
1429
+ * async startTransaction(): Promise<void> {
1430
+ * // Lock is acquired and KEPT for subsequent operations
1431
+ * }
1432
+ * ```
1433
+ */
1434
+ function requiresLock(options) {
1435
+ return function(_target, _propertyKey, descriptor) {
1436
+ const originalMethod = descriptor.value;
1437
+ descriptor.value = async function(...args) {
1438
+ const wasLocked = this.isLocked;
1439
+ try {
1440
+ if (!wasLocked) await this.lock();
1441
+ return await originalMethod.apply(this, args);
1442
+ } finally {
1443
+ if (!wasLocked && this.isLocked && !options?.keep) await this.unlock();
1444
+ }
1445
+ };
1446
+ return descriptor;
1447
+ };
1448
+ }
1449
+
1450
+ //#endregion
1451
+ //#region src/decorators/datetime.ts
1452
+ /**
1453
+ * @datetime - SAP Timestamp Property Decorator
1454
+ *
1455
+ * Parses SAP timestamp formats into JavaScript Date objects.
1456
+ *
1457
+ * SAP Timestamp Formats:
1458
+ * - YYYYMMDDHHMMSS (14 chars) - e.g., "20231215143052"
1459
+ * - YYYYMMDD (8 chars) - date only
1460
+ *
1461
+ * Usage:
1462
+ * class MyObject {
1463
+ * @datetime() lastChangedAt?: Date;
1464
+ * @datetime('lastchanged_timestamp') modifiedAt?: Date;
1465
+ * }
1466
+ */
1467
+ /**
1468
+ * Parse SAP timestamp string to Date
1469
+ * Supports: YYYYMMDDHHMMSS (14 chars) or YYYYMMDD (8 chars)
1470
+ */
1471
+ function parseSapTimestamp(ts) {
1472
+ if (!ts || typeof ts !== "string") return void 0;
1473
+ const s = ts.trim();
1474
+ if (s.length < 8) return void 0;
1475
+ const year = s.slice(0, 4);
1476
+ const month = s.slice(4, 6);
1477
+ const day = s.slice(6, 8);
1478
+ const hour = s.length >= 10 ? s.slice(8, 10) : "00";
1479
+ const min = s.length >= 12 ? s.slice(10, 12) : "00";
1480
+ const sec = s.length >= 14 ? s.slice(12, 14) : "00";
1481
+ return /* @__PURE__ */ new Date(`${year}-${month}-${day}T${hour}:${min}:${sec}Z`);
1482
+ }
1483
+
1484
+ //#endregion
1485
+ //#region src/decorators/lazy.ts
1486
+ /**
1487
+ * @lazy - Lazy Initialization Decorator
1488
+ *
1489
+ * Computes a value once on first access, then caches it.
1490
+ *
1491
+ * Usage:
1492
+ * class MyObject {
1493
+ * @lazy(self => `${self.a}/${self.b}`)
1494
+ * key!: string;
1495
+ * }
1496
+ *
1497
+ * Note: Due to class field shadowing, use `declare` keyword:
1498
+ * @lazy(self => compute())
1499
+ * declare myProp: Type;
1500
+ */
1501
+ const LAZY_CACHE = Symbol("lazy:cache");
1502
+ /**
1503
+ * Invalidate a specific lazy property (force recomputation on next access)
1504
+ */
1505
+ function invalidateLazy(obj, propertyKey) {
1506
+ obj[LAZY_CACHE]?.delete(propertyKey);
1507
+ }
1508
+
1509
+ //#endregion
1510
+ //#region src/objects/repository/clas/clas.model.ts
1511
+ /**
1512
+ * CLAS - ABAP Class
1513
+ *
1514
+ * ADK object for ABAP classes (CLAS).
1515
+ */
1516
+ /**
1517
+ * ADK Class object
1518
+ *
1519
+ * Inherits from AdkMainObject which provides:
1520
+ * - AdkObject: name, type, description, version, language, changedBy/At, createdBy/At, links
1521
+ * - AdkMainObject: package, packageRef, responsible, masterLanguage, masterSystem, abapLanguageVersion
1522
+ *
1523
+ * Access class-specific properties via `data`:
1524
+ * - data.category, data.final, data.abstract, data.visibility
1525
+ * - data.sharedMemoryEnabled, data.modeled, data.fixPointArithmetic
1526
+ * - data.superClassRef, data.messageClassRef, data.include
1527
+ */
1528
+ var AdkClass = class AdkClass extends AdkMainObject {
1529
+ static kind = Class;
1530
+ kind = AdkClass.kind;
1531
+ get objectUri() {
1532
+ return `/sap/bc/adt/oo/classes/${encodeURIComponent(this.name.toLowerCase())}`;
1533
+ }
1534
+ async getMainSource() {
1535
+ return this.lazy("source:main", async () => {
1536
+ return this.crudContract.source.main.get(this.name);
1537
+ });
1538
+ }
1539
+ async getIncludeSource(includeType) {
1540
+ return this.lazy(`source:${includeType}`, async () => {
1541
+ if (includeType === "main") return this.crudContract.source.main.get(this.name);
1542
+ return this.crudContract.includes.get(this.name, includeType);
1543
+ });
1544
+ }
1545
+ async getDefinitions() {
1546
+ return this.getIncludeSource("definitions");
1547
+ }
1548
+ async getImplementations() {
1549
+ return this.getIncludeSource("implementations");
1550
+ }
1551
+ async getTestClasses() {
1552
+ return this.getIncludeSource("testclasses");
1553
+ }
1554
+ /**
1555
+ * Save main source code
1556
+ * Requires object to be locked first
1557
+ */
1558
+ async saveMainSource(source, options) {
1559
+ await this.crudContract.source.main.put(this.name, {
1560
+ ...options?.lockHandle ? { lockHandle: options.lockHandle } : {},
1561
+ ...options?.transport ? { corrNr: options.transport } : {}
1562
+ }, source);
1563
+ invalidateLazy(this, "source:main");
1564
+ }
1565
+ /**
1566
+ * Save include source code
1567
+ * Requires object to be locked first
1568
+ */
1569
+ async saveIncludeSource(includeType, source, options) {
1570
+ const putOptions = {
1571
+ ...options?.lockHandle ? { lockHandle: options.lockHandle } : {},
1572
+ ...options?.transport ? { corrNr: options.transport } : {}
1573
+ };
1574
+ if (includeType === "main") await this.crudContract.source.main.put(this.name, putOptions, source);
1575
+ else await this.crudContract.includes.put(this.name, includeType, putOptions, source);
1576
+ invalidateLazy(this, `source:${includeType}`);
1577
+ }
1578
+ /**
1579
+ * Save all pending sources (set via _pendingSources)
1580
+ * Used by export workflow after deserialization from abapGit
1581
+ * Overrides base class method
1582
+ *
1583
+ * Note: unchanged detection is handled by checkPendingSourcesUnchanged()
1584
+ * which runs BEFORE lock acquisition. By the time we reach here,
1585
+ * at least one source differs — save them all.
1586
+ */
1587
+ async savePendingSources(options) {
1588
+ const pendingSources = this._pendingSources;
1589
+ if (!pendingSources) return;
1590
+ const errors = [];
1591
+ const deferred = [];
1592
+ for (const [key, source] of Object.entries(pendingSources)) try {
1593
+ if (key === "main") await this.saveMainSource(source, options);
1594
+ else await this.saveIncludeSource(key, source, options);
1595
+ } catch (e) {
1596
+ const errorMsg = e instanceof Error ? e.message : String(e);
1597
+ if (errorMsg.includes("409") || errorMsg.includes("Conflict")) continue;
1598
+ if (errorMsg.includes("does not have any inactive version") || errorMsg.includes("ResourceNotFound")) {
1599
+ deferred.push([key, source]);
1600
+ continue;
1601
+ }
1602
+ errors.push(e instanceof Error ? e : new Error(String(e)));
1603
+ }
1604
+ if (deferred.length > 0) this._deferredSources = deferred;
1605
+ delete this._pendingSources;
1606
+ delete this._pendingSource;
1607
+ if (errors.length > 0) throw errors[0];
1608
+ }
1609
+ /**
1610
+ * Pre-lock comparison: check if all pending sources match SAP
1611
+ * If identical, sets _unchanged = true so save() skips locking and PUT
1612
+ */
1613
+ async checkPendingSourcesUnchanged() {
1614
+ const pendingSources = this._pendingSources;
1615
+ if (!pendingSources) return;
1616
+ for (const [key, pendingSource] of Object.entries(pendingSources)) try {
1617
+ const currentSource = await this.getIncludeSource(key);
1618
+ if (this.normalizeSource(currentSource) !== this.normalizeSource(pendingSource)) return;
1619
+ } catch {
1620
+ return;
1621
+ }
1622
+ this._unchanged = true;
1623
+ delete this._pendingSources;
1624
+ delete this._pendingSource;
1625
+ }
1626
+ /**
1627
+ * Check if object has pending sources to save
1628
+ * Overrides base class method
1629
+ */
1630
+ hasPendingSources() {
1631
+ return !!this._pendingSources;
1632
+ }
1633
+ /**
1634
+ * Refresh cached ETags for all pending source endpoints after locking.
1635
+ * Classes have multiple source URLs (main + includes) that all need fresh ETags.
1636
+ */
1637
+ async refreshETagsAfterLock() {
1638
+ const pendingSources = this._pendingSources;
1639
+ if (!pendingSources) return super.refreshETagsAfterLock();
1640
+ const basePath = `/sap/bc/adt/oo/classes/${this.name.toLowerCase()}`;
1641
+ for (const key of Object.keys(pendingSources)) {
1642
+ const endpoint = key === "main" ? `${basePath}/source/main` : `${basePath}/includes/${key}`;
1643
+ try {
1644
+ if (key === "main") await this.crudContract.source.main.get(this.name);
1645
+ else await this.crudContract.includes.get(this.name, key);
1646
+ } catch {
1647
+ this.ctx.client.clearETag(endpoint);
1648
+ }
1649
+ }
1650
+ }
1651
+ get wrapperKey() {
1652
+ return "abapClass";
1653
+ }
1654
+ get crudContract() {
1655
+ return this.ctx.client.adt.oo.classes;
1656
+ }
1657
+ static async get(name, ctx) {
1658
+ return new AdkClass(ctx ?? getGlobalContext(), name).load();
1659
+ }
1660
+ /**
1661
+ * Check if a class exists on SAP
1662
+ */
1663
+ static async exists(name, ctx) {
1664
+ try {
1665
+ await AdkClass.get(name, ctx);
1666
+ return true;
1667
+ } catch {
1668
+ return false;
1669
+ }
1670
+ }
1671
+ /**
1672
+ * Create a new ABAP class on SAP
1673
+ *
1674
+ * @param name - Class name (e.g., 'ZCL_MY_CLASS')
1675
+ * @param description - Short description
1676
+ * @param packageName - Package to assign the class to
1677
+ * @param options - Save options (transport)
1678
+ * @param ctx - Optional ADK context
1679
+ */
1680
+ static async create(name, description, packageName, options, ctx) {
1681
+ const cls = new AdkClass(ctx ?? getGlobalContext(), name.toUpperCase());
1682
+ cls.setData({
1683
+ name: name.toUpperCase(),
1684
+ type: "CLAS/OC",
1685
+ description,
1686
+ language: "EN",
1687
+ masterLanguage: "EN",
1688
+ packageRef: {
1689
+ name: packageName.toUpperCase(),
1690
+ uri: `/sap/bc/adt/packages/${encodeURIComponent(packageName.toUpperCase())}`,
1691
+ type: "DEVC/K"
1692
+ }
1693
+ });
1694
+ await cls.save({
1695
+ transport: options?.transport,
1696
+ mode: "create"
1697
+ });
1698
+ return cls;
1699
+ }
1700
+ /**
1701
+ * Delete an ABAP class from SAP
1702
+ *
1703
+ * @param name - Class name
1704
+ * @param options - Delete options (transport)
1705
+ * @param ctx - Optional ADK context
1706
+ */
1707
+ static async delete(name, options, ctx) {
1708
+ await new AdkClass(ctx ?? getGlobalContext(), name.toUpperCase()).crudContract.delete(name.toUpperCase(), {
1709
+ corrNr: options?.transport,
1710
+ lockHandle: options?.lockHandle
1711
+ });
1712
+ }
1713
+ };
1714
+ registerObjectType("CLAS", Class, AdkClass, { endpoint: "oo/classes" });
1715
+
1716
+ //#endregion
1717
+ //#region src/objects/repository/intf/intf.model.ts
1718
+ /**
1719
+ * INTF - ABAP Interface
1720
+ *
1721
+ * ADK object for ABAP interfaces (INTF).
1722
+ */
1723
+ /**
1724
+ * ADK Interface object
1725
+ *
1726
+ * Inherits from AdkMainObject which provides:
1727
+ * - AdkObject: name, type, description, version, language, changedBy/At, createdBy/At, links
1728
+ * - AdkMainObject: package, packageRef, responsible, masterLanguage, masterSystem, abapLanguageVersion
1729
+ *
1730
+ * Access interface-specific properties via `data`:
1731
+ * - data.modeled, data.sourceUri, data.fixPointArithmetic, data.activeUnicodeCheck
1732
+ */
1733
+ var AdkInterface = class AdkInterface extends AdkMainObject {
1734
+ static kind = Interface;
1735
+ kind = AdkInterface.kind;
1736
+ get objectUri() {
1737
+ return `/sap/bc/adt/oo/interfaces/${encodeURIComponent(this.name.toLowerCase())}`;
1738
+ }
1739
+ async getSource() {
1740
+ return this.lazy("source", async () => {
1741
+ return this.ctx.client.adt.oo.interfaces.source.main.get(this.name);
1742
+ });
1743
+ }
1744
+ get wrapperKey() {
1745
+ return "abapInterface";
1746
+ }
1747
+ get crudContract() {
1748
+ return this.ctx.client.adt.oo.interfaces;
1749
+ }
1750
+ static async get(name, ctx) {
1751
+ return new AdkInterface(ctx ?? getGlobalContext(), name).load();
1752
+ }
1753
+ /**
1754
+ * Check if an interface exists on SAP
1755
+ */
1756
+ static async exists(name, ctx) {
1757
+ try {
1758
+ await AdkInterface.get(name, ctx);
1759
+ return true;
1760
+ } catch {
1761
+ return false;
1762
+ }
1763
+ }
1764
+ /**
1765
+ * Create a new ABAP interface on SAP
1766
+ *
1767
+ * @param name - Interface name (e.g., 'ZIF_MY_INTERFACE')
1768
+ * @param description - Short description
1769
+ * @param packageName - Package to assign the interface to
1770
+ * @param options - Save options (transport)
1771
+ * @param ctx - Optional ADK context
1772
+ */
1773
+ static async create(name, description, packageName, options, ctx) {
1774
+ const intf = new AdkInterface(ctx ?? getGlobalContext(), name.toUpperCase());
1775
+ intf.setData({
1776
+ name: name.toUpperCase(),
1777
+ type: "INTF/OI",
1778
+ description,
1779
+ language: "EN",
1780
+ masterLanguage: "EN",
1781
+ packageRef: {
1782
+ name: packageName.toUpperCase(),
1783
+ uri: `/sap/bc/adt/packages/${encodeURIComponent(packageName.toUpperCase())}`,
1784
+ type: "DEVC/K"
1785
+ }
1786
+ });
1787
+ await intf.save({
1788
+ transport: options?.transport,
1789
+ mode: "create"
1790
+ });
1791
+ return intf;
1792
+ }
1793
+ /**
1794
+ * Delete an ABAP interface from SAP
1795
+ *
1796
+ * @param name - Interface name
1797
+ * @param options - Delete options (transport)
1798
+ * @param ctx - Optional ADK context
1799
+ */
1800
+ static async delete(name, options, ctx) {
1801
+ await new AdkInterface(ctx ?? getGlobalContext(), name.toUpperCase()).crudContract.delete(name.toUpperCase(), {
1802
+ corrNr: options?.transport,
1803
+ lockHandle: options?.lockHandle
1804
+ });
1805
+ }
1806
+ };
1807
+ registerObjectType("INTF", Interface, AdkInterface, { endpoint: "oo/interfaces" });
1808
+
1809
+ //#endregion
1810
+ //#region src/objects/repository/prog/prog.model.ts
1811
+ /**
1812
+ * PROG - ABAP Program
1813
+ *
1814
+ * ADK object for ABAP programs (PROG).
1815
+ */
1816
+ /**
1817
+ * ADK Program object
1818
+ *
1819
+ * Inherits from AdkMainObject which provides:
1820
+ * - AdkObject: name, type, description, version, language, changedBy/At, createdBy/At, links
1821
+ * - AdkMainObject: package, packageRef, responsible, masterLanguage, masterSystem, abapLanguageVersion
1822
+ *
1823
+ * Access program-specific properties via `data`:
1824
+ * - data.programType, data.sourceUri, data.fixPointArithmetic, data.activeUnicodeCheck
1825
+ */
1826
+ var AdkProgram = class AdkProgram extends AdkMainObject {
1827
+ static kind = Program;
1828
+ kind = AdkProgram.kind;
1829
+ get objectUri() {
1830
+ return `/sap/bc/adt/programs/programs/${encodeURIComponent(this.name.toLowerCase())}`;
1831
+ }
1832
+ async getSource() {
1833
+ return this.lazy("source", async () => {
1834
+ return this.ctx.client.adt.programs.programs.source.main.get(this.name);
1835
+ });
1836
+ }
1837
+ get wrapperKey() {
1838
+ return "abapProgram";
1839
+ }
1840
+ get crudContract() {
1841
+ return this.ctx.client.adt.programs.programs;
1842
+ }
1843
+ static async get(name, ctx) {
1844
+ return new AdkProgram(ctx ?? getGlobalContext(), name).load();
1845
+ }
1846
+ /**
1847
+ * Check if a program exists on SAP
1848
+ */
1849
+ static async exists(name, ctx) {
1850
+ try {
1851
+ await AdkProgram.get(name, ctx);
1852
+ return true;
1853
+ } catch {
1854
+ return false;
1855
+ }
1856
+ }
1857
+ /**
1858
+ * Create a new ABAP program on SAP
1859
+ *
1860
+ * @param name - Program name (e.g., 'ZMYPROGRAM')
1861
+ * @param description - Short description
1862
+ * @param packageName - Package to assign the program to
1863
+ * @param options - Save options (transport)
1864
+ * @param ctx - Optional ADK context
1865
+ */
1866
+ static async create(name, description, packageName, options, ctx) {
1867
+ const prog = new AdkProgram(ctx ?? getGlobalContext(), name.toUpperCase());
1868
+ prog.setData({
1869
+ name: name.toUpperCase(),
1870
+ type: "PROG/P",
1871
+ description,
1872
+ language: "EN",
1873
+ masterLanguage: "EN",
1874
+ packageRef: {
1875
+ name: packageName.toUpperCase(),
1876
+ uri: `/sap/bc/adt/packages/${encodeURIComponent(packageName.toUpperCase())}`,
1877
+ type: "DEVC/K"
1878
+ }
1879
+ });
1880
+ await prog.save({
1881
+ transport: options?.transport,
1882
+ mode: "create"
1883
+ });
1884
+ return prog;
1885
+ }
1886
+ /**
1887
+ * Delete an ABAP program from SAP
1888
+ *
1889
+ * @param name - Program name
1890
+ * @param options - Delete options (transport)
1891
+ * @param ctx - Optional ADK context
1892
+ */
1893
+ static async delete(name, options, ctx) {
1894
+ await new AdkProgram(ctx ?? getGlobalContext(), name.toUpperCase()).crudContract.delete(name.toUpperCase(), {
1895
+ corrNr: options?.transport,
1896
+ lockHandle: options?.lockHandle
1897
+ });
1898
+ }
1899
+ };
1900
+ registerObjectType("PROG", Program, AdkProgram, { endpoint: "programs/programs" });
1901
+
1902
+ //#endregion
1903
+ //#region src/objects/repository/incl/incl.model.ts
1904
+ /**
1905
+ * INCL - ABAP Program Include
1906
+ *
1907
+ * ADK object for ABAP program includes (PROG/I). Mirrors the PROG model
1908
+ * but targets the `/sap/bc/adt/programs/includes` endpoint.
1909
+ */
1910
+ /**
1911
+ * ADK Include object
1912
+ *
1913
+ * Inherits from AdkMainObject which provides:
1914
+ * - AdkObject: name, type, description, version, language, changedBy/At,
1915
+ * createdBy/At, links
1916
+ * - AdkMainObject: package, packageRef, responsible, masterLanguage,
1917
+ * masterSystem, abapLanguageVersion
1918
+ *
1919
+ * Access include-specific properties via `data`:
1920
+ * - data.sourceUri, data.fixPointArithmetic, data.activeUnicodeCheck,
1921
+ * data.contextRef (pointer to the main program)
1922
+ */
1923
+ var AdkInclude = class AdkInclude extends AdkMainObject {
1924
+ static kind = Include;
1925
+ kind = AdkInclude.kind;
1926
+ get objectUri() {
1927
+ return `/sap/bc/adt/programs/includes/${encodeURIComponent(this.name.toLowerCase())}`;
1928
+ }
1929
+ async getSource() {
1930
+ return this.lazy("source", async () => {
1931
+ return this.ctx.client.adt.programs.includes.source.main.get(this.name);
1932
+ });
1933
+ }
1934
+ get wrapperKey() {
1935
+ return "abapInclude";
1936
+ }
1937
+ get crudContract() {
1938
+ return this.ctx.client.adt.programs.includes;
1939
+ }
1940
+ /**
1941
+ * Skeleton POST data for includes.
1942
+ *
1943
+ * Extends the base skeleton (name/type/description/packageRef) with
1944
+ * `contextRef`, which sapcli's `sap.adt.Include(..., master=...)` serializes
1945
+ * at creation time. Without this the include would be created detached
1946
+ * from its main program.
1947
+ */
1948
+ async getSkeletonData() {
1949
+ const base = await super.getSkeletonData();
1950
+ const d = await this.data();
1951
+ if (d.contextRef) base.contextRef = d.contextRef;
1952
+ return base;
1953
+ }
1954
+ static async get(name, ctx) {
1955
+ return new AdkInclude(ctx ?? getGlobalContext(), name).load();
1956
+ }
1957
+ /**
1958
+ * Check if an include exists on SAP
1959
+ */
1960
+ static async exists(name, ctx) {
1961
+ try {
1962
+ await AdkInclude.get(name, ctx);
1963
+ return true;
1964
+ } catch {
1965
+ return false;
1966
+ }
1967
+ }
1968
+ /**
1969
+ * Create a new ABAP include on SAP
1970
+ *
1971
+ * @param name - Include name (e.g., 'ZMY_INCLUDE')
1972
+ * @param description - Short description
1973
+ * @param packageName - Package to assign the include to
1974
+ * @param options - Save options (transport, master program)
1975
+ * @param ctx - Optional ADK context
1976
+ */
1977
+ static async create(name, description, packageName, options, ctx) {
1978
+ const incl = new AdkInclude(ctx ?? getGlobalContext(), name.toUpperCase());
1979
+ const data = {
1980
+ name: name.toUpperCase(),
1981
+ type: "PROG/I",
1982
+ description,
1983
+ language: "EN",
1984
+ masterLanguage: "EN",
1985
+ packageRef: {
1986
+ name: packageName.toUpperCase(),
1987
+ uri: `/sap/bc/adt/packages/${encodeURIComponent(packageName.toUpperCase())}`,
1988
+ type: "DEVC/K"
1989
+ }
1990
+ };
1991
+ if (options?.master) {
1992
+ const master = options.master.toUpperCase();
1993
+ data.contextRef = {
1994
+ name: master,
1995
+ uri: `/sap/bc/adt/programs/programs/${encodeURIComponent(master.toLowerCase())}`,
1996
+ type: "PROG/P"
1997
+ };
1998
+ }
1999
+ incl.setData(data);
2000
+ await incl.save({
2001
+ transport: options?.transport,
2002
+ mode: "create"
2003
+ });
2004
+ return incl;
2005
+ }
2006
+ /**
2007
+ * Delete an ABAP include from SAP
2008
+ *
2009
+ * @param name - Include name
2010
+ * @param options - Delete options (transport, lockHandle)
2011
+ * @param ctx - Optional ADK context
2012
+ */
2013
+ static async delete(name, options, ctx) {
2014
+ await new AdkInclude(ctx ?? getGlobalContext(), name.toUpperCase()).crudContract.delete(name.toUpperCase(), {
2015
+ corrNr: options?.transport,
2016
+ lockHandle: options?.lockHandle
2017
+ });
2018
+ }
2019
+ };
2020
+ registerObjectType("INCL", Include, AdkInclude, { endpoint: "programs/includes" });
2021
+
2022
+ //#endregion
2023
+ //#region src/objects/repository/fugr/fugr.model.ts
2024
+ /**
2025
+ * FUGR - ABAP Function Group
2026
+ *
2027
+ * ADK object for ABAP function groups (FUGR).
2028
+ */
2029
+ /**
2030
+ * ADK Function Group object
2031
+ *
2032
+ * Inherits from AdkMainObject which provides:
2033
+ * - AdkObject: name, type, description, version, language, changedBy/At, createdBy/At, links
2034
+ * - AdkMainObject: package, packageRef, responsible, masterLanguage, masterSystem, abapLanguageVersion
2035
+ *
2036
+ * Access function group-specific properties via `data`:
2037
+ * - data.sourceUri, data.fixPointArithmetic, data.activeUnicodeCheck
2038
+ */
2039
+ var AdkFunctionGroup = class AdkFunctionGroup extends AdkMainObject {
2040
+ static kind = FunctionGroup;
2041
+ kind = AdkFunctionGroup.kind;
2042
+ get objectUri() {
2043
+ return `/sap/bc/adt/functions/groups/${encodeURIComponent(this.name.toLowerCase())}`;
2044
+ }
2045
+ async getSource() {
2046
+ return this.lazy("source", async () => {
2047
+ return this.ctx.client.adt.functions.groups.source.main.get(this.name);
2048
+ });
2049
+ }
2050
+ get wrapperKey() {
2051
+ return "abapFunctionGroup";
2052
+ }
2053
+ get crudContract() {
2054
+ return this.ctx.client.adt.functions.groups;
2055
+ }
2056
+ static async get(name, ctx) {
2057
+ return new AdkFunctionGroup(ctx ?? getGlobalContext(), name).load();
2058
+ }
2059
+ /**
2060
+ * Check if a function group exists on SAP
2061
+ */
2062
+ static async exists(name, ctx) {
2063
+ try {
2064
+ await AdkFunctionGroup.get(name, ctx);
2065
+ return true;
2066
+ } catch {
2067
+ return false;
2068
+ }
2069
+ }
2070
+ /**
2071
+ * Create a new ABAP function group on SAP
2072
+ */
2073
+ static async create(name, description, packageName, options, ctx) {
2074
+ const fugr = new AdkFunctionGroup(ctx ?? getGlobalContext(), name.toUpperCase());
2075
+ fugr.setData({
2076
+ name: name.toUpperCase(),
2077
+ type: "FUGR/F",
2078
+ description,
2079
+ language: "EN",
2080
+ masterLanguage: "EN",
2081
+ packageRef: {
2082
+ name: packageName.toUpperCase(),
2083
+ uri: `/sap/bc/adt/packages/${encodeURIComponent(packageName.toUpperCase())}`,
2084
+ type: "DEVC/K"
2085
+ }
2086
+ });
2087
+ await fugr.save({
2088
+ transport: options?.transport,
2089
+ mode: "create"
2090
+ });
2091
+ return fugr;
2092
+ }
2093
+ /**
2094
+ * Delete an ABAP function group from SAP
2095
+ */
2096
+ static async delete(name, options, ctx) {
2097
+ await new AdkFunctionGroup(ctx ?? getGlobalContext(), name.toUpperCase()).crudContract.delete(name.toUpperCase(), {
2098
+ corrNr: options?.transport,
2099
+ lockHandle: options?.lockHandle
2100
+ });
2101
+ }
2102
+ };
2103
+ registerObjectType("FUGR", FunctionGroup, AdkFunctionGroup, {
2104
+ endpoint: "functions/groups",
2105
+ normalizeName: (name) => name.toUpperCase().startsWith("SAPL") ? name.slice(4) : name
2106
+ });
2107
+
2108
+ //#endregion
2109
+ //#region src/objects/repository/fugr/func/func.model.ts
2110
+ /**
2111
+ * FUGR/FF - ABAP Function Module
2112
+ *
2113
+ * ADK object for ABAP function modules (FUGR/FF).
2114
+ * Function modules are child objects of function groups - they are accessed
2115
+ * via the parent group's URL path and require the group name for all operations.
2116
+ */
2117
+ /**
2118
+ * ADK Function Module object
2119
+ *
2120
+ * Function modules are child objects of function groups. Unlike main objects
2121
+ * (classes, interfaces, etc.), they don't have their own package reference.
2122
+ * All API operations require the parent group name in the URL path.
2123
+ *
2124
+ * Key differences from AdkMainObject:
2125
+ * - Requires `groupName` for URI construction and all CRUD operations
2126
+ * - Overrides lock/unlock/load/save to pass groupName to contract calls
2127
+ * - No packageRef (lives within parent function group's package)
2128
+ */
2129
+ var AdkFunctionModule = class AdkFunctionModule extends AdkObject {
2130
+ static kind = FunctionModule;
2131
+ kind = AdkFunctionModule.kind;
2132
+ /** Parent function group name */
2133
+ groupName;
2134
+ /**
2135
+ * Constructor supports two calling patterns:
2136
+ *
2137
+ * 1. Direct (3-arg): `new AdkFunctionModule(ctx, groupName, nameOrData)`
2138
+ * Used by static factory method and when group name is known upfront.
2139
+ *
2140
+ * 2. Factory (2-arg): `new AdkFunctionModule(ctx, data)`
2141
+ * Used by ADK factory's `getWithData()`. The groupName is extracted from
2142
+ * `data._groupName` or `data.containerRef.name`.
2143
+ */
2144
+ constructor(ctx, groupNameOrData, dataOrName) {
2145
+ if (dataOrName !== void 0) {
2146
+ super(ctx, dataOrName);
2147
+ this.groupName = groupNameOrData;
2148
+ } else if (typeof groupNameOrData === "string") {
2149
+ super(ctx, groupNameOrData);
2150
+ this.groupName = "";
2151
+ } else {
2152
+ const data = groupNameOrData;
2153
+ super(ctx, groupNameOrData);
2154
+ this.groupName = data._groupName ?? data.containerRef?.name ?? "";
2155
+ }
2156
+ }
2157
+ get objectUri() {
2158
+ return `/sap/bc/adt/functions/groups/${encodeURIComponent(this.groupName.toLowerCase())}/fmodules/${encodeURIComponent(this.name.toLowerCase())}`;
2159
+ }
2160
+ get collectionUri() {
2161
+ return `/sap/bc/adt/functions/groups/${encodeURIComponent(this.groupName.toLowerCase())}/fmodules`;
2162
+ }
2163
+ get wrapperKey() {
2164
+ return "abapFunctionModule";
2165
+ }
2166
+ get crudContract() {
2167
+ return this.ctx.client.adt.functions.groups.fmodules;
2168
+ }
2169
+ /**
2170
+ * Load function module data from SAP
2171
+ *
2172
+ * Overrides base to pass groupName as first arg to contract.get()
2173
+ */
2174
+ async load() {
2175
+ const contract = this.crudContract;
2176
+ const wrapperKey = this.wrapperKey;
2177
+ if (!contract || !wrapperKey) throw new Error(`Load not implemented for ${this.kind}. Override load() or provide crudContract/wrapperKey.`);
2178
+ const response = await contract.get(this.groupName, this.name);
2179
+ if (!response || !(wrapperKey in response)) throw new Error(`${this.kind} '${this.name}' in group '${this.groupName}' not found or returned empty response`);
2180
+ this.setData(response[wrapperKey]);
2181
+ return this;
2182
+ }
2183
+ /**
2184
+ * Get skeleton data for FM creation (POST).
2185
+ *
2186
+ * FMs only need name, type, description, and processing attributes.
2187
+ * No packageRef — FMs inherit the package from their parent FUGR.
2188
+ */
2189
+ async getSkeletonData() {
2190
+ const d = await this.data();
2191
+ return {
2192
+ name: d.name,
2193
+ type: d.type,
2194
+ description: d.description ?? "",
2195
+ processingType: d.processingType,
2196
+ basXMLEnabled: d.basXMLEnabled
2197
+ };
2198
+ }
2199
+ /**
2200
+ * Execute the typed contract call for save
2201
+ *
2202
+ * Overrides base to pass groupName to contract.put()/post()
2203
+ */
2204
+ async saveViaContract(mode, options) {
2205
+ const wrapperKey = this.wrapperKey;
2206
+ const contract = this.crudContract;
2207
+ if (!wrapperKey || !contract) throw new Error(`Save not supported for ${this.kind}.`);
2208
+ if (mode === "create") {
2209
+ const skeleton = await this.getSkeletonData();
2210
+ const data = { [wrapperKey]: skeleton };
2211
+ await contract.post(this.groupName, { corrNr: options.transport }, data);
2212
+ } else {
2213
+ const { abapLanguageVersion: _, ...rest } = await this.data();
2214
+ const saveData = rest;
2215
+ const data = { [wrapperKey]: saveData };
2216
+ await contract.put(this.groupName, this.name, {
2217
+ corrNr: options.transport,
2218
+ lockHandle: options.lockHandle
2219
+ }, data);
2220
+ }
2221
+ }
2222
+ /**
2223
+ * Check if the function module exists on the SAP system.
2224
+ *
2225
+ * Overrides base to pass groupName to contract.get()
2226
+ */
2227
+ async checkObjectExists() {
2228
+ const contract = this.crudContract;
2229
+ if (!contract?.get) return true;
2230
+ try {
2231
+ await contract.get(this.groupName, this.name);
2232
+ return true;
2233
+ } catch (e) {
2234
+ if (this.shouldFallbackToCreate(e)) return false;
2235
+ throw e;
2236
+ }
2237
+ }
2238
+ /**
2239
+ * Refresh cached ETags after acquiring a lock.
2240
+ *
2241
+ * FM's savePendingSources() does a metadata PUT first (to apply processingType),
2242
+ * then a source PUT. Both need fresh ETags after locking.
2243
+ * The contract uses groupName + name (potentially UPPERCASE), so we must
2244
+ * refresh via the contract to match the same cache key.
2245
+ */
2246
+ async refreshETagsAfterLock() {
2247
+ try {
2248
+ await this.crudContract.get(this.groupName, this.name);
2249
+ } catch {
2250
+ this.ctx.client.clearETag();
2251
+ }
2252
+ try {
2253
+ await this.crudContract.source.main.get(this.groupName, this.name);
2254
+ } catch {
2255
+ this.ctx.client.clearETag(`${this.objectUri}/source/main`);
2256
+ }
2257
+ }
2258
+ /**
2259
+ * Strip the parameter comment block from FM source code.
2260
+ *
2261
+ * abapGit serializes FM source with a "Local Interface" comment block
2262
+ * that describes IMPORTING/EXPORTING/CHANGING/TABLES/EXCEPTIONS.
2263
+ * SAP ADT rejects this block when saving source — it manages the
2264
+ * interface metadata separately. Strip it before sending.
2265
+ *
2266
+ * Pattern:
2267
+ * ```
2268
+ * *"----------------------------------------------------------------------
2269
+ * *"*"Local Interface:
2270
+ * *" IMPORTING ...
2271
+ * *"----------------------------------------------------------------------
2272
+ * ```
2273
+ */
2274
+ stripParameterCommentBlock(source) {
2275
+ const lines = source.split("\n");
2276
+ const result = [];
2277
+ let inBlock = false;
2278
+ for (let i = 0; i < lines.length; i++) {
2279
+ const trimmed = lines[i].trimEnd();
2280
+ if (!inBlock && trimmed.startsWith("*\"") && trimmed.includes("---")) {
2281
+ if (i + 1 < lines.length && lines[i + 1].trimEnd().startsWith("*\"")) {
2282
+ inBlock = true;
2283
+ continue;
2284
+ }
2285
+ }
2286
+ if (inBlock) {
2287
+ if (trimmed.startsWith("*\"") && trimmed.includes("---")) {
2288
+ inBlock = false;
2289
+ continue;
2290
+ }
2291
+ if (trimmed.startsWith("*\"")) continue;
2292
+ inBlock = false;
2293
+ }
2294
+ result.push(lines[i]);
2295
+ }
2296
+ return result.join("\n");
2297
+ }
2298
+ /**
2299
+ * Save pending source for function module.
2300
+ *
2301
+ * Overrides base to:
2302
+ * 1. PUT metadata first (SAP ignores processingType and other attributes during POST)
2303
+ * 2. Refresh source ETag (metadata PUT changes the object version)
2304
+ * 3. Strip the parameter comment block that abapGit includes
2305
+ * 4. Use the FM-specific source endpoint via groupName
2306
+ */
2307
+ async savePendingSources(options) {
2308
+ const self = this;
2309
+ if (!self._pendingSource) return;
2310
+ await this.saveViaContract("update", {
2311
+ lockHandle: options?.lockHandle,
2312
+ transport: options?.transport
2313
+ });
2314
+ await this.crudContract.source.main.get(this.groupName, this.name);
2315
+ const cleanSource = this.stripParameterCommentBlock(self._pendingSource);
2316
+ await this.crudContract.source.main.put(this.groupName, this.name, {
2317
+ ...options?.lockHandle ? { lockHandle: options.lockHandle } : {},
2318
+ ...options?.transport ? { corrNr: options.transport } : {}
2319
+ }, cleanSource);
2320
+ delete self._pendingSource;
2321
+ }
2322
+ /**
2323
+ * Extract the body of a FUNCTION...ENDFUNCTION block.
2324
+ *
2325
+ * SAP reconstructs the FUNCTION header when returning source code:
2326
+ * Local: `FUNCTION zage_fm.` (lowercase, period inline)
2327
+ * SAP: `FUNCTION ZAGE_FM\n " template comment"\n.` (uppercase, period on own line)
2328
+ *
2329
+ * The body between the header and ENDFUNCTION is identical, so we compare
2330
+ * only that part. The header ends at the first period that terminates the
2331
+ * FUNCTION statement (either inline `FUNCTION name.` or on a separate line `.`).
2332
+ */
2333
+ extractFunctionBody(source) {
2334
+ const lines = source.split("\n");
2335
+ let bodyStart = 0;
2336
+ let bodyEnd = lines.length;
2337
+ for (let i = 0; i < lines.length; i++) {
2338
+ const trimmed = lines[i].trimEnd();
2339
+ if (i === 0 && /^FUNCTION\s+\S+\.\s*$/i.test(trimmed)) {
2340
+ bodyStart = i + 1;
2341
+ break;
2342
+ }
2343
+ if (i > 0 && trimmed === ".") {
2344
+ bodyStart = i + 1;
2345
+ break;
2346
+ }
2347
+ }
2348
+ for (let i = lines.length - 1; i >= bodyStart; i--) if (/^\s*ENDFUNCTION\.\s*$/i.test(lines[i].trimEnd())) {
2349
+ bodyEnd = i;
2350
+ break;
2351
+ }
2352
+ return lines.slice(bodyStart, bodyEnd).join("\n");
2353
+ }
2354
+ /**
2355
+ * Pre-lock comparison for FM source.
2356
+ *
2357
+ * Overrides base to:
2358
+ * 1. Strip parameter comment block from local source
2359
+ * 2. Extract only the function body (between FUNCTION header and ENDFUNCTION)
2360
+ * from both local and SAP source, because SAP reconstructs the FUNCTION
2361
+ * header with uppercase name and template comments.
2362
+ */
2363
+ async checkPendingSourcesUnchanged() {
2364
+ const self = this;
2365
+ if (!self._pendingSource) return;
2366
+ try {
2367
+ const currentSource = await this.crudContract.source.main.get(this.groupName, this.name);
2368
+ const cleanPending = this.stripParameterCommentBlock(self._pendingSource);
2369
+ const localBody = this.extractFunctionBody(cleanPending);
2370
+ const sapBody = this.extractFunctionBody(currentSource);
2371
+ if (this.normalizeSource(localBody) === this.normalizeSource(sapBody)) {
2372
+ this._unchanged = true;
2373
+ delete self._pendingSource;
2374
+ }
2375
+ } catch {}
2376
+ }
2377
+ async getSource() {
2378
+ return this.lazy("source", async () => {
2379
+ return this.ctx.client.adt.functions.groups.fmodules.source.main.get(this.groupName, this.name);
2380
+ });
2381
+ }
2382
+ /**
2383
+ * Get a function module by name
2384
+ *
2385
+ * @param groupName - Parent function group name
2386
+ * @param name - Function module name
2387
+ * @param ctx - Optional ADK context (uses global if not provided)
2388
+ */
2389
+ static async get(groupName, name, ctx) {
2390
+ return new AdkFunctionModule(ctx ?? getGlobalContext(), groupName, name).load();
2391
+ }
2392
+ /**
2393
+ * Check if a function module exists on SAP
2394
+ */
2395
+ static async exists(groupName, name, ctx) {
2396
+ try {
2397
+ await AdkFunctionModule.get(groupName, name, ctx);
2398
+ return true;
2399
+ } catch {
2400
+ return false;
2401
+ }
2402
+ }
2403
+ /**
2404
+ * Create a new ABAP function module on SAP
2405
+ */
2406
+ static async create(groupName, name, description, options, ctx) {
2407
+ const fm = new AdkFunctionModule(ctx ?? getGlobalContext(), groupName.toUpperCase(), name.toUpperCase());
2408
+ fm.setData({
2409
+ name: name.toUpperCase(),
2410
+ type: "FUGR/FF",
2411
+ description,
2412
+ processingType: options?.processingType ?? "normal"
2413
+ });
2414
+ await fm.save({
2415
+ transport: options?.transport,
2416
+ mode: "create"
2417
+ });
2418
+ return fm;
2419
+ }
2420
+ /**
2421
+ * Delete a function module from SAP
2422
+ */
2423
+ static async delete(groupName, name, options, ctx) {
2424
+ await new AdkFunctionModule(ctx ?? getGlobalContext(), groupName.toUpperCase(), name.toUpperCase()).crudContract.delete(groupName.toUpperCase(), name.toUpperCase(), {
2425
+ corrNr: options?.transport,
2426
+ lockHandle: options?.lockHandle
2427
+ });
2428
+ }
2429
+ };
2430
+ registerObjectType("FUGR/FF", FunctionModule, AdkFunctionModule, { endpoint: "functions/groups" });
2431
+
2432
+ //#endregion
2433
+ //#region src/objects/ddic/doma/doma.model.ts
2434
+ /**
2435
+ * DOMA - Domain
2436
+ *
2437
+ * ADK object for ABAP Domains (DOMA).
2438
+ * DDIC objects are metadata-only (no source code).
2439
+ */
2440
+ /**
2441
+ * ADK Domain object
2442
+ *
2443
+ * Inherits from AdkMainObject which provides:
2444
+ * - name, type, description, version, language, changedBy/At, createdBy/At, links
2445
+ * - package, packageRef, responsible, masterLanguage, masterSystem, abapLanguageVersion
2446
+ *
2447
+ * Domain-specific properties via `data`:
2448
+ * - data.typeInformation (dataType, length, decimals, outputLength)
2449
+ * - data.outputInformation (conversionExit, signPresentation, lowerCase)
2450
+ * - data.fixedValues
2451
+ */
2452
+ var AdkDomain = class AdkDomain extends AdkMainObject {
2453
+ static kind = Domain;
2454
+ kind = AdkDomain.kind;
2455
+ get objectUri() {
2456
+ return `/sap/bc/adt/ddic/domains/${encodeURIComponent(this.name.toLowerCase())}`;
2457
+ }
2458
+ get wrapperKey() {
2459
+ return "domain";
2460
+ }
2461
+ get crudContract() {
2462
+ return this.ctx.client.adt.ddic.domains;
2463
+ }
2464
+ static async get(name, ctx) {
2465
+ return new AdkDomain(ctx ?? getGlobalContext(), name).load();
2466
+ }
2467
+ static async exists(name, ctx) {
2468
+ try {
2469
+ await AdkDomain.get(name, ctx);
2470
+ return true;
2471
+ } catch {
2472
+ return false;
2473
+ }
2474
+ }
2475
+ /**
2476
+ * Create a new ABAP domain on SAP.
2477
+ *
2478
+ * Note: Domains are metadata-only objects (no source code). After creation,
2479
+ * use the `adt get domain <name>` command or abapGit-based deploy to fill in
2480
+ * the domain properties (data type, field length, etc.).
2481
+ */
2482
+ static async create(name, description, packageName, options, ctx) {
2483
+ const domain = new AdkDomain(ctx ?? getGlobalContext(), name.toUpperCase());
2484
+ domain.setData({
2485
+ name: name.toUpperCase(),
2486
+ type: "DOMA",
2487
+ description,
2488
+ language: "EN",
2489
+ masterLanguage: "EN",
2490
+ packageRef: {
2491
+ name: packageName.toUpperCase(),
2492
+ uri: `/sap/bc/adt/packages/${encodeURIComponent(packageName.toUpperCase())}`,
2493
+ type: "DEVC/K"
2494
+ }
2495
+ });
2496
+ await domain.save({
2497
+ transport: options?.transport,
2498
+ mode: "create"
2499
+ });
2500
+ return domain;
2501
+ }
2502
+ static async delete(name, options, ctx) {
2503
+ await new AdkDomain(ctx ?? getGlobalContext(), name.toUpperCase()).crudContract.delete(name.toUpperCase(), {
2504
+ ...options?.transport && { corrNr: options.transport },
2505
+ ...options?.lockHandle && { lockHandle: options.lockHandle }
2506
+ });
2507
+ }
2508
+ };
2509
+ registerObjectType("DOMA", Domain, AdkDomain, { endpoint: "ddic/domains" });
2510
+
2511
+ //#endregion
2512
+ //#region src/objects/ddic/dtel/dtel.model.ts
2513
+ /**
2514
+ * DTEL - Data Element
2515
+ *
2516
+ * ADK object for ABAP Data Elements (DTEL).
2517
+ * DDIC objects are metadata-only (no source code).
2518
+ */
2519
+ /**
2520
+ * ADK Data Element object
2521
+ *
2522
+ * Inherits from AdkMainObject which provides:
2523
+ * - name, type, description, version, language, changedBy/At, createdBy/At, links
2524
+ * - package, packageRef, responsible, masterLanguage, masterSystem, abapLanguageVersion
2525
+ *
2526
+ * Data element-specific properties via `data`:
2527
+ * - data.typeKind, data.typeName, data.dataType
2528
+ * - data.shortDescription, data.mediumDescription, data.longDescription, data.headingDescription
2529
+ * - data.searchHelp
2530
+ */
2531
+ var AdkDataElement = class AdkDataElement extends AdkMainObject {
2532
+ static kind = DataElement;
2533
+ kind = AdkDataElement.kind;
2534
+ get objectUri() {
2535
+ return `/sap/bc/adt/ddic/dataelements/${encodeURIComponent(this.name.toLowerCase())}`;
2536
+ }
2537
+ get wrapperKey() {
2538
+ return "wbobj";
2539
+ }
2540
+ get crudContract() {
2541
+ return this.ctx.client.adt.ddic.dataelements;
2542
+ }
2543
+ static async get(name, ctx) {
2544
+ return new AdkDataElement(ctx ?? getGlobalContext(), name).load();
2545
+ }
2546
+ static async exists(name, ctx) {
2547
+ try {
2548
+ await AdkDataElement.get(name, ctx);
2549
+ return true;
2550
+ } catch {
2551
+ return false;
2552
+ }
2553
+ }
2554
+ /**
2555
+ * Create a new ABAP data element on SAP.
2556
+ */
2557
+ static async create(name, description, packageName, options, ctx) {
2558
+ const dtel = new AdkDataElement(ctx ?? getGlobalContext(), name.toUpperCase());
2559
+ dtel.setData({
2560
+ name: name.toUpperCase(),
2561
+ type: "DTEL",
2562
+ description,
2563
+ language: "EN",
2564
+ masterLanguage: "EN",
2565
+ packageRef: {
2566
+ name: packageName.toUpperCase(),
2567
+ uri: `/sap/bc/adt/packages/${encodeURIComponent(packageName.toUpperCase())}`,
2568
+ type: "DEVC/K"
2569
+ }
2570
+ });
2571
+ await dtel.save({
2572
+ transport: options?.transport,
2573
+ mode: "create"
2574
+ });
2575
+ return dtel;
2576
+ }
2577
+ static async delete(name, options, ctx) {
2578
+ await new AdkDataElement(ctx ?? getGlobalContext(), name.toUpperCase()).crudContract.delete(name.toUpperCase(), {
2579
+ ...options?.transport && { corrNr: options.transport },
2580
+ ...options?.lockHandle && { lockHandle: options.lockHandle }
2581
+ });
2582
+ }
2583
+ };
2584
+ registerObjectType("DTEL", DataElement, AdkDataElement, { endpoint: "ddic/dataelements" });
2585
+
2586
+ //#endregion
2587
+ //#region src/objects/ddic/tabl/tabl.model.ts
2588
+ /**
2589
+ * TABL - Database Table / Structure
2590
+ *
2591
+ * ADK object for ABAP Database Tables (TABL/DT) and Structures (TABL/DS).
2592
+ * Tables and structures are source-based DDIC objects whose definition
2593
+ * lives in ABAP source code (retrieved via sourceUri).
2594
+ *
2595
+ * Note: Tables and structures share the same ADT main type (TABL)
2596
+ * but use different endpoints and subtypes.
2597
+ * - Tables: /sap/bc/adt/ddic/tables (TABL/DT)
2598
+ * - Structures: /sap/bc/adt/ddic/structures (TABL/DS)
2599
+ *
2600
+ * SAP wraps both in a blue:blueSource root element
2601
+ * (namespace http://www.sap.com/wbobj/blue) extending AbapSourceMainObject.
2602
+ */
2603
+ /**
2604
+ * ADK Table object (database table - TABL/DT)
2605
+ */
2606
+ var AdkTable = class AdkTable extends AdkMainObject {
2607
+ static kind = Table;
2608
+ kind = AdkTable.kind;
2609
+ get objectUri() {
2610
+ return `/sap/bc/adt/ddic/tables/${encodeURIComponent(this.name.toLowerCase())}`;
2611
+ }
2612
+ /**
2613
+ * Get CDS-style table source code from SAP
2614
+ * Returns the ABAP source definition (annotations + field definitions)
2615
+ */
2616
+ async getSource() {
2617
+ return this.lazy("source", async () => {
2618
+ return this.ctx.client.adt.ddic.tables.source.main.get(this.name);
2619
+ });
2620
+ }
2621
+ /**
2622
+ * Get table technical settings (DD09L data)
2623
+ * Returns XML from /sap/bc/adt/ddic/db/settings/{name}
2624
+ */
2625
+ async getSettings() {
2626
+ return this.lazy("settings", async () => {
2627
+ return this.ctx.client.adt.ddic.tablesettings.get(this.name);
2628
+ });
2629
+ }
2630
+ get wrapperKey() {
2631
+ return "blueSource";
2632
+ }
2633
+ get crudContract() {
2634
+ return this.ctx.client.adt.ddic.tables;
2635
+ }
2636
+ static async get(name, ctx) {
2637
+ return new AdkTable(ctx ?? getGlobalContext(), name).load();
2638
+ }
2639
+ static async exists(name, ctx) {
2640
+ try {
2641
+ await AdkTable.get(name, ctx);
2642
+ return true;
2643
+ } catch {
2644
+ return false;
2645
+ }
2646
+ }
2647
+ /**
2648
+ * Create a new ABAP database table on SAP.
2649
+ */
2650
+ static async create(name, description, packageName, options, ctx) {
2651
+ const table = new AdkTable(ctx ?? getGlobalContext(), name.toUpperCase());
2652
+ table.setData({
2653
+ name: name.toUpperCase(),
2654
+ type: "TABL/DT",
2655
+ description,
2656
+ language: "EN",
2657
+ masterLanguage: "EN",
2658
+ packageRef: {
2659
+ name: packageName.toUpperCase(),
2660
+ uri: `/sap/bc/adt/packages/${encodeURIComponent(packageName.toUpperCase())}`,
2661
+ type: "DEVC/K"
2662
+ }
2663
+ });
2664
+ await table.save({
2665
+ transport: options?.transport,
2666
+ mode: "create"
2667
+ });
2668
+ return table;
2669
+ }
2670
+ static async delete(name, options, ctx) {
2671
+ await new AdkTable(ctx ?? getGlobalContext(), name.toUpperCase()).crudContract.delete(name.toUpperCase(), {
2672
+ ...options?.transport && { corrNr: options.transport },
2673
+ ...options?.lockHandle && { lockHandle: options.lockHandle }
2674
+ });
2675
+ }
2676
+ };
2677
+ /**
2678
+ * ADK Structure object (TABL/DS)
2679
+ */
2680
+ var AdkStructure = class AdkStructure extends AdkMainObject {
2681
+ static kind = Structure;
2682
+ kind = AdkStructure.kind;
2683
+ get objectUri() {
2684
+ return `/sap/bc/adt/ddic/structures/${encodeURIComponent(this.name.toLowerCase())}`;
2685
+ }
2686
+ /**
2687
+ * Get CDS-style structure source code from SAP
2688
+ * Returns the ABAP source definition (annotations + field definitions)
2689
+ */
2690
+ async getSource() {
2691
+ return this.lazy("source", async () => {
2692
+ return this.ctx.client.adt.ddic.structures.source.main.get(this.name);
2693
+ });
2694
+ }
2695
+ get wrapperKey() {
2696
+ return "blueSource";
2697
+ }
2698
+ get crudContract() {
2699
+ return this.ctx.client.adt.ddic.structures;
2700
+ }
2701
+ static async get(name, ctx) {
2702
+ return new AdkStructure(ctx ?? getGlobalContext(), name).load();
2703
+ }
2704
+ static async exists(name, ctx) {
2705
+ try {
2706
+ await AdkStructure.get(name, ctx);
2707
+ return true;
2708
+ } catch {
2709
+ return false;
2710
+ }
2711
+ }
2712
+ /**
2713
+ * Create a new ABAP structure on SAP.
2714
+ */
2715
+ static async create(name, description, packageName, options, ctx) {
2716
+ const struct = new AdkStructure(ctx ?? getGlobalContext(), name.toUpperCase());
2717
+ struct.setData({
2718
+ name: name.toUpperCase(),
2719
+ type: "TABL/DS",
2720
+ description,
2721
+ language: "EN",
2722
+ masterLanguage: "EN",
2723
+ packageRef: {
2724
+ name: packageName.toUpperCase(),
2725
+ uri: `/sap/bc/adt/packages/${encodeURIComponent(packageName.toUpperCase())}`,
2726
+ type: "DEVC/K"
2727
+ }
2728
+ });
2729
+ await struct.save({
2730
+ transport: options?.transport,
2731
+ mode: "create"
2732
+ });
2733
+ return struct;
2734
+ }
2735
+ static async delete(name, options, ctx) {
2736
+ await new AdkStructure(ctx ?? getGlobalContext(), name.toUpperCase()).crudContract.delete(name.toUpperCase(), {
2737
+ ...options?.transport && { corrNr: options.transport },
2738
+ ...options?.lockHandle && { lockHandle: options.lockHandle }
2739
+ });
2740
+ }
2741
+ };
2742
+ registerObjectType("TABL", Table, AdkTable, { endpoint: "ddic/tables" });
2743
+ registerObjectType("TABL/DS", Structure, AdkStructure, { endpoint: "ddic/structures" });
2744
+
2745
+ //#endregion
2746
+ //#region src/objects/ddic/ttyp/ttyp.model.ts
2747
+ /**
2748
+ * TTYP - Table Type
2749
+ *
2750
+ * ADK object for ABAP Table Types (TTYP).
2751
+ * DDIC objects are metadata-only (no source code).
2752
+ */
2753
+ /**
2754
+ * ADK Table Type object
2755
+ *
2756
+ * Inherits from AdkMainObject which provides:
2757
+ * - name, type, description, version, language, changedBy/At, createdBy/At, links
2758
+ * - package, packageRef, responsible, masterLanguage, masterSystem, abapLanguageVersion
2759
+ *
2760
+ * Table type-specific properties via `data`:
2761
+ * - data.rowType (typeName, typeCategory, tableTypeSchemaReference)
2762
+ * - data.primaryKey
2763
+ * - data.secondaryKeys
2764
+ */
2765
+ var AdkTableType = class AdkTableType extends AdkMainObject {
2766
+ static kind = TableType;
2767
+ kind = AdkTableType.kind;
2768
+ get objectUri() {
2769
+ return `/sap/bc/adt/ddic/tabletypes/${encodeURIComponent(this.name.toLowerCase())}`;
2770
+ }
2771
+ get wrapperKey() {
2772
+ return "tableType";
2773
+ }
2774
+ get crudContract() {
2775
+ return this.ctx.client.adt.ddic.tabletypes;
2776
+ }
2777
+ static async get(name, ctx) {
2778
+ return new AdkTableType(ctx ?? getGlobalContext(), name).load();
2779
+ }
2780
+ };
2781
+ registerObjectType("TTYP", TableType, AdkTableType, { endpoint: "ddic/tabletypes" });
2782
+
2783
+ //#endregion
2784
+ //#region src/objects/cds/ddl.model.ts
2785
+ /**
2786
+ * DDL - CDS Data Definition Language Source (DDLS)
2787
+ *
2788
+ * ADK object for ABAP CDS Data Definition sources.
2789
+ * These are source-based objects stored at:
2790
+ * GET/PUT /sap/bc/adt/ddic/ddl/sources/<name>/source/main
2791
+ *
2792
+ * The metadata document is at:
2793
+ * GET /sap/bc/adt/ddic/ddl/sources/<name>
2794
+ *
2795
+ * Lock/activate/create follow the same patterns as other source objects.
2796
+ */
2797
+ var AdkDdlSource = class AdkDdlSource {
2798
+ name;
2799
+ ctx;
2800
+ constructor(ctx, name) {
2801
+ this.ctx = ctx;
2802
+ this.name = name.toUpperCase();
2803
+ }
2804
+ get objectUri() {
2805
+ return `/sap/bc/adt/ddic/ddl/sources/${encodeURIComponent(this.name.toLowerCase())}`;
2806
+ }
2807
+ /** Placeholder description — full metadata requires additional SAP fetch */
2808
+ get description() {
2809
+ return this.name;
2810
+ }
2811
+ get contract() {
2812
+ return this.ctx.client.adt.ddic.ddl.sources;
2813
+ }
2814
+ async getSource() {
2815
+ return toText(await this.contract.source.main.get(this.name));
2816
+ }
2817
+ async saveMainSource(source, options) {
2818
+ await this.contract.source.main.put(this.name, {
2819
+ ...options?.lockHandle ? { lockHandle: options.lockHandle } : {},
2820
+ ...options?.transport ? { corrNr: options.transport } : {}
2821
+ }, source);
2822
+ }
2823
+ async lock(transport) {
2824
+ const lockService = this.ctx.lockService;
2825
+ if (!lockService) throw new Error("Lock not available: no lockService in context. Did you call initializeAdk()?");
2826
+ return lockService.lock(this.objectUri, {
2827
+ transport,
2828
+ objectName: this.name,
2829
+ objectType: "DDLS"
2830
+ });
2831
+ }
2832
+ async unlock(lockHandle) {
2833
+ const lockService = this.ctx.lockService;
2834
+ if (!lockService) throw new Error("Unlock not available: no lockService in context. Did you call initializeAdk()?");
2835
+ await lockService.unlock(this.objectUri, { lockHandle });
2836
+ }
2837
+ async activate() {
2838
+ await this.ctx.client.adt.activation.activate.post({}, { objectReferences: { objectReference: [{
2839
+ uri: this.objectUri,
2840
+ name: this.name
2841
+ }] } });
2842
+ return this;
2843
+ }
2844
+ /**
2845
+ * Get a DDL source (does not fetch metadata, just returns handle)
2846
+ */
2847
+ static async get(name, ctx) {
2848
+ const obj = new AdkDdlSource(ctx ?? getGlobalContext(), name);
2849
+ await obj.getSource();
2850
+ return obj;
2851
+ }
2852
+ static async exists(name, ctx) {
2853
+ try {
2854
+ await AdkDdlSource.get(name, ctx);
2855
+ return true;
2856
+ } catch {
2857
+ return false;
2858
+ }
2859
+ }
2860
+ /**
2861
+ * Create a new CDS DDL source on SAP
2862
+ *
2863
+ * POST /sap/bc/adt/ddic/ddl/sources?corrNr=...
2864
+ * Body matches the `ddl:source` schema (extends abapsource:AbapSourceMainObject).
2865
+ */
2866
+ static async create(name, description, packageName, options, ctx) {
2867
+ const context = ctx ?? getGlobalContext();
2868
+ const nameU = name.toUpperCase();
2869
+ const pkgU = packageName.toUpperCase();
2870
+ await context.client.adt.ddic.ddl.sources.post(options?.transport ? { corrNr: options.transport } : {}, { source: {
2871
+ name: nameU,
2872
+ description,
2873
+ language: "EN",
2874
+ masterLanguage: "EN",
2875
+ responsible: "$TMP",
2876
+ packageRef: {
2877
+ name: pkgU,
2878
+ type: "DEVC/K",
2879
+ uri: `/sap/bc/adt/packages/${pkgU.toLowerCase()}`
2880
+ }
2881
+ } });
2882
+ return new AdkDdlSource(context, nameU);
2883
+ }
2884
+ static async delete(name, options, ctx) {
2885
+ await (ctx ?? getGlobalContext()).client.adt.ddic.ddl.sources.delete(name.toUpperCase(), {
2886
+ ...options?.transport ? { corrNr: options.transport } : {},
2887
+ ...options?.lockHandle ? { lockHandle: options.lockHandle } : {}
2888
+ });
2889
+ }
2890
+ };
2891
+
2892
+ //#endregion
2893
+ //#region src/objects/cds/dcl.model.ts
2894
+ /**
2895
+ * DCL - CDS Access Control Definition Language Source (DCLS)
2896
+ *
2897
+ * ADK object for ABAP CDS Access Control (DCL) sources.
2898
+ * These are source-based objects stored at:
2899
+ * GET/PUT /sap/bc/adt/acm/dcl/sources/<name>/source/main
2900
+ *
2901
+ * The metadata document is at:
2902
+ * GET /sap/bc/adt/acm/dcl/sources/<name>
2903
+ *
2904
+ * Lock/activate/create follow the same patterns as DDL sources.
2905
+ */
2906
+ var AdkDclSource = class AdkDclSource {
2907
+ name;
2908
+ ctx;
2909
+ constructor(ctx, name) {
2910
+ this.ctx = ctx;
2911
+ this.name = name.toUpperCase();
2912
+ }
2913
+ get objectUri() {
2914
+ return `/sap/bc/adt/acm/dcl/sources/${encodeURIComponent(this.name.toLowerCase())}`;
2915
+ }
2916
+ /** Placeholder description — full metadata requires additional SAP fetch */
2917
+ get description() {
2918
+ return this.name;
2919
+ }
2920
+ get contract() {
2921
+ return this.ctx.client.adt.ddic.dcl.sources;
2922
+ }
2923
+ async getSource() {
2924
+ return toText(await this.contract.source.main.get(this.name));
2925
+ }
2926
+ async saveMainSource(source, options) {
2927
+ await this.contract.source.main.put(this.name, {
2928
+ ...options?.lockHandle ? { lockHandle: options.lockHandle } : {},
2929
+ ...options?.transport ? { corrNr: options.transport } : {}
2930
+ }, source);
2931
+ }
2932
+ async lock(transport) {
2933
+ const lockService = this.ctx.lockService;
2934
+ if (!lockService) throw new Error("Lock not available: no lockService in context. Did you call initializeAdk()?");
2935
+ return lockService.lock(this.objectUri, {
2936
+ transport,
2937
+ objectName: this.name,
2938
+ objectType: "DCLS"
2939
+ });
2940
+ }
2941
+ async unlock(lockHandle) {
2942
+ const lockService = this.ctx.lockService;
2943
+ if (!lockService) throw new Error("Unlock not available: no lockService in context. Did you call initializeAdk()?");
2944
+ await lockService.unlock(this.objectUri, { lockHandle });
2945
+ }
2946
+ async activate() {
2947
+ await this.ctx.client.adt.activation.activate.post({}, { objectReferences: { objectReference: [{
2948
+ uri: this.objectUri,
2949
+ name: this.name
2950
+ }] } });
2951
+ return this;
2952
+ }
2953
+ static async get(name, ctx) {
2954
+ const obj = new AdkDclSource(ctx ?? getGlobalContext(), name);
2955
+ await obj.getSource();
2956
+ return obj;
2957
+ }
2958
+ static async exists(name, ctx) {
2959
+ try {
2960
+ await AdkDclSource.get(name, ctx);
2961
+ return true;
2962
+ } catch {
2963
+ return false;
2964
+ }
2965
+ }
2966
+ /**
2967
+ * Create a new CDS DCL source on SAP
2968
+ */
2969
+ static async create(name, description, packageName, options, ctx) {
2970
+ const context = ctx ?? getGlobalContext();
2971
+ const nameU = name.toUpperCase();
2972
+ const pkgU = packageName.toUpperCase();
2973
+ await context.client.adt.ddic.dcl.sources.post(options?.transport ? { corrNr: options.transport } : {}, { source: {
2974
+ name: nameU,
2975
+ description,
2976
+ language: "EN",
2977
+ masterLanguage: "EN",
2978
+ responsible: "$TMP",
2979
+ packageRef: {
2980
+ name: pkgU,
2981
+ type: "DEVC/K",
2982
+ uri: `/sap/bc/adt/packages/${pkgU.toLowerCase()}`
2983
+ }
2984
+ } });
2985
+ return new AdkDclSource(context, nameU);
2986
+ }
2987
+ static async delete(name, options, ctx) {
2988
+ await (ctx ?? getGlobalContext()).client.adt.ddic.dcl.sources.delete(name.toUpperCase(), {
2989
+ ...options?.transport ? { corrNr: options.transport } : {},
2990
+ ...options?.lockHandle ? { lockHandle: options.lockHandle } : {}
2991
+ });
2992
+ }
2993
+ };
2994
+
2995
+ //#endregion
2996
+ //#region src/objects/repository/bdef/bdef.model.ts
2997
+ /**
2998
+ * BDEF - Behavior Definition (RAP)
2999
+ *
3000
+ * ADK object for ABAP RAP Behavior Definitions (BDEF).
3001
+ * These are source-based objects (`.abdl`) stored at:
3002
+ * GET /sap/bc/adt/bo/behaviordefinitions/<name>
3003
+ * GET/PUT /sap/bc/adt/bo/behaviordefinitions/<name>/source/main
3004
+ *
3005
+ * Lock/activate/create follow the same patterns as other source objects
3006
+ * (DDL, DCL). The metadata document uses the shared `blue:blueSource`
3007
+ * wrapper — same envelope as TABL/STRUCT.
3008
+ *
3009
+ * This class intentionally mirrors `AdkDdlSource` (lightweight ADK object,
3010
+ * not a full AdkMainObject subclass) because BDEF metadata is source-driven
3011
+ * and the typical lifecycle is: create skeleton → PUT source → activate.
3012
+ */
3013
+ var AdkBehaviorDefinition = class AdkBehaviorDefinition {
3014
+ /** Static ADK kind marker — used by abapGit handler registry if needed. */
3015
+ static kind = "BehaviorDefinition";
3016
+ kind = AdkBehaviorDefinition.kind;
3017
+ name;
3018
+ ctx;
3019
+ constructor(ctx, name) {
3020
+ this.ctx = ctx;
3021
+ this.name = name.toUpperCase();
3022
+ }
3023
+ get objectUri() {
3024
+ return `/sap/bc/adt/bo/behaviordefinitions/${encodeURIComponent(this.name.toLowerCase())}`;
3025
+ }
3026
+ /** Placeholder description — full metadata requires additional SAP fetch */
3027
+ get description() {
3028
+ return this.name;
3029
+ }
3030
+ get contract() {
3031
+ return this.ctx.client.adt.bo.behaviordefinitions;
3032
+ }
3033
+ async getSource() {
3034
+ return toText(await this.contract.source.main.get(this.name));
3035
+ }
3036
+ async saveMainSource(source, options) {
3037
+ await this.contract.source.main.put(this.name, {
3038
+ ...options?.lockHandle ? { lockHandle: options.lockHandle } : {},
3039
+ ...options?.transport ? { corrNr: options.transport } : {}
3040
+ }, source);
3041
+ }
3042
+ async lock(transport) {
3043
+ const lockService = this.ctx.lockService;
3044
+ if (!lockService) throw new Error("Lock not available: no lockService in context. Did you call initializeAdk()?");
3045
+ return lockService.lock(this.objectUri, {
3046
+ transport,
3047
+ objectName: this.name,
3048
+ objectType: "BDEF"
3049
+ });
3050
+ }
3051
+ async unlock(lockHandle) {
3052
+ const lockService = this.ctx.lockService;
3053
+ if (!lockService) throw new Error("Unlock not available: no lockService in context. Did you call initializeAdk()?");
3054
+ await lockService.unlock(this.objectUri, { lockHandle });
3055
+ }
3056
+ async activate() {
3057
+ await this.ctx.client.adt.activation.activate.post({}, { objectReferences: { objectReference: [{
3058
+ uri: this.objectUri,
3059
+ name: this.name
3060
+ }] } });
3061
+ return this;
3062
+ }
3063
+ /**
3064
+ * Get a BDEF (validates it exists by fetching source).
3065
+ */
3066
+ static async get(name, ctx) {
3067
+ const obj = new AdkBehaviorDefinition(ctx ?? getGlobalContext(), name);
3068
+ await obj.getSource();
3069
+ return obj;
3070
+ }
3071
+ static async exists(name, ctx) {
3072
+ try {
3073
+ await AdkBehaviorDefinition.get(name, ctx);
3074
+ return true;
3075
+ } catch {
3076
+ return false;
3077
+ }
3078
+ }
3079
+ /**
3080
+ * Create a new BDEF on SAP.
3081
+ *
3082
+ * POST /sap/bc/adt/bo/behaviordefinitions?corrNr=...
3083
+ * Body matches the `blue:blueSource` envelope (extends
3084
+ * abapsource:AbapSourceMainObject).
3085
+ */
3086
+ static async create(name, description, packageName, options, ctx) {
3087
+ const context = ctx ?? getGlobalContext();
3088
+ const nameU = name.toUpperCase();
3089
+ const pkgU = packageName.toUpperCase();
3090
+ await context.client.adt.bo.behaviordefinitions.post(options?.transport ? { corrNr: options.transport } : {}, { blueSource: {
3091
+ name: nameU,
3092
+ type: "BDEF/BDO",
3093
+ description,
3094
+ language: "EN",
3095
+ masterLanguage: "EN",
3096
+ responsible: pkgU,
3097
+ packageRef: {
3098
+ name: pkgU,
3099
+ type: "DEVC/K",
3100
+ uri: `/sap/bc/adt/packages/${pkgU.toLowerCase()}`
3101
+ }
3102
+ } });
3103
+ return new AdkBehaviorDefinition(context, nameU);
3104
+ }
3105
+ static async delete(name, options, ctx) {
3106
+ await (ctx ?? getGlobalContext()).client.adt.bo.behaviordefinitions.delete(name.toUpperCase(), {
3107
+ ...options?.transport ? { corrNr: options.transport } : {},
3108
+ ...options?.lockHandle ? { lockHandle: options.lockHandle } : {}
3109
+ });
3110
+ }
3111
+ };
3112
+
3113
+ //#endregion
3114
+ //#region src/objects/repository/badi/badi.model.ts
3115
+ /**
3116
+ * BAdI — Enhancement Implementation (ENHO/XHH) — RAP-era BAdI container.
3117
+ *
3118
+ * ADK object for ABAP Enhancement Implementations that host BAdI
3119
+ * implementations. These live at:
3120
+ *
3121
+ * GET /sap/bc/adt/enhancements/enhoxhh/<name>
3122
+ * PUT /sap/bc/adt/enhancements/enhoxhh/<name>
3123
+ * DELETE /sap/bc/adt/enhancements/enhoxhh/<name>
3124
+ * GET/PUT /sap/bc/adt/enhancements/enhoxhh/<name>/source/main
3125
+ *
3126
+ * Mirrors the source-driven pattern used by `AdkBehaviorDefinition`
3127
+ * (BDEF): create skeleton → PUT source → activate.
3128
+ *
3129
+ * sapcli reference: `sap/cli/badi.py` (`_get_enhancement_implementation`).
3130
+ */
3131
+ var AdkBadi = class AdkBadi {
3132
+ /** Static ADK kind marker. */
3133
+ static kind = "Badi";
3134
+ kind = AdkBadi.kind;
3135
+ name;
3136
+ ctx;
3137
+ constructor(ctx, name) {
3138
+ this.ctx = ctx;
3139
+ this.name = name.toUpperCase();
3140
+ }
3141
+ /** ADT URI (lowercase path segment — SAP convention). */
3142
+ get objectUri() {
3143
+ return `/sap/bc/adt/enhancements/enhoxhh/${encodeURIComponent(this.name.toLowerCase())}`;
3144
+ }
3145
+ /** Placeholder description — real metadata arrives via GET/objectstructure. */
3146
+ get description() {
3147
+ return this.name;
3148
+ }
3149
+ get contract() {
3150
+ return this.ctx.client.adt.enhancements.enhoxhh;
3151
+ }
3152
+ async getMetadata() {
3153
+ return await this.contract.get(this.name);
3154
+ }
3155
+ async getSource() {
3156
+ return toText(await this.contract.source.main.get(this.name));
3157
+ }
3158
+ async saveMainSource(source, options) {
3159
+ await this.contract.source.main.put(this.name, {
3160
+ ...options?.lockHandle ? { lockHandle: options.lockHandle } : {},
3161
+ ...options?.transport ? { corrNr: options.transport } : {}
3162
+ }, source);
3163
+ }
3164
+ async lock(transport) {
3165
+ const lockService = this.ctx.lockService;
3166
+ if (!lockService) throw new Error("Lock not available: no lockService in context. Did you call initializeAdk()?");
3167
+ return lockService.lock(this.objectUri, {
3168
+ transport,
3169
+ objectName: this.name,
3170
+ objectType: "ENHO"
3171
+ });
3172
+ }
3173
+ async unlock(lockHandle) {
3174
+ const lockService = this.ctx.lockService;
3175
+ if (!lockService) throw new Error("Unlock not available: no lockService in context. Did you call initializeAdk()?");
3176
+ await lockService.unlock(this.objectUri, { lockHandle });
3177
+ }
3178
+ async activate() {
3179
+ await this.ctx.client.adt.activation.activate.post({}, { objectReferences: { objectReference: [{
3180
+ uri: this.objectUri,
3181
+ name: this.name
3182
+ }] } });
3183
+ return this;
3184
+ }
3185
+ /** Fetch a BAdI / ENHO, validating existence via a metadata GET. */
3186
+ static async get(name, ctx) {
3187
+ const obj = new AdkBadi(ctx ?? getGlobalContext(), name);
3188
+ await obj.getMetadata();
3189
+ return obj;
3190
+ }
3191
+ static async exists(name, ctx) {
3192
+ try {
3193
+ await AdkBadi.get(name, ctx);
3194
+ return true;
3195
+ } catch {
3196
+ return false;
3197
+ }
3198
+ }
3199
+ /**
3200
+ * Create a new Enhancement Implementation (BAdI container).
3201
+ *
3202
+ * Trial systems typically reject this with HTTP 403 — this is an
3203
+ * area that requires elevated authorisation on most SAP installs.
3204
+ */
3205
+ static async create(name, description, packageName, options, ctx) {
3206
+ const context = ctx ?? getGlobalContext();
3207
+ const nameU = name.toUpperCase();
3208
+ const pkgU = packageName.toUpperCase();
3209
+ await context.client.adt.enhancements.enhoxhh.post(options?.transport ? { corrNr: options.transport } : {}, { enhancementImplementation: {
3210
+ name: nameU,
3211
+ type: "ENHO/XHH",
3212
+ description,
3213
+ language: "EN",
3214
+ masterLanguage: "EN",
3215
+ responsible: pkgU,
3216
+ packageRef: {
3217
+ name: pkgU,
3218
+ type: "DEVC/K",
3219
+ uri: `/sap/bc/adt/packages/${pkgU.toLowerCase()}`
3220
+ }
3221
+ } });
3222
+ return new AdkBadi(context, nameU);
3223
+ }
3224
+ static async delete(name, options, ctx) {
3225
+ await (ctx ?? getGlobalContext()).client.adt.enhancements.enhoxhh.delete(name.toUpperCase(), {
3226
+ ...options?.transport ? { corrNr: options.transport } : {},
3227
+ ...options?.lockHandle ? { lockHandle: options.lockHandle } : {}
3228
+ });
3229
+ }
3230
+ };
3231
+
3232
+ //#endregion
3233
+ //#region src/objects/repository/srvd/srvd.model.ts
3234
+ /**
3235
+ * SRVD - Service Definition (RAP)
3236
+ *
3237
+ * ADK object for ABAP RAP Service Definitions (SRVD).
3238
+ * Source-based objects (`.asrvd`) stored at:
3239
+ * GET /sap/bc/adt/ddic/srvd/sources/<name>
3240
+ * GET/PUT /sap/bc/adt/ddic/srvd/sources/<name>/source/main
3241
+ *
3242
+ * Lock/activate/create follow the same patterns as other source objects
3243
+ * (DDL, DCL, BDEF). Metadata envelope is the dedicated `srvd:source`
3244
+ * wrapper extending abapsource:AbapSourceMainObject (mirrors DDL).
3245
+ */
3246
+ var AdkServiceDefinition = class AdkServiceDefinition {
3247
+ /** Static ADK kind marker — used by abapGit handler registry if needed. */
3248
+ static kind = "ServiceDefinition";
3249
+ kind = AdkServiceDefinition.kind;
3250
+ name;
3251
+ ctx;
3252
+ constructor(ctx, name) {
3253
+ this.ctx = ctx;
3254
+ this.name = name.toUpperCase();
3255
+ }
3256
+ get objectUri() {
3257
+ return `/sap/bc/adt/ddic/srvd/sources/${encodeURIComponent(this.name.toLowerCase())}`;
3258
+ }
3259
+ /** Placeholder description — full metadata requires additional SAP fetch */
3260
+ get description() {
3261
+ return this.name;
3262
+ }
3263
+ get contract() {
3264
+ return this.ctx.client.adt.ddic.srvd.sources;
3265
+ }
3266
+ async getSource() {
3267
+ return toText(await this.contract.source.main.get(this.name));
3268
+ }
3269
+ async saveMainSource(source, options) {
3270
+ await this.contract.source.main.put(this.name, {
3271
+ ...options?.lockHandle ? { lockHandle: options.lockHandle } : {},
3272
+ ...options?.transport ? { corrNr: options.transport } : {}
3273
+ }, source);
3274
+ }
3275
+ async lock(transport) {
3276
+ const lockService = this.ctx.lockService;
3277
+ if (!lockService) throw new Error("Lock not available: no lockService in context. Did you call initializeAdk()?");
3278
+ return lockService.lock(this.objectUri, {
3279
+ transport,
3280
+ objectName: this.name,
3281
+ objectType: "SRVD"
3282
+ });
3283
+ }
3284
+ async unlock(lockHandle) {
3285
+ const lockService = this.ctx.lockService;
3286
+ if (!lockService) throw new Error("Unlock not available: no lockService in context. Did you call initializeAdk()?");
3287
+ await lockService.unlock(this.objectUri, { lockHandle });
3288
+ }
3289
+ async activate() {
3290
+ await this.ctx.client.adt.activation.activate.post({}, { objectReferences: { objectReference: [{
3291
+ uri: this.objectUri,
3292
+ name: this.name
3293
+ }] } });
3294
+ return this;
3295
+ }
3296
+ /**
3297
+ * Get a SRVD (validates it exists by fetching source).
3298
+ */
3299
+ static async get(name, ctx) {
3300
+ const obj = new AdkServiceDefinition(ctx ?? getGlobalContext(), name);
3301
+ await obj.getSource();
3302
+ return obj;
3303
+ }
3304
+ static async exists(name, ctx) {
3305
+ try {
3306
+ await AdkServiceDefinition.get(name, ctx);
3307
+ return true;
3308
+ } catch {
3309
+ return false;
3310
+ }
3311
+ }
3312
+ /**
3313
+ * Create a new SRVD on SAP.
3314
+ *
3315
+ * POST /sap/bc/adt/ddic/srvd/sources?corrNr=...
3316
+ * Body matches the `srvd:source` envelope (extends
3317
+ * abapsource:AbapSourceMainObject).
3318
+ */
3319
+ static async create(name, description, packageName, options, ctx) {
3320
+ const context = ctx ?? getGlobalContext();
3321
+ const nameU = name.toUpperCase();
3322
+ const pkgU = packageName.toUpperCase();
3323
+ await context.client.adt.ddic.srvd.sources.post(options?.transport ? { corrNr: options.transport } : {}, { source: {
3324
+ name: nameU,
3325
+ type: "SRVD/SRV",
3326
+ description,
3327
+ language: "EN",
3328
+ masterLanguage: "EN",
3329
+ responsible: pkgU,
3330
+ packageRef: {
3331
+ name: pkgU,
3332
+ type: "DEVC/K",
3333
+ uri: `/sap/bc/adt/packages/${pkgU.toLowerCase()}`
3334
+ }
3335
+ } });
3336
+ return new AdkServiceDefinition(context, nameU);
3337
+ }
3338
+ static async delete(name, options, ctx) {
3339
+ await (ctx ?? getGlobalContext()).client.adt.ddic.srvd.sources.delete(name.toUpperCase(), {
3340
+ ...options?.transport ? { corrNr: options.transport } : {},
3341
+ ...options?.lockHandle ? { lockHandle: options.lockHandle } : {}
3342
+ });
3343
+ }
3344
+ };
3345
+
3346
+ //#endregion
3347
+ //#region src/objects/repository/srvb/srvb.model.ts
3348
+ /**
3349
+ * SRVB - Service Binding (RAP)
3350
+ *
3351
+ * ADK object for ABAP RAP Service Bindings (SRVB). Unlike BDEF/SRVD,
3352
+ * SRVB is **metadata-only** — there is no source text. The binding
3353
+ * XML carries the service + protocol references.
3354
+ *
3355
+ * GET /sap/bc/adt/businessservices/bindings/<name>
3356
+ * POST /sap/bc/adt/businessservices/bindings
3357
+ * PUT /sap/bc/adt/businessservices/bindings/<name>
3358
+ * DELETE /sap/bc/adt/businessservices/bindings/<name>
3359
+ * POST /sap/bc/adt/businessservices/bindings/<name>/publishedstates (publish)
3360
+ * DELETE /sap/bc/adt/businessservices/bindings/<name>/publishedstates (unpublish)
3361
+ *
3362
+ * Lifecycle follows lock/activate patterns from sibling RAP objects.
3363
+ */
3364
+ var AdkServiceBinding = class AdkServiceBinding {
3365
+ /** Static ADK kind marker — used by abapGit handler registry if needed. */
3366
+ static kind = "ServiceBinding";
3367
+ kind = AdkServiceBinding.kind;
3368
+ name;
3369
+ ctx;
3370
+ constructor(ctx, name) {
3371
+ this.ctx = ctx;
3372
+ this.name = name.toUpperCase();
3373
+ }
3374
+ get objectUri() {
3375
+ return `/sap/bc/adt/businessservices/bindings/${encodeURIComponent(this.name.toLowerCase())}`;
3376
+ }
3377
+ /** Placeholder description — full metadata requires additional SAP fetch */
3378
+ get description() {
3379
+ return this.name;
3380
+ }
3381
+ get contract() {
3382
+ return this.ctx.client.adt.businessservices.bindings;
3383
+ }
3384
+ /**
3385
+ * Fetch the binding metadata document. SRVB has no source text;
3386
+ * `getSource()` returns an empty string for uniform CLI parity.
3387
+ */
3388
+ async getMetadata() {
3389
+ return this.contract.get(this.name);
3390
+ }
3391
+ async getSource() {
3392
+ return "";
3393
+ }
3394
+ async lock(transport) {
3395
+ const lockService = this.ctx.lockService;
3396
+ if (!lockService) throw new Error("Lock not available: no lockService in context. Did you call initializeAdk()?");
3397
+ return lockService.lock(this.objectUri, {
3398
+ transport,
3399
+ objectName: this.name,
3400
+ objectType: "SRVB"
3401
+ });
3402
+ }
3403
+ async unlock(lockHandle) {
3404
+ const lockService = this.ctx.lockService;
3405
+ if (!lockService) throw new Error("Unlock not available: no lockService in context. Did you call initializeAdk()?");
3406
+ await lockService.unlock(this.objectUri, { lockHandle });
3407
+ }
3408
+ async activate() {
3409
+ await this.ctx.client.adt.activation.activate.post({}, { objectReferences: { objectReference: [{
3410
+ uri: this.objectUri,
3411
+ name: this.name
3412
+ }] } });
3413
+ return this;
3414
+ }
3415
+ /**
3416
+ * Publish (activate) the binding in the SAP Gateway.
3417
+ * POST {basePath}/{name}/publishedstates
3418
+ */
3419
+ async publish() {
3420
+ await this.contract.publish(this.name);
3421
+ }
3422
+ /**
3423
+ * Unpublish (deactivate) the binding.
3424
+ * DELETE {basePath}/{name}/publishedstates
3425
+ */
3426
+ async unpublish() {
3427
+ await this.contract.unpublish(this.name);
3428
+ }
3429
+ /**
3430
+ * Get a SRVB (validates it exists by fetching metadata).
3431
+ */
3432
+ static async get(name, ctx) {
3433
+ const obj = new AdkServiceBinding(ctx ?? getGlobalContext(), name);
3434
+ await obj.getMetadata();
3435
+ return obj;
3436
+ }
3437
+ static async exists(name, ctx) {
3438
+ try {
3439
+ await AdkServiceBinding.get(name, ctx);
3440
+ return true;
3441
+ } catch {
3442
+ return false;
3443
+ }
3444
+ }
3445
+ /**
3446
+ * Create a new SRVB on SAP.
3447
+ *
3448
+ * POST /sap/bc/adt/businessservices/bindings?corrNr=...
3449
+ * Body matches the `srvb:serviceBinding` envelope.
3450
+ */
3451
+ static async create(name, description, packageName, options, ctx) {
3452
+ const context = ctx ?? getGlobalContext();
3453
+ const nameU = name.toUpperCase();
3454
+ const pkgU = packageName.toUpperCase();
3455
+ await context.client.adt.businessservices.bindings.post(options?.transport ? { corrNr: options.transport } : {}, { serviceBinding: {
3456
+ name: nameU,
3457
+ type: "SRVB/SVB",
3458
+ description,
3459
+ language: "EN",
3460
+ masterLanguage: "EN",
3461
+ responsible: pkgU,
3462
+ packageRef: {
3463
+ name: pkgU,
3464
+ type: "DEVC/K",
3465
+ uri: `/sap/bc/adt/packages/${pkgU.toLowerCase()}`
3466
+ }
3467
+ } });
3468
+ return new AdkServiceBinding(context, nameU);
3469
+ }
3470
+ static async delete(name, options, ctx) {
3471
+ await (ctx ?? getGlobalContext()).client.adt.businessservices.bindings.delete(name.toUpperCase(), {
3472
+ ...options?.transport ? { corrNr: options.transport } : {},
3473
+ ...options?.lockHandle ? { lockHandle: options.lockHandle } : {}
3474
+ });
3475
+ }
3476
+ static async publish(name, ctx) {
3477
+ await new AdkServiceBinding(ctx ?? getGlobalContext(), name).publish();
3478
+ }
3479
+ static async unpublish(name, ctx) {
3480
+ await new AdkServiceBinding(ctx ?? getGlobalContext(), name).unpublish();
3481
+ }
3482
+ };
3483
+
3484
+ //#endregion
3485
+ //#region src/objects/cts/transport/transport-object.ts
3486
+ /**
3487
+ * Transport Object - wrapper for ABAP objects in a transport
3488
+ */
3489
+ var AdkTransportObject = class {
3490
+ constructor(data) {
3491
+ this.data = data;
3492
+ }
3493
+ get pgmid() {
3494
+ return this.data.pgmid || "";
3495
+ }
3496
+ get type() {
3497
+ return this.data.type || "";
3498
+ }
3499
+ get name() {
3500
+ return this.data.name || "";
3501
+ }
3502
+ get wbtype() {
3503
+ return this.data.wbtype;
3504
+ }
3505
+ get objectInfo() {
3506
+ return this.data.obj_info;
3507
+ }
3508
+ get objectDescription() {
3509
+ return this.data.obj_desc;
3510
+ }
3511
+ get lockStatus() {
3512
+ return this.data.lock_status;
3513
+ }
3514
+ get uri() {
3515
+ return this.data.uri;
3516
+ }
3517
+ /** Full object key (PGMID/TYPE/NAME) */
3518
+ get key() {
3519
+ return `${this.pgmid}/${this.type}/${this.name}`;
3520
+ }
3521
+ /** Raw schema data */
3522
+ get raw() {
3523
+ return this.data;
3524
+ }
3525
+ };
3526
+
3527
+ //#endregion
3528
+ //#region \0@oxc-project+runtime@0.115.0/helpers/decorateMetadata.js
3529
+ function __decorateMetadata(k, v) {
3530
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
3531
+ }
3532
+
3533
+ //#endregion
3534
+ //#region \0@oxc-project+runtime@0.115.0/helpers/decorate.js
3535
+ function __decorate(decorators, target, key, desc) {
3536
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3537
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
3538
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
3539
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
3540
+ }
3541
+
3542
+ //#endregion
3543
+ //#region src/objects/cts/transport/transport.ts
3544
+ const STATUS_TEXT = {
3545
+ D: "Modifiable",
3546
+ R: "Released",
3547
+ N: "Not released"
3548
+ };
3549
+ function asArray$1(val) {
3550
+ if (!val) return [];
3551
+ return Array.isArray(val) ? val : [val];
3552
+ }
3553
+ let cachedConfigUri;
3554
+ async function getConfigUri(ctx) {
3555
+ if (cachedConfigUri) return cachedConfigUri;
3556
+ const configs = (await ctx.client.adt.cts.transportrequests.searchconfiguration.configurations.get())?.configurations;
3557
+ if (!configs) throw new Error("No search configuration found");
3558
+ const configArray = Array.isArray(configs) ? configs : [configs];
3559
+ if (configArray.length === 0) throw new Error("No search configuration found");
3560
+ const uri = configArray[0]?.link?.href;
3561
+ if (!uri) throw new Error("No search configuration URI found");
3562
+ cachedConfigUri = uri;
3563
+ return uri;
3564
+ }
3565
+ /** Clear config cache (for testing) */
3566
+ function clearConfigCache() {
3567
+ cachedConfigUri = void 0;
3568
+ }
3569
+ /**
3570
+ * Collect all requests from the transport response structure
3571
+ * The schema has requests in multiple places:
3572
+ * - workbench.modifiable.request[]
3573
+ * - workbench.relstarted.request[]
3574
+ * - workbench.released.request[]
3575
+ * - workbench.target[].modifiable.request[]
3576
+ * - customizing.* (same structure)
3577
+ */
3578
+ function collectAllRequests(result) {
3579
+ const requests = [];
3580
+ if (!result || typeof result !== "object") return requests;
3581
+ const data = result;
3582
+ const extractFromContainer = (container) => {
3583
+ if (!container || typeof container !== "object") return;
3584
+ const reqs = container.request;
3585
+ if (reqs) {
3586
+ const reqArray = Array.isArray(reqs) ? reqs : [reqs];
3587
+ requests.push(...reqArray);
3588
+ }
3589
+ };
3590
+ const processSection = (section) => {
3591
+ if (!section || typeof section !== "object") return;
3592
+ const s = section;
3593
+ extractFromContainer(s.modifiable);
3594
+ extractFromContainer(s.relstarted);
3595
+ extractFromContainer(s.released);
3596
+ const targets = s.target;
3597
+ if (targets) {
3598
+ const targetArray = Array.isArray(targets) ? targets : [targets];
3599
+ for (const target of targetArray) if (target && typeof target === "object") {
3600
+ const t = target;
3601
+ extractFromContainer(t.modifiable);
3602
+ extractFromContainer(t.relstarted);
3603
+ extractFromContainer(t.released);
3604
+ }
3605
+ }
3606
+ };
3607
+ processSection(data.workbench);
3608
+ processSection(data.customizing);
3609
+ return requests;
3610
+ }
3611
+ /**
3612
+ * Transport Request - main transport object
3613
+ *
3614
+ * Handles both requests (K) and can be extended for tasks (T).
3615
+ * Uses ADT contracts directly - no intermediate service layer.
3616
+ */
3617
+ var AdkTransportRequest = class AdkTransportRequest extends AdkObject {
3618
+ kind = TransportRequest;
3619
+ _tasks;
3620
+ _objects;
3621
+ constructor(ctx, dataOrNumber) {
3622
+ if (typeof dataOrNumber === "string") super(ctx, dataOrNumber);
3623
+ else super(ctx, {
3624
+ name: dataOrNumber.name || dataOrNumber.request?.number || "",
3625
+ type: dataOrNumber.object_type === "T" ? "RQTQ" : "RQRQ",
3626
+ response: dataOrNumber
3627
+ });
3628
+ }
3629
+ get response() {
3630
+ return this.dataSync.response;
3631
+ }
3632
+ /** The item's data - override in subclass for different source */
3633
+ get itemData() {
3634
+ return this.response.request || {};
3635
+ }
3636
+ get objectUri() {
3637
+ return `/sap/bc/adt/cts/transportrequests/${this.name}`;
3638
+ }
3639
+ async load() {
3640
+ const response = (await this.ctx.client.adt.cts.transportrequests.get(this.name)).root;
3641
+ this.setData({
3642
+ name: this.name,
3643
+ type: response.object_type === "T" ? "RQTQ" : "RQRQ",
3644
+ response
3645
+ });
3646
+ return this;
3647
+ }
3648
+ get itemType() {
3649
+ return this.response.object_type === "T" ? "task" : "request";
3650
+ }
3651
+ get number() {
3652
+ return this.name;
3653
+ }
3654
+ get owner() {
3655
+ return this.itemData.owner || "";
3656
+ }
3657
+ get description() {
3658
+ return this.itemData.desc || "";
3659
+ }
3660
+ get status() {
3661
+ return this.itemData.status || "D";
3662
+ }
3663
+ get statusText() {
3664
+ return this.itemData.status_text || STATUS_TEXT[this.status] || this.status;
3665
+ }
3666
+ get target() {
3667
+ return this.itemData.target || "";
3668
+ }
3669
+ get targetDescription() {
3670
+ return this.itemData.target_desc || "";
3671
+ }
3672
+ get uri() {
3673
+ return this.itemData.uri || this.objectUri;
3674
+ }
3675
+ get parent() {
3676
+ return this.itemData.parent || "";
3677
+ }
3678
+ get lastChangedAt() {
3679
+ return parseSapTimestamp(this.itemData.lastchanged_timestamp);
3680
+ }
3681
+ /** Tasks belonging to this transport request */
3682
+ get tasks() {
3683
+ if (!this._tasks) {
3684
+ const taskData = this.itemData.task;
3685
+ this._tasks = asArray$1(taskData).map((t) => {
3686
+ const { request, task: _existingTasks, ...rootProps } = this.response;
3687
+ const { task: _nestedTasks, ...requestWithoutTasks } = request || {};
3688
+ const taskResponse = {
3689
+ ...rootProps,
3690
+ object_type: "T",
3691
+ name: t.number || "",
3692
+ request: request ? requestWithoutTasks : void 0,
3693
+ task: [t]
3694
+ };
3695
+ return new AdkTransportTask(this.ctx, taskResponse, this);
3696
+ });
3697
+ }
3698
+ return this._tasks;
3699
+ }
3700
+ /**
3701
+ * All objects in this request (aggregated from tasks)
3702
+ * Override in AdkTransportTask for direct objects
3703
+ */
3704
+ get objects() {
3705
+ if (!this._objects) {
3706
+ const directObjects = asArray$1(this.itemData.abap_object).map((o) => new AdkTransportObject(o));
3707
+ const taskObjects = this.tasks.flatMap((t) => t.objects);
3708
+ this._objects = [...directObjects, ...taskObjects];
3709
+ }
3710
+ return this._objects;
3711
+ }
3712
+ async release() {
3713
+ try {
3714
+ await this.ctx.client.adt.cts.transportrequests.useraction.release(this.number, { root: { useraction: "release" } });
3715
+ this.itemData.status = "R";
3716
+ this.itemData.status_text = "Released";
3717
+ return { success: true };
3718
+ } catch (error) {
3719
+ return {
3720
+ success: false,
3721
+ message: error instanceof Error ? error.message : String(error)
3722
+ };
3723
+ }
3724
+ }
3725
+ async releaseAll() {
3726
+ for (const task of this.tasks) if (task.status !== "R") {
3727
+ const result = await task.release();
3728
+ if (!result.success) return {
3729
+ success: false,
3730
+ message: `Failed to release task ${task.number}: ${result.message}`
3731
+ };
3732
+ }
3733
+ return this.release();
3734
+ }
3735
+ async update(changes) {
3736
+ await this.ctx.client.adt.cts.transportrequests.put(this.number, {
3737
+ desc: changes.description ?? this.description,
3738
+ target: changes.target ?? this.target
3739
+ });
3740
+ if (changes.description !== void 0) this.itemData.desc = changes.description;
3741
+ if (changes.target !== void 0) this.itemData.target = changes.target;
3742
+ }
3743
+ async delete() {
3744
+ await this.ctx.client.adt.cts.transportrequests.delete(this.number);
3745
+ }
3746
+ /**
3747
+ * Reassign ownership of this transport (and optionally all tasks) to a new user.
3748
+ *
3749
+ * @param newOwner - SAP username to become the new owner
3750
+ * @param recursive - When true, also reassign all modifiable tasks
3751
+ */
3752
+ async reassign(newOwner, recursive = false) {
3753
+ await this.ctx.client.adt.cts.transportrequests.useraction.reassign(this.number, {
3754
+ targetUser: newOwner,
3755
+ recursive
3756
+ }, { root: {
3757
+ useraction: "changeowner",
3758
+ targetuser: newOwner
3759
+ } });
3760
+ this.itemData.owner = newOwner;
3761
+ if (recursive) {
3762
+ for (const task of this.tasks) if (task.status !== "R") await task.reassign(newOwner);
3763
+ }
3764
+ }
3765
+ /**
3766
+ * Create a new transport request
3767
+ *
3768
+ * @param options - Transport creation options
3769
+ * @param ctx - Optional ADK context (uses global context if not provided)
3770
+ */
3771
+ static async create(options, ctx) {
3772
+ const context = ctx ?? getGlobalContext();
3773
+ let owner = options.owner;
3774
+ if (!owner) owner = await AdkTransportRequest.getCurrentUser(context);
3775
+ const response = await context.client.adt.cts.transportrequests.useraction.create({
3776
+ description: options.description,
3777
+ type: options.type,
3778
+ target: options.target,
3779
+ project: options.project,
3780
+ owner
3781
+ }, { root: {
3782
+ useraction: "newrequest",
3783
+ request: {
3784
+ desc: options.description,
3785
+ type: options.type || "K",
3786
+ target: options.target || "LOCAL",
3787
+ cts_project: options.project || "",
3788
+ task: [{ owner }]
3789
+ }
3790
+ } });
3791
+ const number = response?.root?.request?.number ?? response?.root?.name ?? void 0;
3792
+ if (!number) throw new Error("Failed to create transport - no number returned");
3793
+ return AdkTransportRequest.get(number, context);
3794
+ }
3795
+ /**
3796
+ * Get a transport request by number
3797
+ *
3798
+ * @param number - Transport number (e.g., 'S0DK900001')
3799
+ * @param ctx - Optional ADK context (uses global context if not provided)
3800
+ */
3801
+ static async get(number, ctx) {
3802
+ const context = ctx ?? getGlobalContext();
3803
+ const response = (await context.client.adt.cts.transportrequests.get(number)).root;
3804
+ if (response.object_type === "T") return new AdkTransportTask(context, response);
3805
+ return new AdkTransportRequest(context, response);
3806
+ }
3807
+ /**
3808
+ * List all transports for the current user
3809
+ *
3810
+ * @param ctx - Optional ADK context (uses global context if not provided)
3811
+ */
3812
+ static async list(ctx) {
3813
+ const context = ctx ?? getGlobalContext();
3814
+ const configUri = await getConfigUri(context);
3815
+ return collectAllRequests(await context.client.adt.cts.transportrequests.list({
3816
+ targets: "true",
3817
+ configUri
3818
+ })).map((r) => new AdkTransportRequest(context, {
3819
+ name: r.number || "",
3820
+ object_type: "K",
3821
+ request: {
3822
+ number: r.number,
3823
+ owner: r.owner,
3824
+ desc: r.desc,
3825
+ status: r.status,
3826
+ uri: r.uri,
3827
+ task: r.task,
3828
+ abap_object: r.abap_object
3829
+ }
3830
+ }));
3831
+ }
3832
+ /**
3833
+ * Get current user from the system metadata
3834
+ *
3835
+ * @param ctx - Optional ADK context (uses global context if not provided)
3836
+ */
3837
+ static async getCurrentUser(ctx) {
3838
+ const user = ((await (ctx ?? getGlobalContext()).client.adt.cts.transportrequests.searchconfiguration.metadata.get())?.configuration?.properties?.property ?? []).find((p) => p.key === "User")?.$value?.trim();
3839
+ if (user) return user;
3840
+ throw new Error("Could not detect current user from metadata response");
3841
+ }
3842
+ };
3843
+ __decorate([
3844
+ requiresLock(),
3845
+ __decorateMetadata("design:type", Function),
3846
+ __decorateMetadata("design:paramtypes", [Object]),
3847
+ __decorateMetadata("design:returntype", Promise)
3848
+ ], AdkTransportRequest.prototype, "update", null);
3849
+ /**
3850
+ * Transport Task - child of a transport request
3851
+ *
3852
+ * Minimal overrides:
3853
+ * - itemData: from response.task instead of response.request
3854
+ * - objects: direct from task, not aggregated
3855
+ * - request: parent reference
3856
+ * - No tasks, no CRUD
3857
+ */
3858
+ var AdkTransportTask = class AdkTransportTask extends AdkTransportRequest {
3859
+ _parentRequest;
3860
+ parentRef;
3861
+ constructor(ctx, dataOrNumber, parentRef) {
3862
+ super(ctx, dataOrNumber);
3863
+ this.parentRef = parentRef;
3864
+ }
3865
+ get itemData() {
3866
+ const rootTask = this.response.task;
3867
+ if (rootTask) {
3868
+ const taskArr = Array.isArray(rootTask) ? rootTask : [rootTask];
3869
+ const found = taskArr.find((t) => t.number === this.name) || taskArr[0];
3870
+ if (found) return found;
3871
+ }
3872
+ return this.response.request || {};
3873
+ }
3874
+ get tasks() {
3875
+ return [];
3876
+ }
3877
+ get objects() {
3878
+ if (!this._objects) {
3879
+ const taskData = this.itemData;
3880
+ this._objects = asArray$1(taskData?.abap_object).map((o) => new AdkTransportObject(o));
3881
+ }
3882
+ return this._objects;
3883
+ }
3884
+ /** Parent transport request */
3885
+ get request() {
3886
+ if (this.parentRef) return this.parentRef;
3887
+ if (!this._parentRequest) {
3888
+ const parentNumber = this.response.request?.number || this.parent;
3889
+ this._parentRequest = new AdkTransportRequest(this.ctx, {
3890
+ ...this.response,
3891
+ name: parentNumber,
3892
+ object_type: "K"
3893
+ });
3894
+ }
3895
+ return this._parentRequest;
3896
+ }
3897
+ /**
3898
+ * Get a transport task by number
3899
+ *
3900
+ * @param number - Task number (e.g., 'S0DK900001')
3901
+ * @param ctx - Optional ADK context (uses global context if not provided)
3902
+ */
3903
+ static async get(number, ctx) {
3904
+ const context = ctx ?? getGlobalContext();
3905
+ return new AdkTransportTask(context, (await context.client.adt.cts.transportrequests.get(number)).root);
3906
+ }
3907
+ };
3908
+
3909
+ //#endregion
3910
+ //#region src/objects/cts/transport-import.ts
3911
+ /**
3912
+ * Helper to normalize array/single value to array
3913
+ */
3914
+ function asArray(val) {
3915
+ if (!val) return [];
3916
+ return Array.isArray(val) ? val : [val];
3917
+ }
3918
+ /**
3919
+ * Check if a value matches a selector dimension.
3920
+ *
3921
+ * - If `expected` is undefined → no filter (always matches).
3922
+ * - If `expected` is '*' → matches any truthy value.
3923
+ * - If `expected` is an array → value must be in the array.
3924
+ * - Otherwise exact match (case-insensitive).
3925
+ */
3926
+ function matchesDimension(value, expected) {
3927
+ if (expected === void 0) return true;
3928
+ if (Array.isArray(expected)) return expected.some((e) => e === "*" ? !!value : e.toUpperCase() === value.toUpperCase());
3929
+ if (expected === "*") return !!value;
3930
+ return expected.toUpperCase() === value.toUpperCase();
3931
+ }
3932
+ /**
3933
+ * Check if an object ref matches all dimensions of a {@link TransportObjectSelector}.
3934
+ *
3935
+ * Exported so that consumers (e.g. import service) can reuse the same logic
3936
+ * without duplicating it.
3937
+ */
3938
+ function matchesSelector(obj, selector) {
3939
+ return matchesDimension(obj.objFunc, selector.objFunc) && matchesDimension(obj.pgmid, selector.pgmid) && matchesDimension(obj.type, selector.type);
3940
+ }
3941
+ /**
3942
+ * Transport object reference - lightweight wrapper
3943
+ *
3944
+ * Contains metadata about an object in the transport.
3945
+ * Call load() to get the full ADK object.
3946
+ */
3947
+ var AdkTransportObjectRef = class {
3948
+ constructor(ctx, data) {
3949
+ this.ctx = ctx;
3950
+ this.data = data;
3951
+ }
3952
+ /** Program ID (R3TR, LIMU, etc.) */
3953
+ get pgmid() {
3954
+ return this.data.pgmid ?? "";
3955
+ }
3956
+ /** Object type (CLAS, INTF, DOMA, etc.) */
3957
+ get type() {
3958
+ return this.data.type ?? "";
3959
+ }
3960
+ /** Object name */
3961
+ get name() {
3962
+ return this.data.name ?? "";
3963
+ }
3964
+ /** Workbench type (more specific type) */
3965
+ get wbtype() {
3966
+ return this.data.wbtype;
3967
+ }
3968
+ /** Object URI for direct access */
3969
+ get uri() {
3970
+ return this.data.uri;
3971
+ }
3972
+ /** Object description */
3973
+ get description() {
3974
+ return this.data.obj_desc;
3975
+ }
3976
+ /**
3977
+ * Object function code (SAP OBJFUNC).
3978
+ * 'D' = marked for deletion, 'K' = key entry, '' = regular modification.
3979
+ */
3980
+ get objFunc() {
3981
+ return this.data.obj_func ?? "";
3982
+ }
3983
+ /** Whether this object is marked for deletion (obj_func === 'D') */
3984
+ get isDeleted() {
3985
+ return this.data.obj_func === "D";
3986
+ }
3987
+ /** Full object key (PGMID/TYPE/NAME) */
3988
+ get key() {
3989
+ return `${this.pgmid}/${this.type}/${this.name}`;
3990
+ }
3991
+ /**
3992
+ * Load the full ADK object
3993
+ *
3994
+ * Uses the ADK factory to create the appropriate object type
3995
+ * (AdkClass, AdkInterface, AdkPackage, etc.)
3996
+ *
3997
+ * @returns The loaded ADK object, or undefined if type not supported
3998
+ */
3999
+ async load() {
4000
+ const { createAdk } = await import("./factory-DtyrTGlN.mjs").then((n) => n.i);
4001
+ const adk = createAdk(this.ctx.client);
4002
+ try {
4003
+ const obj = adk.get(this.name, this.type);
4004
+ if ("load" in obj && typeof obj.load === "function") await obj.load();
4005
+ return obj;
4006
+ } catch {
4007
+ return;
4008
+ }
4009
+ }
4010
+ /** Raw data from API */
4011
+ get raw() {
4012
+ return this.data;
4013
+ }
4014
+ };
4015
+ /**
4016
+ * Transport task reference
4017
+ */
4018
+ var AdkTransportTaskRef = class {
4019
+ constructor(ctx, data) {
4020
+ this.ctx = ctx;
4021
+ this.data = data;
4022
+ }
4023
+ get number() {
4024
+ return this.data.number ?? "";
4025
+ }
4026
+ get owner() {
4027
+ return this.data.owner ?? "";
4028
+ }
4029
+ get description() {
4030
+ return this.data.desc ?? "";
4031
+ }
4032
+ get status() {
4033
+ return this.data.status ?? "";
4034
+ }
4035
+ get statusText() {
4036
+ return this.data.status_text ?? "";
4037
+ }
4038
+ /** Objects in this task */
4039
+ get objects() {
4040
+ return asArray(this.data.abap_object).map((obj) => new AdkTransportObjectRef(this.ctx, obj));
4041
+ }
4042
+ };
4043
+ /**
4044
+ * AdkTransport - Transport request for import operations
4045
+ *
4046
+ * Simple, focused API for importing transport objects:
4047
+ *
4048
+ * @example
4049
+ * ```typescript
4050
+ * const transport = await AdkTransport.get('DEVK900001');
4051
+ *
4052
+ * for (const objRef of transport.objects) {
4053
+ * console.log(`${objRef.type} ${objRef.name}`);
4054
+ * const adkObject = await objRef.load();
4055
+ * if (adkObject) {
4056
+ * // Serialize with plugin
4057
+ * await plugin.serialize(adkObject);
4058
+ * }
4059
+ * }
4060
+ * ```
4061
+ */
4062
+ var AdkTransport = class AdkTransport {
4063
+ _objects;
4064
+ _tasks;
4065
+ constructor(ctx, data) {
4066
+ this.ctx = ctx;
4067
+ this.data = data;
4068
+ }
4069
+ /** Transport number */
4070
+ get number() {
4071
+ return this.data.name ?? this.data.request?.number ?? "";
4072
+ }
4073
+ /** Transport description */
4074
+ get description() {
4075
+ return this.data.request?.desc ?? "";
4076
+ }
4077
+ /** Transport owner */
4078
+ get owner() {
4079
+ return this.data.request?.owner ?? "";
4080
+ }
4081
+ /** Transport status (D=Modifiable, R=Released) */
4082
+ get status() {
4083
+ return this.data.request?.status ?? "";
4084
+ }
4085
+ /** Transport status text */
4086
+ get statusText() {
4087
+ return this.data.request?.status_text ?? "";
4088
+ }
4089
+ /** Transport target system */
4090
+ get target() {
4091
+ return this.data.request?.target ?? "";
4092
+ }
4093
+ /** Object type (K=Request, T=Task) */
4094
+ get objectType() {
4095
+ return this.data.object_type ?? "K";
4096
+ }
4097
+ /** Tasks belonging to this transport */
4098
+ get tasks() {
4099
+ if (!this._tasks) {
4100
+ const requestTasks = asArray(this.data.request?.task);
4101
+ const rootTasks = asArray(this.data.task);
4102
+ this._tasks = [...requestTasks, ...rootTasks].map((t) => new AdkTransportTaskRef(this.ctx, t));
4103
+ }
4104
+ return this._tasks;
4105
+ }
4106
+ /**
4107
+ * All objects in this transport
4108
+ *
4109
+ * Collects objects from:
4110
+ * - Direct objects on request
4111
+ * - Objects from all tasks
4112
+ * - all_objects container (if present)
4113
+ */
4114
+ get objects() {
4115
+ if (!this._objects) this._objects = this.collectObjects();
4116
+ return this._objects;
4117
+ }
4118
+ collectObjects() {
4119
+ const objects = [];
4120
+ const seen = /* @__PURE__ */ new Set();
4121
+ const addObject = (obj) => {
4122
+ const key = `${obj.pgmid}/${obj.type}/${obj.name}`;
4123
+ if (!seen.has(key)) {
4124
+ seen.add(key);
4125
+ objects.push(new AdkTransportObjectRef(this.ctx, obj));
4126
+ }
4127
+ };
4128
+ for (const obj of asArray(this.data.request?.abap_object)) addObject(obj);
4129
+ for (const obj of asArray(this.data.request?.all_objects?.abap_object)) addObject(obj);
4130
+ for (const task of this.tasks) for (const objRef of task.objects) addObject(objRef.raw);
4131
+ return objects;
4132
+ }
4133
+ /**
4134
+ * Get objects filtered by type
4135
+ *
4136
+ * @param types - Object types to include (e.g., ['CLAS', 'INTF'])
4137
+ */
4138
+ getObjectsByType(...types) {
4139
+ const typeSet = new Set(types.map((t) => t.toUpperCase()));
4140
+ return this.objects.filter((obj) => typeSet.has(obj.type.toUpperCase()));
4141
+ }
4142
+ /**
4143
+ * Get objects filtered by a {@link TransportObjectSelector}.
4144
+ *
4145
+ * All dimensions specified in the selector are ANDed together.
4146
+ *
4147
+ * @example
4148
+ * ```typescript
4149
+ * // Get only deletion objects with pgmid=R3TR
4150
+ * const deleted = transport.getObjectsBySelector({ objFunc: 'D', pgmid: 'R3TR' });
4151
+ * ```
4152
+ */
4153
+ getObjectsBySelector(selector) {
4154
+ return this.objects.filter((obj) => matchesSelector(obj, selector));
4155
+ }
4156
+ /**
4157
+ * Convenience accessor for objects marked for deletion (obj_func === 'D').
4158
+ *
4159
+ * Equivalent to `getObjectsBySelector({ objFunc: 'D' })`.
4160
+ */
4161
+ get deletionObjects() {
4162
+ return this.getObjectsBySelector({ objFunc: "D" });
4163
+ }
4164
+ /**
4165
+ * Get unique object types in this transport
4166
+ */
4167
+ getObjectTypes() {
4168
+ const types = new Set(this.objects.map((obj) => obj.type));
4169
+ return Array.from(types).sort();
4170
+ }
4171
+ /**
4172
+ * Get object count by type
4173
+ */
4174
+ getObjectCountByType() {
4175
+ const counts = {};
4176
+ for (const obj of this.objects) counts[obj.type] = (counts[obj.type] || 0) + 1;
4177
+ return counts;
4178
+ }
4179
+ /** Raw API response (unwrapped) */
4180
+ get raw() {
4181
+ return this.data;
4182
+ }
4183
+ /**
4184
+ * Get a transport by number
4185
+ *
4186
+ * @param number - Transport number (e.g., 'DEVK900001')
4187
+ * @param ctx - Optional ADK context (uses global context if not provided)
4188
+ *
4189
+ * @example
4190
+ * ```typescript
4191
+ * const transport = await AdkTransport.get('DEVK900001');
4192
+ * console.log(`${transport.description} - ${transport.objects.length} objects`);
4193
+ * ```
4194
+ */
4195
+ static async get(number, ctx) {
4196
+ const context = ctx ?? getGlobalContext();
4197
+ return new AdkTransport(context, (await context.client.adt.cts.transportrequests.get(number)).root);
4198
+ }
4199
+ /**
4200
+ * Load multiple transports and merge their objects into a single view.
4201
+ *
4202
+ * De-duplication key is `pgmid/type/name`. When the same key appears in
4203
+ * multiple transports the **first** occurrence wins (first transport in the
4204
+ * `numbers` array). The source transport number is available via
4205
+ * `AdkTransportObjectRef.sourceTransport`.
4206
+ *
4207
+ * @param numbers - Transport numbers to load and merge
4208
+ * @param ctx - Optional ADK context
4209
+ *
4210
+ * @example
4211
+ * ```typescript
4212
+ * const merged = await AdkTransport.merge(['DEVK900001', 'DEVK900002']);
4213
+ * const deletions = merged.getObjectsBySelector({ objFunc: 'D' });
4214
+ * ```
4215
+ */
4216
+ static async merge(numbers, ctx) {
4217
+ return new MergedTransportView(await Promise.all(numbers.map((n) => AdkTransport.get(n, ctx))));
4218
+ }
4219
+ };
4220
+ function getFilteredObjects(transport, selector) {
4221
+ return Object.keys(selector).length > 0 ? transport.getObjectsBySelector(selector) : transport.objects;
4222
+ }
4223
+ function addResolvedObject(object, sourceTransport, objects, sourceTransportMap, seenKeys) {
4224
+ if (seenKeys && seenKeys.has(object.key)) return;
4225
+ if (seenKeys) seenKeys.add(object.key);
4226
+ objects.push(object);
4227
+ sourceTransportMap.set(object.key, sourceTransport);
4228
+ }
4229
+ /**
4230
+ * Load and resolve objects from one or more transport numbers, with optional
4231
+ * selector-based filtering and deduplication across TRs.
4232
+ *
4233
+ * This is the shared logic used by both the CLI `cts tr objects` command and
4234
+ * the MCP `cts_transport_objects` tool — extracted here to avoid duplication.
4235
+ *
4236
+ * @param transportNumbers - Ordered list of TR numbers (first-win deduplication).
4237
+ * @param selector - Optional dimension filter (objFunc, pgmid, type).
4238
+ * @param ctx - Optional ADK context (uses global context if omitted).
4239
+ */
4240
+ async function resolveTransportObjects(transportNumbers, selector, ctx) {
4241
+ const objects = [];
4242
+ const sourceTransportMap = /* @__PURE__ */ new Map();
4243
+ if (transportNumbers.length === 1) {
4244
+ const primaryNumber = transportNumbers[0] ?? "";
4245
+ const tr = await AdkTransport.get(primaryNumber, ctx);
4246
+ for (const object of getFilteredObjects(tr, selector)) addResolvedObject(object, primaryNumber, objects, sourceTransportMap);
4247
+ } else {
4248
+ const transports = await Promise.all(transportNumbers.map((n) => AdkTransport.get(n, ctx)));
4249
+ const seen = /* @__PURE__ */ new Set();
4250
+ for (const tr of transports) for (const object of getFilteredObjects(tr, selector)) addResolvedObject(object, tr.number, objects, sourceTransportMap, seen);
4251
+ }
4252
+ return {
4253
+ objects,
4254
+ sourceTransportMap
4255
+ };
4256
+ }
4257
+ /**
4258
+ * Merged view of objects from multiple transports.
4259
+ *
4260
+ * De-duplicates by `pgmid/type/name`; first occurrence wins.
4261
+ */
4262
+ var MergedTransportView = class MergedTransportView {
4263
+ _objects;
4264
+ transports;
4265
+ constructor(transports) {
4266
+ this.transports = transports;
4267
+ const seen = /* @__PURE__ */ new Set();
4268
+ const all = [];
4269
+ for (const tr of transports) for (const obj of tr.objects) if (!seen.has(obj.key)) {
4270
+ seen.add(obj.key);
4271
+ all.push(obj);
4272
+ }
4273
+ this._objects = all;
4274
+ }
4275
+ /** All objects across transports (deduplicated) */
4276
+ get objects() {
4277
+ return this._objects;
4278
+ }
4279
+ /** Objects matching a selector across all transports */
4280
+ getObjectsBySelector(selector) {
4281
+ return this._objects.filter((obj) => matchesSelector(obj, selector));
4282
+ }
4283
+ /** Convenience: objects marked for deletion (obj_func === 'D') */
4284
+ get deletionObjects() {
4285
+ return this.getObjectsBySelector({ objFunc: "D" });
4286
+ }
4287
+ /**
4288
+ * Load multiple transports and return a merged view.
4289
+ *
4290
+ * @param numbers - Transport numbers to load and merge
4291
+ * @param ctx - Optional ADK context
4292
+ */
4293
+ static async create(numbers, ctx) {
4294
+ return new MergedTransportView(await Promise.all(numbers.map((n) => AdkTransport.get(n, ctx))));
4295
+ }
4296
+ };
4297
+
4298
+ //#endregion
4299
+ export { ADT_TYPE_MAPPINGS, AdkBadi, AdkBehaviorDefinition, AdkClass, AdkDataElement, AdkDclSource, AdkDdlSource, AdkDomain, AdkFunctionGroup, AdkFunctionModule, AdkGenericObject, AdkInclude, AdkInterface, AdkMainObject, AdkObject, AdkObjectSet, AdkPackage, AdkProgram, AdkServiceBinding, AdkServiceDefinition, AdkStructure, AdkTable, AdkTableType, AdkTransport, AdkTransportRequest as AdkTransportItem, AdkTransportRequest, AdkTransportObject, AdkTransportObjectRef, AdkTransportTask, AdkTransportTaskRef, Class, DataElement, Domain, EnhancementSpot, FunctionGroup, FunctionModule, Include, Interface, MergedTransportView, MessageClass, Package, Program, Structure, Table, TableType, TransportRequest, TransportTask, clearConfigCache, createAdk, createAdkContract, createAdkFactory, createLockService, getEndpointForType, getGlobalContext, getKindForType, getMainType, getObjectRootUri, getObjectUri, getRegisteredKinds, getRegisteredTypes, getTypeForKind, initializeAdk, isAdkInitialized, isTypeRegistered, matchesSelector, normalizeObjectName, parseAdtType, parseXmlIdentity, registerObjectType, resetAdk, resolveKind, resolveTransportObjects, resolveType, tryGetGlobalContext };
4300
+ //# sourceMappingURL=index.mjs.map