@sap/cds 7.4.1 → 7.5.0
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 +101 -0
- package/apis/cds.d.ts +1 -38
- package/apis/core.d.ts +21 -101
- package/apis/cqn.d.ts +18 -76
- package/apis/csn.d.ts +18 -114
- package/apis/events.d.ts +16 -123
- package/apis/internal/inference.d.ts +18 -32
- package/apis/linked.d.ts +18 -97
- package/apis/log.d.ts +19 -164
- package/apis/models.d.ts +18 -180
- package/apis/ql.d.ts +16 -322
- package/apis/reflect.d.ts +32 -0
- package/apis/server.d.ts +18 -135
- package/apis/services.d.ts +18 -380
- package/bin/cds-serve.js +5 -2
- package/bin/serve.js +7 -16
- package/lib/auth/basic-auth.js +3 -1
- package/lib/auth/ias-auth.js +62 -48
- package/lib/auth/ias-claims.js +34 -0
- package/lib/auth/index.js +54 -33
- package/lib/auth/jwt-auth.js +55 -52
- package/lib/compile/cdsc.js +2 -2
- package/lib/compile/to/edm.js +4 -4
- package/lib/compile/to/hdbtabledata.js +5 -8
- package/lib/compile/to/srvinfo.js +2 -2
- package/lib/env/cds-env.js +3 -9
- package/lib/env/cds-requires.js +16 -17
- package/lib/env/compat.js +0 -9
- package/lib/env/defaults.js +17 -6
- package/lib/i18n/localize.js +46 -42
- package/lib/index.js +6 -8
- package/lib/linked/classes.js +7 -118
- package/lib/linked/entities.js +1 -1
- package/lib/log/cds-log.js +15 -10
- package/lib/log/format/aspects/als.js +41 -0
- package/lib/log/format/aspects/cf.js +36 -0
- package/lib/log/format/json.js +96 -0
- package/lib/plugins.js +7 -3
- package/lib/req/context.js +4 -2
- package/lib/srv/cds-connect.js +3 -5
- package/lib/srv/cds-serve.js +13 -26
- package/lib/srv/factory.js +3 -3
- package/lib/srv/middlewares/index.js +0 -2
- package/lib/srv/middlewares/trace.js +2 -3
- package/lib/srv/protocols/_legacy.js +27 -30
- package/lib/srv/protocols/index.js +173 -58
- package/lib/srv/protocols/odata-v4.js +29 -16
- package/lib/srv/srv-api.js +8 -13
- package/lib/srv/srv-handlers.js +14 -14
- package/lib/utils/cds-utils.js +15 -0
- package/libx/_runtime/auth/index.js +4 -5
- package/libx/_runtime/auth/strategies/basic.js +2 -2
- package/libx/_runtime/cds-services/adapter/odata-v4/OData.js +23 -13
- package/libx/_runtime/cds-services/adapter/odata-v4/ODataRequest.js +6 -15
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/update.js +10 -3
- package/libx/_runtime/cds-services/adapter/odata-v4/to.js +5 -2
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/metaInfo.js +2 -1
- package/libx/_runtime/cds-services/services/utils/columns.js +3 -9
- package/libx/_runtime/cds.js +13 -0
- package/libx/_runtime/common/composition/data.js +3 -0
- package/libx/_runtime/common/composition/delete.js +1 -1
- package/libx/_runtime/common/error/frontend.js +2 -2
- package/libx/_runtime/common/generic/auth/readOnly.js +1 -1
- package/libx/_runtime/common/generic/auth/restrictions.js +1 -1
- package/libx/_runtime/common/generic/sorting.js +4 -5
- package/libx/_runtime/common/utils/csn.js +23 -18
- package/libx/_runtime/common/utils/propagateForeignKeys.js +2 -1
- package/libx/_runtime/common/utils/restrictions.js +6 -15
- package/libx/_runtime/db/generic/input.js +3 -2
- package/libx/_runtime/fiori/generic/readOverDraft.js +2 -5
- package/libx/_runtime/fiori/lean-draft.js +69 -5
- package/libx/_runtime/hana/Service.js +1 -1
- package/libx/_runtime/messaging/AMQPWebhookMessaging.js +1 -1
- package/libx/_runtime/messaging/Outbox.js +3 -8
- package/libx/_runtime/messaging/enterprise-messaging.js +1 -1
- package/libx/_runtime/messaging/file-based.js +1 -1
- package/libx/_runtime/messaging/service.js +7 -10
- package/libx/_runtime/remote/Service.js +15 -45
- package/libx/_runtime/remote/utils/client.js +20 -33
- package/libx/_runtime/remote/utils/cloudSdkProvider.js +30 -0
- package/libx/_runtime/sqlite/Service.js +2 -2
- package/libx/odata/afterburner.js +29 -21
- package/libx/odata/cqn2odata.js +1 -1
- package/libx/odata/error.js +7 -0
- package/libx/odata/grammar.peggy +16 -20
- package/libx/odata/metadata.js +73 -78
- package/libx/odata/parser.js +1 -1
- package/libx/odata/read.js +94 -0
- package/libx/odata/result.js +91 -0
- package/libx/odata/service-document.js +31 -37
- package/libx/odata/utils.js +2 -1
- package/libx/outbox/index.js +9 -4
- package/libx/rest/RestAdapter.js +68 -67
- package/libx/rest/middleware/create.js +20 -26
- package/libx/rest/middleware/delete.js +5 -3
- package/libx/rest/middleware/error.js +2 -3
- package/libx/rest/middleware/input.js +5 -5
- package/libx/rest/middleware/operation.js +96 -41
- package/libx/rest/middleware/parse.js +4 -6
- package/libx/rest/middleware/payload.js +5 -5
- package/libx/rest/middleware/read.js +11 -17
- package/libx/rest/middleware/update.js +20 -25
- package/package.json +2 -1
- package/server.js +7 -4
- package/srv/outbox.cds +9 -10
- package/apis/env.d.ts +0 -25
- package/apis/test.d.ts +0 -81
- package/apis/utils.d.ts +0 -15
- package/lib/auth/passport-basic.js +0 -14
- package/lib/auth/passport-digest.js +0 -16
- package/lib/env/presets.js +0 -35
- package/lib/log/format/cf.js +0 -16
- package/lib/log/format/kibana.js +0 -92
- package/lib/srv/middlewares/ctx-auth.js +0 -11
- package/libx/_runtime/cds-services/adapter/rest/utils/validation-checks.js +0 -119
|
@@ -1,58 +1,113 @@
|
|
|
1
1
|
const cds = require('../../_runtime/cds')
|
|
2
|
-
const { validateReturnType } = require('../../_runtime/cds-services/adapter/rest/utils/validation-checks')
|
|
3
2
|
|
|
4
3
|
const RestRequest = require('../RestRequest')
|
|
5
4
|
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
const { checkStatic, CDS_TYPE_CHECKS } = require('../../_runtime/cds-services/util/assert')
|
|
6
|
+
const getError = require('../../_runtime/common/error')
|
|
8
7
|
|
|
9
|
-
|
|
8
|
+
// REVISIT: use i18n
|
|
9
|
+
const _enrichErrorDetails = (isPrimitive, error) => {
|
|
10
|
+
const element = error.target ? ` '${error.target}' ` : ' '
|
|
11
|
+
const typeDetails = isPrimitive ? '.' : ` according to type definition '${error.type}'.`
|
|
12
|
+
const value = typeof error.value === 'string' ? `'${error.value}'` : error.value
|
|
13
|
+
if (element && element.match(/\w/)) return `Value ${value} of element${element}is invalid${typeDetails}`
|
|
14
|
+
return `Value ${value} is invalid${typeDetails}`
|
|
15
|
+
}
|
|
10
16
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
// REVISIT: use i18n
|
|
18
|
+
const _getTypeError = (operation, type, errorDetails) => {
|
|
19
|
+
const typeErrors = errorDetails.map(error => _enrichErrorDetails(cds.builtin.types[type], error))
|
|
20
|
+
const msg = `Failed to validate return value ${type ? `of type '${type}' ` : ''}for custom ${operation.kind} '${
|
|
21
|
+
operation.name
|
|
22
|
+
}': ${typeErrors.join(' ')}`
|
|
23
|
+
return getError(msg)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const _validateReturnType = (operation, data) => {
|
|
27
|
+
// array of or single return type
|
|
28
|
+
// in case of modeled return type: { type: 'bookModel.Books', _type: csnDefinition }
|
|
29
|
+
// in case of inline return type: { elements: ... } and no explicit name of return type
|
|
30
|
+
const returnType = operation.returns.items ? operation.returns.items : operation.returns
|
|
31
|
+
|
|
32
|
+
if (typeof data === 'undefined') return true
|
|
33
|
+
if (returnType['@open']) return true
|
|
20
34
|
|
|
21
|
-
|
|
22
|
-
|
|
35
|
+
let checkResult
|
|
36
|
+
|
|
37
|
+
// .type of action/function behaves different to .type of other csn elements
|
|
38
|
+
// Return type contains primitives
|
|
39
|
+
// eslint-disable-next-line no-proto
|
|
40
|
+
const _type = typeof returnType._type === 'object' ? returnType.__proto__._type : returnType._type // REVISIT: super dirty hack for compiler's to.edmx polluting the csn definitions with ._type -> please use Symbols instead
|
|
41
|
+
const check = CDS_TYPE_CHECKS[_type] // IMPORTANT: use ._type
|
|
42
|
+
if (check) {
|
|
43
|
+
const array = Array.isArray(data) ? data : [data]
|
|
44
|
+
checkResult = array.filter(value => !check(value)).map(value => ({ type: _type, value }))
|
|
23
45
|
} else {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
// REVISIT: new impl should return instead of throwing to avoid try catch
|
|
28
|
-
validateReturnType(operation, result)
|
|
29
|
-
|
|
30
|
-
// set content-type header to text/plain for returned primitive data types, except for boolean
|
|
31
|
-
const returnType = operation.returns._type
|
|
32
|
-
if (
|
|
33
|
-
!_res.get('content-type') &&
|
|
34
|
-
!operation.returns.items &&
|
|
35
|
-
returnType &&
|
|
36
|
-
cds.builtin.types[returnType] &&
|
|
37
|
-
returnType !== 'cds.Boolean'
|
|
46
|
+
if (typeof data !== 'object') {
|
|
47
|
+
throw new Error(
|
|
48
|
+
`Invalid scalar value ${typeof data === 'string' ? `"${data}"` : data} for return type "${returnType.type}"`
|
|
38
49
|
)
|
|
39
|
-
_res.set('content-type', 'text/plain')
|
|
40
|
-
} catch (e) {
|
|
41
|
-
return next(e)
|
|
42
50
|
}
|
|
43
51
|
|
|
44
|
-
//
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
52
|
+
// Only check complex objects, ignore non-modelled data
|
|
53
|
+
data = (Array.isArray(data) ? data : [data]).filter(entry => typeof entry === 'object' && !Array.isArray(entry))
|
|
54
|
+
|
|
55
|
+
// Determine entity from bound or unbound action/function
|
|
56
|
+
const returnTypeCsnDefinition = returnType._type || returnType
|
|
57
|
+
|
|
58
|
+
// REVISIT: remove exception with cds^6
|
|
59
|
+
// mtx returns object instead of string (as in modell) -> skip validation
|
|
60
|
+
if (returnTypeCsnDefinition.type !== 'cds.String') {
|
|
61
|
+
checkResult = checkStatic(returnTypeCsnDefinition, data, true)
|
|
48
62
|
}
|
|
63
|
+
}
|
|
49
64
|
|
|
50
|
-
|
|
51
|
-
|
|
65
|
+
if (checkResult && checkResult.length !== 0) {
|
|
66
|
+
throw _getTypeError(operation, returnType.type, checkResult)
|
|
67
|
+
}
|
|
52
68
|
|
|
53
|
-
|
|
54
|
-
|
|
69
|
+
return true
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// TODO: add headers to return object to avoid passing _res
|
|
73
|
+
module.exports = srv => async (_req, _res) => {
|
|
74
|
+
const { _query: query, _operation: operation, _data: data, _params } = _req
|
|
75
|
+
|
|
76
|
+
let result
|
|
77
|
+
|
|
78
|
+
const req = query
|
|
79
|
+
? new RestRequest({ query, event: operation.name, data, params: _params })
|
|
80
|
+
: new RestRequest({ event: operation.name.replace(`${srv.namespace}.`, ''), data, params: _params })
|
|
81
|
+
result = await srv.dispatch(req)
|
|
82
|
+
|
|
83
|
+
if (!operation.returns) return { status: 204 }
|
|
84
|
+
|
|
85
|
+
// REVISIT: do not use from old rest adapter
|
|
86
|
+
// REVISIT: new impl should return instead of throwing to avoid try catch
|
|
87
|
+
_validateReturnType(operation, result)
|
|
88
|
+
|
|
89
|
+
// set content-type header to text/plain for returned primitive data types, except for boolean
|
|
90
|
+
const returnType = operation.returns._type
|
|
91
|
+
if (
|
|
92
|
+
!_res.get('content-type') &&
|
|
93
|
+
!operation.returns.items &&
|
|
94
|
+
returnType &&
|
|
95
|
+
cds.builtin.types[returnType] &&
|
|
96
|
+
returnType !== 'cds.Boolean'
|
|
97
|
+
) {
|
|
98
|
+
_res.set('content-type', 'text/plain')
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// REVISIT: Still needed with cds-mtxs?
|
|
102
|
+
// mtx compat, modeled as string but object returned
|
|
103
|
+
if (operation.returns._type === 'cds.String' && typeof result === 'object') {
|
|
104
|
+
_res.set('content-type', 'application/json')
|
|
55
105
|
}
|
|
56
106
|
|
|
57
|
-
|
|
107
|
+
// REVISIT: still needed?
|
|
108
|
+
if (!operation.returns.items && Array.isArray(result)) result = result[0]
|
|
109
|
+
|
|
110
|
+
if (result === undefined) return { status: 204 }
|
|
111
|
+
|
|
112
|
+
return { result }
|
|
58
113
|
}
|
|
@@ -6,12 +6,10 @@ const { where2obj } = require('../../_runtime/common/utils/cqn')
|
|
|
6
6
|
const { convertStructured } = require('../../_runtime/common/utils/ucsn')
|
|
7
7
|
const { deepCopy } = require('../../_runtime/common/utils/copy')
|
|
8
8
|
|
|
9
|
-
module.exports = (req, res, next) => {
|
|
10
|
-
const { _srv: service } = req
|
|
11
|
-
|
|
9
|
+
module.exports = srv => (req, res, next) => {
|
|
12
10
|
// REVISIT: Once we don't display the error message location in terms of an offset, but instead a copy of the
|
|
13
11
|
// original request including a marker, we don't need to provide the baseUrl here.
|
|
14
|
-
let query = cds.odata.parse(req.url, { service, baseUrl: req.baseUrl })
|
|
12
|
+
let query = cds.odata.parse(req.url, { service: srv, baseUrl: req.baseUrl })
|
|
15
13
|
|
|
16
14
|
// parser always produces selects
|
|
17
15
|
const _target = (req._target = query.SELECT && query.SELECT.from)
|
|
@@ -22,7 +20,7 @@ module.exports = (req, res, next) => {
|
|
|
22
20
|
__target: definition,
|
|
23
21
|
SELECT: { one }
|
|
24
22
|
} = query
|
|
25
|
-
if (typeof definition === 'string') definition =
|
|
23
|
+
if (typeof definition === 'string') definition = srv.model.definitions[definition] || srv.model.definitions[definition.split(':$:')[0]].actions[definition.split(':$:')[1]]
|
|
26
24
|
delete query.__target
|
|
27
25
|
|
|
28
26
|
// REVISIT: hack for actions and functions
|
|
@@ -104,7 +102,7 @@ module.exports = (req, res, next) => {
|
|
|
104
102
|
req._data = {}
|
|
105
103
|
} else {
|
|
106
104
|
const payload = deepCopy(args || req.body)
|
|
107
|
-
convertStructured(
|
|
105
|
+
convertStructured(srv, operation || definition, payload, { cleanupStruct: cds.env.features.rest_struct_data })
|
|
108
106
|
req._data = payload
|
|
109
107
|
}
|
|
110
108
|
}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
const { base64ToBuffer } = require('../../_runtime/common/utils/binary')
|
|
2
2
|
|
|
3
|
-
module.exports = (req, res, next) => {
|
|
4
|
-
const {
|
|
3
|
+
module.exports = srv => (req, res, next) => {
|
|
4
|
+
const { _query, _data, _operation } = req
|
|
5
5
|
let definition = _operation || _query.__target
|
|
6
|
-
if (typeof definition === 'string') definition =
|
|
6
|
+
if (typeof definition === 'string') definition = srv.model.definitions[definition] || srv.model.definitions[definition.split(':$:')[0]].actions[definition.split(':$:')[1]]
|
|
7
7
|
|
|
8
|
-
if (!(_data &&
|
|
8
|
+
if (!(_data && srv && definition)) return next()
|
|
9
9
|
|
|
10
|
-
base64ToBuffer(_data,
|
|
10
|
+
base64ToBuffer(_data, srv, definition)
|
|
11
11
|
|
|
12
12
|
next()
|
|
13
13
|
}
|
|
@@ -1,27 +1,22 @@
|
|
|
1
1
|
const RestRequest = require('../RestRequest')
|
|
2
2
|
|
|
3
|
-
module.exports = async
|
|
4
|
-
const {
|
|
3
|
+
module.exports = srv => async _req => {
|
|
4
|
+
const { _query: query, _target, _params } = _req
|
|
5
5
|
|
|
6
6
|
let result,
|
|
7
7
|
status = 200
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
try {
|
|
11
|
-
const req = new RestRequest({ query, _target, params: _params, _req })
|
|
9
|
+
const req = new RestRequest({ query, _target, params: _params, _req })
|
|
12
10
|
|
|
13
|
-
|
|
14
|
-
|
|
11
|
+
// req.data is filled with keys during read and delete
|
|
12
|
+
if (_params) req.data = _params[_params.length - 1]
|
|
15
13
|
|
|
16
|
-
|
|
14
|
+
result = await srv.dispatch(req)
|
|
17
15
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
}
|
|
23
|
-
} catch (e) {
|
|
24
|
-
return next(e)
|
|
16
|
+
// 204 or 404?
|
|
17
|
+
if (result == null && query.SELECT.one) {
|
|
18
|
+
if (_target.ref.length > 1) status = 204
|
|
19
|
+
else throw { code: 404 }
|
|
25
20
|
}
|
|
26
21
|
|
|
27
22
|
// REVISIT: Still needed with cds-mtxs?
|
|
@@ -35,7 +30,6 @@ module.exports = async (_req, _res, next) => {
|
|
|
35
30
|
// TODO check if this is needed
|
|
36
31
|
result = result.toString()
|
|
37
32
|
}
|
|
38
|
-
_req._result = { result, status }
|
|
39
33
|
|
|
40
|
-
|
|
34
|
+
return { result, status }
|
|
41
35
|
}
|
|
@@ -7,36 +7,31 @@ const UPSERT_ALLOWED = !(cds.env.runtime && cds.env.runtime.allow_upsert === fal
|
|
|
7
7
|
|
|
8
8
|
const { deepCopyObject } = require('../../_runtime/common/utils/copy')
|
|
9
9
|
|
|
10
|
-
module.exports = async
|
|
11
|
-
let {
|
|
10
|
+
module.exports = srv => async _req => {
|
|
11
|
+
let { _query: query, _target, _data, _params } = _req
|
|
12
|
+
|
|
12
13
|
let result,
|
|
13
14
|
status = 200
|
|
14
15
|
|
|
15
|
-
//
|
|
16
|
+
// if upsert it allowed, we need to catch 404 and retry with create
|
|
16
17
|
try {
|
|
17
|
-
//
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
result = await srv.dispatch(new RestRequest({ query, _target, method: _req.method, params: _params }))
|
|
24
|
-
if (_params && result) Object.assign(result, _params[_params.length - 1])
|
|
25
|
-
} catch (e) {
|
|
26
|
-
if ((e.code === 404 || e.status === 404 || e.statusCode === 404) && UPSERT_ALLOWED) {
|
|
27
|
-
query = INSERT.into(query.UPDATE.entity).entries(
|
|
28
|
-
_params ? Object.assign(_data, _params[_params.length - 1]) : _data
|
|
29
|
-
)
|
|
30
|
-
result = await srv.dispatch(new RestRequest({ query, _target, params: _params }))
|
|
31
|
-
status = 201
|
|
32
|
-
} else {
|
|
33
|
-
throw e
|
|
34
|
-
}
|
|
35
|
-
}
|
|
18
|
+
// add the data (as copy, if upsert allowed)
|
|
19
|
+
query.data(UPSERT_ALLOWED ? deepCopyObject(_data) : _data)
|
|
20
|
+
|
|
21
|
+
// REVISIT: if PUT, req.method should be PUT -> Crud2Http maps UPSERT to PUT
|
|
22
|
+
result = await srv.dispatch(new RestRequest({ query, _target, method: _req.method, params: _params }))
|
|
23
|
+
if (_params && result) Object.assign(result, _params[_params.length - 1])
|
|
36
24
|
} catch (e) {
|
|
37
|
-
|
|
25
|
+
if ((e.code === 404 || e.status === 404 || e.statusCode === 404) && UPSERT_ALLOWED) {
|
|
26
|
+
query = INSERT.into(query.UPDATE.entity).entries(
|
|
27
|
+
_params ? Object.assign(_data, _params[_params.length - 1]) : _data
|
|
28
|
+
)
|
|
29
|
+
result = await srv.dispatch(new RestRequest({ query, _target, params: _params }))
|
|
30
|
+
status = 201
|
|
31
|
+
} else {
|
|
32
|
+
throw e
|
|
33
|
+
}
|
|
38
34
|
}
|
|
39
35
|
|
|
40
|
-
|
|
41
|
-
next()
|
|
36
|
+
return { result, status }
|
|
42
37
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sap/cds",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.5.0",
|
|
4
4
|
"description": "SAP Cloud Application Programming Model - CDS for Node.js",
|
|
5
5
|
"homepage": "https://cap.cloud.sap/",
|
|
6
6
|
"keywords": [
|
|
@@ -33,6 +33,7 @@
|
|
|
33
33
|
"node": ">=16"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
+
"@cap-js/cds-types": "<1",
|
|
36
37
|
"@sap/cds-compiler": "^4",
|
|
37
38
|
"@sap/cds-fiori": "^1",
|
|
38
39
|
"@sap/cds-foss": "^5.0.0"
|
package/server.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const cds = require('./lib'), { features } = cds.env
|
|
2
2
|
// eslint-disable-next-line cds/no-missing-dependencies -- needs to be added by app dev
|
|
3
|
-
const express = require('express')
|
|
3
|
+
const express = require('express'), fs = require('fs'), path = require('path')
|
|
4
|
+
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Standard express.js bootstrapping, constructing an express `application`
|
|
@@ -72,7 +73,11 @@ const defaults = {
|
|
|
72
73
|
|
|
73
74
|
cors,
|
|
74
75
|
|
|
75
|
-
get static() {
|
|
76
|
+
get static() {
|
|
77
|
+
const dir = cds.env.folders.app //> defaults to ./app
|
|
78
|
+
if (dir && !fs.existsSync(path.resolve(cds.root, dir))) return undefined
|
|
79
|
+
return dir
|
|
80
|
+
},
|
|
76
81
|
|
|
77
82
|
// default generic index.html page
|
|
78
83
|
get index() {
|
|
@@ -89,7 +94,6 @@ const defaults = {
|
|
|
89
94
|
|
|
90
95
|
|
|
91
96
|
// Helpers to delegate to imported UIs
|
|
92
|
-
const path = require('path')
|
|
93
97
|
const _app_serve = function (endpoint) { return {
|
|
94
98
|
from: (pkg,folder) => {
|
|
95
99
|
folder = !folder ? pkg : path.resolve(require.resolve(pkg+'/package.json',{paths:[cds.root]}),'../'+folder)
|
|
@@ -98,7 +102,6 @@ const _app_serve = function (endpoint) { return {
|
|
|
98
102
|
}
|
|
99
103
|
}}
|
|
100
104
|
|
|
101
|
-
|
|
102
105
|
function cors (req, res, next) { // REVISIT: should that move into middlewares?
|
|
103
106
|
const { origin } = req.headers
|
|
104
107
|
if (origin) res.set('access-control-allow-origin', origin)
|
package/srv/outbox.cds
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
|
-
using cuid from '@sap/cds/common';
|
|
2
|
-
|
|
3
1
|
namespace cds.outbox;
|
|
4
2
|
|
|
5
|
-
entity Messages
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
3
|
+
entity Messages {
|
|
4
|
+
key ID : UUID;
|
|
5
|
+
timestamp : Timestamp;
|
|
6
|
+
target : String;
|
|
7
|
+
msg : LargeString;
|
|
8
|
+
attempts : Integer default 0;
|
|
9
|
+
partition : Integer default 0;
|
|
10
|
+
lastError : LargeString;
|
|
11
|
+
lastAttemptTimestamp : Timestamp @cds.on.update: $now;
|
|
13
12
|
}
|
package/apis/env.d.ts
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
export default class {
|
|
2
|
-
/**
|
|
3
|
-
* Access to the configuration for Node.js runtime and tools.
|
|
4
|
-
* The object is the effective result of configuration merged from various sources,
|
|
5
|
-
* filtered through the currently active profiles, thus highly dependent on the current working
|
|
6
|
-
* directory and process environment.
|
|
7
|
-
*/
|
|
8
|
-
env : {
|
|
9
|
-
build: any,
|
|
10
|
-
hana: any,
|
|
11
|
-
i18n: any,
|
|
12
|
-
mtx: any,
|
|
13
|
-
requires: any,
|
|
14
|
-
folders: any,
|
|
15
|
-
odata: any,
|
|
16
|
-
query: any,
|
|
17
|
-
sql: any
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
requires: any
|
|
21
|
-
version: string
|
|
22
|
-
home: string
|
|
23
|
-
root: string
|
|
24
|
-
|
|
25
|
-
}
|
package/apis/test.d.ts
DELETED
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
import { AxiosInstance } from 'axios';
|
|
2
|
-
import chai from 'chai';
|
|
3
|
-
import * as http from 'http';
|
|
4
|
-
import { Service } from './services';
|
|
5
|
-
|
|
6
|
-
declare class Axios {
|
|
7
|
-
get axios(): AxiosInstance;
|
|
8
|
-
|
|
9
|
-
get : AxiosInstance['get'];
|
|
10
|
-
put : AxiosInstance['put'];
|
|
11
|
-
post : AxiosInstance['post'];
|
|
12
|
-
patch : AxiosInstance['patch'];
|
|
13
|
-
delete : AxiosInstance['delete'];
|
|
14
|
-
options : AxiosInstance['options'];
|
|
15
|
-
|
|
16
|
-
get GET() : Axios['get'];
|
|
17
|
-
get PUT() : Axios['put'];
|
|
18
|
-
get POST() : Axios['post'];
|
|
19
|
-
get PATCH() : Axios['patch'];
|
|
20
|
-
get DELETE() : Axios['delete'];
|
|
21
|
-
get OPTIONS() : Axios['options'];
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
declare class DataUtil {
|
|
25
|
-
delete(db?: Service): Promise<void>;
|
|
26
|
-
reset(db?: Service): Promise<void>;
|
|
27
|
-
/** @deprecated */ autoReset(enabled: boolean): this;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
declare class Test extends Axios {
|
|
31
|
-
|
|
32
|
-
test : Test
|
|
33
|
-
|
|
34
|
-
run(cmd: string, ...args: string[]): this;
|
|
35
|
-
in(...paths: string[]): this;
|
|
36
|
-
silent(): this;
|
|
37
|
-
/** @deprecated */ verbose(v: boolean): this;
|
|
38
|
-
|
|
39
|
-
get chai(): typeof chai;
|
|
40
|
-
get expect(): typeof chai.expect;
|
|
41
|
-
get assert(): typeof chai.assert;
|
|
42
|
-
get data(): DataUtil;
|
|
43
|
-
get cds(): typeof import('./cds')
|
|
44
|
-
|
|
45
|
-
log() : {
|
|
46
|
-
output: string
|
|
47
|
-
clear(): void
|
|
48
|
-
release(): void
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
then(r: (args: { server: http.Server, url: string }) => void): void;
|
|
52
|
-
|
|
53
|
-
// get sleep(): (ms: number) => Promise<void>;
|
|
54
|
-
// get spy(): <T, K extends keyof T>(o: T, f: K) => T[K] extends (...args: infer TArgs) => infer TReturnValue
|
|
55
|
-
// ? Spy<TArgs, TReturnValue>
|
|
56
|
-
// : Spy;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// typings for spy inspired by @types/sinon
|
|
60
|
-
// interface Spy<TArgs extends any[] = any[], TReturnValue = any> {
|
|
61
|
-
// (...args: TArgs): TReturnValue;
|
|
62
|
-
// called: number;
|
|
63
|
-
// restore(): (...args: TArgs) => TReturnValue;
|
|
64
|
-
// }
|
|
65
|
-
|
|
66
|
-
export = cds
|
|
67
|
-
|
|
68
|
-
declare class cds {
|
|
69
|
-
test: {
|
|
70
|
-
Test: typeof Test
|
|
71
|
-
/**
|
|
72
|
-
* @see [capire docs](https://cap.cloud.sap/docs/node.js/cds-test?q=cds.test#run)
|
|
73
|
-
*/
|
|
74
|
-
(projectDir: string): Test;
|
|
75
|
-
/**
|
|
76
|
-
* @see [capire docs](https://cap.cloud.sap/docs/node.js/cds-test?q=cds.test#run-2)
|
|
77
|
-
*/
|
|
78
|
-
(command: string, ...args: string[]): Test;
|
|
79
|
-
in (string) : Test
|
|
80
|
-
}
|
|
81
|
-
}
|
package/apis/utils.d.ts
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
// REVISIT: either document passport basic auth or remove it
|
|
2
|
-
|
|
3
|
-
/* eslint-disable cds/no-missing-dependencies */
|
|
4
|
-
module.exports = function passport_basic_auth (options) {
|
|
5
|
-
// const session = require('express-session')({ secret:'secret', resave:false, saveUninitialized:true, })
|
|
6
|
-
const { BasicStrategy } = require('passport-http')
|
|
7
|
-
const users = require ('./mocked-users') (options)
|
|
8
|
-
const passport = require('passport') .use (new BasicStrategy ((id, pwd, done) => {
|
|
9
|
-
let user = users.verify (id,pwd)
|
|
10
|
-
if (user.failed) return done (null, false, { message: user.failed })
|
|
11
|
-
else return done (null, user)
|
|
12
|
-
}))
|
|
13
|
-
return passport.authenticate('basic', {session:false})
|
|
14
|
-
}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
// REVISIT: either document passport digest auth or remove it
|
|
2
|
-
|
|
3
|
-
/* eslint-disable cds/no-missing-dependencies */
|
|
4
|
-
module.exports = function passport_digest_auth (options) {
|
|
5
|
-
// const session = require('express-session')({ secret:'secret', resave:false, saveUninitialized:true, })
|
|
6
|
-
const { users } = require ('./mocked-users') (options)
|
|
7
|
-
const { DigestStrategy } = require('passport-http')
|
|
8
|
-
const passport = require('passport') .use (new DigestStrategy ((id, done) => {
|
|
9
|
-
// REVISIT: this is never called -> no clue why
|
|
10
|
-
console.trace (id)
|
|
11
|
-
const u = users[id]
|
|
12
|
-
if (!u) return done (null, false)
|
|
13
|
-
else return done (null, u, u.password)
|
|
14
|
-
}))
|
|
15
|
-
return passport.authenticate('digest', {session:false})
|
|
16
|
-
}
|
package/lib/env/presets.js
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
const cds = require('../index')
|
|
2
|
-
|
|
3
|
-
const { join } = cds.utils.path
|
|
4
|
-
|
|
5
|
-
const PROTOCOLS = {
|
|
6
|
-
'odata-v4': { path: '/odata/v4', impl: join(__dirname,'../srv/protocols/odata-v4') },
|
|
7
|
-
rest: { path: '/rest', impl: join(__dirname,'../srv/protocols/rest') }
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
// REVISIT: Looks very hard-coded -> move this to consumers?
|
|
11
|
-
module.exports = function (conf) {
|
|
12
|
-
let { features } = conf
|
|
13
|
-
|
|
14
|
-
// protocols configuration
|
|
15
|
-
let p = conf.protocols || {}
|
|
16
|
-
for (let [k, o] of Object.entries(p)) {
|
|
17
|
-
if (typeof o === 'string') p[k] = { path: o }
|
|
18
|
-
if (!p[k].path.startsWith('/')) p[k].path = `/${p[k].path}`
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
p['odata-v4'] = Object.assign({}, PROTOCOLS['odata-v4'], p.odata, p['odata-v4'])
|
|
22
|
-
p.odata = Object.assign({}, PROTOCOLS['odata-v4'], p['odata-v4'], p.odata)
|
|
23
|
-
p.rest = Object.assign({}, PROTOCOLS.rest, p.rest)
|
|
24
|
-
|
|
25
|
-
// odata must always be first for fallback
|
|
26
|
-
conf.protocols = { odata: p.odata, ...p }
|
|
27
|
-
|
|
28
|
-
// integrity checks
|
|
29
|
-
if (!features) return
|
|
30
|
-
if (typeof features.assert_integrity === 'string' && features.assert_integrity.match(/db/i)) {
|
|
31
|
-
features.assert_integrity = true
|
|
32
|
-
features.assert_integrity_type = 'DB'
|
|
33
|
-
} else features.assert_integrity = false
|
|
34
|
-
}
|
|
35
|
-
|
package/lib/log/format/cf.js
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
const cds = require ('../../')
|
|
2
|
-
const kibana = require('./kibana')
|
|
3
|
-
|
|
4
|
-
/*
|
|
5
|
-
* extension of log formatter for kibana that additionally logs Cloud Foundry specific data
|
|
6
|
-
*/
|
|
7
|
-
module.exports = (module, level, ...args) => {
|
|
8
|
-
const toLog = kibana.addFields(module, level, ...args)
|
|
9
|
-
|
|
10
|
-
toLog.layer = 'cds'
|
|
11
|
-
|
|
12
|
-
// cds.context._ instead of cds.context.http because of messaging
|
|
13
|
-
toLog.tenant_subdomain = cds.context?._?.req?.authInfo?.getSubdomain?.()
|
|
14
|
-
|
|
15
|
-
return kibana.format(toLog)
|
|
16
|
-
}
|