arc-1 0.9.25 → 1.0.0

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.
Files changed (332) hide show
  1. package/README.md +29 -12
  2. package/dist/adt/abapgit.d.ts +19 -6
  3. package/dist/adt/abapgit.d.ts.map +1 -1
  4. package/dist/adt/abapgit.js +141 -36
  5. package/dist/adt/abapgit.js.map +1 -1
  6. package/dist/adt/authorization-trace.d.ts +23 -0
  7. package/dist/adt/authorization-trace.d.ts.map +1 -0
  8. package/dist/adt/authorization-trace.js +196 -0
  9. package/dist/adt/authorization-trace.js.map +1 -0
  10. package/dist/adt/client.d.ts +21 -8
  11. package/dist/adt/client.d.ts.map +1 -1
  12. package/dist/adt/client.js +47 -7
  13. package/dist/adt/client.js.map +1 -1
  14. package/dist/adt/config.d.ts +15 -0
  15. package/dist/adt/config.d.ts.map +1 -1
  16. package/dist/adt/config.js.map +1 -1
  17. package/dist/adt/crud.d.ts +7 -2
  18. package/dist/adt/crud.d.ts.map +1 -1
  19. package/dist/adt/crud.js +12 -4
  20. package/dist/adt/crud.js.map +1 -1
  21. package/dist/adt/ddic-xml.d.ts +27 -17
  22. package/dist/adt/ddic-xml.d.ts.map +1 -1
  23. package/dist/adt/ddic-xml.js +45 -34
  24. package/dist/adt/ddic-xml.js.map +1 -1
  25. package/dist/adt/devtools.d.ts +13 -0
  26. package/dist/adt/devtools.d.ts.map +1 -1
  27. package/dist/adt/devtools.js +120 -50
  28. package/dist/adt/devtools.js.map +1 -1
  29. package/dist/adt/diagnostics.d.ts +1 -1
  30. package/dist/adt/diagnostics.d.ts.map +1 -1
  31. package/dist/adt/diagnostics.js +1 -0
  32. package/dist/adt/diagnostics.js.map +1 -1
  33. package/dist/adt/errors.d.ts +8 -8
  34. package/dist/adt/errors.d.ts.map +1 -1
  35. package/dist/adt/errors.js +30 -11
  36. package/dist/adt/errors.js.map +1 -1
  37. package/dist/adt/http.d.ts +17 -1
  38. package/dist/adt/http.d.ts.map +1 -1
  39. package/dist/adt/http.js +102 -19
  40. package/dist/adt/http.js.map +1 -1
  41. package/dist/adt/oauth.d.ts +2 -2
  42. package/dist/adt/oauth.d.ts.map +1 -1
  43. package/dist/adt/oauth.js +5 -3
  44. package/dist/adt/oauth.js.map +1 -1
  45. package/dist/adt/package-hierarchy.d.ts.map +1 -1
  46. package/dist/adt/package-hierarchy.js.map +1 -1
  47. package/dist/adt/rap-generate.js.map +1 -1
  48. package/dist/adt/rap-handlers.js.map +1 -1
  49. package/dist/adt/rap-preflight.js.map +1 -1
  50. package/dist/adt/safety.d.ts +13 -13
  51. package/dist/adt/safety.d.ts.map +1 -1
  52. package/dist/adt/semaphore.d.ts.map +1 -1
  53. package/dist/adt/server-driven.d.ts +154 -34
  54. package/dist/adt/server-driven.d.ts.map +1 -1
  55. package/dist/adt/server-driven.js +178 -53
  56. package/dist/adt/server-driven.js.map +1 -1
  57. package/dist/adt/structure-hierarchy.js.map +1 -1
  58. package/dist/adt/transport.d.ts +6 -6
  59. package/dist/adt/transport.d.ts.map +1 -1
  60. package/dist/adt/transport.js +23 -34
  61. package/dist/adt/transport.js.map +1 -1
  62. package/dist/adt/types.d.ts +94 -6
  63. package/dist/adt/types.d.ts.map +1 -1
  64. package/dist/adt/version-diff.js.map +1 -1
  65. package/dist/adt/xml-parser.d.ts +52 -12
  66. package/dist/adt/xml-parser.d.ts.map +1 -1
  67. package/dist/adt/xml-parser.js +120 -10
  68. package/dist/adt/xml-parser.js.map +1 -1
  69. package/dist/aff/validator.js.map +1 -1
  70. package/dist/authz/policy.d.ts +8 -0
  71. package/dist/authz/policy.d.ts.map +1 -1
  72. package/dist/authz/policy.js +24 -0
  73. package/dist/authz/policy.js.map +1 -1
  74. package/dist/cache/cache.d.ts +4 -36
  75. package/dist/cache/cache.d.ts.map +1 -1
  76. package/dist/cache/cache.js +4 -5
  77. package/dist/cache/cache.js.map +1 -1
  78. package/dist/cache/caching-layer.d.ts +6 -22
  79. package/dist/cache/caching-layer.d.ts.map +1 -1
  80. package/dist/cache/caching-layer.js +5 -29
  81. package/dist/cache/caching-layer.js.map +1 -1
  82. package/dist/cache/inactive-list-cache.d.ts.map +1 -1
  83. package/dist/cache/memory.d.ts +2 -13
  84. package/dist/cache/memory.d.ts.map +1 -1
  85. package/dist/cache/memory.js +1 -70
  86. package/dist/cache/memory.js.map +1 -1
  87. package/dist/cache/sqlite.d.ts +3 -10
  88. package/dist/cache/sqlite.d.ts.map +1 -1
  89. package/dist/cache/sqlite.js +9 -85
  90. package/dist/cache/sqlite.js.map +1 -1
  91. package/dist/cli.js +6 -3
  92. package/dist/cli.js.map +1 -1
  93. package/dist/context/compressor.js.map +1 -1
  94. package/dist/context/grep.js.map +1 -1
  95. package/dist/context/unit-surgery.d.ts +28 -0
  96. package/dist/context/unit-surgery.d.ts.map +1 -0
  97. package/dist/context/unit-surgery.js +150 -0
  98. package/dist/context/unit-surgery.js.map +1 -0
  99. package/dist/extract-sap-cookies.js.map +1 -1
  100. package/dist/handlers/activate.d.ts.map +1 -1
  101. package/dist/handlers/activate.js +44 -6
  102. package/dist/handlers/activate.js.map +1 -1
  103. package/dist/handlers/context.d.ts +1 -1
  104. package/dist/handlers/context.d.ts.map +1 -1
  105. package/dist/handlers/context.js +98 -28
  106. package/dist/handlers/context.js.map +1 -1
  107. package/dist/handlers/diagnose.d.ts.map +1 -1
  108. package/dist/handlers/diagnose.js +74 -31
  109. package/dist/handlers/diagnose.js.map +1 -1
  110. package/dist/handlers/dispatch.d.ts +12 -1
  111. package/dist/handlers/dispatch.d.ts.map +1 -1
  112. package/dist/handlers/dispatch.js +160 -25
  113. package/dist/handlers/dispatch.js.map +1 -1
  114. package/dist/handlers/feature-cache.d.ts +27 -14
  115. package/dist/handlers/feature-cache.d.ts.map +1 -1
  116. package/dist/handlers/feature-cache.js +63 -25
  117. package/dist/handlers/feature-cache.js.map +1 -1
  118. package/dist/handlers/function-processing.d.ts +61 -0
  119. package/dist/handlers/function-processing.d.ts.map +1 -0
  120. package/dist/handlers/function-processing.js +45 -0
  121. package/dist/handlers/function-processing.js.map +1 -0
  122. package/dist/handlers/git.d.ts.map +1 -1
  123. package/dist/handlers/git.js +44 -19
  124. package/dist/handlers/git.js.map +1 -1
  125. package/dist/handlers/hyperfocused.d.ts.map +1 -1
  126. package/dist/handlers/hyperfocused.js +2 -3
  127. package/dist/handlers/hyperfocused.js.map +1 -1
  128. package/dist/handlers/lint.d.ts.map +1 -1
  129. package/dist/handlers/lint.js +7 -7
  130. package/dist/handlers/lint.js.map +1 -1
  131. package/dist/handlers/manage.d.ts.map +1 -1
  132. package/dist/handlers/manage.js +47 -28
  133. package/dist/handlers/manage.js.map +1 -1
  134. package/dist/handlers/navigate.d.ts.map +1 -1
  135. package/dist/handlers/navigate.js +27 -90
  136. package/dist/handlers/navigate.js.map +1 -1
  137. package/dist/handlers/object-types.d.ts +2 -0
  138. package/dist/handlers/object-types.d.ts.map +1 -1
  139. package/dist/handlers/object-types.js +10 -0
  140. package/dist/handlers/object-types.js.map +1 -1
  141. package/dist/handlers/query-errors.d.ts +11 -0
  142. package/dist/handlers/query-errors.d.ts.map +1 -0
  143. package/dist/handlers/query-errors.js +216 -0
  144. package/dist/handlers/query-errors.js.map +1 -0
  145. package/dist/handlers/query.d.ts.map +1 -1
  146. package/dist/handlers/query.js +62 -67
  147. package/dist/handlers/query.js.map +1 -1
  148. package/dist/handlers/read.d.ts.map +1 -1
  149. package/dist/handlers/read.js +64 -41
  150. package/dist/handlers/read.js.map +1 -1
  151. package/dist/handlers/schemas.d.ts +285 -234
  152. package/dist/handlers/schemas.d.ts.map +1 -1
  153. package/dist/handlers/schemas.js +126 -32
  154. package/dist/handlers/schemas.js.map +1 -1
  155. package/dist/handlers/search.d.ts.map +1 -1
  156. package/dist/handlers/search.js +8 -7
  157. package/dist/handlers/search.js.map +1 -1
  158. package/dist/handlers/shared.d.ts +13 -0
  159. package/dist/handlers/shared.d.ts.map +1 -1
  160. package/dist/handlers/shared.js +15 -0
  161. package/dist/handlers/shared.js.map +1 -1
  162. package/dist/handlers/tool-descriptions.d.ts +4 -0
  163. package/dist/handlers/tool-descriptions.d.ts.map +1 -0
  164. package/dist/handlers/tool-descriptions.js +52 -0
  165. package/dist/handlers/tool-descriptions.js.map +1 -0
  166. package/dist/handlers/tool-registry.d.ts +20 -6
  167. package/dist/handlers/tool-registry.d.ts.map +1 -1
  168. package/dist/handlers/tool-registry.js +18 -0
  169. package/dist/handlers/tool-registry.js.map +1 -1
  170. package/dist/handlers/tools.d.ts.map +1 -1
  171. package/dist/handlers/tools.js +124 -92
  172. package/dist/handlers/tools.js.map +1 -1
  173. package/dist/handlers/transport.d.ts +1 -1
  174. package/dist/handlers/transport.d.ts.map +1 -1
  175. package/dist/handlers/transport.js +37 -10
  176. package/dist/handlers/transport.js.map +1 -1
  177. package/dist/handlers/where-used.d.ts +25 -0
  178. package/dist/handlers/where-used.d.ts.map +1 -0
  179. package/dist/handlers/where-used.js +94 -0
  180. package/dist/handlers/where-used.js.map +1 -0
  181. package/dist/handlers/write/class-surgery.d.ts.map +1 -1
  182. package/dist/handlers/write/class-surgery.js +11 -12
  183. package/dist/handlers/write/class-surgery.js.map +1 -1
  184. package/dist/handlers/write/create.d.ts.map +1 -1
  185. package/dist/handlers/write/create.js +194 -84
  186. package/dist/handlers/write/create.js.map +1 -1
  187. package/dist/handlers/write/rap.d.ts.map +1 -1
  188. package/dist/handlers/write/rap.js +9 -9
  189. package/dist/handlers/write/rap.js.map +1 -1
  190. package/dist/handlers/write/unit-surgery.d.ts +5 -0
  191. package/dist/handlers/write/unit-surgery.d.ts.map +1 -0
  192. package/dist/handlers/write/unit-surgery.js +47 -0
  193. package/dist/handlers/write/unit-surgery.js.map +1 -0
  194. package/dist/handlers/write/update-delete.js +8 -8
  195. package/dist/handlers/write/update-delete.js.map +1 -1
  196. package/dist/handlers/write-helpers.d.ts +7 -4
  197. package/dist/handlers/write-helpers.d.ts.map +1 -1
  198. package/dist/handlers/write-helpers.js +118 -63
  199. package/dist/handlers/write-helpers.js.map +1 -1
  200. package/dist/handlers/write.d.ts.map +1 -1
  201. package/dist/handlers/write.js +35 -13
  202. package/dist/handlers/write.js.map +1 -1
  203. package/dist/lint/config-builder.js.map +1 -1
  204. package/dist/lint/lint.d.ts.map +1 -1
  205. package/dist/lint/lint.js +4 -2
  206. package/dist/lint/lint.js.map +1 -1
  207. package/dist/probe/catalog.js +1 -1
  208. package/dist/probe/catalog.js.map +1 -1
  209. package/dist/public/testing.js.map +1 -1
  210. package/dist/public/ui/app.js +1 -14
  211. package/dist/registry/tool-registry.d.ts.map +1 -1
  212. package/dist/server/audit.d.ts +27 -15
  213. package/dist/server/audit.d.ts.map +1 -1
  214. package/dist/server/audit.js.map +1 -1
  215. package/dist/server/auth-rate-limit.d.ts +18 -9
  216. package/dist/server/auth-rate-limit.d.ts.map +1 -1
  217. package/dist/server/auth-rate-limit.js +31 -6
  218. package/dist/server/auth-rate-limit.js.map +1 -1
  219. package/dist/server/auth-summary.d.ts +4 -0
  220. package/dist/server/auth-summary.d.ts.map +1 -0
  221. package/dist/server/auth-summary.js +67 -0
  222. package/dist/server/auth-summary.js.map +1 -0
  223. package/dist/server/config.d.ts.map +1 -1
  224. package/dist/server/config.js +110 -7
  225. package/dist/server/config.js.map +1 -1
  226. package/dist/server/context.d.ts +12 -0
  227. package/dist/server/context.d.ts.map +1 -1
  228. package/dist/server/context.js.map +1 -1
  229. package/dist/server/destination-discovery.d.ts +36 -0
  230. package/dist/server/destination-discovery.d.ts.map +1 -0
  231. package/dist/server/destination-discovery.js +130 -0
  232. package/dist/server/destination-discovery.js.map +1 -0
  233. package/dist/server/destination-registry.d.ts +111 -0
  234. package/dist/server/destination-registry.d.ts.map +1 -0
  235. package/dist/server/destination-registry.js +449 -0
  236. package/dist/server/destination-registry.js.map +1 -0
  237. package/dist/server/http.d.ts +43 -1
  238. package/dist/server/http.d.ts.map +1 -1
  239. package/dist/server/http.js +283 -73
  240. package/dist/server/http.js.map +1 -1
  241. package/dist/server/logger.d.ts.map +1 -1
  242. package/dist/server/logger.js +58 -13
  243. package/dist/server/logger.js.map +1 -1
  244. package/dist/server/mcp-rate-limit.d.ts +6 -4
  245. package/dist/server/mcp-rate-limit.d.ts.map +1 -1
  246. package/dist/server/mcp-rate-limit.js +6 -4
  247. package/dist/server/mcp-rate-limit.js.map +1 -1
  248. package/dist/server/multi-target-basic-auth.d.ts +49 -0
  249. package/dist/server/multi-target-basic-auth.d.ts.map +1 -0
  250. package/dist/server/multi-target-basic-auth.js +246 -0
  251. package/dist/server/multi-target-basic-auth.js.map +1 -0
  252. package/dist/server/multi-target-catalog.d.ts +33 -0
  253. package/dist/server/multi-target-catalog.d.ts.map +1 -0
  254. package/dist/server/multi-target-catalog.js +130 -0
  255. package/dist/server/multi-target-catalog.js.map +1 -0
  256. package/dist/server/multi-target-destination-config.d.ts +12 -0
  257. package/dist/server/multi-target-destination-config.d.ts.map +1 -0
  258. package/dist/server/multi-target-destination-config.js +37 -0
  259. package/dist/server/multi-target-destination-config.js.map +1 -0
  260. package/dist/server/multi-target-destination-runtime.d.ts +20 -0
  261. package/dist/server/multi-target-destination-runtime.d.ts.map +1 -0
  262. package/dist/server/multi-target-destination-runtime.js +191 -0
  263. package/dist/server/multi-target-destination-runtime.js.map +1 -0
  264. package/dist/server/multi-target-feature-state.d.ts +6 -0
  265. package/dist/server/multi-target-feature-state.d.ts.map +1 -0
  266. package/dist/server/multi-target-feature-state.js +41 -0
  267. package/dist/server/multi-target-feature-state.js.map +1 -0
  268. package/dist/server/multi-target-identity.d.ts +10 -0
  269. package/dist/server/multi-target-identity.d.ts.map +1 -0
  270. package/dist/server/multi-target-identity.js +18 -0
  271. package/dist/server/multi-target-identity.js.map +1 -0
  272. package/dist/server/multi-target-runtime.d.ts +27 -0
  273. package/dist/server/multi-target-runtime.d.ts.map +1 -0
  274. package/dist/server/multi-target-runtime.js +110 -0
  275. package/dist/server/multi-target-runtime.js.map +1 -0
  276. package/dist/server/multi-target-server.d.ts +53 -0
  277. package/dist/server/multi-target-server.d.ts.map +1 -0
  278. package/dist/server/multi-target-server.js +434 -0
  279. package/dist/server/multi-target-server.js.map +1 -0
  280. package/dist/server/multi-target-shared-auth-state.d.ts +82 -0
  281. package/dist/server/multi-target-shared-auth-state.d.ts.map +1 -0
  282. package/dist/server/multi-target-shared-auth-state.js +226 -0
  283. package/dist/server/multi-target-shared-auth-state.js.map +1 -0
  284. package/dist/server/multi-target-tools.d.ts +20 -0
  285. package/dist/server/multi-target-tools.d.ts.map +1 -0
  286. package/dist/server/multi-target-tools.js +191 -0
  287. package/dist/server/multi-target-tools.js.map +1 -0
  288. package/dist/server/oauth-session-recovery.d.ts +22 -0
  289. package/dist/server/oauth-session-recovery.d.ts.map +1 -0
  290. package/dist/server/oauth-session-recovery.js +69 -0
  291. package/dist/server/oauth-session-recovery.js.map +1 -0
  292. package/dist/server/server.d.ts +47 -25
  293. package/dist/server/server.d.ts.map +1 -1
  294. package/dist/server/server.js +490 -301
  295. package/dist/server/server.js.map +1 -1
  296. package/dist/server/sinks/btp-auditlog.d.ts.map +1 -1
  297. package/dist/server/sinks/btp-auditlog.js +83 -11
  298. package/dist/server/sinks/btp-auditlog.js.map +1 -1
  299. package/dist/server/sinks/file.d.ts.map +1 -1
  300. package/dist/server/sinks/file.js.map +1 -1
  301. package/dist/server/sinks/stderr.d.ts.map +1 -1
  302. package/dist/server/sinks/stderr.js.map +1 -1
  303. package/dist/server/tool-auth.d.ts +10 -0
  304. package/dist/server/tool-auth.d.ts.map +1 -0
  305. package/dist/server/tool-auth.js +75 -0
  306. package/dist/server/tool-auth.js.map +1 -0
  307. package/dist/server/trace-context.d.ts +51 -0
  308. package/dist/server/trace-context.d.ts.map +1 -0
  309. package/dist/server/trace-context.js +100 -0
  310. package/dist/server/trace-context.js.map +1 -0
  311. package/dist/server/types.d.ts +28 -7
  312. package/dist/server/types.d.ts.map +1 -1
  313. package/dist/server/types.js +5 -2
  314. package/dist/server/types.js.map +1 -1
  315. package/dist/server/ui-log-buffer.d.ts.map +1 -1
  316. package/dist/server/ui-log-buffer.js.map +1 -1
  317. package/dist/server/ui-state.d.ts +0 -2
  318. package/dist/server/ui-state.d.ts.map +1 -1
  319. package/dist/server/ui-state.js +2 -6
  320. package/dist/server/ui-state.js.map +1 -1
  321. package/dist/server/ui.d.ts.map +1 -1
  322. package/dist/server/ui.js +8 -9
  323. package/dist/server/ui.js.map +1 -1
  324. package/package.json +21 -18
  325. package/dist/cache/warmup.d.ts +0 -41
  326. package/dist/cache/warmup.d.ts.map +0 -1
  327. package/dist/cache/warmup.js +0 -337
  328. package/dist/cache/warmup.js.map +0 -1
  329. package/dist/server/elicit.d.ts +0 -43
  330. package/dist/server/elicit.d.ts.map +0 -1
  331. package/dist/server/elicit.js +0 -183
  332. package/dist/server/elicit.js.map +0 -1
@@ -13,56 +13,149 @@ export interface SdoRegistryEntry {
13
13
  */
14
14
  createType: string;
15
15
  /**
16
- * blues content-type for BOTH the metadata GET (Accept) and the create POST (Content-Type).
17
- * NOT uniformly v1 — EVTO advertises/accepts v2. The supportsServerDrivenObject() gate matches
18
- * either via a `.includes('blues')` substring test, so it is version-agnostic.
16
+ * Metadata content-type for BOTH the metadata GET (Accept) and the create POST (Content-Type).
17
+ * Most types use `application/vnd.sap.adt.blues.vN+xml` (EVTO is v2, the rest v1); DTDC uses its
18
+ * own `application/vnd.sap.adt.ddic.dtdc.v1+xml`. Matched by `discoveryMarker` in the gate.
19
19
  */
20
- blueContentType: string;
20
+ metadataContentType: string;
21
+ /**
22
+ * Local name of the metadata root element AFTER the parser strips namespace prefixes
23
+ * (`removeNSPrefix: true`): `blueSource` for the blue family, `dtdcSource` for DTDC. Drives the
24
+ * parse path (`parseServerDrivenMetadata`).
25
+ */
26
+ metadataRootLocalName: string;
27
+ /**
28
+ * Qualified root element name + its namespace URI for the create body. Blue family:
29
+ * `blue:blueSource` / `http://www.sap.com/wbobj/blue`. DTDC: `dtdc:dtdcSource` /
30
+ * `http://www.sap.com/adt/ddic/dtdcsources`. Drives the build path.
31
+ */
32
+ metadataRootQName: string;
33
+ metadataNamespace: string;
34
+ /**
35
+ * Substring the discovery gate matches against the collection's advertised Accept type: `blues`
36
+ * for the blue family, `dtdc` for DTDC. Version-agnostic (matches v1/v2).
37
+ */
38
+ discoveryMarker: string;
39
+ /**
40
+ * Source flavor — drives BOTH the client-side validation and the PUT Content-Type. NOT uniform:
41
+ * the AFF-JSON types 415 on text/plain, and the DDL-text types (DTSC, DSFD, DTDC) 415 on
42
+ * application/json. Live-verified per type on 816.
43
+ */
44
+ sourceFormat: SdoSourceFormat;
21
45
  }
46
+ /** AFF JSON body vs plain DDL text. Required per entry — a wrong guess is a hard 415 from SAP. */
47
+ export type SdoSourceFormat = 'json' | 'text';
48
+ /** Content-Type for the source PUT, derived from the type's declared source flavor. */
49
+ export declare function serverDrivenSourceContentType(code: string): string;
50
+ /** Declared source flavor for a registered type (drives the client-side JSON parse gate). */
51
+ export declare function serverDrivenSourceFormat(code: string): SdoSourceFormat;
22
52
  /**
23
53
  * The registered server-driven type codes, in registry (= LLM tool-surface) order. The SAPRead/
24
54
  * SAPWrite rows in src/handlers/tool-registry.ts derive from this tuple, so registering a type
25
- * here is the ONLY step needed to expose it — `btp: true` by construction (every SDO type is
26
- * 8.16+, and runtime availability is discovery-gated per system anyway).
55
+ * here is the ONLY step needed to expose it — `btp: true` by construction (runtime availability is
56
+ * discovery-gated per system, so a type absent on a release degrades cleanly).
27
57
  */
28
- export declare const SDO_TYPES: readonly ["DESD", "DTSC", "CSNM", "EVTB", "EVTO", "COTA"];
29
- /** Curated registry of high-value 816 server-driven object types — keys are exactly SDO_TYPES. */
58
+ export declare const SDO_TYPES: readonly ['DESD', 'DTSC', 'CSNM', 'EVTB', 'EVTO', 'COTA', 'DSFD', 'DTDC', 'UIAD'];
59
+ /** Curated registry of high-value server-driven object types — keys are exactly SDO_TYPES. */
30
60
  export declare const SDO_REGISTRY: {
31
61
  DESD: {
62
+ metadataRootLocalName: 'blueSource';
63
+ metadataRootQName: 'blue:blueSource';
64
+ metadataNamespace: 'http://www.sap.com/wbobj/blue';
65
+ discoveryMarker: 'blues';
32
66
  href: string;
33
67
  label: string;
34
68
  createType: string;
35
- blueContentType: string;
69
+ metadataContentType: string;
70
+ sourceFormat: "json";
36
71
  };
37
72
  DTSC: {
73
+ metadataRootLocalName: 'blueSource';
74
+ metadataRootQName: 'blue:blueSource';
75
+ metadataNamespace: 'http://www.sap.com/wbobj/blue';
76
+ discoveryMarker: 'blues';
38
77
  href: string;
39
78
  label: string;
40
79
  createType: string;
41
- blueContentType: string;
80
+ metadataContentType: string;
81
+ sourceFormat: "text";
42
82
  };
43
83
  CSNM: {
84
+ metadataRootLocalName: 'blueSource';
85
+ metadataRootQName: 'blue:blueSource';
86
+ metadataNamespace: 'http://www.sap.com/wbobj/blue';
87
+ discoveryMarker: 'blues';
44
88
  href: string;
45
89
  label: string;
46
90
  createType: string;
47
- blueContentType: string;
91
+ metadataContentType: string;
92
+ sourceFormat: "json";
48
93
  };
49
94
  EVTB: {
95
+ metadataRootLocalName: 'blueSource';
96
+ metadataRootQName: 'blue:blueSource';
97
+ metadataNamespace: 'http://www.sap.com/wbobj/blue';
98
+ discoveryMarker: 'blues';
50
99
  href: string;
51
100
  label: string;
52
101
  createType: string;
53
- blueContentType: string;
102
+ metadataContentType: string;
103
+ sourceFormat: "json";
54
104
  };
55
105
  EVTO: {
106
+ metadataRootLocalName: 'blueSource';
107
+ metadataRootQName: 'blue:blueSource';
108
+ metadataNamespace: 'http://www.sap.com/wbobj/blue';
109
+ discoveryMarker: 'blues';
56
110
  href: string;
57
111
  label: string;
58
112
  createType: string;
59
- blueContentType: string;
113
+ metadataContentType: string;
114
+ sourceFormat: "json";
60
115
  };
61
116
  COTA: {
117
+ metadataRootLocalName: 'blueSource';
118
+ metadataRootQName: 'blue:blueSource';
119
+ metadataNamespace: 'http://www.sap.com/wbobj/blue';
120
+ discoveryMarker: 'blues';
121
+ href: string;
122
+ label: string;
123
+ createType: string;
124
+ metadataContentType: string;
125
+ sourceFormat: "json";
126
+ };
127
+ DSFD: {
128
+ metadataRootLocalName: 'blueSource';
129
+ metadataRootQName: 'blue:blueSource';
130
+ metadataNamespace: 'http://www.sap.com/wbobj/blue';
131
+ discoveryMarker: 'blues';
62
132
  href: string;
63
133
  label: string;
64
134
  createType: string;
65
- blueContentType: string;
135
+ metadataContentType: string;
136
+ sourceFormat: "text";
137
+ };
138
+ DTDC: {
139
+ href: string;
140
+ label: string;
141
+ createType: string;
142
+ metadataContentType: string;
143
+ metadataRootLocalName: string;
144
+ metadataRootQName: string;
145
+ metadataNamespace: string;
146
+ discoveryMarker: string;
147
+ sourceFormat: "text";
148
+ };
149
+ UIAD: {
150
+ metadataRootLocalName: 'blueSource';
151
+ metadataRootQName: 'blue:blueSource';
152
+ metadataNamespace: 'http://www.sap.com/wbobj/blue';
153
+ discoveryMarker: 'blues';
154
+ href: string;
155
+ label: string;
156
+ createType: string;
157
+ metadataContentType: string;
158
+ sourceFormat: "json";
66
159
  };
67
160
  };
68
161
  /** True when `code` is one of the registered server-driven object types. */
@@ -70,36 +163,61 @@ export declare function isServerDrivenObjectType(code: string): boolean;
70
163
  /** ADT object URL for a server-driven object: collection href + url-encoded name. */
71
164
  export declare function serverDrivenObjectUrl(code: string, name: string): string;
72
165
  /**
73
- * The blues content-type for a type — used as the metadata GET Accept (incl. package resolution,
74
- * where the <blue:blueSource> packageRef only renders under this Accept). Version-correct per type
75
- * (EVTO → v2). Throws AdtApiError for an unknown code.
166
+ * The metadata content-type for a type — used as the metadata GET Accept (incl. package resolution,
167
+ * where the metadata root's packageRef only renders under this Accept) and the create POST
168
+ * Content-Type. Per type (EVTO → blues v2, DTDC → its own dtdc type). Throws for an unknown code.
76
169
  */
77
- export declare function serverDrivenBlueContentType(code: string): string;
170
+ export declare function serverDrivenMetadataContentType(code: string): string;
78
171
  /**
79
- * Capability gate — true iff ADT discovery advertises the type's collection with the
80
- * server-driven `blues` accept (present on 8.16+, absent on 7.5x / 758). Returns undefined
81
- * when discovery has not been loaded (caller may attempt and let a 404 surface). Mirrors
82
- * supportsExplicitTransportTarget() / supportsCdsTestCases(). Version-agnostic: matches v1 and v2.
172
+ * Capability gate — true iff ADT discovery advertises the type's collection with its per-type
173
+ * metadata accept (the blue family's `blues`, DTDC's `dtdc`; present on the releases that ship the
174
+ * type, absent otherwise). Returns undefined when discovery has not been loaded (caller may attempt
175
+ * and let a 404 surface). Mirrors supportsExplicitTransportTarget() / supportsCdsTestCases().
176
+ * Version-agnostic: `discoveryMarker` is a substring, so it matches v1 and v2.
83
177
  */
84
178
  export declare function supportsServerDrivenObject(http: AdtHttpClient, code: string): boolean | undefined;
85
179
  /**
86
- * Read a server-driven object: its `<blue:blueSource>` metadata + AFF JSON source.
87
- * The source is JSON-parsed when possible (raw text otherwise). Throws AdtApiError 404 for a
88
- * nonexistent object. Gate availability with supportsServerDrivenObject() on unknown systems.
180
+ * Resolve SDO availability, fetching ADT discovery when it has not been loaded yet.
181
+ *
182
+ * The sync check returns `undefined` on a cold discovery map — which the CLI always is
183
+ * (`handleToolCall` runs without the startup probe). Callers that treated only an explicit `false`
184
+ * as "unavailable" therefore fell through to the request and surfaced a raw 404 with a "verify the
185
+ * name exists" hint, when in truth the object type does not exist on that release.
186
+ *
187
+ * `safety` is REQUIRED: fetchDiscoveryDocument issues an unguarded GET, and this runs inside a tool
188
+ * call, so it must pass the safety ceiling. Read is always permitted at that layer today, so this is
189
+ * a convention guard (and a real gate if a Read restriction is ever added), not an active control.
190
+ * The fetched map is used locally and deliberately NOT stored: server.ts re-injects the cached map
191
+ * before every tool call, and writing to the shared client would leak one user's capability view
192
+ * under the non-strict principal-propagation fallback.
193
+ *
194
+ * Still-unknown resolves to `true` (proceed): `hasDiscoveryData()` cannot tell "discovery
195
+ * unreachable" from "discovery empty", and failing closed would break every SDO read on a system
196
+ * where /sap/bc/adt/discovery is 403'd. This gate only improves the error message — the real
197
+ * controls are checkOperation and the package allowlist.
198
+ */
199
+ export declare function ensureServerDrivenSupport(http: AdtHttpClient, safety: SafetyConfig, code: string): Promise<boolean>;
200
+ /** Shared "this release does not have this type" message for the three SDO entry points. */
201
+ export declare function serverDrivenUnavailableMessage(tool: string, code: string): string;
202
+ /**
203
+ * Read a server-driven object: its metadata (blue:blueSource or dtdc:dtdcSource) + source (AFF JSON
204
+ * or DDL text). The source is JSON-parsed when possible (raw text otherwise). Throws AdtApiError 404
205
+ * for a nonexistent object. Gate availability with supportsServerDrivenObject() on unknown systems.
89
206
  */
90
207
  export declare function getServerDrivenObject(http: AdtHttpClient, safety: SafetyConfig, code: string, name: string): Promise<ServerDrivenObjectResult>;
91
208
  /**
92
- * Build the minimal `<blue:blueSource>` create body for a server-driven object. Uses the type's
93
- * verified `createType` for `adtcore:type` (e.g. DESD/TYP, EVTB/EVB) + the package ref.
209
+ * Build the minimal metadata create body for a server-driven object — the per-type root element
210
+ * (blue:blueSource or dtdc:dtdcSource) with the verified `createType` for `adtcore:type`
211
+ * (e.g. DESD/TYP, EVTB/EVB, DTDC/DF) + the package ref.
94
212
  *
95
213
  * NOTE — no `adtcore:masterLanguage`: live-verified on a4h-2025 (816) that ADT *silently ignores*
96
214
  * that attribute for these objects (create with masterLanguage="DE" → object still read back as the
97
215
  * session language). The object's master language comes from the `sap-language` request param (the
98
216
  * session = `config.language` / SAP_LANGUAGE), as with other source-based objects (cf. #343). Emitting
99
- * it would be an ADT-ignored attribute that's only ever been create-tested on DESD — so the body here
100
- * is exactly the form proven to create all 6 registered types.
217
+ * it would be an ADT-ignored attribute — so the body here is exactly the form proven to create every
218
+ * registered type.
101
219
  */
102
- export declare function buildBlueSourceXml(code: string, name: string, pkg: string, description: string): string;
220
+ export declare function buildServerDrivenMetadataXml(code: string, name: string, pkg: string, description: string): string;
103
221
  /** Options shared by the SDO write operations. */
104
222
  export interface ServerDrivenWriteOptions {
105
223
  transport?: string;
@@ -115,11 +233,13 @@ export declare function createServerDrivenObject(http: AdtHttpClient, safety: Sa
115
233
  transport?: string;
116
234
  }): Promise<string>;
117
235
  /**
118
- * Write the AFF JSON source of a server-driven object: lock → PUT …/source/main (application/json)
119
- * → unlock (guaranteed via try-finally). Auto-propagates the lock's corrNr when no explicit
120
- * transport is supplied (same contract as crud.ts safeUpdateSource).
236
+ * Write the source of a server-driven object: lock → PUT …/source/main → unlock (guaranteed via
237
+ * try-finally). The Content-Type comes from the type's declared sourceFormat — AFF-JSON types take
238
+ * application/json, DDL-text types (DTSC, DSFD) take text/plain; sending the wrong one is a 415.
239
+ * Auto-propagates the lock's corrNr when no explicit transport is supplied (same contract as
240
+ * crud.ts safeUpdateSource).
121
241
  */
122
- export declare function updateServerDrivenObjectSource(http: AdtHttpClient, safety: SafetyConfig, code: string, name: string, sourceJson: string, opts?: ServerDrivenWriteOptions): Promise<void>;
242
+ export declare function updateServerDrivenObjectSource(http: AdtHttpClient, safety: SafetyConfig, code: string, name: string, source: string, opts?: ServerDrivenWriteOptions): Promise<void>;
123
243
  /**
124
244
  * Delete a server-driven object: lock → http.delete(…?lockHandle=…) → best-effort unlock.
125
245
  * The unlock is swallowed on failure (the object is already gone after the delete).
@@ -1 +1 @@
1
- {"version":3,"file":"server-driven.d.ts","sourceRoot":"","sources":["../../src/adt/server-driven.ts"],"names":[],"mappings":"AAwBA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC/C,OAAO,EAAiC,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC;AAC/E,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AAG3D,8DAA8D;AAC9D,MAAM,WAAW,gBAAgB;IAC/B,iEAAiE;IACjE,IAAI,EAAE,MAAM,CAAC;IACb,4BAA4B;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,UAAU,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,eAAe,EAAE,MAAM,CAAC;CACzB;AAOD;;;;;GAKG;AACH,eAAO,MAAM,SAAS,2DAA4D,CAAC;AAEnF,kGAAkG;AAClG,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqCuC,CAAC;AAMjE,4EAA4E;AAC5E,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE9D;AASD,qFAAqF;AACrF,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAExE;AAED;;;;GAIG;AACH,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEhE;AAED;;;;;GAKG;AACH,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS,CAKjG;AAED;;;;GAIG;AACH,wBAAsB,qBAAqB,CACzC,IAAI,EAAE,aAAa,EACnB,MAAM,EAAE,YAAY,EACpB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,wBAAwB,CAAC,CAgBnC;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAMvG;AAED,kDAAkD;AAClD,MAAM,WAAW,wBAAwB;IACvC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;GAIG;AACH,wBAAsB,wBAAwB,CAC5C,IAAI,EAAE,aAAa,EACnB,MAAM,EAAE,YAAY,EACpB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GACjE,OAAO,CAAC,MAAM,CAAC,CAOjB;AAED;;;;GAIG;AACH,wBAAsB,8BAA8B,CAClD,IAAI,EAAE,aAAa,EACnB,MAAM,EAAE,YAAY,EACpB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,MAAM,EAClB,IAAI,GAAE,wBAA6B,GAClC,OAAO,CAAC,IAAI,CAAC,CAcf;AAED;;;GAGG;AACH,wBAAsB,wBAAwB,CAC5C,IAAI,EAAE,aAAa,EACnB,MAAM,EAAE,YAAY,EACpB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,IAAI,GAAE,wBAA6B,GAClC,OAAO,CAAC,IAAI,CAAC,CAkBf"}
1
+ {"version":3,"file":"server-driven.d.ts","sourceRoot":"","sources":["../../src/adt/server-driven.ts"],"names":[],"mappings":"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"}
@@ -1,77 +1,156 @@
1
1
  /**
2
- * Generic "server-driven object" (SDO) read/write path for ABAP Platform 2025 (SAP_BASIS 8.16+).
2
+ * Generic "server-driven object" (SDO) read/write path. Most SDO types need ABAP Platform 2025
3
+ * (SAP_BASIS 8.16+), but some (DTDC, DSFD, EVTB) also ship on S/4HANA 2023 (758) — availability is
4
+ * discovery-gated per type, never a hardcoded release.
3
5
  *
4
- * 816 introduced ~46 repository object types that all share ONE AFF generic-object contract:
5
- * - metadata: GET …/{name} (Accept application/vnd.sap.adt.blues.vN+xml) → <blue:blueSource>
6
- * - content : GET …/{name}/source/main → AFF JSON
6
+ * These repository object types share ONE AFF generic-object contract:
7
+ * - metadata: GET …/{name} (Accept = per-type metadataContentType) → <blue:blueSource> or <dtdc:dtdcSource>
8
+ * - content : GET …/{name}/source/main → AFF JSON *or* DDL text
7
9
  * Rather than per-type plumbing, this module exposes a curated registry of high-value types
8
10
  * and ONE generic engine, discovery-gated so pre-8.16 systems degrade cleanly.
9
11
  *
10
12
  * WRITE (create/update-source/delete) is supported and reuses the verified machinery:
11
- * - CREATE = POST <collection-href> (Content-Type = the type's blues.vN+xml) with a minimal
12
- * <blue:blueSource> body (adtcore:type/name/description + packageRef) → 201.
13
- * - SOURCE = lock (crud.ts) → PUT <url>/source/main?lockHandle=… (Content-Type application/json,
14
- * the AFF JSON body) → unlock.
13
+ * - CREATE = POST <collection-href> (Content-Type = the type's metadataContentType) with a minimal
14
+ * metadata body (blue:blueSource / dtdc:dtdcSource; adtcore:type/name/description + packageRef) → 201.
15
+ * - SOURCE = lock (crud.ts) → PUT <url>/source/main?lockHandle=… → unlock. The Content-Type is
16
+ * per-type (registry `sourceFormat`): application/json for the AFF-JSON types,
17
+ * text/plain for the DDL-text ones (DTSC, DSFD, DTDC). The wrong one is a hard 415.
15
18
  * - DELETE = lock → http.delete(<url>?lockHandle=…) → unlock.
16
19
  * - ACTIVATE is the generic devtools activate() against the object URL (callers use SAPActivate).
17
20
  * Create leaves the object inactive — callers follow with SAPActivate (never auto-activated).
18
21
  *
19
- * The create `adtcore:type` subtype is NOT uniformly "<code>/TYP" (EVTB uses EVTB/EVB) and the
20
- * blues content-type is NOT uniformly v1 (EVTO uses v2) — both are stored per registry entry,
21
- * verified live on a4h-2025 (816): DESD/DTSC/CSNM/EVTB/COTA create with blues.v1, EVTO with blues.v2.
22
+ * The create `adtcore:type` subtype is NOT uniformly "<code>/TYP" (EVTB=EVTB/EVB, DTDC=DTDC/DF) and
23
+ * the metadata content-type varies (blues v1, EVTO=blues v2, DTDC=ddic.dtdc.v1) — all stored per
24
+ * registry entry, verified live: the blue family on 816, DTDC create→activate on 758 + 816.
22
25
  */
23
26
  import { lockObject, unlockObject } from './crud.js';
27
+ import { fetchDiscoveryDocument, resolveAcceptType } from './discovery.js';
24
28
  import { AdtApiError } from './errors.js';
25
29
  import { checkOperation, OperationType } from './safety.js';
26
- import { escapeXmlAttr, parseBlueSource } from './xml-parser.js';
30
+ import { escapeXmlAttr, parseServerDrivenMetadata } from './xml-parser.js';
31
+ /**
32
+ * Shared metadata-format fields for the "blue" family (DESD/DTSC/CSNM/EVTB/EVTO/COTA/DSFD) — every
33
+ * blue type has the identical root element/namespace/discovery marker; only its content-type version
34
+ * (v1/v2) and source flavor differ. Spread into each blue entry so the shape can't drift.
35
+ */
36
+ const BLUE_METADATA = {
37
+ metadataRootLocalName: 'blueSource',
38
+ metadataRootQName: 'blue:blueSource',
39
+ metadataNamespace: 'http://www.sap.com/wbobj/blue',
40
+ discoveryMarker: 'blues',
41
+ };
27
42
  const BLUES_V1 = 'application/vnd.sap.adt.blues.v1+xml';
28
43
  const BLUES_V2 = 'application/vnd.sap.adt.blues.v2+xml';
29
- /** AFF source is JSON for every server-driven type (read GET + write PUT). */
30
- const SDO_SOURCE_CONTENT_TYPE = 'application/json';
44
+ /** Content-Type for the source PUT, derived from the type's declared source flavor. */
45
+ export function serverDrivenSourceContentType(code) {
46
+ const format = sdoEntry(code).sourceFormat;
47
+ switch (format) {
48
+ case 'json':
49
+ return 'application/json';
50
+ case 'text':
51
+ return 'text/plain';
52
+ default: {
53
+ // A new SdoSourceFormat must map to a content type here — falling through would only
54
+ // surface as a live 415. Exhaustiveness is a compile error, not a runtime surprise.
55
+ const unhandled = format;
56
+ throw new AdtApiError(`Unhandled server-driven source format "${String(unhandled)}".`, 500, '');
57
+ }
58
+ }
59
+ }
60
+ /** Declared source flavor for a registered type (drives the client-side JSON parse gate). */
61
+ export function serverDrivenSourceFormat(code) {
62
+ return sdoEntry(code).sourceFormat;
63
+ }
31
64
  /**
32
65
  * The registered server-driven type codes, in registry (= LLM tool-surface) order. The SAPRead/
33
66
  * SAPWrite rows in src/handlers/tool-registry.ts derive from this tuple, so registering a type
34
- * here is the ONLY step needed to expose it — `btp: true` by construction (every SDO type is
35
- * 8.16+, and runtime availability is discovery-gated per system anyway).
67
+ * here is the ONLY step needed to expose it — `btp: true` by construction (runtime availability is
68
+ * discovery-gated per system, so a type absent on a release degrades cleanly).
36
69
  */
37
- export const SDO_TYPES = ['DESD', 'DTSC', 'CSNM', 'EVTB', 'EVTO', 'COTA'];
38
- /** Curated registry of high-value 816 server-driven object types — keys are exactly SDO_TYPES. */
70
+ export const SDO_TYPES = ['DESD', 'DTSC', 'CSNM', 'EVTB', 'EVTO', 'COTA', 'DSFD', 'DTDC', 'UIAD'];
71
+ /** Curated registry of high-value server-driven object types — keys are exactly SDO_TYPES. */
39
72
  export const SDO_REGISTRY = {
40
73
  DESD: {
41
74
  href: '/sap/bc/adt/ddic/desd',
42
75
  label: 'CDS Logical External Schema',
43
76
  createType: 'DESD/TYP',
44
- blueContentType: BLUES_V1,
77
+ metadataContentType: BLUES_V1,
78
+ ...BLUE_METADATA,
79
+ sourceFormat: 'json',
45
80
  },
46
81
  DTSC: {
47
82
  href: '/sap/bc/adt/ddic/dtsc/sources',
48
83
  label: 'CDS Static Cache (table-entity buffer)',
49
84
  createType: 'DTSC/TYP',
50
- blueContentType: BLUES_V1,
85
+ metadataContentType: BLUES_V1,
86
+ ...BLUE_METADATA,
87
+ sourceFormat: 'text',
51
88
  },
52
89
  CSNM: {
53
90
  href: '/sap/bc/adt/csn/csnm',
54
91
  label: 'Core Schema Notation Model (CSN)',
55
92
  createType: 'CSNM/TYP',
56
- blueContentType: BLUES_V1,
93
+ metadataContentType: BLUES_V1,
94
+ ...BLUE_METADATA,
95
+ sourceFormat: 'json',
57
96
  },
58
97
  EVTB: {
59
98
  href: '/sap/bc/adt/businessservices/evtbevb',
60
99
  label: 'RAP Event Binding',
61
100
  createType: 'EVTB/EVB',
62
- blueContentType: BLUES_V1,
101
+ metadataContentType: BLUES_V1,
102
+ ...BLUE_METADATA,
103
+ sourceFormat: 'json',
63
104
  },
64
105
  EVTO: {
65
106
  href: '/sap/bc/adt/businessservices/evtoevo',
66
107
  label: 'RAP Event Object',
67
108
  createType: 'EVTO/EVO',
68
- blueContentType: BLUES_V2,
109
+ metadataContentType: BLUES_V2,
110
+ ...BLUE_METADATA,
111
+ sourceFormat: 'json',
69
112
  },
70
113
  COTA: {
71
114
  href: '/sap/bc/adt/conn/commtargets',
72
115
  label: 'Communication Target',
73
116
  createType: 'COTA/TYP',
74
- blueContentType: BLUES_V1,
117
+ metadataContentType: BLUES_V1,
118
+ ...BLUE_METADATA,
119
+ sourceFormat: 'json',
120
+ },
121
+ DSFD: {
122
+ href: '/sap/bc/adt/ddic/dsfd/sources',
123
+ label: 'CDS Scalar Function Definition',
124
+ createType: 'DSFD/SCF',
125
+ metadataContentType: BLUES_V1,
126
+ ...BLUE_METADATA,
127
+ sourceFormat: 'text',
128
+ },
129
+ // DTDC is the first NON-blue server-driven type: its own metadata format (<dtdc:dtdcSource> +
130
+ // application/vnd.sap.adt.ddic.dtdc.v1+xml), DDL-text source. Available on 758 + 816.
131
+ DTDC: {
132
+ href: '/sap/bc/adt/ddic/dtdc/sources',
133
+ label: 'CDS Dynamic Cache',
134
+ createType: 'DTDC/DF',
135
+ metadataContentType: 'application/vnd.sap.adt.ddic.dtdc.v1+xml',
136
+ metadataRootLocalName: 'dtdcSource',
137
+ metadataRootQName: 'dtdc:dtdcSource',
138
+ metadataNamespace: 'http://www.sap.com/adt/ddic/dtdcsources',
139
+ discoveryMarker: 'dtdc',
140
+ sourceFormat: 'text',
141
+ },
142
+ // Launchpad content: the LADI replaces the deprecated tile/target-mapping model and is the
143
+ // developer-owned unit on ABAP Cloud. blues.v2 (v1 -> 406, verified on 816).
144
+ // Read-only in practice on on-prem: create -> 400 'Editing of LADIs with ALV "Standard" not
145
+ // allowed in workbench tools' (LADI edits need the ABAP Cloud language version). SAP's refusal is
146
+ // clear and also covers read-only manifest-generated items, so no client-side guard.
147
+ UIAD: {
148
+ href: '/sap/bc/adt/fiori/uiad',
149
+ label: 'Launchpad App Descriptor Item (LADI)',
150
+ createType: 'UIAD/TYP',
151
+ metadataContentType: BLUES_V2,
152
+ ...BLUE_METADATA,
153
+ sourceFormat: 'json',
75
154
  },
76
155
  };
77
156
  // String-indexed view of the registry for the unknown-code lookups below (the satisfies-typed
@@ -93,18 +172,19 @@ export function serverDrivenObjectUrl(code, name) {
93
172
  return `${sdoEntry(code).href}/${encodeURIComponent(name)}`;
94
173
  }
95
174
  /**
96
- * The blues content-type for a type — used as the metadata GET Accept (incl. package resolution,
97
- * where the <blue:blueSource> packageRef only renders under this Accept). Version-correct per type
98
- * (EVTO → v2). Throws AdtApiError for an unknown code.
175
+ * The metadata content-type for a type — used as the metadata GET Accept (incl. package resolution,
176
+ * where the metadata root's packageRef only renders under this Accept) and the create POST
177
+ * Content-Type. Per type (EVTO → blues v2, DTDC → its own dtdc type). Throws for an unknown code.
99
178
  */
100
- export function serverDrivenBlueContentType(code) {
101
- return sdoEntry(code).blueContentType;
179
+ export function serverDrivenMetadataContentType(code) {
180
+ return sdoEntry(code).metadataContentType;
102
181
  }
103
182
  /**
104
- * Capability gate — true iff ADT discovery advertises the type's collection with the
105
- * server-driven `blues` accept (present on 8.16+, absent on 7.5x / 758). Returns undefined
106
- * when discovery has not been loaded (caller may attempt and let a 404 surface). Mirrors
107
- * supportsExplicitTransportTarget() / supportsCdsTestCases(). Version-agnostic: matches v1 and v2.
183
+ * Capability gate — true iff ADT discovery advertises the type's collection with its per-type
184
+ * metadata accept (the blue family's `blues`, DTDC's `dtdc`; present on the releases that ship the
185
+ * type, absent otherwise). Returns undefined when discovery has not been loaded (caller may attempt
186
+ * and let a 404 surface). Mirrors supportsExplicitTransportTarget() / supportsCdsTestCases().
187
+ * Version-agnostic: `discoveryMarker` is a substring, so it matches v1 and v2.
108
188
  */
109
189
  export function supportsServerDrivenObject(http, code) {
110
190
  const entry = REGISTRY_BY_CODE[code];
@@ -112,19 +192,60 @@ export function supportsServerDrivenObject(http, code) {
112
192
  return false;
113
193
  if (!http.hasDiscoveryData())
114
194
  return undefined;
115
- return (http.discoveryAcceptFor(entry.href) ?? '').includes('blues');
195
+ return (http.discoveryAcceptFor(entry.href) ?? '').includes(entry.discoveryMarker);
196
+ }
197
+ /**
198
+ * Resolve SDO availability, fetching ADT discovery when it has not been loaded yet.
199
+ *
200
+ * The sync check returns `undefined` on a cold discovery map — which the CLI always is
201
+ * (`handleToolCall` runs without the startup probe). Callers that treated only an explicit `false`
202
+ * as "unavailable" therefore fell through to the request and surfaced a raw 404 with a "verify the
203
+ * name exists" hint, when in truth the object type does not exist on that release.
204
+ *
205
+ * `safety` is REQUIRED: fetchDiscoveryDocument issues an unguarded GET, and this runs inside a tool
206
+ * call, so it must pass the safety ceiling. Read is always permitted at that layer today, so this is
207
+ * a convention guard (and a real gate if a Read restriction is ever added), not an active control.
208
+ * The fetched map is used locally and deliberately NOT stored: server.ts re-injects the cached map
209
+ * before every tool call, and writing to the shared client would leak one user's capability view
210
+ * under the non-strict principal-propagation fallback.
211
+ *
212
+ * Still-unknown resolves to `true` (proceed): `hasDiscoveryData()` cannot tell "discovery
213
+ * unreachable" from "discovery empty", and failing closed would break every SDO read on a system
214
+ * where /sap/bc/adt/discovery is 403'd. This gate only improves the error message — the real
215
+ * controls are checkOperation and the package allowlist.
216
+ */
217
+ export async function ensureServerDrivenSupport(http, safety, code) {
218
+ const known = supportsServerDrivenObject(http, code);
219
+ if (known !== undefined)
220
+ return known;
221
+ const entry = REGISTRY_BY_CODE[code];
222
+ if (!entry)
223
+ return false;
224
+ checkOperation(safety, OperationType.Read, 'FetchDiscovery');
225
+ const { map } = await fetchDiscoveryDocument(http); // never throws
226
+ // Empty map = discovery unreachable, NOT "collection absent" — those must not collapse together,
227
+ // or a 403'd discovery would block every SDO read. A populated map lacking the href IS unsupported.
228
+ if (map.size === 0)
229
+ return true;
230
+ return (resolveAcceptType(map, entry.href) ?? '').includes(entry.discoveryMarker);
231
+ }
232
+ /** Shared "this release does not have this type" message for the three SDO entry points. */
233
+ export function serverDrivenUnavailableMessage(tool, code) {
234
+ return (`${tool} type=${code} (server-driven object): this system does not advertise ADT support for it. ` +
235
+ 'These types are discovery-gated and depend on the SAP release / support package ' +
236
+ '(e.g. DTSC/CSNM/EVTO/UIAD need ABAP Platform 2025 / SAP_BASIS 8.16+, while DTDC/DSFD/EVTB also ship on S/4HANA 2023 / 758).');
116
237
  }
117
238
  /**
118
- * Read a server-driven object: its `<blue:blueSource>` metadata + AFF JSON source.
119
- * The source is JSON-parsed when possible (raw text otherwise). Throws AdtApiError 404 for a
120
- * nonexistent object. Gate availability with supportsServerDrivenObject() on unknown systems.
239
+ * Read a server-driven object: its metadata (blue:blueSource or dtdc:dtdcSource) + source (AFF JSON
240
+ * or DDL text). The source is JSON-parsed when possible (raw text otherwise). Throws AdtApiError 404
241
+ * for a nonexistent object. Gate availability with supportsServerDrivenObject() on unknown systems.
121
242
  */
122
243
  export async function getServerDrivenObject(http, safety, code, name) {
123
244
  checkOperation(safety, OperationType.Read, 'GetServerDrivenObject');
124
245
  const entry = sdoEntry(code);
125
246
  const objUrl = serverDrivenObjectUrl(code, name);
126
- const metaResp = await http.get(objUrl, { Accept: entry.blueContentType });
127
- const metadata = parseBlueSource(metaResp.body);
247
+ const metaResp = await http.get(objUrl, { Accept: entry.metadataContentType });
248
+ const metadata = parseServerDrivenMetadata(metaResp.body, entry.metadataRootLocalName);
128
249
  const srcResp = await http.get(`${objUrl}/source/main`, { Accept: 'application/json, */*' });
129
250
  let source = srcResp.body;
130
251
  try {
@@ -136,22 +257,24 @@ export async function getServerDrivenObject(http, safety, code, name) {
136
257
  return { ...metadata, source };
137
258
  }
138
259
  /**
139
- * Build the minimal `<blue:blueSource>` create body for a server-driven object. Uses the type's
140
- * verified `createType` for `adtcore:type` (e.g. DESD/TYP, EVTB/EVB) + the package ref.
260
+ * Build the minimal metadata create body for a server-driven object — the per-type root element
261
+ * (blue:blueSource or dtdc:dtdcSource) with the verified `createType` for `adtcore:type`
262
+ * (e.g. DESD/TYP, EVTB/EVB, DTDC/DF) + the package ref.
141
263
  *
142
264
  * NOTE — no `adtcore:masterLanguage`: live-verified on a4h-2025 (816) that ADT *silently ignores*
143
265
  * that attribute for these objects (create with masterLanguage="DE" → object still read back as the
144
266
  * session language). The object's master language comes from the `sap-language` request param (the
145
267
  * session = `config.language` / SAP_LANGUAGE), as with other source-based objects (cf. #343). Emitting
146
- * it would be an ADT-ignored attribute that's only ever been create-tested on DESD — so the body here
147
- * is exactly the form proven to create all 6 registered types.
268
+ * it would be an ADT-ignored attribute — so the body here is exactly the form proven to create every
269
+ * registered type.
148
270
  */
149
- export function buildBlueSourceXml(code, name, pkg, description) {
271
+ export function buildServerDrivenMetadataXml(code, name, pkg, description) {
150
272
  const entry = sdoEntry(code);
273
+ const [prefix] = entry.metadataRootQName.split(':');
151
274
  return `<?xml version="1.0" encoding="UTF-8"?>
152
- <blue:blueSource xmlns:blue="http://www.sap.com/wbobj/blue" xmlns:adtcore="http://www.sap.com/adt/core" adtcore:type="${escapeXmlAttr(entry.createType)}" adtcore:name="${escapeXmlAttr(name)}" adtcore:description="${escapeXmlAttr(description)}">
275
+ <${entry.metadataRootQName} xmlns:${prefix}="${entry.metadataNamespace}" xmlns:adtcore="http://www.sap.com/adt/core" adtcore:type="${escapeXmlAttr(entry.createType)}" adtcore:name="${escapeXmlAttr(name)}" adtcore:description="${escapeXmlAttr(description)}">
153
276
  <adtcore:packageRef adtcore:name="${escapeXmlAttr(pkg)}"/>
154
- </blue:blueSource>`;
277
+ </${entry.metadataRootQName}>`;
155
278
  }
156
279
  /**
157
280
  * Create a server-driven object (metadata only — POST the <blue:blueSource> body to the collection
@@ -161,17 +284,19 @@ export function buildBlueSourceXml(code, name, pkg, description) {
161
284
  export async function createServerDrivenObject(http, safety, code, name, opts) {
162
285
  checkOperation(safety, OperationType.Create, 'CreateServerDrivenObject');
163
286
  const entry = sdoEntry(code);
164
- const body = buildBlueSourceXml(code, name, opts.package, opts.description);
287
+ const body = buildServerDrivenMetadataXml(code, name, opts.package, opts.description);
165
288
  const url = opts.transport ? `${entry.href}?corrNr=${encodeURIComponent(opts.transport)}` : entry.href;
166
- const resp = await http.post(url, body, entry.blueContentType);
289
+ const resp = await http.post(url, body, entry.metadataContentType);
167
290
  return resp.body;
168
291
  }
169
292
  /**
170
- * Write the AFF JSON source of a server-driven object: lock → PUT …/source/main (application/json)
171
- * → unlock (guaranteed via try-finally). Auto-propagates the lock's corrNr when no explicit
172
- * transport is supplied (same contract as crud.ts safeUpdateSource).
293
+ * Write the source of a server-driven object: lock → PUT …/source/main → unlock (guaranteed via
294
+ * try-finally). The Content-Type comes from the type's declared sourceFormat — AFF-JSON types take
295
+ * application/json, DDL-text types (DTSC, DSFD) take text/plain; sending the wrong one is a 415.
296
+ * Auto-propagates the lock's corrNr when no explicit transport is supplied (same contract as
297
+ * crud.ts safeUpdateSource).
173
298
  */
174
- export async function updateServerDrivenObjectSource(http, safety, code, name, sourceJson, opts = {}) {
299
+ export async function updateServerDrivenObjectSource(http, safety, code, name, source, opts = {}) {
175
300
  checkOperation(safety, OperationType.Update, 'UpdateServerDrivenObjectSource');
176
301
  const objUrl = serverDrivenObjectUrl(code, name);
177
302
  await http.withStatefulSession(async (session) => {
@@ -181,7 +306,7 @@ export async function updateServerDrivenObjectSource(http, safety, code, name, s
181
306
  const params = [`lockHandle=${encodeURIComponent(lock.lockHandle)}`];
182
307
  if (transport)
183
308
  params.push(`corrNr=${encodeURIComponent(transport)}`);
184
- await session.put(`${objUrl}/source/main?${params.join('&')}`, sourceJson, SDO_SOURCE_CONTENT_TYPE);
309
+ await session.put(`${objUrl}/source/main?${params.join('&')}`, source, serverDrivenSourceContentType(code));
185
310
  }
186
311
  finally {
187
312
  await unlockObject(session, objUrl, lock.lockHandle);