@sap/cds-dk 10.0.6 → 10.0.7
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 +13 -0
- package/lib/import/asyncapi/parserContext.js +136 -54
- package/lib/init/template/nodejs/index.js +4 -2
- package/node_modules/@cap-js/openapi/lib/compile/csdl.js +3 -3
- package/node_modules/@cap-js/openapi/lib/compile/csdl2openapi.js +111 -103
- package/node_modules/@cap-js/openapi/lib/compile/diagram.js +4 -4
- package/node_modules/@cap-js/openapi/lib/compile/types.d.ts +3 -1
- package/node_modules/@cap-js/openapi/package.json +3 -3
- package/node_modules/@sap/cds/CHANGELOG.md +7 -0
- package/node_modules/@sap/cds/lib/compile/for/nodejs.js +1 -0
- package/node_modules/@sap/cds/libx/_runtime/messaging/common-utils/authorizedRequest.js +3 -2
- package/node_modules/@sap/cds/package.json +1 -1
- package/node_modules/@sap/cds-mtxs/CHANGELOG.md +36 -0
- package/node_modules/@sap/cds-mtxs/bin/cds-mtx-migrate.js +32 -48
- package/node_modules/@sap/cds-mtxs/bin/cds-mtx.js +1 -0
- package/node_modules/@sap/cds-mtxs/cds-plugin.js +18 -0
- package/node_modules/@sap/cds-mtxs/lib/migration/migration.js +3 -408
- package/node_modules/@sap/cds-mtxs/package.json +1 -1
- package/node_modules/@sap/cds-mtxs/srv/cf/abstract-provisioning-service.js +5 -6
- package/node_modules/@sap/cds-mtxs/srv/extensibility/linter/annotations.js +5 -2
- package/node_modules/@sap/cds-mtxs/srv/extensibility/linter/index.js +6 -5
- package/node_modules/@sap/cds-mtxs/srv/extensibility-service.cds +0 -11
- package/node_modules/@sap/cds-mtxs/srv/extensibility-service.js +12 -22
- package/node_modules/@sap/cds-mtxs/srv/jobs-service.js +30 -24
- package/node_modules/@sap/cds-mtxs/srv/model-provider.js +2 -2
- package/node_modules/@sap/cds-mtxs/srv/plugins/hana/ctnr-mgr-base.js +5 -2
- package/node_modules/@sap/cds-mtxs/srv/plugins/hana/hdi.js +5 -3
- package/node_modules/@sap/cds-mtxs/srv/plugins/hana/srv-mgr.js +3 -2
- package/node_modules/@sap/cds-mtxs/srv/plugins/hana/tms.js +17 -0
- package/node_modules/@sap/cds-mtxs/srv/plugins/hana.js +14 -13
- package/node_modules/sax/lib/sax.js +27 -9
- package/node_modules/sax/package.json +1 -1
- package/node_modules/ws/package.json +1 -1
- package/package.json +4 -4
- package/lib/init/template/nodejs/files/.gitignore.hbs +0 -34
- package/node_modules/@sap/cds-mtxs/lib/migration/extension-project-builder.js +0 -129
- package/node_modules/@sap/cds-mtxs/lib/migration/extension-project.js +0 -89
- package/node_modules/@sap/cds-mtxs/lib/migration/mtx-adapter.js +0 -230
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
const cds = require('@sap/cds')
|
|
2
|
-
const path = require('path')
|
|
3
|
-
const fs = require('fs').promises
|
|
4
|
-
const mtxAdapter = require('./mtx-adapter')
|
|
5
|
-
const { build } = require('./extension-project-builder')
|
|
6
|
-
module.exports.DEFAULT_TAG = 'migrated'
|
|
7
|
-
|
|
8
|
-
module.exports.getExtensionTag = function (filename, tagRegexString, defaultTag = module.exports.DEFAULT_TAG) {
|
|
9
|
-
if (!tagRegexString) return defaultTag
|
|
10
|
-
const regex = new RegExp(tagRegexString)
|
|
11
|
-
const match = filename.match(regex)
|
|
12
|
-
return match?.[1] ? match[1] : defaultTag
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
module.exports.createProjects = async function (mtxExtension, dir, tagRegex, defaultTag = module.exports.DEFAULT_TAG) {
|
|
16
|
-
|
|
17
|
-
const validTags = []
|
|
18
|
-
|
|
19
|
-
const extensions = _splitExtensionByTag(mtxExtension, tagRegex, defaultTag)
|
|
20
|
-
|
|
21
|
-
for (const [tag, extension] of Object.entries(extensions)) {
|
|
22
|
-
|
|
23
|
-
const projectFolder = path.join(dir, tag)
|
|
24
|
-
try {
|
|
25
|
-
await fs.rm(projectFolder, { recursive: true, force: true })
|
|
26
|
-
} catch {
|
|
27
|
-
// ignore
|
|
28
|
-
}
|
|
29
|
-
await fs.mkdir(projectFolder, { recursive: true })
|
|
30
|
-
// extension is a map of files
|
|
31
|
-
await mtxAdapter.writeFilesFromMap(Array.from(extension), projectFolder)
|
|
32
|
-
// overwrite package.json
|
|
33
|
-
await _writePackageJson(projectFolder, tag, '_base')
|
|
34
|
-
|
|
35
|
-
// keep in mind to avoid parallel execution !! - use runner from old mtx?
|
|
36
|
-
|
|
37
|
-
try {
|
|
38
|
-
await build({ project: projectFolder })
|
|
39
|
-
} catch (error) {
|
|
40
|
-
if (error.code !== 'MODEL_NOT_FOUND') throw error
|
|
41
|
-
// ignore extensions with no model
|
|
42
|
-
continue
|
|
43
|
-
}
|
|
44
|
-
validTags.push(tag)
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
return validTags
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
function _splitExtensionByTag(mtxExtension, tagRegex, defaultTag) {
|
|
51
|
-
|
|
52
|
-
const result = {}
|
|
53
|
-
|
|
54
|
-
// create separate tags
|
|
55
|
-
for (const [file, content] of mtxExtension) {
|
|
56
|
-
if (!file.startsWith('node_modules')) {
|
|
57
|
-
const tag = module.exports.getExtensionTag(file, tagRegex, defaultTag)
|
|
58
|
-
if (!result[tag]) result[tag] = new Map()
|
|
59
|
-
result[tag].set(file, content)
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
// add node modules to each project to allow build
|
|
64
|
-
for (const [file, content] of mtxExtension) {
|
|
65
|
-
if (file.startsWith('node_modules')) {
|
|
66
|
-
for (const tag in result) {
|
|
67
|
-
result[tag].set(file, content)
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
return result
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
async function _writePackageJson(dir, name, main) {
|
|
76
|
-
const packageJson = {
|
|
77
|
-
"name": name,
|
|
78
|
-
"version": "1.0.0",
|
|
79
|
-
"description": "Generated extension project",
|
|
80
|
-
"cds": {
|
|
81
|
-
"extends": main
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
// add compiler settings from main
|
|
86
|
-
packageJson.cds.cdsc = cds.env.cdsc
|
|
87
|
-
|
|
88
|
-
await fs.writeFile(path.join(dir, 'package.json'), JSON.stringify(packageJson, 2))
|
|
89
|
-
}
|
|
@@ -1,230 +0,0 @@
|
|
|
1
|
-
const cds = require('@sap/cds')
|
|
2
|
-
|
|
3
|
-
const { fs, path } = cds.utils
|
|
4
|
-
const tempDir = fs.realpathSync(require('os').tmpdir());
|
|
5
|
-
const LOG = cds.log('mtx')
|
|
6
|
-
|
|
7
|
-
module.exports.getDbId = async () => {
|
|
8
|
-
LOG.info('Retrieving database ID from existing containers...')
|
|
9
|
-
const hana = require('@sap/cds-mtxs/srv/plugins/hana/hdi-ctnr-mgr').defaultInstance()
|
|
10
|
-
const all = await hana.getAll()
|
|
11
|
-
const foundDbId = all.length ? all[0].credentials?.database_id : null
|
|
12
|
-
LOG.info('Found database ID:', foundDbId || 'none')
|
|
13
|
-
return foundDbId
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
module.exports.getAllTenantIds = async () => {
|
|
17
|
-
|
|
18
|
-
const hana = require('@sap/cds-mtxs/srv/plugins/hana/hdi-ctnr-mgr').defaultInstance()
|
|
19
|
-
|
|
20
|
-
// copied from mtx
|
|
21
|
-
const META_TENANT_REGEX = /TENANT-(.*)-META/i
|
|
22
|
-
const MT_LIB_TENANT_REGEX = /MT_LIB_TENANT-(.*)/i
|
|
23
|
-
const GLOBAL_DATA_META_TENANT = '__META__'
|
|
24
|
-
function _tenantFilter(tenantId, index, allTenants) {
|
|
25
|
-
const t0 = cds.env.requires.multitenancy?.t0 ?? 't0'
|
|
26
|
-
return tenantId
|
|
27
|
-
&& !META_TENANT_REGEX.test(tenantId)
|
|
28
|
-
&& !MT_LIB_TENANT_REGEX.test(tenantId)
|
|
29
|
-
&& tenantId.toLowerCase() !== GLOBAL_DATA_META_TENANT.toLowerCase()
|
|
30
|
-
&& tenantId !== t0
|
|
31
|
-
&& allTenants.includes(_prefixTenant(tenantId))
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
// TODO remove duplicates resulting from multiple bindings
|
|
35
|
-
// replaces Tenant.getAllTenantIds()
|
|
36
|
-
return (await hana.getAll()).reduce((result, t) => [ ...result, t.labels.tenant_id[0]] , []).filter(_tenantFilter)
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
function _prefixTenant(tenantId) {
|
|
40
|
-
return `TENANT-${tenantId}-META`
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
module.exports.getMetaTenantName = (tenant) => {
|
|
44
|
-
return _prefixTenant(tenant)
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
module.exports.getMetadata = async (tenant) => {
|
|
48
|
-
return getMetadata(tenant)
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
async function getMetadata(tenant, type = 'onboarding') {
|
|
52
|
-
|
|
53
|
-
// replaces Tenant.getMetadata(tenant)
|
|
54
|
-
const CONTENT_METADATA_QUERY = 'SELECT CONTENT FROM TENANT_METADATA WHERE ID = ? AND DOMAIN = ? LIMIT 1'
|
|
55
|
-
const domain = cds.env.mtx && cds.env.mtx.domain || '__default__'
|
|
56
|
-
|
|
57
|
-
try {
|
|
58
|
-
const result = (await cds.tx({ tenant: _prefixTenant(tenant) }, tx => tx.run(CONTENT_METADATA_QUERY, [type, domain])))
|
|
59
|
-
const CONTENT = result?.[0]?.CONTENT || result?.[0]?.content // small tribute to sqlite for testing
|
|
60
|
-
if (type === 'onboarding') {
|
|
61
|
-
const metadata = CONTENT ? JSON.parse(CONTENT) : {}
|
|
62
|
-
// more robust behaviour
|
|
63
|
-
if (!metadata.subscribedTenantId) metadata.subscribedTenantId = tenant
|
|
64
|
-
return metadata
|
|
65
|
-
} else {
|
|
66
|
-
return CONTENT ? JSON.parse(CONTENT) : null
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
} catch (error) {
|
|
70
|
-
LOG.error('Failed to query metadata for tenant', tenant, '(domain:', domain, '):', error)
|
|
71
|
-
throw error;
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
module.exports.saveMetadata = async (tenant, type, data) => {
|
|
76
|
-
const domain = cds.env.mtx && cds.env.mtx.domain || '__default__'
|
|
77
|
-
const statement = 'UPSERT TENANT_METADATA (ID, CONTENT, DOMAIN) VALUES(?, ?, ?) WHERE ID = ? AND DOMAIN = ?';
|
|
78
|
-
await cds.tx({ tenant: _prefixTenant(tenant) }, tx => tx.run(statement, [type, JSON.stringify(data), domain, type, domain]))
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
const COMPILED_FILES = {
|
|
82
|
-
CSN_NODE: 'csn_node.json', // deprecated
|
|
83
|
-
CSN: 'csn.json',
|
|
84
|
-
ODATA_CSN: 'odata_csn.json',
|
|
85
|
-
I18N: '_i18n/i18n.json'
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
const MODEL_TYPE = {
|
|
89
|
-
base: 'base',
|
|
90
|
-
extension: 'extension',
|
|
91
|
-
compiled: 'compiled',
|
|
92
|
-
migration: 'migration'
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
module.exports.getCsn = async (tenant) => {
|
|
96
|
-
|
|
97
|
-
const CONTENT_FILE_QUERY = 'SELECT CONTENT FROM TENANT_FILES WHERE TYPE = ? AND FILENAME = ? AND DOMAIN = ? LIMIT 1';
|
|
98
|
-
|
|
99
|
-
const domain = cds.env.mtx && cds.env.mtx.domain || '__default__'
|
|
100
|
-
|
|
101
|
-
try {
|
|
102
|
-
const result = (await cds.tx({ tenant: _prefixTenant(tenant) }, tx => tx.run(CONTENT_FILE_QUERY, [MODEL_TYPE.compiled, COMPILED_FILES.CSN_NODE, domain])))
|
|
103
|
-
const { CONTENT } = result && result[0] || {}
|
|
104
|
-
return CONTENT ? JSON.parse(CONTENT) : null
|
|
105
|
-
|
|
106
|
-
} catch (error) {
|
|
107
|
-
this.logger.error(`Failed to query collectedSources for tenant '${tenant}' (domain: ${domain}): ${error}`)
|
|
108
|
-
throw error;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
// const loadedModel = await Tenant.getModel(tenant, 'collectedSources');
|
|
112
|
-
// return JSON.parse(loadedModel);
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
// replaces Content.getExtension(tenant)
|
|
116
|
-
module.exports.getExtension = async (tenant) => {
|
|
117
|
-
|
|
118
|
-
function _isModelFile(filename) {
|
|
119
|
-
const BASE_MODEL_EXTENSION_PROJECT_FILTER = /(.*\.cds$|.*\.csn$|.*\/csn.json$|^csn.json$|.*\/i18n(|_.*)(\.json|\.properties)$)/
|
|
120
|
-
return BASE_MODEL_EXTENSION_PROJECT_FILTER.test(filename);
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
function _convertToExtensionProject(files) {
|
|
124
|
-
const BASE_MODEL_NAME = '_base'
|
|
125
|
-
const basemodelFiles = new Map();
|
|
126
|
-
|
|
127
|
-
for (const [file, content] of files) {
|
|
128
|
-
if (_isModelFile(file)) {
|
|
129
|
-
const prefixedPath = path.join('node_modules', BASE_MODEL_NAME, file);
|
|
130
|
-
basemodelFiles.set(prefixedPath, content);
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
return basemodelFiles;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
async function readFiles(modelType) {
|
|
138
|
-
const MODEL_FILE_QUERY = 'SELECT FILENAME, CONTENT, TYPE FROM TENANT_FILES WHERE TYPE = ? AND DOMAIN = ?';
|
|
139
|
-
const domain = cds.env.mtx && cds.env.mtx.domain || '__default__'
|
|
140
|
-
try {
|
|
141
|
-
const files = (await cds.tx({ tenant: _prefixTenant(tenant) }, tx => tx.run(MODEL_FILE_QUERY, [modelType, domain])));
|
|
142
|
-
return files.map(({ FILENAME, CONTENT }) => [FILENAME, CONTENT.toString('utf-8')]);
|
|
143
|
-
|
|
144
|
-
} catch (error) {
|
|
145
|
-
LOG.error('Failed to query extensions for tenant', tenant, '(domain:', domain, '):', error);
|
|
146
|
-
throw error;
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
const extensions = await readFiles(MODEL_TYPE.extension);
|
|
151
|
-
if (!extensions?.length) return // return nothing if no extensions exist
|
|
152
|
-
|
|
153
|
-
const base = await readFiles(MODEL_TYPE.base);
|
|
154
|
-
|
|
155
|
-
return [...extensions, ..._convertToExtensionProject(base)]
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
module.exports.hasExtensions = async (tenant) => {
|
|
159
|
-
if (!(await module.exports.wasOldMtx())) return false
|
|
160
|
-
const MODEL_FILE_QUERY = 'SELECT FILENAME FROM TENANT_FILES WHERE TYPE = ? AND DOMAIN = ?';
|
|
161
|
-
const domain = cds.env.mtx && cds.env.mtx.domain || '__default__'
|
|
162
|
-
try {
|
|
163
|
-
const files = (await cds.tx({ tenant: _prefixTenant(tenant) }, tx => tx.run(MODEL_FILE_QUERY, ['extension', domain])));
|
|
164
|
-
return files.length
|
|
165
|
-
} catch (error) {
|
|
166
|
-
LOG.debug('Upgrade check: No @sap/mtx (old mtx) extensions found for tenant', tenant, '(domain:', domain, '):', error);
|
|
167
|
-
return false;
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
const wasOldMtx = []
|
|
172
|
-
|
|
173
|
-
// use this before automatic tenant list update in upgrade
|
|
174
|
-
module.exports.wasOldMtx = async () => {
|
|
175
|
-
if (!wasOldMtx.length) {
|
|
176
|
-
if (cds.env.requires.db?.credentials?.sm_url) { // old mtx was service-manager based
|
|
177
|
-
const hana = require('@sap/cds-mtxs/srv/plugins/hana/hdi-ctnr-mgr').defaultInstance()
|
|
178
|
-
try {
|
|
179
|
-
wasOldMtx.push(!!(await hana.get('__META__')))
|
|
180
|
-
} catch (error) {
|
|
181
|
-
if (error.status === 404) wasOldMtx.push(false)
|
|
182
|
-
else throw error
|
|
183
|
-
}
|
|
184
|
-
} else {
|
|
185
|
-
wasOldMtx.push(false)
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
return wasOldMtx[0]
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
module.exports.isMigrated = async (tenant) => {
|
|
192
|
-
return getMetadata(tenant, 'migrated')
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
module.exports.getMigrationParameters = async (tenant) => {
|
|
196
|
-
return getMetadata(tenant, 'migrationParameters')
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
module.exports.setMigrated = async (tenant, tagRule, defaultTag, force) => {
|
|
200
|
-
const timestamp = new Date();
|
|
201
|
-
const timestampIso = timestamp.toISOString();
|
|
202
|
-
const data = {
|
|
203
|
-
timestamp: timestampIso
|
|
204
|
-
}
|
|
205
|
-
await module.exports.saveMetadata(tenant, 'migrated', data)
|
|
206
|
-
await module.exports.saveMetadata(tenant, 'migrationParameters', { tagRule, defaultTag, force })
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
function unixPath(filename) {
|
|
210
|
-
return filename.replace(/\\/g, '/');
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
module.exports.writeFilesFromMap = async (files, baseDir) => {
|
|
214
|
-
for (const [filename, content] of files) {
|
|
215
|
-
const unixFilename = unixPath(filename);
|
|
216
|
-
const absoluteFilename = path.resolve(baseDir, unixFilename);
|
|
217
|
-
|
|
218
|
-
if (absoluteFilename.includes(baseDir)) {
|
|
219
|
-
//this.logger.debug(`Writing file: ${absoluteFilename}`);
|
|
220
|
-
await fs.promises.mkdir(path.dirname(absoluteFilename), { recursive: true });
|
|
221
|
-
await fs.promises.writeFile(absoluteFilename, content);
|
|
222
|
-
} else {
|
|
223
|
-
//this.logger.debug(`Do not write file outside of target: ${absoluteFilename}`);
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
module.exports.mkdirTemp = async () => {
|
|
229
|
-
return fs.promises.mkdtemp(`${tempDir}${path.sep}`);
|
|
230
|
-
}
|