@sap/cds 6.0.4 → 6.1.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.
Files changed (120) hide show
  1. package/CHANGELOG.md +128 -18
  2. package/apis/cds.d.ts +11 -7
  3. package/apis/log.d.ts +48 -0
  4. package/apis/ql.d.ts +72 -15
  5. package/bin/build/buildTaskHandler.js +5 -2
  6. package/bin/build/constants.js +4 -1
  7. package/bin/build/provider/buildTaskHandlerEdmx.js +11 -39
  8. package/bin/build/provider/buildTaskHandlerFeatureToggles.js +13 -32
  9. package/bin/build/provider/buildTaskHandlerInternal.js +56 -4
  10. package/bin/build/provider/buildTaskProviderInternal.js +22 -14
  11. package/bin/build/provider/hana/index.js +8 -7
  12. package/bin/build/provider/java/index.js +18 -8
  13. package/bin/build/provider/mtx/index.js +7 -4
  14. package/bin/build/provider/mtx/resourcesTarBuilder.js +64 -35
  15. package/bin/build/provider/mtx-extension/index.js +57 -0
  16. package/bin/build/provider/mtx-sidecar/index.js +46 -18
  17. package/bin/build/provider/nodejs/index.js +34 -13
  18. package/bin/deploy/to-hana/cfUtil.js +7 -2
  19. package/bin/serve.js +7 -4
  20. package/lib/compile/{index.js → cds-compile.js} +0 -0
  21. package/lib/compile/extend.js +15 -5
  22. package/lib/compile/minify.js +1 -15
  23. package/lib/compile/parse.js +1 -1
  24. package/lib/compile/resolve.js +2 -2
  25. package/lib/compile/to/srvinfo.js +6 -4
  26. package/lib/{deploy.js → dbs/cds-deploy.js} +7 -6
  27. package/lib/env/{index.js → cds-env.js} +1 -17
  28. package/lib/env/{requires.js → cds-requires.js} +24 -3
  29. package/lib/env/defaults.js +7 -1
  30. package/lib/env/schemas/cds-package.json +11 -0
  31. package/lib/env/schemas/cds-rc.json +605 -0
  32. package/lib/index.js +19 -16
  33. package/lib/log/{errors.js → cds-error.js} +1 -1
  34. package/lib/log/{index.js → cds-log.js} +0 -0
  35. package/lib/ql/SELECT.js +1 -1
  36. package/lib/ql/{index.js → cds-ql.js} +0 -0
  37. package/lib/req/context.js +35 -7
  38. package/lib/req/locale.js +5 -1
  39. package/lib/{serve → srv}/adapters.js +23 -19
  40. package/lib/{connect → srv}/bindings.js +0 -0
  41. package/lib/{connect/index.js → srv/cds-connect.js} +1 -1
  42. package/lib/{serve/index.js → srv/cds-serve.js} +0 -0
  43. package/lib/{serve → srv}/factory.js +1 -1
  44. package/lib/{serve/Service-api.js → srv/srv-api.js} +14 -6
  45. package/lib/{serve/Service-dispatch.js → srv/srv-dispatch.js} +3 -2
  46. package/lib/{serve/Service-handlers.js → srv/srv-handlers.js} +10 -0
  47. package/lib/{serve/Service-methods.js → srv/srv-methods.js} +10 -8
  48. package/lib/srv/srv-models.js +206 -0
  49. package/lib/{serve/Transaction.js → srv/srv-tx.js} +6 -1
  50. package/lib/utils/{tests.js → cds-test.js} +2 -2
  51. package/lib/utils/cds-utils.js +146 -0
  52. package/lib/utils/index.js +2 -145
  53. package/lib/utils/jest.js +43 -0
  54. package/lib/utils/resources/index.js +14 -24
  55. package/lib/utils/resources/tar.js +18 -41
  56. package/libx/_runtime/auth/index.js +13 -10
  57. package/libx/_runtime/cds-services/adapter/odata-v4/OData.js +7 -19
  58. package/libx/_runtime/cds-services/adapter/odata-v4/ODataRequest.js +1 -4
  59. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/action.js +1 -4
  60. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/create.js +1 -4
  61. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/delete.js +1 -4
  62. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/error.js +2 -2
  63. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/metadata.js +6 -19
  64. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/read.js +1 -4
  65. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/request.js +1 -1
  66. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/update.js +1 -4
  67. package/libx/_runtime/cds-services/adapter/odata-v4/to.js +38 -4
  68. package/libx/_runtime/cds-services/adapter/odata-v4/utils/readAfterWrite.js +1 -3
  69. package/libx/_runtime/cds-services/services/utils/differ.js +4 -0
  70. package/libx/_runtime/cds-services/util/errors.js +1 -29
  71. package/libx/_runtime/common/i18n/messages.properties +2 -1
  72. package/libx/_runtime/common/perf/index.js +10 -15
  73. package/libx/_runtime/common/utils/cqn2cqn4sql.js +0 -1
  74. package/libx/_runtime/common/utils/entityFromCqn.js +8 -5
  75. package/libx/_runtime/common/utils/template.js +1 -1
  76. package/libx/_runtime/db/Service.js +2 -14
  77. package/libx/_runtime/db/expand/expandCQNToJoin.js +28 -25
  78. package/libx/_runtime/db/generic/input.js +4 -0
  79. package/libx/_runtime/db/sql-builder/SelectBuilder.js +37 -18
  80. package/libx/_runtime/extensibility/activate.js +47 -47
  81. package/libx/_runtime/extensibility/add.js +19 -13
  82. package/libx/_runtime/extensibility/addExtension.js +17 -13
  83. package/libx/_runtime/extensibility/defaults.js +25 -30
  84. package/libx/_runtime/extensibility/linter/allowlist_checker.js +373 -0
  85. package/libx/_runtime/extensibility/linter/annotations_checker.js +113 -0
  86. package/libx/_runtime/extensibility/linter/checker_base.js +20 -0
  87. package/libx/_runtime/extensibility/linter/namespace_checker.js +180 -0
  88. package/libx/_runtime/extensibility/linter.js +32 -0
  89. package/libx/_runtime/extensibility/push.js +78 -21
  90. package/libx/_runtime/extensibility/service.js +29 -12
  91. package/libx/_runtime/extensibility/token.js +56 -0
  92. package/libx/_runtime/extensibility/validation.js +6 -9
  93. package/libx/_runtime/fiori/generic/new.js +0 -11
  94. package/libx/_runtime/hana/Service.js +0 -1
  95. package/libx/_runtime/hana/conversion.js +12 -1
  96. package/libx/_runtime/hana/customBuilder/CustomFunctionBuilder.js +4 -3
  97. package/libx/_runtime/hana/customBuilder/CustomSelectBuilder.js +5 -0
  98. package/libx/_runtime/hana/pool.js +6 -10
  99. package/libx/_runtime/hana/search2Contains.js +0 -5
  100. package/libx/_runtime/hana/search2cqn4sql.js +1 -0
  101. package/libx/_runtime/messaging/outbox/utils.js +1 -1
  102. package/libx/_runtime/messaging/service.js +11 -6
  103. package/libx/_runtime/remote/utils/data.js +5 -0
  104. package/libx/_runtime/sqlite/Service.js +0 -1
  105. package/libx/odata/afterburner.js +79 -2
  106. package/libx/odata/cqn2odata.js +9 -7
  107. package/libx/odata/grammar.pegjs +157 -76
  108. package/libx/odata/index.js +9 -3
  109. package/libx/odata/parser.js +1 -1
  110. package/libx/odata/utils.js +39 -5
  111. package/libx/rest/RestAdapter.js +1 -2
  112. package/libx/rest/middleware/delete.js +4 -5
  113. package/libx/rest/middleware/parse.js +3 -2
  114. package/package.json +3 -3
  115. package/server.js +1 -1
  116. package/srv/extensibility-service.cds +6 -3
  117. package/srv/model-provider.cds +3 -1
  118. package/srv/model-provider.js +84 -104
  119. package/srv/mtx.js +7 -1
  120. package/libx/_runtime/cds-services/adapter/odata-v4/Dispatcher.js +0 -240
@@ -0,0 +1,146 @@
1
+ const cwd = process.env._original_cwd || process.cwd()
2
+ const path = require ('path'), { dirname, extname, join, resolve, relative } = path
3
+ const fs = require('fs')
4
+ const cds = require('../index')
5
+
6
+ const all = module.exports = exports = { ...fs,
7
+ get inspect() { return $set (this, 'inspect', require('util').inspect) },
8
+ get uuid() { return $set (this, 'uuid', require('@sap/cds-foss').uuid) },
9
+ }
10
+
11
+ exports.fs = all
12
+ exports.path = path
13
+
14
+ exports.local = (file) => relative(cwd,file)
15
+
16
+ exports.readdir = async function (x) {
17
+ const d = resolve (cds.root,x)
18
+ return fs.promises.readdir(d)
19
+ }
20
+
21
+ exports.stat = async function (x) {
22
+ const d = resolve (cds.root,x)
23
+ return fs.promises.stat(d)
24
+ }
25
+
26
+ exports.exists = function exists (x) {
27
+ if (x) {
28
+ const y = resolve (cds.root,x)
29
+ return fs.existsSync(y)
30
+ }
31
+ }
32
+
33
+ exports.isdir = function isdir (x) {
34
+ if (x) try {
35
+ const y = resolve (cds.root,x)
36
+ const ls = fs.lstatSync(y)
37
+ if (ls.isDirectory()) return y
38
+ if (ls.isSymbolicLink()) return isdir (join (dirname(y), fs.readlinkSync(y)))
39
+ } catch(e){/* ignore */}
40
+ }
41
+
42
+ exports.isfile = function isfile (x) {
43
+ if (x) try {
44
+ const y = resolve (cds.root,x)
45
+ const ls = fs.lstatSync(y)
46
+ if (ls.isFile()) return y
47
+ if (ls.isSymbolicLink()) return isfile (join (dirname(y), fs.readlinkSync(y)))
48
+ } catch(e){/* ignore */}
49
+ }
50
+
51
+ exports.read = async function read (file, _encoding) {
52
+ const f = resolve (cds.root,file)
53
+ const src = await fs.promises.readFile (f, _encoding !== 'json' && _encoding || 'utf8')
54
+ return _encoding === 'json' || !_encoding && f.endsWith('.json') ? JSON.parse(src) : src
55
+ }
56
+
57
+ exports.write = function write (file, data, o) {
58
+ if (arguments.length === 1) return {to:(...path) => write(join(...path),file)}
59
+ if (typeof data === 'object' && !Buffer.isBuffer(data))
60
+ data = JSON.stringify(data, null, ' '.repeat(o && o.spaces))
61
+ const f = resolve (cds.root,file)
62
+ return mkdirp (dirname(f)).then (()=> fs.promises.writeFile (f,data,o))
63
+ }
64
+
65
+ exports.mkdirp = async function (...path) {
66
+ const d = resolve (cds.root,...path)
67
+ await fs.promises.mkdir (d,{recursive:true})
68
+ return d
69
+ }
70
+
71
+ exports.rmdir = (...path) => {
72
+ const d = resolve (cds.root,...path)
73
+ return (fs.promises.rm || fs.promises.rmdir) (d, {recursive:true})
74
+ }
75
+
76
+ exports.rimraf = (...path) => {
77
+ const d = resolve (cds.root,...path)
78
+ return (fs.promises.rm || fs.promises.rmdir) (d, {recursive:true,force:true})
79
+ }
80
+
81
+ exports.rm = async function rm (x) {
82
+ const y = resolve (cds.root,x)
83
+ return (fs.promises.rm || fs.promises.unlink)(y)
84
+ }
85
+
86
+ exports.copy = async function copy (x,y) {
87
+ const src = resolve (cds.root,x)
88
+ const dst = resolve (cds.root,y)
89
+ if (fs.promises.cp) return fs.promises.cp (src,dst,{recursive:true})
90
+ await mkdirp (dirname(dst))
91
+ if (isdir(src)) {
92
+ const entries = await fs.promises.readdir(src)
93
+ return Promise.all (entries.map (async each => {
94
+ const e = join (src,each)
95
+ const f = join (dst,each)
96
+ return copy (e,f)
97
+ }))
98
+ } else {
99
+ return fs.promises.copyFile (src,dst)
100
+ }
101
+ }
102
+
103
+ exports.find = function find (base, patterns='*', filter=()=>true) {
104
+ const files=[]; base = resolve (cds.root,base)
105
+ if (typeof patterns === 'string') patterns = patterns.split(',')
106
+ if (typeof filter === 'string') filter = this[filter]
107
+ patterns.forEach (pattern => {
108
+ const star = pattern.indexOf('*')
109
+ if (star >= 0) {
110
+ const head = pattern.slice(0,star).replace(/[^/\\]*$/,'')
111
+ const dir = join (base,head)
112
+ try {
113
+ const ls = fs.lstatSync(dir)
114
+ if (ls.isDirectory()) {
115
+ const [,suffix,tail] = /([^/\\]*)?(?:.(.*))?/.exec (pattern.slice(star+1))
116
+ const prefix = pattern.slice(head.length,star)
117
+ let entries = fs.readdirSync(dir) //.filter (_filter)
118
+ if (prefix) entries = entries.filter (e => e.startsWith(prefix)); if (!entries.length) return
119
+ if (suffix) entries = entries.filter (e => e.endsWith(suffix)); if (!entries.length) return
120
+ let paths = entries.map (e=>join(dir,e))
121
+ if (filter) paths = paths.filter (filter); if (!paths.length) return
122
+ if (tail) for (let _files of paths.map (e=>find (e,tail,filter))) files.push (..._files)
123
+ else files.push (...paths)
124
+ }
125
+ } catch(e) {/* ignore */}
126
+ } else {
127
+ const file = join (base, pattern)
128
+ if (fs.existsSync(file)) files.push (file)
129
+ }
130
+ })
131
+ return files
132
+ }
133
+
134
+
135
+ // internal utility to load a file through ESM or CommonJs. TODO find a better place.
136
+ const { pathToFileURL } = require('url')
137
+ exports._import = async function(filePath) {
138
+ return typeof jest !== 'undefined' || extname(filePath) === '.ts' // ts-node w/ ESM not working (cap/issues#11980)
139
+ ? require(filePath)
140
+ : import (pathToFileURL(filePath).href) // must use a file: URL, esp. on Windows for C:\... paths
141
+ }
142
+
143
+
144
+ /** @type <T>(o,p,v:T) => T */
145
+ const $set = (o,p,v) => { Object.defineProperty(o,p,{value:v}); return v }
146
+ const { mkdirp, isdir } = exports
@@ -1,145 +1,2 @@
1
- const cwd = process.env._original_cwd || process.cwd()
2
- const path = require ('path'), { dirname, extname, join, resolve, sep, relative } = path
3
- const fs = require('fs')
4
- const cds = require('../index')
5
-
6
- const all = module.exports = exports = { ...fs,
7
- get inspect() { return $set (this, 'inspect', require('util').inspect) },
8
- get uuid() { return $set (this, 'uuid', require('@sap/cds-foss').uuid) },
9
- }
10
-
11
- exports.fs = all
12
- exports.path = path
13
-
14
- exports.local = (file) => relative(cwd,file)
15
-
16
- exports.readdir = async function (x) {
17
- const d = resolve (cds.root,x)
18
- return fs.promises.readdir(d)
19
- }
20
-
21
- exports.stat = async function (x) {
22
- const d = resolve (cds.root,x)
23
- return fs.promises.stat(d)
24
- }
25
-
26
- exports.exists = function exists (x) {
27
- if (x) {
28
- const y = resolve (cds.root,x)
29
- return fs.existsSync(y)
30
- }
31
- }
32
-
33
- exports.isdir = function isdir (x) {
34
- if (x) try {
35
- const y = resolve (cds.root,x)
36
- const ls = fs.lstatSync(y)
37
- if (ls.isDirectory()) return y
38
- if (ls.isSymbolicLink()) return isdir (join (dirname(y), fs.readlinkSync(y)))
39
- } catch(e){/* ignore */}
40
- }
41
-
42
- exports.isfile = function isfile (x) {
43
- if (x) try {
44
- const y = resolve (cds.root,x)
45
- const ls = fs.lstatSync(y)
46
- if (ls.isFile()) return y
47
- if (ls.isSymbolicLink()) return isfile (join (dirname(y), fs.readlinkSync(y)))
48
- } catch(e){/* ignore */}
49
- }
50
-
51
- exports.read = async function read (file, _encoding) {
52
- const f = resolve (cds.root,file)
53
- const src = await fs.promises.readFile (f, _encoding !== 'json' && _encoding || 'utf8')
54
- return _encoding === 'json' || !_encoding && f.endsWith('.json') ? JSON.parse(src) : src
55
- }
56
-
57
- exports.write = function write (file, data, o) {
58
- if (arguments.length === 1) return {to:(...path) => write(join(...path),file)}
59
- if (typeof data === 'object' && !Buffer.isBuffer(data))
60
- data = JSON.stringify(data, null, ' '.repeat(o && o.spaces))
61
- const f = resolve (cds.root,file)
62
- return mkdirp (dirname(f)).then (()=> fs.promises.writeFile (f,data,o))
63
- }
64
-
65
- exports.mkdirp = async function (...path) {
66
- const d = resolve (cds.root,...path)
67
- await fs.promises.mkdir (d,{recursive:true})
68
- return d
69
- }
70
-
71
- exports.rmdir = (...path) => {
72
- const d = resolve (cds.root,...path)
73
- return (fs.promises.rm || fs.promises.rmdir) (d, {recursive:true})
74
- }
75
-
76
- exports.rimraf = (...path) => {
77
- const d = resolve (cds.root,...path)
78
- return (fs.promises.rm || fs.promises.rmdir) (d, {recursive:true,force:true})
79
- }
80
-
81
- exports.rm = async function rm (x) {
82
- const y = resolve (cds.root,x)
83
- return (fs.promises.rm || fs.promises.unlink)(y)
84
- }
85
-
86
- exports.copy = async function copy (x,y) {
87
- const src = resolve (cds.root,x)
88
- const dst = resolve (cds.root,y)
89
- if (fs.promises.cp) return fs.promises.cp (src,dst,{recursive:true})
90
- await mkdirp (dirname(dst))
91
- if (isdir(src)) {
92
- const entries = await fs.promises.readdir(src)
93
- return Promise.all (entries.map (async each => {
94
- const e = join (src,each)
95
- const f = join (dst,each)
96
- return copy (e,f)
97
- }))
98
- } else {
99
- return fs.promises.copyFile (src,dst)
100
- }
101
- }
102
-
103
- exports.find = function find (base, patterns='*', filter=()=>true) {
104
- const files=[]; base = resolve (cds.root,base)
105
- if (typeof patterns === 'string') patterns = patterns.split(',')
106
- if (typeof filter === 'string') filter = this[filter]
107
- patterns.forEach (pattern => {
108
- const star = pattern.indexOf('*')
109
- if (star >= 0) {
110
- const head = pattern.slice(0,star).replace(/[^/\\]*$/,'')
111
- const dir = join (base,head)
112
- try {
113
- const ls = fs.lstatSync(dir)
114
- if (ls.isDirectory()) {
115
- const [,suffix,tail] = /([^/\\]*)?(?:.(.*))?/.exec (pattern.slice(star+1))
116
- const prefix = pattern.slice(head.length,star)
117
- let entries = fs.readdirSync(dir) //.filter (_filter)
118
- if (prefix) entries = entries.filter (e => e.startsWith(prefix)); if (!entries.length) return
119
- if (suffix) entries = entries.filter (e => e.endsWith(suffix)); if (!entries.length) return
120
- let paths = entries.map (e=>join(dir,e))
121
- if (filter) paths = paths.filter (filter); if (!paths.length) return
122
- if (tail) for (let _files of paths.map (e=>find (e,tail,filter))) files.push (..._files)
123
- else files.push (...paths)
124
- }
125
- } catch(e) {/* ignore */}
126
- } else {
127
- const file = join (base, pattern)
128
- if (fs.existsSync(file)) files.push (file)
129
- }
130
- })
131
- return files
132
- }
133
-
134
- // internal utility to load a file through ESM or CommonJs. TODO find a better place.
135
- const { pathToFileURL } = require('url')
136
- exports._import = async function(filePath) {
137
- return typeof jest !== 'undefined' || extname(filePath) === '.ts' // ts-node w/ ESM not working (cap/issues#11980)
138
- ? require(filePath)
139
- : import (pathToFileURL(filePath).href) // on Windows, must use a file: URL for ESM import
140
- }
141
-
142
-
143
- /** @type <T>(o,p,v:T) => T */
144
- const $set = (o,p,v) => { Object.defineProperty(o,p,{value:v}); return v }
145
- const { mkdirp, isdir } = exports
1
+ // for compatibility with old releases of cds-lint
2
+ module.exports = require('./cds-utils')
@@ -0,0 +1,43 @@
1
+ let vm = require('vm')
2
+ if (!vm.__caching__) {
3
+ vm.__caching__ = true
4
+ const scriptCache = {}
5
+ vm._Script = vm._Script || vm.Script
6
+ class CachedScript extends vm._Script {
7
+ constructor(src, options) {
8
+ const cached = scriptCache[options.filename]
9
+ if (cached) {
10
+ return cached
11
+ }
12
+ super(src, options)
13
+ // Assume that .test.js files are only loaded once
14
+ if (!options.filename.endsWith('.test.js')) {
15
+ scriptCache[options.filename] = this
16
+ }
17
+ }
18
+ }
19
+
20
+ vm.Script = CachedScript
21
+ }
22
+ vm = undefined
23
+
24
+ let asyncHooks = require('async_hooks')
25
+ if (!asyncHooks._AsyncLocalStorage) {
26
+ asyncHooks._AsyncLocalStorage = asyncHooks.AsyncLocalStorage
27
+ class TmpAsyncLocalStorage extends asyncHooks._AsyncLocalStorage {
28
+ disable() {
29
+ if (this._timer) clearTimeout(this._timer)
30
+ return super.disable()
31
+ }
32
+
33
+ _enable() {
34
+ if (this._timer) clearTimeout(this._timer)
35
+ this._timer = setTimeout(() => this.disable(), 60 * 1000)
36
+ this._timer.unref()
37
+ return super._enable()
38
+ }
39
+ }
40
+
41
+ asyncHooks.AsyncLocalStorage = TmpAsyncLocalStorage
42
+ }
43
+ asyncHooks = null
@@ -1,36 +1,26 @@
1
1
  const fs = require('fs')
2
2
  const path = require('path')
3
3
 
4
- const cds = require('../../../libx/_runtime/cds')
5
- const { packArchive, packArchiveCLI, unpackArchive, unpackArchiveCLI } = require('./tar')
4
+ const { packArchiveCLI, unpackArchiveCLI } = require('./tar')
6
5
  const { exists } = require('./utils')
7
6
 
8
- // use tar command line interface
9
7
  const TEMP_DIR = fs.realpathSync(require('os').tmpdir())
10
8
 
11
- const packTarArchive = async (files, root, flat = false, cli = true) => {
9
+ const packTarArchive = async (files, root, flat = false) => {
10
+ if (typeof files === 'string') return await packArchiveCLI(files)
11
+
12
12
  let tgzBuffer, temp
13
-
14
13
  try {
15
- temp = await fs.promises.mkdtemp(`${TEMP_DIR}${path.sep}tar-`)
16
- if (flat) {
17
- const files_ = []
18
- for (const file of files) {
19
- const destination = path.join(temp, path.basename(file))
20
- await fs.promises.copyFile(file, destination)
21
- files_.push(destination)
22
- }
23
- files = files_
24
- root = temp
14
+ temp = await fs.promises.mkdtemp(`${TEMP_DIR}${path.sep}tar-`)
15
+ for (const file of files) {
16
+ const fname = flat ? path.basename(file) : path.relative(root, file)
17
+ const destination = path.join(temp, fname)
18
+ const dirname = path.dirname(destination)
19
+ if (!await exists(dirname)) await fs.promises.mkdir(dirname, { recursive: true })
20
+ await fs.promises.copyFile(file, destination)
25
21
  }
26
22
 
27
- const relativeFiles = files.map(file => path.relative(root, file))
28
- if (cli) {
29
- const output = path.relative(root, path.join(temp, `${cds.utils.uuid()}.tgz`))
30
- tgzBuffer = await packArchiveCLI(relativeFiles, root, output)
31
- } else {
32
- tgzBuffer = await packArchive(relativeFiles, root)
33
- }
23
+ tgzBuffer = await packArchiveCLI(temp)
34
24
  } finally {
35
25
  if (await exists(temp)) {
36
26
  await (fs.promises.rm || fs.promises.rmdir)(temp, { recursive: true, force: true })
@@ -40,13 +30,13 @@ const packTarArchive = async (files, root, flat = false, cli = true) => {
40
30
  return tgzBuffer
41
31
  }
42
32
 
43
- const unpackTarArchive = async (buffer, folder, cli = true) => {
33
+ const unpackTarArchive = async (buffer, folder) => {
44
34
  const temp = await fs.promises.mkdtemp(`${TEMP_DIR}${path.sep}tar-`)
45
35
  const tgz = path.join(temp, 'resources.tgz')
46
36
  await fs.promises.writeFile(tgz, Buffer.from(buffer), 'binary')
47
37
 
48
38
  try {
49
- cli ? await unpackArchiveCLI(tgz, folder) : await unpackArchive(tgz, folder)
39
+ await unpackArchiveCLI(tgz, folder)
50
40
  } finally {
51
41
  if (await exists(temp)) await (fs.promises.rm || fs.promises.rmdir)(temp, { recursive: true, force: true })
52
42
  }
@@ -1,21 +1,13 @@
1
1
  const fs = require('fs')
2
2
  const path = require('path')
3
3
  const exec = require('child_process').exec
4
+ const cds = require('../../../libx/_runtime/cds')
5
+ const { exists } = require('./utils')
4
6
 
5
- const _createArchive = (files, root) => {
6
- const tar = require('tar')
7
- return tar.c(
8
- {
9
- gzip: true,
10
- preservePaths: false,
11
- cwd: root
12
- },
13
- files
14
- )
15
- }
7
+ const TEMP_DIR = fs.realpathSync(require('os').tmpdir())
16
8
 
17
- const _createArchiveCLI = (files, root, output) => {
18
- const cmd = 'cd ' + root + ' && tar -czf ' + output + ' ' + files.join(' ')
9
+ const _createArchiveCLI = (root, output) => {
10
+ const cmd = 'tar -zcvf ' + output + ' -C ' + root + ' .'
19
11
 
20
12
  return new Promise((resolve, reject) => {
21
13
  exec(cmd, err => {
@@ -25,32 +17,19 @@ const _createArchiveCLI = (files, root, output) => {
25
17
  })
26
18
  }
27
19
 
28
- const packArchive = (files, root) => {
29
- _createArchive(files, root)
30
- const stream = _createArchive(files, root)
31
- return new Promise((resolve, reject) => {
32
- const chunks = []
33
- stream.on('data', data => chunks.push(data))
34
- stream.on('error', error => reject(error))
35
- stream.on('end', () => {
36
- resolve(Buffer.concat(chunks))
37
- })
38
- })
39
- }
40
-
41
- const packArchiveCLI = async (files, root, output) => {
42
- await _createArchiveCLI(files, root, output)
43
-
44
- return fs.promises.readFile(path.join(root, output))
45
- }
46
-
47
- const unpackArchive = async (tgz, folder) => {
48
- const tar = require('tar')
49
- await tar.x({
50
- file: tgz,
51
- gzip: true,
52
- C: folder
53
- })
20
+ const packArchiveCLI = async (root) => {
21
+ const temp = await fs.promises.mkdtemp(`${TEMP_DIR}${path.sep}tar-`)
22
+ const output = path.join(temp, `${cds.utils.uuid()}.tgz`)
23
+ try {
24
+ await _createArchiveCLI(root, output)
25
+
26
+ return fs.promises.readFile(output)
27
+ }
28
+ finally {
29
+ if (await exists(temp)) {
30
+ await (fs.promises.rm || fs.promises.rmdir)(temp, { recursive: true, force: true })
31
+ }
32
+ }
54
33
  }
55
34
 
56
35
  const unpackArchiveCLI = async (tgz, folder) => {
@@ -65,8 +44,6 @@ const unpackArchiveCLI = async (tgz, folder) => {
65
44
  }
66
45
 
67
46
  module.exports = {
68
- packArchive,
69
47
  packArchiveCLI,
70
- unpackArchive,
71
48
  unpackArchiveCLI
72
49
  }
@@ -57,7 +57,7 @@ const _log = (req, challenges) => {
57
57
  LOG.debug(`User "${req.user.id}" request URL`, req.url, '\n', ...challengesLog)
58
58
  }
59
59
 
60
- const _authCallback = (req, res, next, internalError, user, challenges) => {
60
+ const cap_auth_callback = (req, res, next, internalError, user, challenges) => {
61
61
  // An internal error occurs during the authentication process
62
62
  if (internalError) {
63
63
  // REVISIT: What to do? Security log?
@@ -83,7 +83,7 @@ const _authCallback = (req, res, next, internalError, user, challenges) => {
83
83
 
84
84
  const _mountCustomAuth = (srv, app, config) => {
85
85
  const impl = cds.resolve(config.impl)
86
- app.use(srv.path, _require(impl))
86
+ app.use(_require(impl))
87
87
  }
88
88
 
89
89
  const _mountMockAuth = (srv, app, strategy, config) => {
@@ -92,12 +92,12 @@ const _mountMockAuth = (srv, app, strategy, config) => {
92
92
  ? new (require('./strategies/dummy'))()
93
93
  : new (require('./strategies/mock'))(config, `mock_${srv.name}`)
94
94
 
95
- app.use(srv.path, (req, res, next) => {
95
+ app.use(function cap_auth(req, res, next) {
96
96
  let user, challenge
97
97
  impl.success = arg => (user = arg)
98
98
  impl.fail = arg => (challenge = arg)
99
99
  impl.authenticate(req)
100
- _authCallback(req, res, next, undefined, user, [challenge])
100
+ cap_auth_callback(req, res, next, undefined, user, [challenge])
101
101
  })
102
102
  }
103
103
 
@@ -119,10 +119,10 @@ const _mountPassportAuth = (srv, app, strategy, config) => {
119
119
  }
120
120
 
121
121
  // authenticate
122
- app.use(srv.path, passport.initialize())
123
- app.use(srv.path, (req, res, next) => {
122
+ app.use(passport.initialize())
123
+ app.use((req, res, next) => {
124
124
  const options = { session: false, failWithError: true }
125
- const callback = _authCallback.bind(undefined, req, res, next)
125
+ const callback = cap_auth_callback.bind(undefined, req, res, next)
126
126
  passport.authenticate(strategy === 'jwt' ? 'JWT' : strategy, options, callback)(req, res, next)
127
127
  })
128
128
  }
@@ -131,7 +131,9 @@ const _mountPassportAuth = (srv, app, strategy, config) => {
131
131
  * export authentication middleware
132
132
  */
133
133
  // eslint-disable-next-line complexity
134
- module.exports = (srv, app, options) => {
134
+ module.exports = (srv, options = srv.options) => {
135
+ const handlers = [],
136
+ app = { use: h => handlers.push(h) }
135
137
  // NOTE: options.auth is not an official API
136
138
  let config = 'auth' in options ? options.auth : cds.env.requires.auth
137
139
  if (!config) {
@@ -147,7 +149,7 @@ module.exports = (srv, app, options) => {
147
149
  LOG._warn && LOG.warn(`No authentication configured. This is not recommended in production.`)
148
150
  }
149
151
  // no auth wanted > return
150
- return
152
+ return handlers
151
153
  }
152
154
 
153
155
  // cds.env.requires.auth = { kind: 'xsuaa-auth' } was briefly documented on capire -> also support
@@ -181,11 +183,12 @@ module.exports = (srv, app, options) => {
181
183
  (process.env.NODE_ENV === 'production' && config.credentials && config.restrict_all_services)
182
184
  ) {
183
185
  if (!logged) LOG._debug && LOG.debug(`Enforcing authenticated users for all services`)
184
- app.use(srv.path, _enforce_authenticated_user)
186
+ app.use(_enforce_authenticated_user)
185
187
  }
186
188
 
187
189
  // so we don't log the same stuff multiple times
188
190
  logged = true
191
+ return handlers
189
192
  }
190
193
 
191
194
  const _strategy4 = config => {
@@ -107,8 +107,7 @@ class OData {
107
107
  constructor(edm, csn, options = {}) {
108
108
  this._validateEdm(edm)
109
109
  this._options = options
110
- this._csn = csn
111
- this._createOdataService(edm)
110
+ this._createOdataService(edm, csn)
112
111
  }
113
112
 
114
113
  _validateEdm(edm) {
@@ -118,7 +117,7 @@ class OData {
118
117
  }
119
118
  }
120
119
 
121
- _createOdataService(edm) {
120
+ _createOdataService(edm, csn) {
122
121
  const ServiceFactory = require('./okra/odata-server').ServiceFactory
123
122
 
124
123
  // skip okra's validation in production or implicitly for w4 and x4
@@ -133,7 +132,7 @@ class OData {
133
132
  effective.odata.proxies ||
134
133
  effective.odata.xrefs
135
134
 
136
- this._odataService = ServiceFactory.createService(edm, _config(edm, this._csn, this._options)).trust(isTrusted)
135
+ this._odataService = ServiceFactory.createService(edm, _config(edm, csn, this._options)).trust(isTrusted)
137
136
 
138
137
  // will be added to express app like app.use('/base/path/', service) and odata-v4 wants app.use('/', service) if basePath is set
139
138
  this._odataService.setBasePath('/')
@@ -165,8 +164,7 @@ class OData {
165
164
  req,
166
165
  res
167
166
  } = data
168
- // REVISIT: _model should not be necessary
169
- const tx = (txs[odataContext.id] = cdsService.tx({ user, req, res, _model: cdsService.model }))
167
+ const tx = (txs[odataContext.id] = cdsService.tx({ user, req, res }))
170
168
  cds.context = tx.context
171
169
  // for collecting results and errors
172
170
  data.results = data.results || {}
@@ -183,19 +181,8 @@ class OData {
183
181
  if (errors) {
184
182
  // rollback without errors to not trigger srv.on('error') with array
185
183
  await tx.rollback()
186
- // invoke srv.on('error') for each error and build failedRequests that reflects error modifications
187
- errors = odataContext.applicationData.errors[odataContext.id]
188
- const failedRequests = {}
189
-
190
- for (const e of errors) {
191
- const { error: err, req } = e
192
- for (const each of cdsService._handlers._error) each.handler.call(cdsService, err, req)
193
- const requestId = req._.odataReq.getOdataRequestId()
194
- const { error, statusCode } = normalizeError(err, req)
195
- failedRequests[requestId] = Object.assign(error, { statusCode })
196
- }
197
-
198
- done(new Error(`Atomicity group "${odataContext.id}" failed`), { failedRequests })
184
+
185
+ done()
199
186
  return
200
187
  }
201
188
 
@@ -226,6 +213,7 @@ class OData {
226
213
  this._odataService.use(DATA_DELETE_HANDLER, _delete(cdsService))
227
214
 
228
215
  this._odataService.use(ACTION_EXECUTE_HANDLER, _action(cdsService))
216
+ return this
229
217
  }
230
218
 
231
219
  /**
@@ -163,12 +163,9 @@ class ODataRequest extends cds.Request {
163
163
  */
164
164
  const { user } = req
165
165
 
166
- // REVISIT: _model should not be necessary
167
- const _model = service.model
168
-
169
166
  // REVISIT: public API for query options (express style req.query already in use)?
170
167
  const _queryOptions = odataReq.getQueryOptions()
171
- super({ event, target, data, query, user, method, headers, req, res, _model, _queryOptions })
168
+ super({ event, target, data, query, user, method, headers, req, res, _queryOptions })
172
169
  }
173
170
 
174
171
  /*
@@ -77,10 +77,7 @@ const action = service => {
77
77
  } catch (e) {
78
78
  err = e
79
79
 
80
- if (changeset) {
81
- // for passing into rollback
82
- odataReq.getBatchApplicationData().errors[changeset].push({ error: e, req })
83
- } else {
80
+ if (!changeset) {
84
81
  // REVISIT: rollback needed if an error occurred before commit attempted -> how to distinguish?
85
82
  await tx.rollback(e).catch(() => {})
86
83
  }
@@ -63,10 +63,7 @@ const create = service => {
63
63
  } catch (e) {
64
64
  err = e
65
65
 
66
- if (changeset) {
67
- // for passing into rollback
68
- odataReq.getBatchApplicationData().errors[changeset].push({ error: e, req })
69
- } else {
66
+ if (!changeset) {
70
67
  // REVISIT: rollback needed if an error occurred before commit attempted -> how to distinguish?
71
68
  await tx.rollback(e).catch(() => {})
72
69
  }
@@ -44,10 +44,7 @@ const del = service => {
44
44
  } catch (e) {
45
45
  err = e
46
46
 
47
- if (changeset) {
48
- // for passing into rollback
49
- odataReq.getBatchApplicationData().errors[changeset].push({ error: e, req })
50
- } else {
47
+ if (!changeset) {
51
48
  // REVISIT: rollback needed if an error occurred before commit attempted -> how to distinguish?
52
49
  await tx.rollback(e).catch(() => {})
53
50
  }