@sap/cds 9.3.0 → 9.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,14 @@
4
4
  - The format is based on [Keep a Changelog](https://keepachangelog.com/).
5
5
  - This project adheres to [Semantic Versioning](https://semver.org/).
6
6
 
7
+ ## Version 9.3.1 - 2025-09-03
8
+
9
+ ### Fixed
10
+
11
+ - In messaging services, propagated headers (e.g. `x-correlation-id`) will not be automatically propagated for `format: 'cloudevents'`
12
+ - Avoid deprecation warning for `cds.context.user.tokenInfo`
13
+ - Consider `@Capabilities.ExpandRestrictions.NonExpandableProperties` annotation and ignore fields referenced by the annotation, when rewriting asterisk expand into columns
14
+
7
15
  ## Version 9.3.0 - 2025-08-29
8
16
 
9
17
  ### Added
@@ -113,14 +113,17 @@ function get_user_factory(credentials, skipped_attrs) {
113
113
  if (Array.isArray(payload.ias_apis)) payload.ias_apis.forEach(r => (roles[r] = 1))
114
114
  if (clientid === credentials.clientid) roles['internal-user'] = 1
115
115
  else delete roles['internal-user']
116
- return new cds.User({
117
- id: 'system', roles, authInfo: securityContext,
118
- // REVISIT: remove compat in cds^10
119
- get tokenInfo() {
116
+
117
+ const user = new cds.User({ id: 'system', roles, authInfo: securityContext })
118
+ // REVISIT: remove compat in cds^10
119
+ Object.defineProperty(user, 'tokenInfo', {
120
+ get() {
121
+ // prettier-ignore
120
122
  cds.utils.deprecated({ kind: 'API', old: 'cds.context.user.tokenInfo', use: 'cds.context.user.authInfo.token' })
121
123
  return securityContext.token
122
124
  }
123
125
  })
126
+ return user
124
127
  }
125
128
 
126
129
  // add all unknown attributes to req.user.attr in order to keep public API small
@@ -138,14 +141,15 @@ function get_user_factory(credentials, skipped_attrs) {
138
141
  if (attr.given_name) attr.givenName = attr.given_name
139
142
  if (attr.family_name) attr.familyName = attr.family_name
140
143
 
141
- return new cds.User({
142
- id: payload.sub, attr, authInfo: securityContext,
143
- // REVISIT: remove compat in cds^10
144
- get tokenInfo() {
144
+ const user = new cds.User({ id: payload.sub, attr, authInfo: securityContext })
145
+ // REVISIT: remove compat in cds^10
146
+ Object.defineProperty(user, 'tokenInfo', {
147
+ get() {
145
148
  cds.utils.deprecated({ kind: 'API', old: 'cds.context.user.tokenInfo', use: 'cds.context.user.authInfo.token' })
146
149
  return securityContext.token
147
150
  }
148
151
  })
152
+ return user
149
153
  }
150
154
  }
151
155
 
@@ -87,14 +87,15 @@ function get_user_factory(credentials, xsappname, kind) {
87
87
  attr.email = payload.email
88
88
  }
89
89
 
90
- return new cds.User({
91
- id, roles, attr, authInfo: securityContext,
92
- // REVISIT: remove compat in cds^10
93
- get tokenInfo() {
90
+ const user = new cds.User({ id, roles, attr, authInfo: securityContext })
91
+ // REVISIT: remove compat in cds^10
92
+ Object.defineProperty(user, 'tokenInfo', {
93
+ get() {
94
94
  cds.utils.deprecated({ kind: 'API', old: 'cds.context.user.tokenInfo', use: 'cds.context.user.authInfo.token' })
95
95
  return securityContext.token
96
96
  }
97
97
  })
98
+ return user
98
99
  }
99
100
  }
100
101
 
@@ -89,11 +89,17 @@ const rewriteExpandAsterisk = (columns, target) => {
89
89
  })
90
90
  if (expandAllColIdx > -1) {
91
91
  const { expand } = columns.splice(expandAllColIdx, 1)[0]
92
+
93
+ const annotation = target['@Capabilities.ExpandRestrictions.NonExpandableProperties']
94
+ const restrictions = annotation?.map(element => element['=']) ?? []
95
+
92
96
  for (const elName in target.elements) {
93
- if (target.elements[elName]._target && !columns.find(col => col.expand && col.ref && col.ref[0] === elName)) {
94
- if (elName === 'SiblingEntity') continue
95
- columns.push({ ref: [elName], expand: [...expand] })
96
- }
97
+ if (!target.elements[elName]._target) continue
98
+ if (restrictions.includes(elName)) continue
99
+ if (elName === 'SiblingEntity') continue
100
+ if (columns.find(col => col.expand && col.ref && col.ref[0] === elName)) continue
101
+
102
+ columns.push({ ref: [elName], expand: [...expand] })
97
103
  }
98
104
  }
99
105
  }
@@ -103,6 +103,13 @@ module.exports = class MessagingService extends cds.Service {
103
103
 
104
104
  prepareHeaders(headers, event) {
105
105
  if (this.options.format === 'cloudevents') {
106
+ for (const propagatedHeader of cds.EventContext.propagateHeaders) {
107
+ if (headers[propagatedHeader] && !Object.hasOwn(propagatedHeader, headers)) {
108
+ // For propagated headers, e.g. `x-correlation-id` (from inbound HTTP request), we don't want to set the
109
+ // respective header. It's incompatible to the cloudevents spec, allowed is only [a-zA-Z0-9].
110
+ Object.defineProperty(headers, propagatedHeader, { value: undefined, enumerable: false })
111
+ }
112
+ }
106
113
  if (!('id' in headers)) headers.id = cds.utils.uuid()
107
114
  if (!('type' in headers)) headers.type = event
108
115
  if (!('source' in headers)) headers.source = `/default/sap.cap/${process.pid}`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sap/cds",
3
- "version": "9.3.0",
3
+ "version": "9.3.1",
4
4
  "description": "SAP Cloud Application Programming Model - CDS for Node.js",
5
5
  "homepage": "https://cap.cloud.sap/",
6
6
  "keywords": [