@sap/cds 9.0.2 → 9.0.3

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.0.3 - 2025-06-04
8
+
9
+ ### Fixed
10
+
11
+ - Handling of bad timestamps in URL ($filter and temporals)
12
+ - View metadata for requests with $apply
13
+ - Server crash for some URLs
14
+
7
15
  ## Version 9.0.2 - 2025-05-28
8
16
 
9
17
  ### Changed
@@ -62,13 +62,14 @@ exports.expected = ([,type], arg) => {
62
62
  }
63
63
 
64
64
 
65
- exports.isSystemError = err => err.name in {
66
- TypeError:1,
67
- ReferenceError:1,
68
- SyntaxError:1,
69
- RangeError:1,
70
- URIError:1,
71
- }
65
+ const system_errors = [
66
+ TypeError,
67
+ ReferenceError,
68
+ SyntaxError,
69
+ RangeError,
70
+ URIError
71
+ ]
72
+ exports.isSystemError = err => system_errors.some(e => err instanceof e)
72
73
 
73
74
 
74
75
  //
@@ -4,7 +4,6 @@ const normalizeTimestamp = require('../utils/normalizeTimestamp')
4
4
  const _getDateFromQueryOptions = str => {
5
5
  if (str) {
6
6
  const match = str.match(/^date'(.+)'$/)
7
- // REVISIT: What happens with invalid date values in query parameter? if match.length > 1
8
7
  return normalizeTimestamp(match ? match[1] : str)
9
8
  }
10
9
  }
@@ -9,13 +9,22 @@ const _lengthIfNotFoundIndex = (index, length) => (index > -1 ? index : length)
9
9
  module.exports = value => {
10
10
  if (value instanceof Date) value = value.toISOString()
11
11
  if (typeof value === 'number') value = new Date(value).toISOString()
12
+ if (typeof value !== 'string') {
13
+ const msg = `Value "${value}" is not a valid Timestamp`
14
+ throw Object.assign(new Error(msg), { statusCode: 400 })
15
+ }
12
16
 
13
17
  const decimalPointIndex = _lengthIfNotFoundIndex(value.lastIndexOf('.'), value.length)
14
18
  const tzRegexMatch = TZ_REGEX.exec(value)
15
19
  const tz = tzRegexMatch?.[0] || ''
16
20
  const tzIndex = _lengthIfNotFoundIndex(tzRegexMatch?.index, value.length)
17
21
  const dateEndIndex = Math.min(decimalPointIndex, tzIndex)
18
- const dateNoMillisNoTZ = new Date(value.slice(0, dateEndIndex) + tz).toISOString().slice(0, 19)
22
+ let dt = new Date(value.slice(0, dateEndIndex) + tz)
23
+ if (isNaN(dt)) {
24
+ const msg = `Value "${value}" is not a valid Timestamp`
25
+ throw Object.assign(new Error(msg), { statusCode: 400 })
26
+ }
27
+ const dateNoMillisNoTZ = dt.toISOString().slice(0, 19)
19
28
  const normalizedFractionalDigits = value
20
29
  .slice(dateEndIndex + 1, tzIndex)
21
30
  .replace(NON_DIGIT_REGEX, '')
@@ -32,6 +32,14 @@ const _lastValidRef = ref => {
32
32
  }
33
33
  }
34
34
 
35
+ const _getRef = query => {
36
+ if (query.SELECT?.from?.SELECT) return _getRef(query.SELECT.from)
37
+
38
+ return (
39
+ query.SELECT?.from?.ref ?? query.UPDATE?.entity?.ref ?? query.INSERT?.into?.ref ?? query.DELETE?.from?.ref ?? []
40
+ )
41
+ }
42
+
35
43
  const _toBinaryKeyValue = value => `binary'${value.toString('base64')}'`
36
44
 
37
45
  const _odataContext = (query, options) => {
@@ -49,10 +57,7 @@ const _odataContext = (query, options) => {
49
57
 
50
58
  path += '#'
51
59
 
52
- // REVISIT: subselect is treated as empty array
53
- const ref =
54
- query.SELECT?.from?.ref ?? query.UPDATE?.entity?.ref ?? query.INSERT?.into?.ref ?? query.DELETE?.from?.ref ?? []
55
-
60
+ const ref = _getRef(query)
56
61
  const isNavToDraftAdmin = _isNavToDraftAdmin(ref)
57
62
 
58
63
  let edmName
@@ -8,7 +8,7 @@ const _processorFn = elementInfo => {
8
8
  const { row, key } = elementInfo
9
9
  if (!(row[key] == null) && row[key] !== '$now') {
10
10
  const dt = typeof row[key] === 'string' && new Date(row[key])
11
- if (!isNaN(dt)) {
11
+ if (dt && !isNaN(dt)) {
12
12
  switch (category) {
13
13
  case 'cds.DateTime':
14
14
  row[key] = new Date(row[key]).toISOString().replace(/\.\d\d\d/, '')
@@ -423,6 +423,7 @@ const _createTask = (name, msg, context, taskOpts) => {
423
423
  delete _msg.query._target
424
424
  delete _msg.query.__target
425
425
  delete _msg.query.target
426
+ delete _msg.data // `req.data` should be a getter to whatever is in `req.query`
426
427
  }
427
428
  const taskMsg = {
428
429
  ID: cds.utils.uuid(),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sap/cds",
3
- "version": "9.0.2",
3
+ "version": "9.0.3",
4
4
  "description": "SAP Cloud Application Programming Model - CDS for Node.js",
5
5
  "homepage": "https://cap.cloud.sap/",
6
6
  "keywords": [