@sap/cds 7.5.0 → 7.5.2

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,20 @@
4
4
  - The format is based on [Keep a Changelog](http://keepachangelog.com/).
5
5
  - This project adheres to [Semantic Versioning](http://semver.org/).
6
6
 
7
+ ## Version 7.5.2 - 2024-01-05
8
+
9
+ ### Fixed
10
+
11
+ - Service-level ETag handling in legacy OData server
12
+ - Only provide model to ModelProvider if extensibility or feature toggles are active
13
+ - OData server driven paging when using feature flags `cds.env.features.odata_new_parser` and `cds.env.features.okra_skip_query_options`
14
+
15
+ ## Version 7.5.1 - 2023-12-21
16
+
17
+ ### Fixed
18
+
19
+ - Resolving custom authentication implementation pointer
20
+
7
21
  ## Version 7.5.0 - 2023-12-14
8
22
 
9
23
  ### Added
package/lib/auth/index.js CHANGED
@@ -30,7 +30,8 @@ module.exports = function auth_factory (o) {
30
30
 
31
31
  // try resolving the impl, throw if not found
32
32
  const config = { kind, impl: cds.utils.local(impl) }
33
- try { impl = require.resolve (impl, {paths:[cds.root]}) } catch {
33
+ // use cds.resolve() to allow './srv/auth.js' and 'srv/auth.js'
34
+ try { impl = require.resolve (cds.resolve (impl)?.[0], {paths:[cds.root]}) } catch {
34
35
  throw cds.error `Didn't find auth implementation for ${config}`
35
36
  }
36
37
 
@@ -31,7 +31,11 @@ const metadata = service => {
31
31
  if (mps) {
32
32
  // REVISIT: remove check later
33
33
  if (mpSupportsEmptyLocale()) {
34
- edmx = await mps.getEdmx({ tenant, model: service.model, service: service.definition.name })
34
+ // If no extensibility nor fts, do not provide model to mtxs
35
+ const modelNeeded =
36
+ cds.env.requires.extensibility ||
37
+ (cds.env.requires.toggles && Object.keys(cds.context.features || {}).length)
38
+ edmx = await mps.getEdmx({ tenant, model: modelNeeded && service.model, service: service.definition.name })
35
39
  const extBundle = cds.env.requires.extensibility && (await mps.getI18n({ tenant, locale }))
36
40
  edmx = cds.localize(service.model, locale, edmx, extBundle)
37
41
  } else {
@@ -273,9 +273,9 @@ const _readCollection = async (tx, req, odataReq) => {
273
273
  const limit = Array.isArray(req.query)
274
274
  ? getPageSize(req.query[0]._target).max
275
275
  : req.query.SELECT.limit && req.query.SELECT.limit.rows && req.query.SELECT.limit.rows.val
276
- const top = odataReq.getUriInfo().getQueryOption(QueryOptions.TOP)
276
+ const top = odataReq.getUriInfo().getQueryOption(QueryOptions.TOP) || parseInt(odataReq._queryOptions?.$top)
277
277
  if (limit && limit === result.length && limit !== top && !('$nextLink' in result)) {
278
- const token = odataReq.getUriInfo().getQueryOption(QueryOptions.SKIPTOKEN)
278
+ const token = odataReq.getUriInfo().getQueryOption(QueryOptions.SKIPTOKEN) || odataReq._queryOptions?.$skiptoken
279
279
  if (cds.env.query.limit.reliablePaging && _reliablePagingPossible(req)) {
280
280
  const decoded = token && JSON.parse(Buffer.from(token, 'base64').toString())
281
281
  const skipToken = {
@@ -283,7 +283,10 @@ class OdataRequest {
283
283
  * @throws {PreconditionFailedError} if the validations failed
284
284
  */
285
285
  validateEtag (etag) {
286
- throw new Error("etag validation not supported via okra")
286
+ const url = this.getIncomingRequest().url
287
+ if (!url.match(/\/(\$metadata)?(\?.*)?$/) && !process.env.TEST_OKRA) //> keep etag handling for okra tests
288
+ throw new Error(`etag validation not supported for url "${url}"`)
289
+
287
290
  this._logger.debug('Provided etag:', etag)
288
291
 
289
292
  this._validateEtagHasBeenCalled = true
@@ -12,7 +12,7 @@ class MetadataHandler {
12
12
  */
13
13
  static read (request, response, next) {
14
14
  const metadataETag = request.getService().getMetadataEtag()
15
- // if (metadataETag) request.validateEtag(metadataETag)
15
+ if (metadataETag) request.validateEtag(metadataETag)
16
16
 
17
17
  next(null, { [MetaProperties.ETAG]: metadataETag })
18
18
  }
@@ -16,7 +16,7 @@ class ServiceHandler {
16
16
  */
17
17
  static read (request, response, next) {
18
18
  const metadataETag = request.getService().getMetadataEtag()
19
- // if (metadataETag) request.validateEtag(metadataETag)
19
+ if (metadataETag) request.validateEtag(metadataETag)
20
20
  next(null, { [MetaProperties.ETAG]: metadataETag })
21
21
  // TODO this method may be replaced by a custom service handler, so we need a scenario test that ensures that this method is called...
22
22
  }
@@ -56,7 +56,7 @@ class DispatcherCommand extends Command {
56
56
 
57
57
  if (cachedMetadata) {
58
58
  this._response.setBody({ value: cachedMetadata.metadata, [MetaProperties.ETAG]: cachedMetadata.etag })
59
- // this._request.validateEtag(cachedMetadata.etag)
59
+ this._request.validateEtag(cachedMetadata.etag)
60
60
  next()
61
61
  } else {
62
62
  this._dispatcher
@@ -79,7 +79,7 @@ class DispatcherCommand extends Command {
79
79
  'Metadata size exceeds cache boundary. Use cds option odata.metadataCacheLimit to increase the cache size.'
80
80
  )
81
81
  }
82
- // this._request.validateEtag(metadataEtag)
82
+ this._request.validateEtag(metadataEtag)
83
83
  let data = result.data
84
84
  data[MetaProperties.ETAG] = metadataEtag
85
85
  }
@@ -94,6 +94,7 @@ class EndpointRegistry {
94
94
  }
95
95
  })
96
96
  } catch (error) {
97
+ LOG.error(error)
97
98
  return res.sendStatus(500)
98
99
  }
99
100
  })
@@ -92,7 +92,11 @@ module.exports = srv =>
92
92
  let edmx
93
93
  // REVISIT: remove check later
94
94
  if (mpSupportsEmptyLocale()) {
95
- edmx = metadataCache.edm || (await mps.getEdmx({ tenant, model: srv.model, service: srv.definition.name }))
95
+ // If no extensibility nor fts, do not provide model to mtxs
96
+ const modelNeeded =
97
+ cds.env.requires.extensibility ||
98
+ (cds.env.requires.toggles && Object.keys(cds.context.features || {}).length)
99
+ edmx = metadataCache.edm || (await mps.getEdmx({ tenant, model: modelNeeded && srv.model, service: srv.definition.name }))
96
100
  metadataCache.edm = edmx
97
101
  const extBundle = cds.env.requires.extensibility && (await mps.getI18n({ tenant, locale }))
98
102
  edmx = cds.localize(srv.model, locale, edmx, extBundle)
@@ -27,9 +27,9 @@ const _calculateSkiptoken = (req, result) => {
27
27
  const limit = Array.isArray(req.query)
28
28
  ? getPageSize(req.query[0]._target).max
29
29
  : req.query.SELECT.limit?.rows?.val
30
- const top = parseInt(req.http.req.query['$top'])
30
+ const top = parseInt(req.http.req.query.$top)
31
31
  if (limit === result.length && limit !== top) {
32
- const token = req.http.req.query['$skiptoken']
32
+ const token = req.http.req.query.$skiptoken
33
33
  if (cds.env.query.limit.reliablePaging && _reliablePagingPossible(req)) {
34
34
  const decoded = token && JSON.parse(Buffer.from(token, 'base64').toString())
35
35
  const skipToken = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sap/cds",
3
- "version": "7.5.0",
3
+ "version": "7.5.2",
4
4
  "description": "SAP Cloud Application Programming Model - CDS for Node.js",
5
5
  "homepage": "https://cap.cloud.sap/",
6
6
  "keywords": [