@sap/cds 9.4.3 → 9.4.4
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 +9 -1
- package/lib/compile/etc/properties.js +0 -1
- package/lib/compile/load.js +1 -1
- package/lib/i18n/localize.js +1 -1
- package/libx/_runtime/common/generic/input.js +5 -1
- package/libx/_runtime/fiori/lean-draft.js +3 -5
- package/libx/_runtime/messaging/common-utils/connections.js +29 -40
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,15 @@
|
|
|
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.4.4 - 2025-10-23
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- Input validation of action parameters in action calls on draft state of draft enabled entities
|
|
12
|
+
- Input validation on `NEW` event of draft choreography
|
|
13
|
+
- Ignore outbox model on Windows
|
|
14
|
+
- `enterprise-messaging-shared`: preserve error listener during reconnect
|
|
15
|
+
|
|
7
16
|
## Version 9.4.3 - 2025-10-10
|
|
8
17
|
|
|
9
18
|
### Fixed
|
|
@@ -62,7 +71,6 @@
|
|
|
62
71
|
- Broken link `cds.auth`
|
|
63
72
|
- Persist original error message in draft validation messages
|
|
64
73
|
- Escaping of `\t` and `\f` in edmx during localization
|
|
65
|
-
- Escaping of JSON escape sequences other than `\"` during localization
|
|
66
74
|
|
|
67
75
|
## Version 9.3.1 - 2025-09-03
|
|
68
76
|
|
|
@@ -40,5 +40,4 @@ function string4 (raw) {
|
|
|
40
40
|
return raw
|
|
41
41
|
.replace(/''/g,"'") .replace(/^"(.*)"$/,"$1") .replace(/^'(.*)'$/,"$1")
|
|
42
42
|
.replace(/\\u[\dA-F]{4}/gi, (match) => String.fromCharCode(parseInt(match.replace(/\\u/g, ''), 16)))
|
|
43
|
-
.replace(/\\(.)/g, (_, seq) => ({ n: '\n', r: '\r', t: '\t', f: '\f' }[seq] ?? seq))
|
|
44
43
|
}
|
package/lib/compile/load.js
CHANGED
|
@@ -13,7 +13,7 @@ module.exports = exports = function load (files, options) {
|
|
|
13
13
|
// REVISIT: bandaid for grow as you go scenario with task queues enabled by default
|
|
14
14
|
let locations
|
|
15
15
|
if (cds.watched) {
|
|
16
|
-
const _is_outbox = p => cds.utils.path.posix.normalize(p).match(
|
|
16
|
+
const _is_outbox = p => cds.utils.path.posix.normalize(p).match(/((\/cds\/srv\/outbox)|(\\cds\\srv\\outbox))(\.cds)?$/)
|
|
17
17
|
const _outbox_only = any?.length === 1 && _is_outbox(any[0]) && (!Array.isArray(files) || !files.some(_is_outbox))
|
|
18
18
|
if (_outbox_only) {
|
|
19
19
|
any = undefined
|
package/lib/i18n/localize.js
CHANGED
|
@@ -85,7 +85,7 @@ exports.edmx = edmx => {
|
|
|
85
85
|
|
|
86
86
|
exports.json = json => {
|
|
87
87
|
if (typeof json === 'object') json = JSON.stringify(json)
|
|
88
|
-
const _json_replacer = s => s
|
|
88
|
+
const _json_replacer = s => s?.replace(/"/g, '\\"')
|
|
89
89
|
return localize(json) .using (_json_replacer)
|
|
90
90
|
}
|
|
91
91
|
|
|
@@ -429,7 +429,11 @@ validate_action._initial = true
|
|
|
429
429
|
module.exports = cds.service.impl(function () {
|
|
430
430
|
this.before(['CREATE', 'UPDATE', 'NEW'], '*', validate_input)
|
|
431
431
|
for (const each of this.actions) this.before(each, validate_action)
|
|
432
|
-
for (const entity of this.entities)
|
|
432
|
+
for (const entity of this.entities)
|
|
433
|
+
for (let a in entity.actions) {
|
|
434
|
+
this.before(a, entity, validate_action)
|
|
435
|
+
if (entity.drafts) this.before(a, entity.drafts, validate_action)
|
|
436
|
+
}
|
|
433
437
|
})
|
|
434
438
|
|
|
435
439
|
// needed for testing
|
|
@@ -1915,13 +1915,11 @@ async function beforeNew(req) {
|
|
|
1915
1915
|
|
|
1916
1916
|
// Also support deep insertions
|
|
1917
1917
|
for (const key in data) {
|
|
1918
|
+
if (!target.elements[key]) return data
|
|
1918
1919
|
if (data[key] && target.elements[key].isAssociation) delete data[key].IsActiveEntity
|
|
1919
|
-
if (!target.elements[key]
|
|
1920
|
-
// do array trick
|
|
1920
|
+
if (!target.elements[key].isComposition) continue
|
|
1921
1921
|
if (Array.isArray(data[key])) data[key] = data[key].map(v => _cleanseData(v, target.elements[key]._target))
|
|
1922
|
-
else if (typeof data[key] === 'object')
|
|
1923
|
-
data[key] = _cleanseData(data[key], target.elements[key]._target)
|
|
1924
|
-
}
|
|
1922
|
+
else if (typeof data[key] === 'object') data[key] = _cleanseData(data[key], target.elements[key]._target)
|
|
1925
1923
|
}
|
|
1926
1924
|
|
|
1927
1925
|
return data
|
|
@@ -6,54 +6,39 @@ const _rmHandlers = client => {
|
|
|
6
6
|
client.removeAllListeners('disconnected')
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
-
const _connectUntilConnected = (client, LOG, x) => {
|
|
10
|
-
if (client._reconnecting) return
|
|
11
|
-
client._reconnecting = true
|
|
12
|
-
|
|
13
|
-
const _waitingTime = waitingTime(x)
|
|
14
|
-
setTimeout(() => {
|
|
15
|
-
connect(client, LOG, true)
|
|
16
|
-
.then(() => {
|
|
17
|
-
client._reconnecting = false
|
|
18
|
-
LOG._warn && LOG.warn('Reconnected to Enterprise Messaging Client')
|
|
19
|
-
})
|
|
20
|
-
.catch(e => {
|
|
21
|
-
_rmHandlers(client)
|
|
22
|
-
LOG.error(e)
|
|
23
|
-
|
|
24
|
-
LOG._warn &&
|
|
25
|
-
LOG.warn(
|
|
26
|
-
`Connection to Enterprise Messaging Client lost: Reconnecting in ${Math.round(_waitingTime / 1000)} s`
|
|
27
|
-
)
|
|
28
|
-
client._reconnecting = false
|
|
29
|
-
_connectUntilConnected(client, LOG, x + 1)
|
|
30
|
-
})
|
|
31
|
-
}, _waitingTime)
|
|
32
|
-
}
|
|
33
|
-
|
|
34
9
|
const connect = (client, LOG, keepAlive) => {
|
|
35
10
|
return new Promise((resolve, reject) => {
|
|
36
11
|
_rmHandlers(client)
|
|
37
12
|
|
|
38
13
|
client
|
|
39
14
|
.once('connected', function () {
|
|
40
|
-
|
|
41
|
-
if (client._reconnecting) return
|
|
15
|
+
_rmHandlers(client)
|
|
42
16
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
}
|
|
47
|
-
if (keepAlive) {
|
|
48
|
-
_rmHandlers(client)
|
|
49
|
-
_connectUntilConnected(client, LOG, 0)
|
|
50
|
-
}
|
|
51
|
-
}
|
|
17
|
+
// It's important to _always_ keep an error listener,
|
|
18
|
+
// otherwise it will throw and crash the server
|
|
19
|
+
client.on('error', err => LOG(err?.message))
|
|
52
20
|
|
|
53
|
-
_rmHandlers(client)
|
|
54
|
-
client.once('error', handleReconnection)
|
|
55
21
|
if (keepAlive) {
|
|
56
|
-
client.
|
|
22
|
+
client.on('disconnected', () => {
|
|
23
|
+
let connected = false
|
|
24
|
+
client.once('connected', () => {
|
|
25
|
+
LOG('Reconnected')
|
|
26
|
+
connected = true
|
|
27
|
+
})
|
|
28
|
+
let x = 1
|
|
29
|
+
const _untilConnected = async () => {
|
|
30
|
+
if (!connected) {
|
|
31
|
+
LOG('Reconnecting')
|
|
32
|
+
try {
|
|
33
|
+
client.connect()
|
|
34
|
+
} catch {
|
|
35
|
+
// we try again...
|
|
36
|
+
}
|
|
37
|
+
setTimeout(_untilConnected, waitingTime(x++))
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
_untilConnected()
|
|
41
|
+
})
|
|
57
42
|
}
|
|
58
43
|
|
|
59
44
|
resolve(client)
|
|
@@ -65,7 +50,11 @@ const connect = (client, LOG, keepAlive) => {
|
|
|
65
50
|
reject(e)
|
|
66
51
|
})
|
|
67
52
|
|
|
68
|
-
|
|
53
|
+
try {
|
|
54
|
+
client.connect()
|
|
55
|
+
} catch (e) {
|
|
56
|
+
reject(e)
|
|
57
|
+
}
|
|
69
58
|
})
|
|
70
59
|
}
|
|
71
60
|
|