@sap/cds 5.8.2 → 5.9.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 +214 -78
- package/app/fiori/preview.js +16 -11
- package/app/fiori/routes.js +3 -0
- package/app/index.js +1 -1
- package/bin/build/buildTaskFactory.js +3 -3
- package/bin/build/buildTaskProviderFactory.js +1 -1
- package/bin/build/constants.js +1 -1
- package/bin/build/provider/buildTaskHandlerEdmx.js +12 -7
- package/bin/build/provider/buildTaskHandlerInternal.js +1 -1
- package/bin/build/provider/buildTaskProviderInternal.js +8 -2
- package/bin/build/provider/hana/2migration.js +27 -24
- package/bin/build/provider/hana/index.js +17 -18
- package/bin/build/provider/hana/migrationtable.js +9 -10
- package/bin/build/provider/java-cf/index.js +4 -5
- package/bin/build/provider/node-cf/index.js +99 -6
- package/bin/cds.js +20 -17
- package/bin/deploy/to-hana/cfUtil.js +16 -19
- package/bin/deploy/to-hana/hana.js +7 -24
- package/bin/deploy/to-hana/hdiDeployUtil.js +8 -4
- package/bin/mtx/in-cds.js +2 -2
- package/bin/serve.js +12 -5
- package/bin/utils/modules.js +7 -0
- package/bin/version.js +56 -3
- package/lib/compile/cdsc.js +26 -3
- package/lib/compile/etc/_localized.js +36 -25
- package/lib/compile/etc/csv.js +8 -8
- package/lib/compile/for/drafts.js +9 -0
- package/lib/compile/for/java.js +16 -0
- package/lib/compile/for/nodejs.js +12 -0
- package/lib/compile/for/odata.js +1 -1
- package/lib/compile/index.js +3 -0
- package/lib/compile/minify.js +16 -2
- package/lib/compile/parse.js +2 -2
- package/lib/compile/resolve.js +35 -18
- package/lib/compile/to/json.js +3 -1
- package/lib/compile/to/sql.js +2 -2
- package/lib/compile/to/srvinfo.js +4 -2
- package/lib/connect/index.js +1 -1
- package/lib/core/entities.js +15 -14
- package/lib/core/index.js +39 -36
- package/lib/core/reflect.js +4 -2
- package/lib/deploy.js +114 -127
- package/lib/env/defaults.js +1 -0
- package/lib/env/index.js +165 -165
- package/lib/env/presets.js +1 -0
- package/lib/env/requires.js +120 -49
- package/lib/index.js +1 -0
- package/lib/log/format/kibana.js +2 -2
- package/lib/ql/SELECT.js +10 -0
- package/lib/ql/parse.js +1 -0
- package/lib/req/cds-context.js +4 -1
- package/lib/req/context.js +50 -56
- package/lib/req/event.js +1 -6
- package/lib/req/locale.js +6 -5
- package/lib/req/request.js +2 -0
- package/lib/req/user.js +7 -5
- package/lib/serve/Service-api.js +10 -7
- package/lib/serve/Service-dispatch.js +9 -11
- package/lib/serve/Service-methods.js +30 -41
- package/lib/serve/Transaction.js +10 -7
- package/lib/serve/adapters.js +7 -5
- package/lib/serve/index.js +24 -12
- package/lib/utils/data.js +1 -1
- package/lib/utils/index.js +27 -30
- package/lib/utils/resources/index.js +101 -0
- package/lib/utils/resources/tar.js +71 -0
- package/lib/utils/resources/utils.js +11 -0
- package/libx/_runtime/audit/Service.js +36 -39
- package/libx/_runtime/audit/generic/personal/access.js +3 -4
- package/libx/_runtime/audit/generic/personal/modification.js +3 -4
- package/libx/_runtime/audit/utils/v2.js +1 -2
- package/libx/_runtime/auth/index.js +126 -84
- package/libx/_runtime/auth/strategies/JWT.js +12 -19
- package/libx/_runtime/auth/strategies/dummy.js +1 -5
- package/libx/_runtime/auth/strategies/dwc.js +11 -9
- package/libx/_runtime/auth/strategies/mock.js +0 -4
- package/libx/_runtime/auth/strategies/{utils/xssec.js → xssecUtils.js} +7 -4
- package/libx/_runtime/auth/strategies/xsuaa.js +12 -19
- package/libx/_runtime/auth/utils.js +22 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/Dispatcher.js +104 -98
- package/libx/_runtime/cds-services/adapter/odata-v4/OData.js +2 -2
- package/libx/_runtime/cds-services/adapter/odata-v4/ODataRequest.js +1 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/action.js +13 -0
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/language.js +2 -8
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/metadata.js +4 -29
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/read.js +2 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/request.js +3 -2
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/update.js +2 -2
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/ExpressionToCQN.js +4 -6
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/expandToCQN.js +24 -21
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/index.js +8 -2
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/uri/UriHelper.js +1 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/deserializer/DeserializerFactory.js +2 -0
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/deserializer/ResourceJsonDeserializer.js +5 -6
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/invocation/DispatcherCommand.js +2 -6
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/utils/UriHelper.js +4 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/to.js +1 -12
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/data.js +33 -9
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/dispatcherUtils.js +50 -0
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/readAfterWrite.js +2 -2
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/request.js +10 -3
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/result.js +9 -11
- package/libx/_runtime/cds-services/adapter/rest/RestRequest.js +6 -3
- package/libx/_runtime/cds-services/adapter/rest/handlers/operation.js +4 -2
- package/libx/_runtime/cds-services/adapter/rest/rest-to-cqn/utils.js +1 -1
- package/libx/_runtime/cds-services/adapter/rest/utils/binary.js +1 -1
- package/libx/_runtime/cds-services/adapter/rest/utils/key-value-utils.js +2 -3
- package/libx/_runtime/cds-services/adapter/rest/utils/parse-url.js +6 -4
- package/libx/_runtime/cds-services/adapter/rest/utils/result.js +1 -0
- package/libx/_runtime/cds-services/adapter/rest/utils/validation-checks.js +8 -5
- package/libx/_runtime/cds-services/services/Service.js +40 -0
- package/libx/_runtime/cds-services/services/utils/columns.js +4 -3
- package/libx/_runtime/cds-services/services/utils/compareJson.js +4 -4
- package/libx/_runtime/cds-services/services/utils/differ.js +3 -3
- package/libx/_runtime/cds-services/services/utils/handlerUtils.js +4 -4
- package/libx/_runtime/cds-services/services/utils/restrictions.js +78 -0
- package/libx/_runtime/cds-services/util/assert.js +20 -14
- package/libx/_runtime/cds.js +9 -1
- package/libx/_runtime/common/aspects/any.js +5 -0
- package/libx/_runtime/common/aspects/entity.js +25 -7
- package/libx/_runtime/common/aspects/utils.js +2 -2
- package/libx/_runtime/common/composition/data.js +6 -0
- package/libx/_runtime/common/composition/insert.js +3 -2
- package/libx/_runtime/common/composition/tree.js +4 -10
- package/libx/_runtime/common/composition/update.js +4 -4
- package/libx/_runtime/common/constants/draft.js +29 -26
- package/libx/_runtime/common/error/constants.js +2 -2
- package/libx/_runtime/common/error/frontend.js +7 -15
- package/libx/_runtime/common/generic/auth/capabilities.js +59 -0
- package/libx/_runtime/common/generic/auth/constants.js +20 -0
- package/libx/_runtime/common/generic/auth/expand.js +54 -0
- package/libx/_runtime/common/generic/auth/index.js +32 -0
- package/libx/_runtime/common/generic/auth/insertOnly.js +15 -0
- package/libx/_runtime/common/generic/auth/readOnly.js +26 -0
- package/libx/_runtime/common/generic/auth/requires.js +34 -0
- package/libx/_runtime/common/generic/auth/restrict.js +296 -0
- package/libx/_runtime/common/generic/auth/utils.js +213 -0
- package/libx/_runtime/common/generic/crud.js +14 -10
- package/libx/_runtime/common/generic/etag.js +1 -1
- package/libx/_runtime/common/generic/input.js +35 -35
- package/libx/_runtime/common/generic/sorting.js +2 -3
- package/libx/_runtime/common/generic/temporal.js +2 -2
- package/libx/_runtime/common/i18n/index.js +2 -31
- package/libx/_runtime/common/i18n/messages.properties +1 -1
- package/libx/_runtime/common/toggles/handler.js +21 -0
- package/libx/_runtime/common/utils/copy.js +10 -1
- package/libx/_runtime/common/utils/cqn2cqn4sql.js +100 -29
- package/libx/_runtime/common/utils/csn.js +63 -1
- package/libx/_runtime/common/utils/dollar.js +10 -1
- package/libx/_runtime/common/utils/draft.js +46 -7
- package/libx/_runtime/common/utils/entityFromCqn.js +13 -9
- package/libx/_runtime/common/utils/extensibilityUtils.js +18 -0
- package/libx/_runtime/common/utils/foreignKeyPropagations.js +88 -104
- package/libx/_runtime/common/utils/generateOnCond.js +9 -6
- package/libx/_runtime/common/utils/quotingStyles.js +2 -0
- package/libx/_runtime/common/utils/resolveStructured.js +25 -9
- package/libx/_runtime/common/utils/resolveView.js +4 -1
- package/libx/_runtime/common/utils/rewriteAsterisks.js +3 -16
- package/libx/_runtime/common/utils/structured.js +33 -37
- package/libx/_runtime/common/utils/template.js +17 -8
- package/libx/_runtime/common/utils/templateProcessor.js +28 -28
- package/libx/_runtime/db/data-conversion/post-processing.js +118 -417
- package/libx/_runtime/db/expand/expandCQNToJoin.js +45 -41
- package/libx/_runtime/db/expand/rawToExpanded.js +29 -8
- package/libx/_runtime/db/generic/index.js +1 -3
- package/libx/_runtime/db/generic/input.js +5 -10
- package/libx/_runtime/db/generic/rewrite.js +5 -2
- package/libx/_runtime/db/generic/structured.js +2 -2
- package/libx/_runtime/db/query/delete.js +2 -2
- package/libx/_runtime/db/query/insert.js +1 -1
- package/libx/_runtime/db/query/update.js +9 -14
- package/libx/_runtime/db/sql-builder/CreateBuilder.js +4 -3
- package/libx/_runtime/db/sql-builder/InsertBuilder.js +14 -1
- package/libx/_runtime/db/sql-builder/SelectBuilder.js +3 -2
- package/libx/_runtime/db/sql-builder/dataTypes.js +3 -3
- package/libx/_runtime/db/utils/columns.js +3 -3
- package/libx/_runtime/db/utils/normalizeTimeData.js +2 -2
- package/libx/_runtime/db/utils/propagateForeignKeys.js +6 -2
- package/libx/_runtime/extensibility/mps/index.js +5 -0
- package/libx/_runtime/extensibility/mps/service.js +111 -0
- package/libx/_runtime/extensibility/mps/tar.js +42 -0
- package/libx/_runtime/extensibility/mps/utils.js +11 -0
- package/libx/_runtime/{fiori → extensibility}/uiflex/handler/transformREAD.js +0 -0
- package/libx/_runtime/{fiori → extensibility}/uiflex/handler/transformRESULT.js +17 -5
- package/libx/_runtime/{fiori → extensibility}/uiflex/handler/transformWRITE.js +1 -0
- package/libx/_runtime/extensibility/uiflex/index.js +54 -0
- package/libx/_runtime/extensibility/uiflex/service.js +276 -0
- package/libx/_runtime/{fiori → extensibility}/uiflex/utils.js +22 -7
- package/libx/_runtime/fiori/generic/activate.js +2 -2
- package/libx/_runtime/fiori/generic/before.js +4 -4
- package/libx/_runtime/fiori/generic/new.js +3 -3
- package/libx/_runtime/fiori/generic/patch.js +1 -1
- package/libx/_runtime/fiori/generic/read.js +58 -66
- package/libx/_runtime/fiori/generic/readOverDraft.js +71 -16
- package/libx/_runtime/fiori/utils/handler.js +6 -13
- package/libx/_runtime/fiori/utils/where.js +6 -5
- package/libx/_runtime/hana/Service.js +4 -10
- package/libx/_runtime/hana/customBuilder/CustomSelectBuilder.js +2 -2
- package/libx/_runtime/hana/driver.js +2 -2
- package/libx/_runtime/hana/execute.js +29 -75
- package/libx/_runtime/hana/pool.js +1 -1
- package/libx/_runtime/hana/streaming.js +2 -1
- package/libx/_runtime/index.js +6 -6
- package/libx/_runtime/messaging/AMQPWebhookMessaging.js +5 -21
- package/libx/_runtime/messaging/Outbox.js +2 -2
- package/libx/_runtime/messaging/common-utils/AMQPClient.js +4 -14
- package/libx/_runtime/messaging/common-utils/connections.js +5 -7
- package/libx/_runtime/messaging/common-utils/normalizeIncomingMessage.js +30 -0
- package/libx/_runtime/messaging/enterprise-messaging-shared.js +2 -1
- package/libx/_runtime/messaging/enterprise-messaging-utils/EMManagement.js +36 -30
- package/libx/_runtime/messaging/enterprise-messaging-utils/registerEndpoints.js +19 -12
- package/libx/_runtime/messaging/enterprise-messaging.js +8 -8
- package/libx/_runtime/messaging/file-based.js +5 -5
- package/libx/_runtime/messaging/message-queuing.js +14 -12
- package/libx/_runtime/messaging/outbox/utils.js +18 -19
- package/libx/_runtime/messaging/redis-messaging.js +91 -0
- package/libx/_runtime/messaging/service.js +8 -6
- package/libx/_runtime/remote/Service.js +44 -8
- package/libx/_runtime/remote/utils/client.js +25 -13
- package/libx/_runtime/remote/utils/data.js +11 -11
- package/libx/_runtime/sqlite/Service.js +6 -9
- package/libx/_runtime/sqlite/customBuilder/CustomFunctionBuilder.js +5 -2
- package/libx/_runtime/types/api.js +10 -2
- package/libx/common/utils/ucsn.js +109 -0
- package/libx/gql/resolvers/crud/create.js +6 -1
- package/libx/gql/resolvers/crud/delete.js +6 -1
- package/libx/gql/resolvers/crud/read.js +6 -1
- package/libx/gql/resolvers/crud/update.js +9 -1
- package/libx/gql/resolvers/parse/ast2cqn/columns.js +3 -1
- package/libx/gql/schema/typeDefMap.js +2 -2
- package/libx/odata/afterburner.js +110 -16
- package/libx/odata/grammar.pegjs +9 -1
- package/libx/odata/parseToCqn.js +39 -0
- package/libx/odata/parser.js +1 -1
- package/libx/rest/RestAdapter.js +9 -1
- package/libx/rest/middleware/input.js +54 -0
- package/libx/rest/middleware/operation.js +14 -1
- package/libx/rest/middleware/parse.js +11 -7
- package/package.json +1 -1
- package/server.js +34 -19
- package/srv/audit-log.cds +2 -2
- package/srv/flex.cds +8 -2
- package/srv/flex.js +1 -1
- package/srv/mps.cds +23 -0
- package/srv/mps.js +1 -0
- package/libx/_runtime/auth/strategies/utils/uaa.js +0 -21
- package/libx/_runtime/common/generic/auth.js +0 -874
- package/libx/_runtime/common/toggles/alpha.js +0 -43
- package/libx/_runtime/db/generic/arrayed.js +0 -33
- package/libx/_runtime/fiori/uiflex/index.js +0 -35
- package/libx/_runtime/fiori/uiflex/service.js +0 -150
- package/libx/rest/utils/data.js +0 -60
package/lib/index.js
CHANGED
|
@@ -81,6 +81,7 @@ if (global.cds) Object.assign(module,{exports:global.cds}) ; else {
|
|
|
81
81
|
MessagingService: lazy => require('../libx/_runtime/messaging/service.js'),
|
|
82
82
|
DatabaseService: lazy => require('../libx/_runtime/db/Service.js'),
|
|
83
83
|
RemoteService: lazy => require('../libx/_runtime/rest/service.js'),
|
|
84
|
+
AuditLogService: lazy => require('../libx/_runtime/audit/Service.js'),
|
|
84
85
|
odata: require('../libx/odata'),
|
|
85
86
|
|
|
86
87
|
// Helpers
|
package/lib/log/format/kibana.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const cds = require('../../')
|
|
1
|
+
const cds = require ('../../')
|
|
2
2
|
const util = require('util')
|
|
3
3
|
|
|
4
4
|
const _l2l = { 1: 'error', 2: 'warn', 3: 'info', 4: 'debug', 5: 'trace' }
|
|
@@ -8,7 +8,7 @@ const _l2l = { 1: 'error', 2: 'warn', 3: 'info', 4: 'debug', 5: 'trace' }
|
|
|
8
8
|
*/
|
|
9
9
|
module.exports = (module, level, ...args) => {
|
|
10
10
|
// config
|
|
11
|
-
const { user: log_user, kibana_custom_fields } = cds.env.log
|
|
11
|
+
const { user: log_user , kibana_custom_fields } = cds.env.log
|
|
12
12
|
|
|
13
13
|
// build the object to log
|
|
14
14
|
const toLog = {
|
package/lib/ql/SELECT.js
CHANGED
|
@@ -40,6 +40,16 @@ module.exports = class SELECT extends Whereable {
|
|
|
40
40
|
if (cols === '*') return this.columns(...arguments)
|
|
41
41
|
const c = _columns_or_not (cols)
|
|
42
42
|
if (c) return this._add('columns',c)
|
|
43
|
+
if (typeof cols === 'string') {
|
|
44
|
+
try { parse.path(cols) }
|
|
45
|
+
catch(e) { //> it can't be a from
|
|
46
|
+
try { return this.columns(...arguments) }
|
|
47
|
+
catch(e) {
|
|
48
|
+
if (!e.message.startsWith('CDS compilation failed')) throw e
|
|
49
|
+
this._expected `Argument ${{cols}} to be a valid argument for SELECT.from or .columns`
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
43
53
|
}
|
|
44
54
|
|
|
45
55
|
// return a proxy assuming it's a from and switching to
|
package/lib/ql/parse.js
CHANGED
package/lib/req/cds-context.js
CHANGED
|
@@ -21,7 +21,10 @@ const { EventEmitter } = require('events')
|
|
|
21
21
|
Reflect.defineProperty (cds,'context',{ enumerable:1,
|
|
22
22
|
set(v) {
|
|
23
23
|
const cr = current(); if (!cr) return
|
|
24
|
-
const ctx =
|
|
24
|
+
const ctx = (
|
|
25
|
+
v instanceof EventContext || typeof v !== 'object' ? v :
|
|
26
|
+
v.context || EventContext.for (v.req ? {_:v} : v)
|
|
27
|
+
)
|
|
25
28
|
cr[_context] = ctx
|
|
26
29
|
},
|
|
27
30
|
get() {
|
package/lib/req/context.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const cds = require ('../index'), { features } = cds.env, { uuid } = cds.utils
|
|
2
2
|
const async_events = { succeeded:1, failed:1, done:1 }
|
|
3
|
+
const req_locale = require('./locale')
|
|
3
4
|
const { EventEmitter } = require('events')
|
|
4
5
|
|
|
5
6
|
/**
|
|
@@ -10,31 +11,23 @@ const { EventEmitter } = require('events')
|
|
|
10
11
|
*/
|
|
11
12
|
class EventContext {
|
|
12
13
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
if (
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
if (!u || !u.tenant) _inherit('tenant')
|
|
20
|
-
if (!u || !u.locale) _inherit('locale')
|
|
21
|
-
}
|
|
22
|
-
function _inherit (p,fn) {
|
|
23
|
-
if (p in data) return data[p]
|
|
24
|
-
let pd = Reflect.getOwnPropertyDescriptor(base,p); if (!pd) return
|
|
25
|
-
return data[p] = fn ? fn(pd.value) : pd.value
|
|
14
|
+
/** Creates a new instance that inherits from cds.context */
|
|
15
|
+
static for (_) {
|
|
16
|
+
const ctx = new this (_)
|
|
17
|
+
if (features.cds_tx_inheritance) {
|
|
18
|
+
const base = cds.context
|
|
19
|
+
if (base) ctx._set('_propagated', base)
|
|
26
20
|
}
|
|
27
|
-
|
|
28
|
-
if (data.user) data = { user:1, ...data }
|
|
29
|
-
return new this (data)
|
|
21
|
+
return ctx
|
|
30
22
|
}
|
|
31
23
|
|
|
32
24
|
constructor(_={}) {
|
|
33
|
-
Object.
|
|
25
|
+
Object.defineProperty (this, '_', { value:_, writable:true })
|
|
26
|
+
Object.assign (this, _)
|
|
34
27
|
}
|
|
35
28
|
|
|
36
29
|
_set (property, value) {
|
|
37
|
-
Object.defineProperty (this, property, {value,writable:true})
|
|
30
|
+
Object.defineProperty (this, property, { value, writable:true })
|
|
38
31
|
return value
|
|
39
32
|
}
|
|
40
33
|
|
|
@@ -44,18 +37,16 @@ class EventContext {
|
|
|
44
37
|
// Emitting and listening to succeeded / failed / done events
|
|
45
38
|
//
|
|
46
39
|
|
|
47
|
-
|
|
48
|
-
return this._emitter || (this._emitter =
|
|
40
|
+
get emitter() {
|
|
41
|
+
return this.context._emitter || (this.context._emitter = new EventEmitter)
|
|
49
42
|
}
|
|
50
43
|
|
|
51
44
|
async emit (event,...args) {
|
|
52
|
-
if (!
|
|
53
|
-
if (event in async_events)
|
|
54
|
-
for (const each of
|
|
55
|
-
await each.call(this
|
|
56
|
-
|
|
57
|
-
}
|
|
58
|
-
else return this._emitter.emit (event,...args)
|
|
45
|
+
const emitter = this.context._emitter; if (!emitter) return
|
|
46
|
+
if (event in async_events)
|
|
47
|
+
for (const each of emitter.listeners(event))
|
|
48
|
+
await each.call (this, ...args)
|
|
49
|
+
else return emitter.emit (event,...args)
|
|
59
50
|
}
|
|
60
51
|
|
|
61
52
|
on (event, listener) {
|
|
@@ -75,48 +66,58 @@ class EventContext {
|
|
|
75
66
|
// The following properties are inherited from root contexts, if exist...
|
|
76
67
|
//
|
|
77
68
|
|
|
78
|
-
set context(c) { if (c) this._set('context',c) }
|
|
69
|
+
set context(c) { if (c) this._set('context', this._set('_propagated', c)) }
|
|
79
70
|
get context() { return this }
|
|
80
71
|
|
|
81
|
-
set id(
|
|
72
|
+
set id(id) {
|
|
73
|
+
if (id) super.id = id
|
|
74
|
+
}
|
|
82
75
|
get id() {
|
|
83
|
-
return
|
|
76
|
+
return super.id = this._propagated.id || this.headers[ 'x-correlation-id' ] || uuid()
|
|
84
77
|
}
|
|
85
78
|
|
|
86
79
|
set tenant(t) {
|
|
87
|
-
if (t) super.tenant =
|
|
80
|
+
if (t) super.tenant = t
|
|
88
81
|
}
|
|
89
82
|
get tenant() {
|
|
90
|
-
return
|
|
83
|
+
return super.tenant = this._propagated.tenant
|
|
91
84
|
}
|
|
92
85
|
|
|
93
86
|
set user(u) {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
87
|
+
const user = super.user = u instanceof cds.User ? u : new cds.User(u)
|
|
88
|
+
for (let p of ['tenant','locale']) { // compatibility
|
|
89
|
+
if (u && u.hasOwnProperty(p)) this[p] = u[p] // eslint-disable-line no-prototype-builtins
|
|
90
|
+
else Object.defineProperty (user, p, { get: () => this[p] })
|
|
91
|
+
}
|
|
98
92
|
}
|
|
99
93
|
get user() {
|
|
100
|
-
|
|
94
|
+
const u = this._propagated.user
|
|
95
|
+
return this.user = u ? {__proto__:u} : new cds.User.default
|
|
101
96
|
}
|
|
102
97
|
|
|
103
98
|
set locale(l) {
|
|
104
|
-
if (l) super.locale =
|
|
99
|
+
if (l) super.locale = super._locale = l
|
|
105
100
|
}
|
|
106
101
|
get locale() {
|
|
107
|
-
return
|
|
102
|
+
return super.locale = this._propagated.locale || req_locale(this._.req)
|
|
103
|
+
}
|
|
104
|
+
get _locale() {
|
|
105
|
+
return super._locale = this._propagated._locale || req_locale.from_req(this._.req)
|
|
106
|
+
|| this.hasOwnProperty('locale') && this.locale // eslint-disable-line no-prototype-builtins
|
|
108
107
|
}
|
|
109
108
|
|
|
110
109
|
get timestamp() {
|
|
111
|
-
return super.timestamp = this._propagated
|
|
110
|
+
return super.timestamp = this._propagated.timestamp || new Date
|
|
112
111
|
}
|
|
113
112
|
|
|
114
|
-
set headers(h) {
|
|
113
|
+
set headers(h) {
|
|
114
|
+
if (h) super.headers = h
|
|
115
|
+
}
|
|
115
116
|
get headers() {
|
|
116
117
|
if (this._ && this._.req && this._.req.headers) {
|
|
117
118
|
return super.headers = this._.req.headers
|
|
118
119
|
} else {
|
|
119
|
-
const headers={}, outer = this._propagated
|
|
120
|
+
const headers={}, outer = this._propagated.headers
|
|
120
121
|
if (outer) for (let each of EventContext.propagateHeaders) {
|
|
121
122
|
if (each in outer) headers[each] = outer[each]
|
|
122
123
|
}
|
|
@@ -125,27 +126,18 @@ class EventContext {
|
|
|
125
126
|
}
|
|
126
127
|
|
|
127
128
|
|
|
128
|
-
//
|
|
129
|
-
// Connecting to transactions and request hierarchies
|
|
130
|
-
//
|
|
131
|
-
|
|
132
|
-
_propagated (p) {
|
|
133
|
-
const ctx = this.context
|
|
134
|
-
if (ctx !== this) return ctx[p]
|
|
135
|
-
}
|
|
136
|
-
|
|
137
129
|
set _tx(tx) {
|
|
138
130
|
Object.defineProperty (this,'_tx',{value:tx}) //> allowed only once!
|
|
139
131
|
const ctx = tx.context
|
|
140
132
|
if (ctx && ctx !== this) {
|
|
141
|
-
this.context = ctx
|
|
133
|
+
if (!this.hasOwnProperty('context')) this.context = ctx // eslint-disable-line no-prototype-builtins
|
|
134
|
+
///////////////////////////////////////////////////////////////////
|
|
142
135
|
// REVISIT: Eliminate req._children
|
|
143
|
-
// only collect children if integrity checks are active
|
|
144
136
|
if (features.assert_integrity !== false) {
|
|
145
|
-
const reqs = ctx._children ||
|
|
137
|
+
const reqs = ctx._children || ctx._set('_children', {})
|
|
146
138
|
const all = reqs[tx.name] || (reqs[tx.name] = [])
|
|
147
139
|
all.push(this)
|
|
148
|
-
}
|
|
140
|
+
} //////////////////////////////////////////////////////////////////
|
|
149
141
|
}
|
|
150
142
|
}
|
|
151
143
|
|
|
@@ -153,9 +145,11 @@ class EventContext {
|
|
|
153
145
|
/** REVISIT: remove -> @deprecated */
|
|
154
146
|
set _model(m){ super._model = m }
|
|
155
147
|
get _model() {
|
|
156
|
-
return super._model = this._tx && this._tx.model || this._propagated
|
|
148
|
+
return super._model = this._tx && this._tx.model || this._propagated._model
|
|
157
149
|
}
|
|
158
150
|
}
|
|
159
151
|
|
|
152
|
+
|
|
153
|
+
EventContext.prototype._set('_propagated', Object.seal({}))
|
|
160
154
|
EventContext.propagateHeaders = [ 'x-correlation-id' ]
|
|
161
155
|
module.exports = EventContext
|
package/lib/req/event.js
CHANGED
|
@@ -4,12 +4,7 @@ const EventContext = require ('./context')
|
|
|
4
4
|
* Instances of class cds.Event represent asynchronous messages as well as
|
|
5
5
|
* synchronous requests. The latter are instances of subclass cds.Request.
|
|
6
6
|
*/
|
|
7
|
-
class EventMessage extends EventContext {
|
|
8
|
-
static for (eve) {
|
|
9
|
-
if (eve instanceof this) return eve
|
|
10
|
-
if (typeof eve === 'object') return new this(eve)
|
|
11
|
-
}
|
|
12
|
-
}
|
|
7
|
+
class EventMessage extends EventContext {}
|
|
13
8
|
|
|
14
9
|
module.exports = exports = EventMessage
|
|
15
10
|
exports.Context = EventContext
|
package/lib/req/locale.js
CHANGED
|
@@ -7,15 +7,16 @@ const INCLUDE_LIST = i18n.preserved_locales.reduce((p,n)=>{
|
|
|
7
7
|
en_US_x_sappsd: 'en_US_sappsd'
|
|
8
8
|
})
|
|
9
9
|
|
|
10
|
-
const from_req = req => req
|
|
10
|
+
const from_req = req => req && (
|
|
11
|
+
req.query && req.query['sap-language'] ||
|
|
12
|
+
req.headers && (req.headers['x-sap-request-language'] || req.headers['accept-language'])
|
|
13
|
+
)
|
|
11
14
|
|
|
12
15
|
function req_locale (req) {
|
|
13
|
-
if (!
|
|
14
|
-
const locale = from_req(req)
|
|
15
|
-
if (!locale) return i18n.default_language
|
|
16
|
+
const locale = from_req(req); if (!locale) return i18n.default_language
|
|
16
17
|
const loc = locale.replace(/-/g,'_')
|
|
17
18
|
return INCLUDE_LIST[loc]
|
|
18
|
-
||
|
|
19
|
+
|| /^([a-z]+)/i.test(loc) && RegExp.$1.toLowerCase()
|
|
19
20
|
|| i18n.default_language
|
|
20
21
|
}
|
|
21
22
|
|
package/lib/req/request.js
CHANGED
|
@@ -7,6 +7,8 @@ const { Responses, Errors } = require('./response')
|
|
|
7
7
|
*/
|
|
8
8
|
class Request extends require('./event') {
|
|
9
9
|
|
|
10
|
+
toString() { return `${this.event} ${this.path}` }
|
|
11
|
+
|
|
10
12
|
set method(m) { if (m) super.method = m }
|
|
11
13
|
get method() {
|
|
12
14
|
return this._set ('method', Crud2Http[this.event] || this.event)
|
package/lib/req/user.js
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
const req_locale = require('./locale')
|
|
2
|
-
|
|
3
1
|
class User {
|
|
4
2
|
|
|
5
3
|
constructor (_) {
|
|
@@ -9,9 +7,6 @@ class User {
|
|
|
9
7
|
if (Array.isArray(_._roles)) this._roles = _._roles.reduce((p,n)=>{p[n]=1; return p},{})
|
|
10
8
|
}
|
|
11
9
|
|
|
12
|
-
get locale() { return super.locale = req_locale (this._req) }
|
|
13
|
-
set locale(l) { if (l) super.locale = l }
|
|
14
|
-
|
|
15
10
|
get attr() { return super.attr = {} }
|
|
16
11
|
|
|
17
12
|
get _roles(){ return super._roles = {
|
|
@@ -24,6 +19,9 @@ class User {
|
|
|
24
19
|
|
|
25
20
|
}
|
|
26
21
|
|
|
22
|
+
/**
|
|
23
|
+
* Subclass representing non-identified unauthenticated users.
|
|
24
|
+
*/
|
|
27
25
|
class Anonymous extends User {
|
|
28
26
|
is (role) { return role === 'any' }
|
|
29
27
|
get _roles() { return {} }
|
|
@@ -31,6 +29,9 @@ class Anonymous extends User {
|
|
|
31
29
|
Anonymous.prototype._is_anonymous = true
|
|
32
30
|
Anonymous.prototype.id = 'anonymous'
|
|
33
31
|
|
|
32
|
+
/**
|
|
33
|
+
* Subclass for executing code with superuser privileges.
|
|
34
|
+
*/
|
|
34
35
|
class Privileged extends User {
|
|
35
36
|
constructor(_) { super(_||{}) }
|
|
36
37
|
is() { return true }
|
|
@@ -38,4 +39,5 @@ class Privileged extends User {
|
|
|
38
39
|
Privileged.prototype._is_privileged = true
|
|
39
40
|
Privileged.prototype.id = 'privileged'
|
|
40
41
|
|
|
42
|
+
// exports -----------------
|
|
41
43
|
module.exports = exports = Object.assign (User, { Anonymous, Privileged, default:Anonymous })
|
package/lib/serve/Service-api.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
const cds = require('..'), { Event, Request } = cds
|
|
1
2
|
const add_methods_to = require ('./Service-methods')
|
|
2
|
-
const
|
|
3
|
+
const { unfold_csn: cds_localized } = cds.compile._localized
|
|
3
4
|
|
|
4
5
|
|
|
5
6
|
class Service extends require('./Service-handlers') {
|
|
@@ -15,7 +16,7 @@ class Service extends require('./Service-handlers') {
|
|
|
15
16
|
*/
|
|
16
17
|
set model (csn) {
|
|
17
18
|
if (csn) {
|
|
18
|
-
super.model =
|
|
19
|
+
super.model = cds.compile.for.nodejs(csn)
|
|
19
20
|
add_methods_to (this)
|
|
20
21
|
} else {
|
|
21
22
|
super.model = undefined
|
|
@@ -27,7 +28,9 @@ class Service extends require('./Service-handlers') {
|
|
|
27
28
|
*/
|
|
28
29
|
emit (event, data, headers) {
|
|
29
30
|
const res = this._compat_sync (event, data, headers); if (res) return res
|
|
30
|
-
const eve =
|
|
31
|
+
const eve = event instanceof Event ? event : new Event (
|
|
32
|
+
is_object(event) ? event : { event, data, headers }
|
|
33
|
+
)
|
|
31
34
|
return this.dispatch (eve)
|
|
32
35
|
}
|
|
33
36
|
|
|
@@ -35,9 +38,8 @@ class Service extends require('./Service-handlers') {
|
|
|
35
38
|
* REST-style API to send synchronous requests...
|
|
36
39
|
*/
|
|
37
40
|
send (method, path, data, headers) {
|
|
38
|
-
const req =
|
|
39
|
-
|
|
40
|
-
new cds.Request({ method, path, data, headers })
|
|
41
|
+
const req = method instanceof Request ? method : new Request (
|
|
42
|
+
is_object(method) ? method : is_object(path) ? { method, data:path, headers:data } : { method, path, data, headers }
|
|
41
43
|
)
|
|
42
44
|
return this.dispatch (req)
|
|
43
45
|
}
|
|
@@ -51,7 +53,7 @@ class Service extends require('./Service-handlers') {
|
|
|
51
53
|
* Querying API to send synchronous requests...
|
|
52
54
|
*/
|
|
53
55
|
run (query, data) {
|
|
54
|
-
const req = new
|
|
56
|
+
const req = new Request ({ query, data })
|
|
55
57
|
return this.dispatch (req)
|
|
56
58
|
}
|
|
57
59
|
read (...args) { return is_query(args[0]) ? this.run(...args) : SELECT(...args).bind(this) }
|
|
@@ -113,3 +115,4 @@ const _reflect = (srv,filter) => !srv.model ? [] : srv.model.childrenOf (srv.nam
|
|
|
113
115
|
const is_rest = x => x && typeof x === 'string' && x[0] === '/'
|
|
114
116
|
const is_query = x => x && x.bind || is_array(x) && !x.raw
|
|
115
117
|
const is_array = (x) => Array.isArray(x) && !x.raw
|
|
118
|
+
const is_object = (x) => typeof x === 'object'
|
|
@@ -13,12 +13,12 @@ exports.dispatch = async function dispatch (req) { //NOSONAR
|
|
|
13
13
|
|
|
14
14
|
// Ensure we are in a proper transaction
|
|
15
15
|
if (!this.context) {
|
|
16
|
-
const
|
|
17
|
-
if (
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
return tx
|
|
21
|
-
}
|
|
16
|
+
const ctx = cds.context
|
|
17
|
+
if (ctx && ctx._tx && !ctx._done) { // join outer context with a nested tx -> we don't modify outer context
|
|
18
|
+
return this.tx(ctx).dispatch(req)
|
|
19
|
+
} else { // start a new root tx for subsequent continuation
|
|
20
|
+
return this.tx(tx => (cds.context=tx).dispatch(req))
|
|
21
|
+
}
|
|
22
22
|
}
|
|
23
23
|
// `this` is a tx from now on...
|
|
24
24
|
if (!req._tx) req._tx = this
|
|
@@ -97,7 +97,7 @@ const _is_array = Array.isArray
|
|
|
97
97
|
const _dummy = ()=>{} // REVISIT: required for some messaging tests which obviously still expect and call next()
|
|
98
98
|
|
|
99
99
|
const _ensure_target = (srv,req) => {
|
|
100
|
-
const q = req.query, p = req._.path; if (!q && !p) return
|
|
100
|
+
const q = req.query, p = req._.path || req._.entity; if (!q && !p) return
|
|
101
101
|
if (srv.namespace) { // ensure fully-qualified names
|
|
102
102
|
if (p) _ensure_fqn (req,'path',srv, p.startsWith('/') ? p.slice(1) : p)
|
|
103
103
|
else if (q.SELECT) _ensure_fqn (q.SELECT,'from',srv)
|
|
@@ -105,10 +105,8 @@ const _ensure_target = (srv,req) => {
|
|
|
105
105
|
else if (q.UPDATE) _ensure_fqn (q.UPDATE,'entity',srv)
|
|
106
106
|
else if (q.DELETE) _ensure_fqn (q.DELETE,'from',srv)
|
|
107
107
|
}
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
req.target = cds.infer(q,defs)
|
|
111
|
-
}
|
|
108
|
+
const m = srv.model, defs = m && m.definitions || {}
|
|
109
|
+
req.target = typeof q === 'object' ? cds.infer(q,defs) : defs[req.path]
|
|
112
110
|
}
|
|
113
111
|
|
|
114
112
|
const _ensure_fqn = (x,p,srv, name = x[p]) => {
|
|
@@ -12,53 +12,42 @@ module.exports = (srv) => {
|
|
|
12
12
|
|
|
13
13
|
const add_handler_for = (srv, def) => {
|
|
14
14
|
const event = def.name.match(/\w*$/)[0]
|
|
15
|
+
|
|
16
|
+
// Use existing methods as handler implementations
|
|
15
17
|
const method = srv[event]
|
|
16
18
|
if (method) {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
srv.on (event, ({data}) => {
|
|
19
|
+
if (method._is_stub || method.name in srv.__proto__.__proto__) return
|
|
20
|
+
srv.on (event, function ({params,data}) {
|
|
20
21
|
const args = []; if (def.parent) args.push (def.parent)
|
|
22
|
+
for (let p in params) args.push(params[p])
|
|
21
23
|
for (let p in data) args.push(data[p])
|
|
22
|
-
return method.apply (
|
|
24
|
+
return method.apply (this,args)
|
|
23
25
|
})
|
|
24
|
-
|
|
25
|
-
} else {
|
|
26
|
-
// add method to emit request
|
|
27
|
-
const method = srv[event] = function (...args) {
|
|
28
|
-
const [$] = args, target = this.entities [ $ && $.name ? $.name.match(/\w*$/)[0] : $ ]
|
|
29
|
-
const data = {}
|
|
30
|
-
if (target) { //> it's a bound action
|
|
31
|
-
def = target.actions[event]; args.shift()
|
|
32
|
-
// In case of bound actions, first argument(s) are expected to be the target's primary key,
|
|
33
|
-
// which we need to fill in to named properties in data
|
|
34
|
-
// object variant of keys, ensure keys are present in args[0] because of complex param
|
|
35
|
-
if (typeof args[0] === 'object' && Object.keys(target.keys).every(k => k in args[0])) {
|
|
36
|
-
const keys = args.shift()
|
|
37
|
-
for (const p in target.keys) {
|
|
38
|
-
data[p] = keys[p]
|
|
39
|
-
}
|
|
40
|
-
} else { // positional
|
|
41
|
-
for (let p in target.keys) {
|
|
42
|
-
data[p] = args.shift()
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// object variant of params, ensure at least one param is present in args[0]
|
|
49
|
-
// REVISIT: still not bullet proof, but parameters might be optional
|
|
50
|
-
if (def.params) {
|
|
51
|
-
if (args[0] !== null && typeof args[0] === 'object' && args.length === 1 && Object.keys(def.params).some(p => p in args[0])) {
|
|
52
|
-
const params = args.shift()
|
|
53
|
-
for (const p in def.params) data[p] = params[p]
|
|
54
|
-
} else { // positional
|
|
55
|
-
for (let p in def.params) data[p] = args.shift()
|
|
56
|
-
}
|
|
57
|
-
}
|
|
26
|
+
}
|
|
58
27
|
|
|
59
|
-
|
|
60
|
-
|
|
28
|
+
// Add stub methods to send request via typed API
|
|
29
|
+
const stub = srv[event] = function (...args) {
|
|
30
|
+
const req = { event, data:{} }, $ = args[0]
|
|
31
|
+
const target = this.entities [ $ && $.name ? $.name.match(/\w*$/)[0] : $ ]
|
|
32
|
+
if (target) { //> bound action/function?
|
|
33
|
+
req.target = target; args.shift() // first argument is the target entity name
|
|
34
|
+
req.params = [ args.shift() ] // second argument is the target's primary key
|
|
61
35
|
}
|
|
62
|
-
|
|
36
|
+
const {params} = target ? target.actions[event] : def
|
|
37
|
+
if (params) req.data = _named(args,params) || _positional(args,params)
|
|
38
|
+
return this.send (req)
|
|
63
39
|
}
|
|
40
|
+
stub._is_stub = true
|
|
64
41
|
}
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
const _named = (args, declared) => {
|
|
45
|
+
if (args.length > 1) return
|
|
46
|
+
const a = args[0]
|
|
47
|
+
if (! a || typeof a !== 'object') return
|
|
48
|
+
if (Object.keys(a).every (k => k in declared)) return a
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const _positional = (args, declared) => Object.keys(declared).reduce (
|
|
52
|
+
(data,k,i) => { data[k] = args[i]; return data }, {}
|
|
53
|
+
)
|
package/lib/serve/Transaction.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
const cds = require('../index'), { cds_tx_protection } = cds.env.features
|
|
2
2
|
const EventContext = require('../req/context')
|
|
3
|
+
class RootContext extends EventContext {}
|
|
4
|
+
|
|
3
5
|
|
|
4
6
|
/**
|
|
5
7
|
* This is the implementation of the `srv.tx(req)` method. It constructs
|
|
@@ -28,12 +30,10 @@ module.exports = function tx (ctx,fn) { const srv = this
|
|
|
28
30
|
// `ctx` is a plain context object or undefined
|
|
29
31
|
if (ctx) { // REVISIT: This is for compatibility with AFC only
|
|
30
32
|
if (ctx._txed_before) return NestedTransaction.for (srv, ctx._txed_before)
|
|
31
|
-
else {
|
|
32
|
-
|
|
33
|
-
return RootTransaction.for (srv, ctx._txed_before)
|
|
34
|
-
}
|
|
33
|
+
else Object.defineProperty(ctx, '_txed_before', { value: RootContext.for(ctx) }) // > must be non-enumerable
|
|
34
|
+
return RootTransaction.for (srv, ctx._txed_before)
|
|
35
35
|
}
|
|
36
|
-
return RootTransaction.for (srv,
|
|
36
|
+
return RootTransaction.for (srv, RootContext.for(ctx))
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
|
|
@@ -174,8 +174,11 @@ const _begin = async function (req) {
|
|
|
174
174
|
return this.ready = this.__proto__.dispatch.call (this,req)
|
|
175
175
|
// Protection against unintended tx.run() after tx.commit/rollback()
|
|
176
176
|
if (typeof this.ready === 'string' || !this.ready && this.context._done) {
|
|
177
|
-
if (cds_tx_protection)
|
|
178
|
-
else
|
|
177
|
+
if (!cds_tx_protection) this.ready = this.begin() // compatibiliy to former behavior, which allowed tx.run() after commit/rollback
|
|
178
|
+
else throw cds.error (
|
|
179
|
+
`Transaction is ${this.ready || this.context._done}, no subsequent .run allowed, without prior .begin`,
|
|
180
|
+
{ code: 'TRANSACTION_CLOSED' }
|
|
181
|
+
)
|
|
179
182
|
}
|
|
180
183
|
else if (!this.ready) this.ready = this.begin()
|
|
181
184
|
await this.ready
|
package/lib/serve/adapters.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const lib = require('../../libx/_runtime')
|
|
2
2
|
const registry = {
|
|
3
|
-
rest: lib.to.
|
|
3
|
+
rest: lib.to.old_rest,
|
|
4
|
+
new_rest: lib.to.new_rest,
|
|
4
5
|
odata: lib.to.odata_v4,
|
|
5
6
|
odata_v2: lib.to.odata_v4,
|
|
6
7
|
odata_v4: lib.to.odata_v4,
|
|
@@ -11,6 +12,7 @@ const registry = {
|
|
|
11
12
|
class ProtocolAdapter {
|
|
12
13
|
|
|
13
14
|
static at (protocol) {
|
|
15
|
+
if (protocol === 'rest' && global.cds.env.features.rest_new_adapter) protocol = 'new_rest'
|
|
14
16
|
const factory = registry[protocol]; if (factory) return factory
|
|
15
17
|
else throw new Error (`Service protocol ${protocol} is not supported`)
|
|
16
18
|
}
|
|
@@ -30,12 +32,12 @@ class ProtocolAdapter {
|
|
|
30
32
|
/**
|
|
31
33
|
* Mounts the adapter to an express app.
|
|
32
34
|
*/
|
|
33
|
-
in (app) {
|
|
34
|
-
const srv = this.service
|
|
35
|
+
in (app, at) {
|
|
36
|
+
const srv = this.service, path = at || srv.path
|
|
35
37
|
lib.perf (app)
|
|
36
38
|
lib.auth (srv, app, srv.options)
|
|
37
|
-
app.use (
|
|
38
|
-
app.use (
|
|
39
|
+
app.use (path+'/webapp/', (_,res)=> res.sendStatus(404))
|
|
40
|
+
app.use (path, this)
|
|
39
41
|
return srv
|
|
40
42
|
}
|
|
41
43
|
|