arc-1 1.5.2 → 1.7.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.
- package/README.md +26 -16
- package/bin/arc1-source.js +83 -0
- package/dist/adt/accept-fallback.d.ts +4 -0
- package/dist/adt/accept-fallback.d.ts.map +1 -0
- package/dist/adt/accept-fallback.js +27 -0
- package/dist/adt/accept-fallback.js.map +1 -0
- package/dist/adt/api-release.d.ts +40 -0
- package/dist/adt/api-release.d.ts.map +1 -0
- package/dist/adt/api-release.js +224 -0
- package/dist/adt/api-release.js.map +1 -0
- package/dist/adt/application-log.d.ts +36 -0
- package/dist/adt/application-log.d.ts.map +1 -0
- package/dist/adt/application-log.js +143 -0
- package/dist/adt/application-log.js.map +1 -0
- package/dist/adt/authorization-trace.d.ts.map +1 -1
- package/dist/adt/authorization-trace.js +2 -1
- package/dist/adt/authorization-trace.js.map +1 -1
- package/dist/adt/class-structure.d.ts +2 -1
- package/dist/adt/class-structure.d.ts.map +1 -1
- package/dist/adt/class-structure.js +28 -10
- package/dist/adt/class-structure.js.map +1 -1
- package/dist/adt/client.d.ts +12 -6
- package/dist/adt/client.d.ts.map +1 -1
- package/dist/adt/client.js +32 -49
- package/dist/adt/client.js.map +1 -1
- package/dist/adt/codeintel.d.ts +9 -23
- package/dist/adt/codeintel.d.ts.map +1 -1
- package/dist/adt/codeintel.js +14 -34
- package/dist/adt/codeintel.js.map +1 -1
- package/dist/adt/ddic-xml.d.ts +5 -3
- package/dist/adt/ddic-xml.d.ts.map +1 -1
- package/dist/adt/ddic-xml.js +14 -0
- package/dist/adt/ddic-xml.js.map +1 -1
- package/dist/adt/devtools.d.ts +8 -1
- package/dist/adt/devtools.d.ts.map +1 -1
- package/dist/adt/devtools.js +94 -40
- package/dist/adt/devtools.js.map +1 -1
- package/dist/adt/diagnostics.d.ts +2 -0
- package/dist/adt/diagnostics.d.ts.map +1 -1
- package/dist/adt/diagnostics.js +10 -8
- package/dist/adt/diagnostics.js.map +1 -1
- package/dist/adt/enhancement-impl.d.ts +125 -0
- package/dist/adt/enhancement-impl.d.ts.map +1 -0
- package/dist/adt/enhancement-impl.js +408 -0
- package/dist/adt/enhancement-impl.js.map +1 -0
- package/dist/adt/enhancements.d.ts.map +1 -1
- package/dist/adt/enhancements.js +4 -2
- package/dist/adt/enhancements.js.map +1 -1
- package/dist/adt/enho-filter.d.ts +49 -0
- package/dist/adt/enho-filter.d.ts.map +1 -0
- package/dist/adt/enho-filter.js +229 -0
- package/dist/adt/enho-filter.js.map +1 -0
- package/dist/adt/errors.d.ts +5 -1
- package/dist/adt/errors.d.ts.map +1 -1
- package/dist/adt/errors.js +32 -8
- package/dist/adt/errors.js.map +1 -1
- package/dist/adt/features.d.ts +3 -9
- package/dist/adt/features.d.ts.map +1 -1
- package/dist/adt/features.js +24 -8
- package/dist/adt/features.js.map +1 -1
- package/dist/adt/feed-schema.d.ts +32 -0
- package/dist/adt/feed-schema.d.ts.map +1 -0
- package/dist/adt/feed-schema.js +123 -0
- package/dist/adt/feed-schema.js.map +1 -0
- package/dist/adt/fm-parameter-docs.d.ts +7 -0
- package/dist/adt/fm-parameter-docs.d.ts.map +1 -0
- package/dist/adt/fm-parameter-docs.js +134 -0
- package/dist/adt/fm-parameter-docs.js.map +1 -0
- package/dist/adt/fm-signature.d.ts +8 -1
- package/dist/adt/fm-signature.d.ts.map +1 -1
- package/dist/adt/fm-signature.js +37 -28
- package/dist/adt/fm-signature.js.map +1 -1
- package/dist/adt/http-deadline.d.ts.map +1 -1
- package/dist/adt/http-deadline.js +4 -1
- package/dist/adt/http-deadline.js.map +1 -1
- package/dist/adt/http-retry-after.d.ts +20 -0
- package/dist/adt/http-retry-after.d.ts.map +1 -0
- package/dist/adt/http-retry-after.js +37 -0
- package/dist/adt/http-retry-after.js.map +1 -0
- package/dist/adt/http.d.ts +7 -20
- package/dist/adt/http.d.ts.map +1 -1
- package/dist/adt/http.js +112 -135
- package/dist/adt/http.js.map +1 -1
- package/dist/adt/include-expansion.d.ts +143 -0
- package/dist/adt/include-expansion.d.ts.map +1 -0
- package/dist/adt/include-expansion.js +475 -0
- package/dist/adt/include-expansion.js.map +1 -0
- package/dist/adt/internal-data-operations.d.ts +3 -3
- package/dist/adt/internal-data-operations.d.ts.map +1 -1
- package/dist/adt/internal-data-operations.js +9 -2
- package/dist/adt/internal-data-operations.js.map +1 -1
- package/dist/adt/legacy-content-handler.d.ts +2 -0
- package/dist/adt/legacy-content-handler.d.ts.map +1 -1
- package/dist/adt/legacy-content-handler.js +13 -1
- package/dist/adt/legacy-content-handler.js.map +1 -1
- package/dist/adt/package-contents.d.ts +5 -0
- package/dist/adt/package-contents.d.ts.map +1 -1
- package/dist/adt/package-contents.js +31 -0
- package/dist/adt/package-contents.js.map +1 -1
- package/dist/adt/rap-generate.d.ts +2 -4
- package/dist/adt/rap-generate.d.ts.map +1 -1
- package/dist/adt/rap-generate.js +2 -4
- package/dist/adt/rap-generate.js.map +1 -1
- package/dist/adt/revision-feed.d.ts +8 -0
- package/dist/adt/revision-feed.d.ts.map +1 -0
- package/dist/adt/revision-feed.js +108 -0
- package/dist/adt/revision-feed.js.map +1 -0
- package/dist/adt/security-session-gate.d.ts +23 -0
- package/dist/adt/security-session-gate.d.ts.map +1 -0
- package/dist/adt/security-session-gate.js +56 -0
- package/dist/adt/security-session-gate.js.map +1 -0
- package/dist/adt/server-driven.d.ts +12 -1
- package/dist/adt/server-driven.d.ts.map +1 -1
- package/dist/adt/server-driven.js +22 -4
- package/dist/adt/server-driven.js.map +1 -1
- package/dist/adt/source-diff.d.ts +4 -1
- package/dist/adt/source-diff.d.ts.map +1 -1
- package/dist/adt/source-diff.js +5 -3
- package/dist/adt/source-diff.js.map +1 -1
- package/dist/adt/stored-text/chunks.d.ts +8 -0
- package/dist/adt/stored-text/chunks.d.ts.map +1 -0
- package/dist/adt/stored-text/chunks.js +55 -0
- package/dist/adt/stored-text/chunks.js.map +1 -0
- package/dist/adt/stored-text/decoder.d.ts +31 -0
- package/dist/adt/stored-text/decoder.d.ts.map +1 -0
- package/dist/adt/stored-text/decoder.js +319 -0
- package/dist/adt/stored-text/decoder.js.map +1 -0
- package/dist/adt/stored-text/errors.d.ts +10 -0
- package/dist/adt/stored-text/errors.d.ts.map +1 -0
- package/dist/adt/stored-text/errors.js +10 -0
- package/dist/adt/stored-text/errors.js.map +1 -0
- package/dist/adt/stored-text/index.d.ts +7 -0
- package/dist/adt/stored-text/index.d.ts.map +1 -0
- package/dist/adt/stored-text/index.js +6 -0
- package/dist/adt/stored-text/index.js.map +1 -0
- package/dist/adt/stored-text/key.d.ts +3 -0
- package/dist/adt/stored-text/key.d.ts.map +1 -0
- package/dist/adt/stored-text/key.js +23 -0
- package/dist/adt/stored-text/key.js.map +1 -0
- package/dist/adt/stored-text/reader.d.ts +52 -0
- package/dist/adt/stored-text/reader.d.ts.map +1 -0
- package/dist/adt/stored-text/reader.js +142 -0
- package/dist/adt/stored-text/reader.js.map +1 -0
- package/dist/adt/stored-text/source.d.ts +5 -0
- package/dist/adt/stored-text/source.d.ts.map +1 -0
- package/dist/adt/stored-text/source.js +284 -0
- package/dist/adt/stored-text/source.js.map +1 -0
- package/dist/adt/stored-text/types.d.ts +38 -0
- package/dist/adt/stored-text/types.d.ts.map +1 -0
- package/dist/adt/stored-text/types.js +2 -0
- package/dist/adt/stored-text/types.js.map +1 -0
- package/dist/adt/structure-hierarchy.d.ts.map +1 -1
- package/dist/adt/structure-hierarchy.js +11 -27
- package/dist/adt/structure-hierarchy.js.map +1 -1
- package/dist/adt/syntax-batch.d.ts +66 -0
- package/dist/adt/syntax-batch.d.ts.map +1 -0
- package/dist/adt/syntax-batch.js +115 -0
- package/dist/adt/syntax-batch.js.map +1 -0
- package/dist/adt/table-index.d.ts +23 -0
- package/dist/adt/table-index.d.ts.map +1 -0
- package/dist/adt/table-index.js +69 -0
- package/dist/adt/table-index.js.map +1 -0
- package/dist/adt/table-query.d.ts +4 -2
- package/dist/adt/table-query.d.ts.map +1 -1
- package/dist/adt/table-query.js +37 -10
- package/dist/adt/table-query.js.map +1 -1
- package/dist/adt/table-settings.d.ts +67 -0
- package/dist/adt/table-settings.d.ts.map +1 -0
- package/dist/adt/table-settings.js +207 -0
- package/dist/adt/table-settings.js.map +1 -0
- package/dist/adt/text-elements.d.ts +7 -1
- package/dist/adt/text-elements.d.ts.map +1 -1
- package/dist/adt/text-elements.js +67 -25
- package/dist/adt/text-elements.js.map +1 -1
- package/dist/adt/text-part-changes.d.ts +4 -0
- package/dist/adt/text-part-changes.d.ts.map +1 -0
- package/dist/adt/text-part-changes.js +43 -0
- package/dist/adt/text-part-changes.js.map +1 -0
- package/dist/adt/transport-diff.d.ts +16 -25
- package/dist/adt/transport-diff.d.ts.map +1 -1
- package/dist/adt/transport-diff.js +201 -103
- package/dist/adt/transport-diff.js.map +1 -1
- package/dist/adt/transport-review-budget.d.ts +15 -0
- package/dist/adt/transport-review-budget.d.ts.map +1 -0
- package/dist/adt/transport-review-budget.js +57 -0
- package/dist/adt/transport-review-budget.js.map +1 -0
- package/dist/adt/transport.d.ts +1 -1
- package/dist/adt/transport.d.ts.map +1 -1
- package/dist/adt/transport.js +4 -3
- package/dist/adt/transport.js.map +1 -1
- package/dist/adt/types.d.ts +10 -4
- package/dist/adt/types.d.ts.map +1 -1
- package/dist/adt/user-agent.d.ts +1 -1
- package/dist/adt/where-used-native.d.ts +22 -0
- package/dist/adt/where-used-native.d.ts.map +1 -0
- package/dist/adt/where-used-native.js +111 -0
- package/dist/adt/where-used-native.js.map +1 -0
- package/dist/adt/xml-parser.d.ts +6 -36
- package/dist/adt/xml-parser.d.ts.map +1 -1
- package/dist/adt/xml-parser.js +28 -235
- package/dist/adt/xml-parser.js.map +1 -1
- package/dist/aff/validator.d.ts.map +1 -1
- package/dist/aff/validator.js +8 -2
- package/dist/aff/validator.js.map +1 -1
- package/dist/authz/policy.d.ts.map +1 -1
- package/dist/authz/policy.js +10 -2
- package/dist/authz/policy.js.map +1 -1
- package/dist/cache/sqlite-driver.d.ts +24 -0
- package/dist/cache/sqlite-driver.d.ts.map +1 -0
- package/dist/cache/sqlite-driver.js +59 -0
- package/dist/cache/sqlite-driver.js.map +1 -0
- package/dist/cache/sqlite.d.ts +4 -2
- package/dist/cache/sqlite.d.ts.map +1 -1
- package/dist/cache/sqlite.js +5 -4
- package/dist/cache/sqlite.js.map +1 -1
- package/dist/cli.js +4 -1
- package/dist/cli.js.map +1 -1
- package/dist/context/grep.d.ts +2 -0
- package/dist/context/grep.d.ts.map +1 -1
- package/dist/context/grep.js +8 -7
- package/dist/context/grep.js.map +1 -1
- package/dist/context/line-range.d.ts +6 -0
- package/dist/context/line-range.d.ts.map +1 -0
- package/dist/context/line-range.js +23 -0
- package/dist/context/line-range.js.map +1 -0
- package/dist/extract-sap-cookies.js +1 -0
- package/dist/extract-sap-cookies.js.map +1 -1
- package/dist/handlers/activate.d.ts.map +1 -1
- package/dist/handlers/activate.js +69 -7
- package/dist/handlers/activate.js.map +1 -1
- package/dist/handlers/activation-results.d.ts.map +1 -1
- package/dist/handlers/activation-results.js +9 -1
- package/dist/handlers/activation-results.js.map +1 -1
- package/dist/handlers/api-release-fields.d.ts +23 -0
- package/dist/handlers/api-release-fields.d.ts.map +1 -0
- package/dist/handlers/api-release-fields.js +21 -0
- package/dist/handlers/api-release-fields.js.map +1 -0
- package/dist/handlers/application-log-input.d.ts +32 -0
- package/dist/handlers/application-log-input.d.ts.map +1 -0
- package/dist/handlers/application-log-input.js +34 -0
- package/dist/handlers/application-log-input.js.map +1 -0
- package/dist/handlers/application-log.d.ts +4 -0
- package/dist/handlers/application-log.d.ts.map +1 -0
- package/dist/handlers/application-log.js +14 -0
- package/dist/handlers/application-log.js.map +1 -0
- package/dist/handlers/cds-hints.d.ts +2 -2
- package/dist/handlers/cds-hints.d.ts.map +1 -1
- package/dist/handlers/cds-hints.js +21 -63
- package/dist/handlers/cds-hints.js.map +1 -1
- package/dist/handlers/context.d.ts.map +1 -1
- package/dist/handlers/context.js +7 -3
- package/dist/handlers/context.js.map +1 -1
- package/dist/handlers/diagnose.d.ts.map +1 -1
- package/dist/handlers/diagnose.js +10 -1
- package/dist/handlers/diagnose.js.map +1 -1
- package/dist/handlers/dispatch.d.ts.map +1 -1
- package/dist/handlers/dispatch.js +54 -9
- package/dist/handlers/dispatch.js.map +1 -1
- package/dist/handlers/dump-filter-inputs.d.ts +38 -0
- package/dist/handlers/dump-filter-inputs.d.ts.map +1 -0
- package/dist/handlers/dump-filter-inputs.js +44 -0
- package/dist/handlers/dump-filter-inputs.js.map +1 -0
- package/dist/handlers/expanded-read.d.ts +24 -0
- package/dist/handlers/expanded-read.d.ts.map +1 -0
- package/dist/handlers/expanded-read.js +56 -0
- package/dist/handlers/expanded-read.js.map +1 -0
- package/dist/handlers/feature-cache.d.ts +11 -3
- package/dist/handlers/feature-cache.d.ts.map +1 -1
- package/dist/handlers/feature-cache.js +57 -3
- package/dist/handlers/feature-cache.js.map +1 -1
- package/dist/handlers/function-parameter-language.d.ts +5 -0
- package/dist/handlers/function-parameter-language.d.ts.map +1 -0
- package/dist/handlers/function-parameter-language.js +19 -0
- package/dist/handlers/function-parameter-language.js.map +1 -0
- package/dist/handlers/function-processing.d.ts +5 -0
- package/dist/handlers/function-processing.d.ts.map +1 -1
- package/dist/handlers/function-processing.js +5 -0
- package/dist/handlers/function-processing.js.map +1 -1
- package/dist/handlers/hyperfocused.d.ts +1 -1
- package/dist/handlers/hyperfocused.d.ts.map +1 -1
- package/dist/handlers/hyperfocused.js +2 -1
- package/dist/handlers/hyperfocused.js.map +1 -1
- package/dist/handlers/long-text-input.d.ts +113 -0
- package/dist/handlers/long-text-input.d.ts.map +1 -0
- package/dist/handlers/long-text-input.js +113 -0
- package/dist/handlers/long-text-input.js.map +1 -0
- package/dist/handlers/long-text.d.ts +5 -0
- package/dist/handlers/long-text.d.ts.map +1 -0
- package/dist/handlers/long-text.js +122 -0
- package/dist/handlers/long-text.js.map +1 -0
- package/dist/handlers/manage.d.ts.map +1 -1
- package/dist/handlers/manage.js +7 -23
- package/dist/handlers/manage.js.map +1 -1
- package/dist/handlers/navigate.d.ts.map +1 -1
- package/dist/handlers/navigate.js +8 -3
- package/dist/handlers/navigate.js.map +1 -1
- package/dist/handlers/object-types.d.ts.map +1 -1
- package/dist/handlers/object-types.js +31 -7
- package/dist/handlers/object-types.js.map +1 -1
- package/dist/handlers/query-input.d.ts +50 -0
- package/dist/handlers/query-input.d.ts.map +1 -0
- package/dist/handlers/query-input.js +59 -0
- package/dist/handlers/query-input.js.map +1 -0
- package/dist/handlers/query-tool.d.ts +11 -0
- package/dist/handlers/query-tool.d.ts.map +1 -0
- package/dist/handlers/query-tool.js +99 -0
- package/dist/handlers/query-tool.js.map +1 -0
- package/dist/handlers/query.d.ts +1 -1
- package/dist/handlers/query.d.ts.map +1 -1
- package/dist/handlers/query.js +7 -1
- package/dist/handlers/query.js.map +1 -1
- package/dist/handlers/read.d.ts +1 -0
- package/dist/handlers/read.d.ts.map +1 -1
- package/dist/handlers/read.js +119 -14
- package/dist/handlers/read.js.map +1 -1
- package/dist/handlers/schemas.d.ts +57 -4
- package/dist/handlers/schemas.d.ts.map +1 -1
- package/dist/handlers/schemas.js +140 -17
- package/dist/handlers/schemas.js.map +1 -1
- package/dist/handlers/search.d.ts.map +1 -1
- package/dist/handlers/search.js +10 -6
- package/dist/handlers/search.js.map +1 -1
- package/dist/handlers/syntax.d.ts.map +1 -1
- package/dist/handlers/syntax.js +8 -0
- package/dist/handlers/syntax.js.map +1 -1
- package/dist/handlers/table-type-fields.d.ts +33 -0
- package/dist/handlers/table-type-fields.d.ts.map +1 -0
- package/dist/handlers/table-type-fields.js +22 -0
- package/dist/handlers/table-type-fields.js.map +1 -0
- package/dist/handlers/tool-descriptions.d.ts.map +1 -1
- package/dist/handlers/tool-descriptions.js +8 -3
- package/dist/handlers/tool-descriptions.js.map +1 -1
- package/dist/handlers/tool-registry.d.ts +5 -5
- package/dist/handlers/tool-registry.d.ts.map +1 -1
- package/dist/handlers/tool-registry.js +10 -7
- package/dist/handlers/tool-registry.js.map +1 -1
- package/dist/handlers/tools.d.ts +1 -1
- package/dist/handlers/tools.d.ts.map +1 -1
- package/dist/handlers/tools.js +99 -101
- package/dist/handlers/tools.js.map +1 -1
- package/dist/handlers/transport-review.d.ts +5 -0
- package/dist/handlers/transport-review.d.ts.map +1 -0
- package/dist/handlers/transport-review.js +108 -0
- package/dist/handlers/transport-review.js.map +1 -0
- package/dist/handlers/transport.d.ts.map +1 -1
- package/dist/handlers/transport.js +3 -58
- package/dist/handlers/transport.js.map +1 -1
- package/dist/handlers/where-used-details.d.ts +28 -0
- package/dist/handlers/where-used-details.d.ts.map +1 -0
- package/dist/handlers/where-used-details.js +67 -0
- package/dist/handlers/where-used-details.js.map +1 -0
- package/dist/handlers/where-used.d.ts +8 -3
- package/dist/handlers/where-used.d.ts.map +1 -1
- package/dist/handlers/where-used.js +40 -18
- package/dist/handlers/where-used.js.map +1 -1
- package/dist/handlers/write/create.d.ts.map +1 -1
- package/dist/handlers/write/create.js +69 -27
- package/dist/handlers/write/create.js.map +1 -1
- package/dist/handlers/write/rap.d.ts.map +1 -1
- package/dist/handlers/write/rap.js +2 -4
- package/dist/handlers/write/rap.js.map +1 -1
- package/dist/handlers/write/table-settings.d.ts +5 -0
- package/dist/handlers/write/table-settings.d.ts.map +1 -0
- package/dist/handlers/write/table-settings.js +27 -0
- package/dist/handlers/write/table-settings.js.map +1 -0
- package/dist/handlers/write/update-delete.d.ts +1 -1
- package/dist/handlers/write/update-delete.d.ts.map +1 -1
- package/dist/handlers/write/update-delete.js +32 -12
- package/dist/handlers/write/update-delete.js.map +1 -1
- package/dist/handlers/write-helpers.d.ts +4 -1
- package/dist/handlers/write-helpers.d.ts.map +1 -1
- package/dist/handlers/write-helpers.js +68 -8
- package/dist/handlers/write-helpers.js.map +1 -1
- package/dist/handlers/write.d.ts.map +1 -1
- package/dist/handlers/write.js +6 -10
- package/dist/handlers/write.js.map +1 -1
- package/dist/server/audit.d.ts +4 -0
- package/dist/server/audit.d.ts.map +1 -1
- package/dist/server/audit.js +49 -2
- package/dist/server/audit.js.map +1 -1
- package/dist/server/config.d.ts.map +1 -1
- package/dist/server/config.js +43 -2
- package/dist/server/config.js.map +1 -1
- package/dist/server/destination-discovery.d.ts +12 -2
- package/dist/server/destination-discovery.d.ts.map +1 -1
- package/dist/server/destination-discovery.js +33 -7
- package/dist/server/destination-discovery.js.map +1 -1
- package/dist/server/destination-registry.d.ts +10 -6
- package/dist/server/destination-registry.d.ts.map +1 -1
- package/dist/server/destination-registry.js +38 -15
- package/dist/server/destination-registry.js.map +1 -1
- package/dist/server/http-request-body.d.ts +4 -0
- package/dist/server/http-request-body.d.ts.map +1 -0
- package/dist/server/http-request-body.js +65 -0
- package/dist/server/http-request-body.js.map +1 -0
- package/dist/server/http.d.ts +5 -2
- package/dist/server/http.d.ts.map +1 -1
- package/dist/server/http.js +71 -9
- package/dist/server/http.js.map +1 -1
- package/dist/server/multi-target-authorization-audit.d.ts +5 -0
- package/dist/server/multi-target-authorization-audit.d.ts.map +1 -0
- package/dist/server/multi-target-authorization-audit.js +18 -0
- package/dist/server/multi-target-authorization-audit.js.map +1 -0
- package/dist/server/multi-target-authorization-startup.d.ts +8 -0
- package/dist/server/multi-target-authorization-startup.d.ts.map +1 -0
- package/dist/server/multi-target-authorization-startup.js +38 -0
- package/dist/server/multi-target-authorization-startup.js.map +1 -0
- package/dist/server/multi-target-authorization.d.ts +29 -0
- package/dist/server/multi-target-authorization.d.ts.map +1 -0
- package/dist/server/multi-target-authorization.js +97 -0
- package/dist/server/multi-target-authorization.js.map +1 -0
- package/dist/server/multi-target-bearer-auth.d.ts +5 -0
- package/dist/server/multi-target-bearer-auth.d.ts.map +1 -0
- package/dist/server/multi-target-bearer-auth.js +39 -0
- package/dist/server/multi-target-bearer-auth.js.map +1 -0
- package/dist/server/multi-target-catalog-enforced.d.ts +29 -0
- package/dist/server/multi-target-catalog-enforced.d.ts.map +1 -0
- package/dist/server/multi-target-catalog-enforced.js +142 -0
- package/dist/server/multi-target-catalog-enforced.js.map +1 -0
- package/dist/server/multi-target-catalog-projection.d.ts +7 -0
- package/dist/server/multi-target-catalog-projection.d.ts.map +1 -0
- package/dist/server/multi-target-catalog-projection.js +52 -0
- package/dist/server/multi-target-catalog-projection.js.map +1 -0
- package/dist/server/multi-target-feature-state.d.ts +0 -2
- package/dist/server/multi-target-feature-state.d.ts.map +1 -1
- package/dist/server/multi-target-feature-state.js +0 -19
- package/dist/server/multi-target-feature-state.js.map +1 -1
- package/dist/server/multi-target-identity.d.ts +3 -0
- package/dist/server/multi-target-identity.d.ts.map +1 -1
- package/dist/server/multi-target-identity.js +9 -0
- package/dist/server/multi-target-identity.js.map +1 -1
- package/dist/server/multi-target-request-projection.d.ts +14 -0
- package/dist/server/multi-target-request-projection.d.ts.map +1 -0
- package/dist/server/multi-target-request-projection.js +16 -0
- package/dist/server/multi-target-request-projection.js.map +1 -0
- package/dist/server/multi-target-runtime.d.ts.map +1 -1
- package/dist/server/multi-target-runtime.js +1 -0
- package/dist/server/multi-target-runtime.js.map +1 -1
- package/dist/server/multi-target-server.d.ts +4 -1
- package/dist/server/multi-target-server.d.ts.map +1 -1
- package/dist/server/multi-target-server.js +111 -11
- package/dist/server/multi-target-server.js.map +1 -1
- package/dist/server/multi-target-tools.d.ts +1 -1
- package/dist/server/multi-target-tools.d.ts.map +1 -1
- package/dist/server/multi-target-tools.js +22 -15
- package/dist/server/multi-target-tools.js.map +1 -1
- package/dist/server/private-mcp-response.d.ts +4 -0
- package/dist/server/private-mcp-response.d.ts.map +1 -0
- package/dist/server/private-mcp-response.js +14 -0
- package/dist/server/private-mcp-response.js.map +1 -0
- package/dist/server/server-cache.d.ts +5 -0
- package/dist/server/server-cache.d.ts.map +1 -0
- package/dist/server/server-cache.js +30 -0
- package/dist/server/server-cache.js.map +1 -0
- package/dist/server/server.d.ts +7 -21
- package/dist/server/server.d.ts.map +1 -1
- package/dist/server/server.js +60 -89
- package/dist/server/server.js.map +1 -1
- package/dist/server/sinks/btp-auditlog.d.ts.map +1 -1
- package/dist/server/sinks/btp-auditlog.js +4 -1
- package/dist/server/sinks/btp-auditlog.js.map +1 -1
- package/dist/server/tool-auth.d.ts +1 -1
- package/dist/server/tool-auth.d.ts.map +1 -1
- package/dist/server/tool-auth.js +24 -4
- package/dist/server/tool-auth.js.map +1 -1
- package/dist/server/types.d.ts +7 -0
- package/dist/server/types.d.ts.map +1 -1
- package/dist/server/types.js +4 -0
- package/dist/server/types.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +21 -13
package/dist/adt/http.js
CHANGED
|
@@ -9,15 +9,19 @@ import { Agent, Client } from 'undici';
|
|
|
9
9
|
import { getCurrentContext } from '../server/context.js';
|
|
10
10
|
import { logger } from '../server/logger.js';
|
|
11
11
|
import { traceHeaders } from '../server/trace-context.js';
|
|
12
|
+
import { acceptFallback } from './accept-fallback.js';
|
|
12
13
|
import { connectivityProxyResponse, prepareBoundedResponse } from './bounded-response.js';
|
|
13
14
|
import { resolveCookies } from './cookies.js';
|
|
14
15
|
import { resolveAcceptType, resolveContentType } from './discovery.js';
|
|
15
16
|
import { AdtApiError, AdtNetworkError, AdtResponseLimitError } from './errors.js';
|
|
16
17
|
import { awaitWithinRequestBudget, requestBudgetSignal, requestSignal, sleepWithinRequestBudget, throwIfRequestCancelled, withoutResponseBudget, } from './http-deadline.js';
|
|
18
|
+
import { parseRetryAfter } from './http-retry-after.js';
|
|
17
19
|
import { prepareDataPreviewWireBody } from './http-wire-body.js';
|
|
18
|
-
import { legacyContentHandlerFallback } from './legacy-content-handler.js';
|
|
20
|
+
import { legacyContentHandlerFallback, rejectEmptyAdtHtmlResponse } from './legacy-content-handler.js';
|
|
19
21
|
import { fetchWithAttemptBudget } from './request-attempt-budget.js';
|
|
22
|
+
import { hasSecuritySessionCookie, SecuritySessionGate } from './security-session-gate.js';
|
|
20
23
|
import { resolveSapUserAgent } from './user-agent.js';
|
|
24
|
+
export { parseRetryAfter } from './http-retry-after.js';
|
|
21
25
|
/**
|
|
22
26
|
* Opt-in wire-level debug logging.
|
|
23
27
|
*
|
|
@@ -103,6 +107,8 @@ export class AdtHttpClient {
|
|
|
103
107
|
dbRetryInProgress = false;
|
|
104
108
|
/** Set after a 401 clears stale cookies — triggers file reload on the next request */
|
|
105
109
|
cookiesCleared = false;
|
|
110
|
+
/** Keeps a cold client at one SAP security session (see security-session-gate.ts). */
|
|
111
|
+
securitySessionGate = new SecuritySessionGate();
|
|
106
112
|
/** Shared by stateful clones so one rejected Basic credential cannot fan out internally. */
|
|
107
113
|
authenticationAttemptState;
|
|
108
114
|
constructor(config, authenticationAttemptState) {
|
|
@@ -235,6 +241,8 @@ export class AdtHttpClient {
|
|
|
235
241
|
}
|
|
236
242
|
if (!options?.signal && options?.deadline === undefined)
|
|
237
243
|
throw error;
|
|
244
|
+
if (options?.signal?.aborted)
|
|
245
|
+
throwIfRequestCancelled(options);
|
|
238
246
|
const cause = error instanceof Error ? error : new Error(String(error));
|
|
239
247
|
throw new AdtNetworkError(cause.message, cause);
|
|
240
248
|
}
|
|
@@ -273,6 +281,7 @@ export class AdtHttpClient {
|
|
|
273
281
|
/** Inner request method — CSRF, retries, content negotiation */
|
|
274
282
|
async requestInner(method, path, body, contentType, extraHeaders, options) {
|
|
275
283
|
throwIfRequestCancelled(options);
|
|
284
|
+
const expectBody = method !== 'HEAD';
|
|
276
285
|
// Auto-fetch CSRF token for modifying requests
|
|
277
286
|
if (isModifyingMethod(method) && !this.csrfToken) {
|
|
278
287
|
await this.fetchCsrfToken(withoutResponseBudget(options));
|
|
@@ -350,7 +359,16 @@ export class AdtHttpClient {
|
|
|
350
359
|
if (this.config.sapConnectivityAuth && !this.config.ppProxyAuth) {
|
|
351
360
|
headers['SAP-Connectivity-Authentication'] = this.config.sapConnectivityAuth;
|
|
352
361
|
}
|
|
353
|
-
|
|
362
|
+
// Quick-fix lookup includes queries (#993); old revision feeds append source paths to them. Use context headers.
|
|
363
|
+
const sapContextInHeaders = (method === 'POST' && path.startsWith('/sap/bc/adt/quickfixes/proposals/')) ||
|
|
364
|
+
(method === 'GET' && /^\/sap\/bc\/adt\/[^?#]+\/versions$/.test(path));
|
|
365
|
+
if (sapContextInHeaders) {
|
|
366
|
+
if (this.config.client)
|
|
367
|
+
headers['sap-client'] = this.config.client;
|
|
368
|
+
if (this.config.language)
|
|
369
|
+
headers['sap-language'] = this.config.language;
|
|
370
|
+
}
|
|
371
|
+
const url = this.buildUrl(path, sapContextInHeaders);
|
|
354
372
|
const httpStart = Date.now();
|
|
355
373
|
// Per-request guards to prevent infinite retry loops
|
|
356
374
|
const retryTransientErrors = options?.retryTransientErrors !== false;
|
|
@@ -358,10 +376,8 @@ export class AdtHttpClient {
|
|
|
358
376
|
let authRetried = false;
|
|
359
377
|
let retried429 = false;
|
|
360
378
|
try {
|
|
361
|
-
let response = await this.doFetch(url, method, headers, wireBody, options);
|
|
379
|
+
let response = await this.doFetch(url, method, headers, wireBody, options, this.config.retryUnauthorized !== false);
|
|
362
380
|
let responseBody = await response.text();
|
|
363
|
-
// Persist any Set-Cookie headers from the response
|
|
364
|
-
this.storeCookies(response);
|
|
365
381
|
// Detect broken DB connection on the assigned work process.
|
|
366
382
|
// SAP's ICM routes all requests with the same session cookie to the same
|
|
367
383
|
// work process. If that WP has a broken HANA connection, every request fails
|
|
@@ -403,8 +419,7 @@ export class AdtHttpClient {
|
|
|
403
419
|
}
|
|
404
420
|
const retryResp = await this.doFetch(url, method, headers, wireBody, options);
|
|
405
421
|
const retryBody = await retryResp.text();
|
|
406
|
-
this.
|
|
407
|
-
const retryResult = this.handleResponse(retryResp.status, retryResp.headers, retryBody, path);
|
|
422
|
+
const retryResult = this.handleResponse(retryResp.status, retryResp.headers, retryBody, path, expectBody);
|
|
408
423
|
logger.emitAudit({
|
|
409
424
|
timestamp: new Date().toISOString(),
|
|
410
425
|
level: 'info',
|
|
@@ -437,9 +452,9 @@ export class AdtHttpClient {
|
|
|
437
452
|
errorBody: `503 Service Unavailable — retrying in ${Math.round(jitterMs)}ms (${source})`,
|
|
438
453
|
});
|
|
439
454
|
await sleepWithinRequestBudget(jitterMs, options);
|
|
455
|
+
this.refreshSessionHeaders(method, headers);
|
|
440
456
|
const retryResp = await this.doFetch(url, method, headers, wireBody, options);
|
|
441
457
|
const retryBody = await retryResp.text();
|
|
442
|
-
this.storeCookies(retryResp);
|
|
443
458
|
logger.emitAudit({
|
|
444
459
|
timestamp: new Date().toISOString(),
|
|
445
460
|
level: retryResp.status === 503 ? 'warn' : 'info',
|
|
@@ -450,7 +465,7 @@ export class AdtHttpClient {
|
|
|
450
465
|
durationMs: Date.now() - httpStart,
|
|
451
466
|
errorBody: `503 retry completed (${retryResp.status})`,
|
|
452
467
|
});
|
|
453
|
-
return this.handleResponse(retryResp.status, retryResp.headers, retryBody, path);
|
|
468
|
+
return this.handleResponse(retryResp.status, retryResp.headers, retryBody, path, expectBody);
|
|
454
469
|
}
|
|
455
470
|
// Handle 429 Too Many Requests — emitted by SAP Web Dispatcher, BTP API
|
|
456
471
|
// Management, or any upstream gateway throttling us. Honors Retry-After when present;
|
|
@@ -469,9 +484,9 @@ export class AdtHttpClient {
|
|
|
469
484
|
errorBody: `429 Too Many Requests — retrying in ${Math.round(jitterMs)}ms (${source})`,
|
|
470
485
|
});
|
|
471
486
|
await sleepWithinRequestBudget(jitterMs, options);
|
|
487
|
+
this.refreshSessionHeaders(method, headers);
|
|
472
488
|
const retryResp = await this.doFetch(url, method, headers, wireBody, options);
|
|
473
489
|
const retryBody = await retryResp.text();
|
|
474
|
-
this.storeCookies(retryResp);
|
|
475
490
|
logger.emitAudit({
|
|
476
491
|
timestamp: new Date().toISOString(),
|
|
477
492
|
level: retryResp.status === 429 ? 'warn' : 'info',
|
|
@@ -482,7 +497,7 @@ export class AdtHttpClient {
|
|
|
482
497
|
durationMs: Date.now() - httpStart,
|
|
483
498
|
errorBody: `429 retry completed (${retryResp.status})`,
|
|
484
499
|
});
|
|
485
|
-
return this.handleResponse(retryResp.status, retryResp.headers, retryBody, path);
|
|
500
|
+
return this.handleResponse(retryResp.status, retryResp.headers, retryBody, path, expectBody);
|
|
486
501
|
}
|
|
487
502
|
// Handle 401 session timeout — reset session and retry once.
|
|
488
503
|
// Uses per-request guard (not instance-level) so concurrent requests each get their own retry.
|
|
@@ -500,8 +515,6 @@ export class AdtHttpClient {
|
|
|
500
515
|
durationMs: Date.now() - httpStart,
|
|
501
516
|
errorBody: '401 session expired — resetting session and retrying',
|
|
502
517
|
});
|
|
503
|
-
// Clear session to force fresh authentication
|
|
504
|
-
this.resetSession();
|
|
505
518
|
// Pick up an out-of-band rotated cookie file so the call that observes the
|
|
506
519
|
// expiry can recover; the lazy `cookiesCleared` reload stays the fallback.
|
|
507
520
|
// `cookieFile`, not `isCookieAuthMode()` — cookieString has nothing to re-read,
|
|
@@ -531,7 +544,6 @@ export class AdtHttpClient {
|
|
|
531
544
|
}
|
|
532
545
|
response = await this.doFetch(url, method, headers, wireBody, options);
|
|
533
546
|
responseBody = await response.text();
|
|
534
|
-
this.storeCookies(response);
|
|
535
547
|
logger.emitAudit({
|
|
536
548
|
timestamp: new Date().toISOString(),
|
|
537
549
|
level: 'info',
|
|
@@ -560,20 +572,9 @@ export class AdtHttpClient {
|
|
|
560
572
|
if (csrfRefreshedCookieHeader) {
|
|
561
573
|
headers.Cookie = csrfRefreshedCookieHeader;
|
|
562
574
|
}
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
const result = this.handleResponse(retryResponse.status, retryResponse.headers, retryBody, path);
|
|
567
|
-
logger.emitAudit({
|
|
568
|
-
timestamp: new Date().toISOString(),
|
|
569
|
-
level: 'info',
|
|
570
|
-
event: 'http_request',
|
|
571
|
-
method,
|
|
572
|
-
path,
|
|
573
|
-
statusCode: retryResponse.status,
|
|
574
|
-
durationMs: Date.now() - httpStart,
|
|
575
|
-
});
|
|
576
|
-
return result;
|
|
575
|
+
response = await this.doFetch(url, method, headers, wireBody, options);
|
|
576
|
+
responseBody = await response.text();
|
|
577
|
+
// A refreshed session can still need legacy content negotiation below (#996).
|
|
577
578
|
}
|
|
578
579
|
// Retry negotiation once, including the narrowly matched NW 7.40 handler error.
|
|
579
580
|
const legacyFallback = legacyContentHandlerFallback(response.status, responseBody, method, negotiationKey, headers);
|
|
@@ -586,25 +587,11 @@ export class AdtHttpClient {
|
|
|
586
587
|
headersChanged = true;
|
|
587
588
|
}
|
|
588
589
|
else if (response.status === 406) {
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
fallbackHeaders.Accept = inferred;
|
|
590
|
+
const fallback = acceptFallback(responseBody, fallbackHeaders.Accept, method, negotiationKey);
|
|
591
|
+
if (fallback) {
|
|
592
|
+
fallbackHeaders.Accept = fallback;
|
|
593
593
|
headersChanged = true;
|
|
594
594
|
}
|
|
595
|
-
else if (fallbackHeaders.Accept &&
|
|
596
|
-
fallbackHeaders.Accept !== '*/*' &&
|
|
597
|
-
fallbackHeaders.Accept !== 'application/xml') {
|
|
598
|
-
// Fall back to generic XML first
|
|
599
|
-
fallbackHeaders.Accept = 'application/xml';
|
|
600
|
-
headersChanged = true;
|
|
601
|
-
}
|
|
602
|
-
else if (fallbackHeaders.Accept === 'application/xml') {
|
|
603
|
-
// application/xml was already rejected — fall back to wildcard
|
|
604
|
-
fallbackHeaders.Accept = '*/*';
|
|
605
|
-
headersChanged = true;
|
|
606
|
-
}
|
|
607
|
-
// If Accept is already */* and no inferred type, no useful fallback — skip retry
|
|
608
595
|
}
|
|
609
596
|
else {
|
|
610
597
|
// 415: Server rejected our Content-Type — try fallbacks:
|
|
@@ -634,15 +621,10 @@ export class AdtHttpClient {
|
|
|
634
621
|
durationMs: Date.now() - httpStart,
|
|
635
622
|
errorBody: `Content negotiation ${response.status} — retrying with fallback headers`,
|
|
636
623
|
});
|
|
624
|
+
this.refreshSessionHeaders(method, fallbackHeaders);
|
|
637
625
|
const retryResp = await this.doFetch(url, method, fallbackHeaders, wireBody, options);
|
|
638
626
|
const retryBody = await retryResp.text();
|
|
639
|
-
this.
|
|
640
|
-
// Store CSRF token from retry response
|
|
641
|
-
const retryToken = retryResp.headers.get('x-csrf-token');
|
|
642
|
-
if (retryToken && retryToken !== 'Required') {
|
|
643
|
-
this.csrfToken = retryToken;
|
|
644
|
-
}
|
|
645
|
-
const retryResult = this.handleResponse(retryResp.status, retryResp.headers, retryBody, path);
|
|
627
|
+
const retryResult = this.handleResponse(retryResp.status, retryResp.headers, retryBody, path, expectBody);
|
|
646
628
|
const currentContentType = contentType ?? headers['Content-Type'];
|
|
647
629
|
const negotiated = {};
|
|
648
630
|
if (retryAccept !== headers.Accept) {
|
|
@@ -669,12 +651,7 @@ export class AdtHttpClient {
|
|
|
669
651
|
}
|
|
670
652
|
// No meaningful header change — fall through to normal error handling
|
|
671
653
|
}
|
|
672
|
-
|
|
673
|
-
const responseToken = response.headers.get('x-csrf-token');
|
|
674
|
-
if (responseToken && responseToken !== 'Required') {
|
|
675
|
-
this.csrfToken = responseToken;
|
|
676
|
-
}
|
|
677
|
-
const result = this.handleResponse(response.status, response.headers, responseBody, path);
|
|
654
|
+
const result = this.handleResponse(response.status, response.headers, responseBody, path, expectBody);
|
|
678
655
|
logger.emitAudit({
|
|
679
656
|
timestamp: new Date().toISOString(),
|
|
680
657
|
level: 'debug',
|
|
@@ -724,6 +701,8 @@ export class AdtHttpClient {
|
|
|
724
701
|
}
|
|
725
702
|
if (err instanceof AdtNetworkError || err instanceof AdtResponseLimitError)
|
|
726
703
|
throw err;
|
|
704
|
+
if (options?.signal?.aborted)
|
|
705
|
+
throwIfRequestCancelled(options);
|
|
727
706
|
const message = err instanceof Error ? err.message : String(err);
|
|
728
707
|
throw new AdtNetworkError(message, err instanceof Error ? err : undefined);
|
|
729
708
|
}
|
|
@@ -762,7 +741,7 @@ export class AdtHttpClient {
|
|
|
762
741
|
}
|
|
763
742
|
}
|
|
764
743
|
/** Handle response: throw on error status, return normalized response */
|
|
765
|
-
handleResponse(status, headers, body, path) {
|
|
744
|
+
handleResponse(status, headers, body, path, expectBody = true) {
|
|
766
745
|
const contentType = headers.get('content-type')?.toLowerCase();
|
|
767
746
|
const isDiscovery = ['/sap/bc/adt/core/discovery', '/sap/bc/adt/discovery'].includes(path.split('?', 1)[0]);
|
|
768
747
|
if (status === 200 &&
|
|
@@ -775,6 +754,8 @@ export class AdtHttpClient {
|
|
|
775
754
|
this.notifyUnauthorized(path);
|
|
776
755
|
throw new AdtApiError('ADT call returned HTML login page — authentication required. If using cookies, they may have expired. If using Basic auth, credentials may be invalid or not authorized for ADT (S_ADT_RES missing). If on an SSO-only system, try SAP_DISABLE_SAML=true or see docs/enterprise-auth.md. Re-run arc-1 after fixing.', 401, path, body.slice(0, 500));
|
|
777
756
|
}
|
|
757
|
+
if (expectBody)
|
|
758
|
+
rejectEmptyAdtHtmlResponse(status, contentType, body, path);
|
|
778
759
|
if (status >= 400) {
|
|
779
760
|
if (status === 401) {
|
|
780
761
|
this.notifyUnauthorized(path);
|
|
@@ -829,12 +810,6 @@ export class AdtHttpClient {
|
|
|
829
810
|
if (this.cookiesCleared && this.isCookieAuthMode()) {
|
|
830
811
|
this.reloadCookiesFromSource();
|
|
831
812
|
}
|
|
832
|
-
// A token only counts as proof when the response itself succeeded: SAP returns one on
|
|
833
|
-
// failures too, and the old code accepted a token from a 401 — masking the auth error.
|
|
834
|
-
const usableToken = (response) => {
|
|
835
|
-
const token = response.headers.get('x-csrf-token')?.trim();
|
|
836
|
-
return response.ok && token && token.toLowerCase() !== 'required' ? token : undefined;
|
|
837
|
-
};
|
|
838
813
|
// Every probe keeps the same identity, current cookies and caller's request budget.
|
|
839
814
|
const probe = async (method) => {
|
|
840
815
|
const cookieHeader = this.composeCookieHeader();
|
|
@@ -844,7 +819,6 @@ export class AdtHttpClient {
|
|
|
844
819
|
delete headers.Cookie;
|
|
845
820
|
const started = Date.now();
|
|
846
821
|
const response = await this.doFetch(this.buildUrl(path), method, headers, undefined, options);
|
|
847
|
-
this.storeCookies(response);
|
|
848
822
|
logger.emitAudit({
|
|
849
823
|
timestamp: new Date().toISOString(),
|
|
850
824
|
level: 'debug',
|
|
@@ -853,13 +827,13 @@ export class AdtHttpClient {
|
|
|
853
827
|
path,
|
|
854
828
|
statusCode: response.status,
|
|
855
829
|
durationMs: Date.now() - started,
|
|
856
|
-
success: !!
|
|
857
|
-
adtMode: this.config.sessionType ?? 'unspecified',
|
|
858
|
-
hasContext: /(?:^|;\s*)sap-contextid=/.test(
|
|
830
|
+
success: !!usableCsrfToken(response),
|
|
831
|
+
adtMode: headers['X-sap-adt-sessiontype'] === undefined ? 'unspecified' : (this.config.sessionType ?? 'unspecified'),
|
|
832
|
+
hasContext: /(?:^|;\s*)sap-contextid=/.test(headers.Cookie ?? ''),
|
|
859
833
|
});
|
|
860
|
-
if (method === 'GET' && response.status === 200 && !
|
|
861
|
-
//
|
|
862
|
-
this.handleResponse(response.status, response.headers, await response.text(), path);
|
|
834
|
+
if (method === 'GET' && response.status === 200 && !usableCsrfToken(response)) {
|
|
835
|
+
// Check login pages, but preserve the header-only legacy discovery fallback.
|
|
836
|
+
this.handleResponse(response.status, response.headers, await response.text(), path, false);
|
|
863
837
|
}
|
|
864
838
|
// Only headers are needed; release GET bodies before a fallback or return.
|
|
865
839
|
if (!response.bodyUsed)
|
|
@@ -888,16 +862,23 @@ export class AdtHttpClient {
|
|
|
888
862
|
// The tested 7.50/7.58/8.16 systems returned HEAD 400 with a token; GET returned 200.
|
|
889
863
|
// Retry these HEAD refusals or a successful response without a token on the same path.
|
|
890
864
|
// A successful HEAD with a usable token remains the one-request fast path.
|
|
891
|
-
|
|
865
|
+
const headStatus = response.status;
|
|
866
|
+
if ([400, 403, 405].includes(response.status) || (response.ok && !usableCsrfToken(response))) {
|
|
867
|
+
response = await probe('GET');
|
|
868
|
+
}
|
|
869
|
+
// Both stateful discovery probes can fail on affected routes (#1044). Bootstrap once
|
|
870
|
+
// without that header; keep identity/cookies and subsequent lock/write requests stateful.
|
|
871
|
+
if (this.config.sessionType === 'stateful' && headStatus === 400 && response.status === 400) {
|
|
872
|
+
delete headers['X-sap-adt-sessiontype'];
|
|
892
873
|
response = await probe('GET');
|
|
893
874
|
}
|
|
894
875
|
// Older ADT handlers may return an empty 200 for a missing core resource (#817).
|
|
895
876
|
// A real auth/server failure must not be hidden by trying another endpoint.
|
|
896
|
-
if (response.status === 404 || response.status === 405 || (response.ok && !
|
|
877
|
+
if (response.status === 404 || response.status === 405 || (response.ok && !usableCsrfToken(response))) {
|
|
897
878
|
path = '/sap/bc/adt/discovery';
|
|
898
879
|
response = await probe('GET');
|
|
899
880
|
}
|
|
900
|
-
const token =
|
|
881
|
+
const token = usableCsrfToken(response);
|
|
901
882
|
if (!token) {
|
|
902
883
|
if (response.status === 401) {
|
|
903
884
|
if (this.isCookieAuthMode())
|
|
@@ -910,12 +891,13 @@ export class AdtHttpClient {
|
|
|
910
891
|
}
|
|
911
892
|
throw new AdtApiError(`No CSRF token in response (HTTP ${response.status})`, response.status, path);
|
|
912
893
|
}
|
|
913
|
-
this.csrfToken = token;
|
|
914
894
|
return path;
|
|
915
895
|
}
|
|
916
896
|
catch (err) {
|
|
917
897
|
if (err instanceof AdtApiError || err instanceof AdtNetworkError)
|
|
918
898
|
throw err;
|
|
899
|
+
if (options?.signal?.aborted)
|
|
900
|
+
throwIfRequestCancelled(options);
|
|
919
901
|
const message = err instanceof Error ? err.message : String(err);
|
|
920
902
|
throw new AdtNetworkError(`CSRF token fetch failed: ${message}`, err instanceof Error ? err : undefined);
|
|
921
903
|
}
|
|
@@ -954,8 +936,7 @@ export class AdtHttpClient {
|
|
|
954
936
|
*/
|
|
955
937
|
clearCookiesAndMark() {
|
|
956
938
|
this.config.cookies = {};
|
|
957
|
-
this.
|
|
958
|
-
this.csrfToken = '';
|
|
939
|
+
this.resetSession();
|
|
959
940
|
this.cookiesCleared = true;
|
|
960
941
|
}
|
|
961
942
|
/**
|
|
@@ -1004,6 +985,7 @@ export class AdtHttpClient {
|
|
|
1004
985
|
resetSession() {
|
|
1005
986
|
this.cookieJar.clear();
|
|
1006
987
|
this.csrfToken = '';
|
|
988
|
+
this.securitySessionGate.reset();
|
|
1007
989
|
}
|
|
1008
990
|
/**
|
|
1009
991
|
* Build the `Cookie` request header by merging the static `config.cookies`
|
|
@@ -1036,11 +1018,18 @@ export class AdtHttpClient {
|
|
|
1036
1018
|
return undefined;
|
|
1037
1019
|
return Array.from(merged, ([name, value]) => `${name}=${value}`).join('; ');
|
|
1038
1020
|
}
|
|
1021
|
+
/** Read the current pair together after a wait or a response that can rotate the session. */
|
|
1022
|
+
refreshSessionHeaders(method, headers) {
|
|
1023
|
+
const cookie = this.composeCookieHeader();
|
|
1024
|
+
if (cookie)
|
|
1025
|
+
headers.Cookie = cookie;
|
|
1026
|
+
else
|
|
1027
|
+
delete headers.Cookie;
|
|
1028
|
+
if (isModifyingMethod(method))
|
|
1029
|
+
headers['X-CSRF-Token'] = this.csrfToken;
|
|
1030
|
+
}
|
|
1039
1031
|
storeCookies(response) {
|
|
1040
|
-
const
|
|
1041
|
-
if (!setCookieHeaders || setCookieHeaders.length === 0)
|
|
1042
|
-
return;
|
|
1043
|
-
for (const cookie of setCookieHeaders) {
|
|
1032
|
+
for (const cookie of response.headers.getSetCookie() ?? []) {
|
|
1044
1033
|
// Set-Cookie: name=value; Path=/; HttpOnly; ...
|
|
1045
1034
|
const nameValue = cookie.split(';')[0];
|
|
1046
1035
|
if (!nameValue)
|
|
@@ -1053,18 +1042,18 @@ export class AdtHttpClient {
|
|
|
1053
1042
|
this.cookieJar.set(name, value);
|
|
1054
1043
|
}
|
|
1055
1044
|
}
|
|
1056
|
-
/**
|
|
1057
|
-
buildUrl(path) {
|
|
1045
|
+
/** Add SAP context query params unless the caller sends that context in headers. */
|
|
1046
|
+
buildUrl(path, sapContextInHeaders = false) {
|
|
1058
1047
|
const base = this.config.baseUrl.replace(/\/$/, '');
|
|
1059
1048
|
const normalizedPath = path.startsWith('/') ? path : `/${path}`;
|
|
1060
1049
|
const url = new URL(base + normalizedPath);
|
|
1061
|
-
if (this.config.client) {
|
|
1050
|
+
if (this.config.client && !sapContextInHeaders) {
|
|
1062
1051
|
url.searchParams.set('sap-client', this.config.client);
|
|
1063
1052
|
}
|
|
1064
|
-
if (this.config.language) {
|
|
1053
|
+
if (this.config.language && !sapContextInHeaders) {
|
|
1065
1054
|
url.searchParams.set('sap-language', this.config.language);
|
|
1066
1055
|
}
|
|
1067
|
-
if (this.config.disableSaml) {
|
|
1056
|
+
if (this.config.disableSaml && !sapContextInHeaders) {
|
|
1068
1057
|
url.searchParams.set('saml2', 'disabled');
|
|
1069
1058
|
}
|
|
1070
1059
|
return url.toString();
|
|
@@ -1101,7 +1090,37 @@ export class AdtHttpClient {
|
|
|
1101
1090
|
* Node 22's built-in fetch embeds an older undici version whose dispatcher
|
|
1102
1091
|
* interface is incompatible with npm undici@8 Agent/ProxyAgent instances.
|
|
1103
1092
|
*/
|
|
1104
|
-
async doFetch(url, method, headers, body, options) {
|
|
1093
|
+
async doFetch(url, method, headers, body, options, resetOnUnauthorized = false) {
|
|
1094
|
+
const cookieNames = () => [...this.cookieJar.keys(), ...Object.keys(this.config.cookies ?? {})];
|
|
1095
|
+
const response = await this.securitySessionGate.run(() => hasSecuritySessionCookie(cookieNames()), async (waited) => {
|
|
1096
|
+
const generation = this.securitySessionGate.generation;
|
|
1097
|
+
if (waited) {
|
|
1098
|
+
// A preceding response may have replaced both fields while this send waited.
|
|
1099
|
+
// Keep the refreshed pair for this logical request's negotiation/retry paths too.
|
|
1100
|
+
this.refreshSessionHeaders(method, headers);
|
|
1101
|
+
}
|
|
1102
|
+
const response = await this.sendRequest(url, method, headers, body, options);
|
|
1103
|
+
const fetchingCsrf = headers['X-CSRF-Token']?.toLowerCase() === 'fetch';
|
|
1104
|
+
if (generation === this.securitySessionGate.generation) {
|
|
1105
|
+
// Store once at the headers boundary, before releasing the bootstrap owner.
|
|
1106
|
+
this.storeCookies(response);
|
|
1107
|
+
// Ordinary responses (including 404) can carry a token without proving a Fetch probe succeeded.
|
|
1108
|
+
const token = fetchingCsrf ? usableCsrfToken(response) : response.headers.get('x-csrf-token');
|
|
1109
|
+
if (token && token !== 'Required')
|
|
1110
|
+
this.csrfToken = token;
|
|
1111
|
+
// Reset before releasing waiters; a slow 401 body must not clear their new session.
|
|
1112
|
+
if (resetOnUnauthorized && response.status === 401)
|
|
1113
|
+
this.resetSession();
|
|
1114
|
+
}
|
|
1115
|
+
else if (fetchingCsrf) {
|
|
1116
|
+
await response.body?.cancel();
|
|
1117
|
+
throw new AdtNetworkError('SAP session changed during CSRF bootstrap. Retry the request.');
|
|
1118
|
+
}
|
|
1119
|
+
return response;
|
|
1120
|
+
}, options);
|
|
1121
|
+
return prepareBoundedResponse(response, url, options);
|
|
1122
|
+
}
|
|
1123
|
+
async sendRequest(url, method, headers, body, options) {
|
|
1105
1124
|
throwIfRequestCancelled(options);
|
|
1106
1125
|
// Forward the caller's W3C trace context to SAP so one trace spans agent → ARC-1 → SAP.
|
|
1107
1126
|
// Empty unless the MCP client sent a valid `traceparent`; ARC-1 never originates a trace.
|
|
@@ -1128,7 +1147,7 @@ export class AdtHttpClient {
|
|
|
1128
1147
|
...(dispatcher ? { dispatcher } : {}),
|
|
1129
1148
|
}, options?.attemptBudget));
|
|
1130
1149
|
}
|
|
1131
|
-
return
|
|
1150
|
+
return response;
|
|
1132
1151
|
}
|
|
1133
1152
|
/**
|
|
1134
1153
|
* Execute an HTTP request through the BTP connectivity proxy using standard
|
|
@@ -1212,52 +1231,10 @@ export class AdtHttpClient {
|
|
|
1212
1231
|
function isModifyingMethod(method) {
|
|
1213
1232
|
return ['POST', 'PUT', 'DELETE', 'PATCH'].includes(method.toUpperCase());
|
|
1214
1233
|
}
|
|
1215
|
-
/**
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
* - delta-seconds (e.g. `"5"`)
|
|
1220
|
-
* - HTTP-date (e.g. `"Wed, 12 May 2026 14:30:00 GMT"`)
|
|
1221
|
-
*
|
|
1222
|
-
* On missing, NaN, malformed, past-date, or negative input, falls back to `fallbackMs`.
|
|
1223
|
-
* Always clamps to `[0, 60_000]` ms so a misbehaving gateway can't stall us indefinitely
|
|
1224
|
-
* and a too-small/past value can't degenerate into a hot retry loop.
|
|
1225
|
-
*
|
|
1226
|
-
* Returns `{ delayMs, source }` — `source: 'header' | 'fallback'` lets audit events
|
|
1227
|
-
* record whether the delay came from the server or from our jitter floor (useful for
|
|
1228
|
-
* capacity tuning).
|
|
1229
|
-
*/
|
|
1230
|
-
export function parseRetryAfter(header, fallbackMs) {
|
|
1231
|
-
const clamp = (ms) => Math.max(0, Math.min(60_000, ms));
|
|
1232
|
-
if (header == null || header === '') {
|
|
1233
|
-
return { delayMs: clamp(fallbackMs), source: 'fallback' };
|
|
1234
|
-
}
|
|
1235
|
-
const trimmed = header.trim();
|
|
1236
|
-
// delta-seconds form: integer (and only digits, optionally signed)
|
|
1237
|
-
if (/^-?\d+$/.test(trimmed)) {
|
|
1238
|
-
const seconds = Number.parseInt(trimmed, 10);
|
|
1239
|
-
if (Number.isFinite(seconds)) {
|
|
1240
|
-
return { delayMs: clamp(seconds * 1000), source: 'header' };
|
|
1241
|
-
}
|
|
1242
|
-
return { delayMs: clamp(fallbackMs), source: 'fallback' };
|
|
1243
|
-
}
|
|
1244
|
-
// HTTP-date form
|
|
1245
|
-
const epochMs = Date.parse(trimmed);
|
|
1246
|
-
if (Number.isFinite(epochMs)) {
|
|
1247
|
-
return { delayMs: clamp(epochMs - Date.now()), source: 'header' };
|
|
1248
|
-
}
|
|
1249
|
-
return { delayMs: clamp(fallbackMs), source: 'fallback' };
|
|
1250
|
-
}
|
|
1251
|
-
/**
|
|
1252
|
-
* Try to extract an accepted media type from a SAP 406 error response body.
|
|
1253
|
-
*
|
|
1254
|
-
* SAP sometimes includes the expected media type in error text, e.g.:
|
|
1255
|
-
* "...expected application/vnd.sap.adt.transportorganizertree.v1+xml..."
|
|
1256
|
-
* Returns the extracted media type or undefined if none found.
|
|
1257
|
-
*/
|
|
1258
|
-
function inferAcceptFromError(body) {
|
|
1259
|
-
const match = body.match(/application\/[\w.+-]+(?:\/[\w.+-]+)?/);
|
|
1260
|
-
return match?.[0];
|
|
1234
|
+
/** A token on an unsuccessful response is not proof of authentication. */
|
|
1235
|
+
function usableCsrfToken(response) {
|
|
1236
|
+
const token = response.headers.get('x-csrf-token')?.trim();
|
|
1237
|
+
return response.ok && token && token.toLowerCase() !== 'required' ? token : undefined;
|
|
1261
1238
|
}
|
|
1262
1239
|
/**
|
|
1263
1240
|
* Distinguish a real SAP logon page from a legitimate HTML response payload.
|