@sap/cds 8.2.0 → 8.2.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 +11 -0
- package/lib/linked/validate.js +13 -8
- package/lib/srv/middlewares/cds-context.js +2 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/validator/ValueValidator.js +1 -1
- package/libx/_runtime/common/utils/streamProp.js +7 -5
- package/libx/odata/parse/multipartToJson.js +3 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,17 @@
|
|
|
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 8.2.1 - 2024-09-04
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- Date validation of legacy OData protocol adapter
|
|
12
|
+
- Content-Length headers in multipart batch request body
|
|
13
|
+
- Streaming requests with virtual properties
|
|
14
|
+
- Bring back support for `x-correlationid`
|
|
15
|
+
- Validation of inlined elements
|
|
16
|
+
- multipart `$batch` parsing with _--_ as part of payload
|
|
17
|
+
|
|
7
18
|
## Version 8.2.0 - 2024-08-30
|
|
8
19
|
|
|
9
20
|
### Added
|
package/lib/linked/validate.js
CHANGED
|
@@ -56,13 +56,15 @@ class Validation {
|
|
|
56
56
|
class ValidationErrors extends Array {
|
|
57
57
|
add (error) {
|
|
58
58
|
const err = Object.create (ValidationErrors.proto)
|
|
59
|
-
err.message =
|
|
59
|
+
err.message = error
|
|
60
60
|
this.push (err)
|
|
61
61
|
return err
|
|
62
62
|
}
|
|
63
63
|
static proto = Object.create (Error.prototype, {
|
|
64
64
|
message: { writable:true, configurable:true },
|
|
65
|
-
stack: {
|
|
65
|
+
stack: { configurable:true, get() { return this.message },
|
|
66
|
+
set(v) { Object.defineProperty (this, 'stack', { value:v, writable:true, configurable:true }) },
|
|
67
|
+
},
|
|
66
68
|
code: { value: '400', writable:true }, // REVISIT: should be 'ASSERT_'... (i.e. msg) but we need to adjust all tests, and have a code catalogue
|
|
67
69
|
statusCode: { value: 400 }, // REVISIT: should go into mappings in adapter's error handlers -> requires a code catalogue // REVISIT: .statusCode vs .status?
|
|
68
70
|
numericSeverity: { value: 4, enumerable: true }, // REVISIT: that is OData-specific
|
|
@@ -118,12 +120,15 @@ const $any = class any {
|
|
|
118
120
|
}
|
|
119
121
|
|
|
120
122
|
_is_mandatory (d=this) {
|
|
121
|
-
return d.own('_mandatory', ()=>
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
123
|
+
return d.own('_mandatory', ()=> (
|
|
124
|
+
!d['@readonly'] // readonly -> not mandatory
|
|
125
|
+
&& (d['@mandatory'] || d['@Common.FieldControl']?.['#'] === 'Mandatory')
|
|
126
|
+
&& !d._is_flattened()
|
|
127
|
+
))
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
_is_flattened (d=this) {
|
|
131
|
+
return d.parent?.query?.SELECT.columns?.some (c => c.ref?.length > 1 && d.name === (c.as || c.ref.at(-1)))
|
|
127
132
|
}
|
|
128
133
|
|
|
129
134
|
_is_readonly (d=this) {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const cds = require ('../../index')
|
|
2
2
|
const corr_id = 'x-correlation-id'
|
|
3
|
+
const crippled_corr_id = 'x-correlationid'
|
|
3
4
|
const req_id = 'x-request-id'
|
|
4
5
|
const vr_id = 'x-vcap-request-id'
|
|
5
6
|
const { uuid } = cds.utils
|
|
@@ -8,7 +9,7 @@ const { EventContext } = cds
|
|
|
8
9
|
module.exports = () => {
|
|
9
10
|
/** @type { import('express').Handler } */
|
|
10
11
|
return function cds_context (req, res, next) {
|
|
11
|
-
const id = req.headers[corr_id] ??= req.headers[req_id] || req.headers[vr_id] || uuid()
|
|
12
|
+
const id = req.headers[corr_id] ??= req.headers[req_id] || req.headers[vr_id] || req.headers[crippled_corr_id] || uuid()
|
|
12
13
|
const ctx = EventContext.for ({ id, http: { req, res } })
|
|
13
14
|
res.set ('X-Correlation-ID', id) // Note: we use capitalized style here as that's common standard in HTTP world
|
|
14
15
|
cds._context.run (ctx, next)
|
package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/validator/ValueValidator.js
CHANGED
|
@@ -4,7 +4,7 @@ const { big } = require('@sap/cds-foss')
|
|
|
4
4
|
const { isInvalidBase64string } = require('../../../../../../common/utils/binary')
|
|
5
5
|
const IllegalArgumentError = require('../errors/IllegalArgumentError')
|
|
6
6
|
|
|
7
|
-
const YEAR_RE = '(?:-?(?:(?:(?:0\\d{3})|(?:[1-9]\\d{3
|
|
7
|
+
const YEAR_RE = '(?:-?(?:(?:(?:0\\d{3})|(?:[1-9]\\d{3}))))'
|
|
8
8
|
const MONTH_RE = '(?:(?:0[1-9])|(?:1[012]))'
|
|
9
9
|
const DAY_RE = '(?:(?:0[1-9])|(?:[12]\\d)|(?:3[01]))'
|
|
10
10
|
const HOURS_RE = '(?:(?:[01]\\d)|(?:2[0-3]))'
|
|
@@ -2,8 +2,10 @@ const cds = require('../../cds')
|
|
|
2
2
|
const { ensureNoDraftsSuffix, ensureUnlocalized } = require('./draft')
|
|
3
3
|
const { isDuplicate } = require('./rewriteAsterisks')
|
|
4
4
|
|
|
5
|
-
const _addColumn = (name, type, columns, url) => {
|
|
6
|
-
|
|
5
|
+
const _addColumn = (name, type, columns, url, target) => {
|
|
6
|
+
let mediaType = typeof type === 'object' && type['=']
|
|
7
|
+
if (mediaType && target.elements[mediaType]?.virtual) return
|
|
8
|
+
mediaType = mediaType ? { ref: [mediaType.replaceAll(/\./g, '_')] } : { val: type }
|
|
7
9
|
const col = {
|
|
8
10
|
xpr: [
|
|
9
11
|
'case',
|
|
@@ -34,8 +36,8 @@ const _addColumn = (name, type, columns, url) => {
|
|
|
34
36
|
const _addColumns = (target, columns) => {
|
|
35
37
|
for (const k in target.elements) {
|
|
36
38
|
const el = target.elements[k]
|
|
37
|
-
if (el['@Core.MediaType']) {
|
|
38
|
-
_addColumn(el.name, el['@Core.MediaType'], columns, el['@Core.IsURL'] && el.type === 'cds.String')
|
|
39
|
+
if (el['@Core.MediaType'] && !el.virtual) {
|
|
40
|
+
_addColumn(el.name, el['@Core.MediaType'], columns, el['@Core.IsURL'] && el.type === 'cds.String', target)
|
|
39
41
|
}
|
|
40
42
|
}
|
|
41
43
|
}
|
|
@@ -58,7 +60,7 @@ const handleStreamProperties = (target, columns, model) => {
|
|
|
58
60
|
_addColumns(target, columns)
|
|
59
61
|
} else if (col.ref && (type === 'cds.LargeBinary' || (mediaType && !ignoreMediaType))) {
|
|
60
62
|
if (mediaType) {
|
|
61
|
-
_addColumn(name, mediaType, columns, element['@Core.IsURL'])
|
|
63
|
+
_addColumn(name, mediaType, columns, element['@Core.IsURL'], target)
|
|
62
64
|
columns.splice(index, 1)
|
|
63
65
|
} else if (!cds.env.features.stream_compat) {
|
|
64
66
|
columns.splice(index, 1)
|
|
@@ -69,7 +69,9 @@ const parseStream = async function* (body, boundary) {
|
|
|
69
69
|
const process = chunk => {
|
|
70
70
|
let changed = chunk
|
|
71
71
|
.toString()
|
|
72
|
-
.replace(
|
|
72
|
+
.replace(/^--(.*)$/gm, (_, g) => `HEAD /${g} HTTP/1.1${g.slice(-2) === '--' ? CRLF : ''}`)
|
|
73
|
+
// correct content-length for non-HEAD requests is inserted below
|
|
74
|
+
.replace(/content-length: \d+\r\n/gim, '')
|
|
73
75
|
.replace(/ \$/g, ' /$')
|
|
74
76
|
|
|
75
77
|
// HACKS!!!
|