@sap/cds-dk 10.0.5 → 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 +28 -0
- package/bin/export.js +1 -1
- package/bin/version.js +7 -3
- package/lib/build/plugins/hana/index.js +19 -2
- package/lib/import/asyncapi/parserContext.js +136 -54
- package/lib/init/projectReader.js +4 -2
- package/lib/init/template/ams/files/package.json.hbs +1 -1
- package/lib/init/template/nodejs/index.js +4 -2
- package/lib/init/template/test/files/test/test.xs.hbs +3 -2
- package/lib/init/template/xsuaa/index.js +11 -7
- 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 +16 -0
- package/node_modules/@sap/cds/lib/compile/for/nodejs.js +1 -0
- package/node_modules/@sap/cds/lib/env/defaults.js +1 -0
- package/node_modules/@sap/cds/lib/plugins.js +4 -2
- package/node_modules/@sap/cds/lib/srv/srv-handlers.js +1 -1
- package/node_modules/@sap/cds/libx/_runtime/common/Service.js +1 -1
- package/node_modules/@sap/cds/libx/_runtime/messaging/common-utils/authorizedRequest.js +3 -2
- package/node_modules/@sap/cds/libx/_runtime/remote/Service.js +1 -1
- package/node_modules/@sap/cds/package.json +1 -1
- package/node_modules/@sap/cds-compiler/CHANGELOG.md +12 -0
- package/node_modules/@sap/cds-compiler/lib/compiler/populate.js +1 -0
- package/node_modules/@sap/cds-compiler/lib/compiler/resolve.js +1 -1
- package/node_modules/@sap/cds-compiler/lib/model/csnUtils.js +13 -8
- package/node_modules/@sap/cds-compiler/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/media-typer/README.md +15 -14
- package/node_modules/media-typer/index.js +0 -8
- package/node_modules/media-typer/package.json +16 -12
- 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
|
@@ -7,14 +7,6 @@ const Jobs = 'cds.xt.Jobs', Tasks = 'cds.xt.Tasks'
|
|
|
7
7
|
|
|
8
8
|
const { t0_ } = require('../lib/utils')
|
|
9
9
|
|
|
10
|
-
const {
|
|
11
|
-
queueSize = 100, clusterSize = 3, workerSize = 4, poolSize = 1
|
|
12
|
-
} = {
|
|
13
|
-
...(cds.env.requires.multitenancy?.jobs ?? {}),
|
|
14
|
-
...(cds.env.requires['cds.xt.SaasProvisioningService']?.jobs ?? {}),
|
|
15
|
-
...(cds.env.requires['cds.xt.SmsProvisioningService']?.jobs ?? {})
|
|
16
|
-
}
|
|
17
|
-
|
|
18
10
|
const RUNNING = 'RUNNING', FINISHED = 'FINISHED', FAILED = 'FAILED', QUEUED = 'QUEUED', TIMEOUT = 'TIMEOUT'
|
|
19
11
|
|
|
20
12
|
// A queue, implemented as a circular buffer for O(1) insert + delete
|
|
@@ -41,12 +33,15 @@ class Queue {
|
|
|
41
33
|
return value
|
|
42
34
|
}
|
|
43
35
|
}
|
|
44
|
-
const jobQueue = new Queue(queueSize)
|
|
45
|
-
let runningJobs = new Map()
|
|
46
36
|
|
|
47
37
|
module.exports = class JobsService extends cds.ApplicationService {
|
|
48
38
|
|
|
49
39
|
async init() {
|
|
40
|
+
|
|
41
|
+
this._conf = this._config()
|
|
42
|
+
this.jobQueue = new Queue(this._conf.queueSize)
|
|
43
|
+
this.runningJobs = new Map()
|
|
44
|
+
|
|
50
45
|
if (cds.requires.multitenancy?.diagnostics) _diagnostics4(this)
|
|
51
46
|
cds.on('listening', () => _scheduled(this))
|
|
52
47
|
|
|
@@ -57,16 +52,16 @@ module.exports = class JobsService extends cds.ApplicationService {
|
|
|
57
52
|
return jobs.map(job => ({ ...job, tasks: job.tasks.sort((a, b) => a.tenant.localeCompare(b.tenant))}))
|
|
58
53
|
})
|
|
59
54
|
this.on('config', () => {
|
|
60
|
-
const conf = main.requires.
|
|
55
|
+
const conf = main.requires['cds.xt.ExtensibilityService'], ext = main.requires.extensibility
|
|
61
56
|
const allowlist = 'extension-allowlist', blocklist = 'namespace-blocklist'
|
|
62
57
|
return {
|
|
63
58
|
pool: main.requires.db.pool,
|
|
64
59
|
poolMtx: cds.requires.db.pool,
|
|
65
60
|
jobs: cds.requires.multitenancy.jobs,
|
|
66
61
|
extensibility: {
|
|
67
|
-
tenantCheckInterval: conf?.tenantCheckInterval,
|
|
68
|
-
[allowlist]: conf?.[allowlist] ??
|
|
69
|
-
[blocklist]: conf?.[blocklist] ??
|
|
62
|
+
tenantCheckInterval: conf?.tenantCheckInterval ?? ext?.tenantCheckInterval,
|
|
63
|
+
[allowlist]: conf?.[allowlist] ?? ext?.[allowlist],
|
|
64
|
+
[blocklist]: conf?.[blocklist] ?? ext?.[blocklist]
|
|
70
65
|
}
|
|
71
66
|
}
|
|
72
67
|
})
|
|
@@ -74,6 +69,17 @@ module.exports = class JobsService extends cds.ApplicationService {
|
|
|
74
69
|
return super.init()
|
|
75
70
|
}
|
|
76
71
|
|
|
72
|
+
_config() {
|
|
73
|
+
const {
|
|
74
|
+
queueSize = 100, clusterSize = 3, workerSize = 4, poolSize = 1
|
|
75
|
+
} = {
|
|
76
|
+
...(cds.env.requires.multitenancy?.jobs ?? {}),
|
|
77
|
+
...(cds.env.requires['cds.xt.SaasProvisioningService']?.jobs ?? {}),
|
|
78
|
+
...(cds.env.requires['cds.xt.SmsProvisioningService']?.jobs ?? {})
|
|
79
|
+
}
|
|
80
|
+
return { queueSize, clusterSize, workerSize, poolSize }
|
|
81
|
+
}
|
|
82
|
+
|
|
77
83
|
async enqueue(service, op, clusters, args, onJobDone) {
|
|
78
84
|
const _inspect = obj => obj && Object.values(obj).filter(Boolean).length > 0 ? inspect(obj, { depth: 5, colors: cds.utils.colors.enabled }) : []
|
|
79
85
|
const inspected = Object.entries(args).reduce((acc, [k, v]) => {
|
|
@@ -112,9 +118,9 @@ module.exports = class JobsService extends cds.ApplicationService {
|
|
|
112
118
|
if (tasks.length) {
|
|
113
119
|
if (cds.services[service]) {
|
|
114
120
|
const fn = task => cds.services[service].tx({ tenant: task.tenant }, tx => tx[op](task.tenant, ...Object.values(args)))
|
|
115
|
-
jobQueue.enqueue({ job_ID, clusters: clustered, fn, onJobDone })
|
|
121
|
+
this.jobQueue.enqueue({ job_ID, clusters: clustered, fn, onJobDone })
|
|
116
122
|
} else {
|
|
117
|
-
jobQueue.enqueue({ job_ID, clusters: clustered, fn: () => {
|
|
123
|
+
this.jobQueue.enqueue({ job_ID, clusters: clustered, fn: () => {
|
|
118
124
|
LOG.warn('service', service, 'is not available, skipping job')
|
|
119
125
|
}, onJobDone })
|
|
120
126
|
}
|
|
@@ -186,16 +192,16 @@ module.exports = class JobsService extends cds.ApplicationService {
|
|
|
186
192
|
}
|
|
187
193
|
|
|
188
194
|
async pickJob() {
|
|
189
|
-
if (jobQueue.size === 0) return
|
|
195
|
+
if (this.jobQueue.size === 0) return
|
|
190
196
|
|
|
191
|
-
const next = new Set(jobQueue.peek().clusters.flat().map(t => t.tenant).flat())
|
|
192
|
-
const running = [...runningJobs.values()].flatMap(j => j.clusters.flat().map(t => t.tenant))
|
|
197
|
+
const next = new Set(this.jobQueue.peek().clusters.flat().map(t => t.tenant).flat())
|
|
198
|
+
const running = [...this.runningJobs.values()].flatMap(j => j.clusters.flat().map(t => t.tenant))
|
|
193
199
|
if (running.some(t => next.has(t))) return
|
|
194
200
|
|
|
195
|
-
const job = jobQueue.dequeue()
|
|
201
|
+
const job = this.jobQueue.dequeue()
|
|
196
202
|
const { job_ID, clusters, fn, onJobDone } = job
|
|
197
203
|
try {
|
|
198
|
-
runningJobs.set(job_ID, job)
|
|
204
|
+
this.runningJobs.set(job_ID, job)
|
|
199
205
|
await t0_(async () => {
|
|
200
206
|
await UPDATE(Jobs, { ID: job_ID }).with({ status: RUNNING })
|
|
201
207
|
await this.emit('jobUpdate', { job: { ID: job_ID, status: RUNNING }})
|
|
@@ -207,16 +213,16 @@ module.exports = class JobsService extends cds.ApplicationService {
|
|
|
207
213
|
await this.emit('jobUpdate', { job: { ID: job_ID, status: FAILED, error: _errorMessage(e) }})
|
|
208
214
|
})
|
|
209
215
|
} finally {
|
|
210
|
-
runningJobs.delete(job_ID)
|
|
216
|
+
this.runningJobs.delete(job_ID)
|
|
211
217
|
}
|
|
212
218
|
setImmediate(() => this.pickJob())
|
|
213
219
|
}
|
|
214
220
|
|
|
215
221
|
async _nextJob(clusters, fn, onJobDone) {
|
|
216
222
|
if (clusters.length > 1) {
|
|
217
|
-
await this.limiter(clusterSize, clusters, cluster => this.limiter(workerSize ?? poolSize, Array.from(cluster), fn, true))
|
|
223
|
+
await this.limiter(this._conf.clusterSize, clusters, cluster => this.limiter(this._conf.workerSize ?? this._conf.poolSize, Array.from(cluster), fn, true))
|
|
218
224
|
} else {
|
|
219
|
-
await this.limiter(workerSize ?? poolSize, Array.from(clusters[0]), fn, true)
|
|
225
|
+
await this.limiter(this._conf.workerSize ?? this._conf.poolSize, Array.from(clusters[0]), fn, true)
|
|
220
226
|
}
|
|
221
227
|
|
|
222
228
|
const { job_ID } = clusters[0][0] // all tasks have the same job ID -> just take the first
|
|
@@ -334,7 +334,7 @@ module.exports = class ModelProviderService extends cds.ApplicationService {
|
|
|
334
334
|
async function _getETag(tenant, activated = true) {
|
|
335
335
|
if (!main.requires.extensibility || main.requires.multitenancy && !tenant) return BASE_MODEL_ETAG
|
|
336
336
|
try {
|
|
337
|
-
const query = SELECT('max(timestamp) as TS').from('
|
|
337
|
+
const query = SELECT('max(timestamp) as TS').from('cds.xt.Extensions')
|
|
338
338
|
if (activated) query.where('activated=', 'database')
|
|
339
339
|
const exts = await cds.db.run(query)
|
|
340
340
|
if (!exts.length || !exts[0].TS) return BASE_MODEL_ETAG
|
|
@@ -377,7 +377,7 @@ module.exports = class ModelProviderService extends cds.ApplicationService {
|
|
|
377
377
|
}
|
|
378
378
|
|
|
379
379
|
async function getExtCsvs(req) {
|
|
380
|
-
if (cds.env.requires['cds.xt.ExtensibilityService']?.activate?.['skip-csv']) return {}
|
|
380
|
+
if (cds.env.requires['cds.xt.ExtensibilityService']?.activate?.['skip-csv'] ?? main.env.requires.extensibility?.activate?.['skip-csv']) return {}
|
|
381
381
|
|
|
382
382
|
const tenant = req.data.tenant || req.tenant
|
|
383
383
|
if (tenant) cds.context = { tenant }
|
|
@@ -68,7 +68,7 @@ class AbstractContainerManagerClient {
|
|
|
68
68
|
conf.baseURL ??= url.startsWith('http') ? '' : this.sm_url + '/v1/'
|
|
69
69
|
|
|
70
70
|
const { retries, maxRetryAfter } = cds.requires?.multitenancy?.serviceManager ?? cds.requires?.multitenancy?.containerManager ?? {}
|
|
71
|
-
return fetchResiliently(conf.baseURL + url, conf, {
|
|
71
|
+
return fetchResiliently(conf.baseURL + url, conf, { retriesLeft: retries ?? 10, maxRetryAfter: maxRetryAfter ?? 5000, retryUntil, failures })
|
|
72
72
|
}
|
|
73
73
|
|
|
74
74
|
_poll = async (location, conf = {}) => {
|
|
@@ -89,9 +89,12 @@ class AbstractContainerManagerClient {
|
|
|
89
89
|
return new Promise(_next)
|
|
90
90
|
}
|
|
91
91
|
|
|
92
|
+
// base implementation used by srv-mgr
|
|
92
93
|
_succeeded = (response) => response.data?.state === 'succeeded'
|
|
93
94
|
_failed = (response) => response.data?.state === 'failed'
|
|
94
|
-
_pollError = (response) =>
|
|
95
|
+
_pollError = (response) =>
|
|
96
|
+
response.data?.errors?.[0] ?? response.data.errors
|
|
97
|
+
?? { error: 'Unknown Error', description: `Polling failed with state ${response.data?.state ?? 'unknown'}. Last operation ${response.data?.id}` }
|
|
95
98
|
|
|
96
99
|
static _errorMessage = (e, action, tenant) => {
|
|
97
100
|
const msg = `Error ${action} tenant ${tenant}: ${e.response?.data?.error ?? e.code ?? e.message ?? 'unknown error'}`
|
|
@@ -13,7 +13,7 @@ exports._logDirectory = async () => {
|
|
|
13
13
|
await mkdirp(defaultDir)
|
|
14
14
|
return defaultDir
|
|
15
15
|
} catch (e) {
|
|
16
|
-
if (e.code !== 'EACCES') throw e
|
|
16
|
+
if (e.code !== 'EACCES' && e.code !== 'EROFS' && e.code !== 'ENOENT') throw e
|
|
17
17
|
LOG?.(`using temporary directory ${TEMP_DIR} for deployment logs`)
|
|
18
18
|
return join(TEMP_DIR, 'logs')
|
|
19
19
|
}
|
|
@@ -86,9 +86,10 @@ exports.deploy = async (hana, tenant, cwd, options, deployEnv) => {
|
|
|
86
86
|
*/
|
|
87
87
|
exports._hdi_env4 = async (t,container,options,deployEnv)=>{
|
|
88
88
|
|
|
89
|
+
let vcapFromFile
|
|
89
90
|
if (process.env.VCAP_SERVICES_FILE_PATH) {
|
|
90
91
|
try {
|
|
91
|
-
|
|
92
|
+
vcapFromFile = await fs.read(process.env.VCAP_SERVICES_FILE_PATH, 'utf-8')
|
|
92
93
|
} catch (e) {
|
|
93
94
|
LOG.warn(`Could not read or parse VCAP_SERVICES_FILE_PATH at ${process.env.VCAP_SERVICES_FILE_PATH}: ${e.message}`)
|
|
94
95
|
}
|
|
@@ -104,7 +105,8 @@ exports._hdi_env4 = async (t,container,options,deployEnv)=>{
|
|
|
104
105
|
...deployEnv // Although VCAP is in here, it will be overwritten
|
|
105
106
|
}
|
|
106
107
|
|
|
107
|
-
const
|
|
108
|
+
const vcapEnv = vcapFromFile ? { VCAP_SERVICES: vcapFromFile } : process.env
|
|
109
|
+
const { hana=[], 'user-provided':up=[] } = _parse_env (vcapEnv, 'VCAP_SERVICES')
|
|
108
110
|
const { hana: customEnvHana=[], 'user-provided':customEnvUp=[] } = _parse_env(deployEnv ?? {}, 'VCAP_SERVICES')
|
|
109
111
|
|
|
110
112
|
const vcapFromEnv = {
|
|
@@ -126,6 +126,7 @@ class ServiceManagerClient extends AbstractContainerManagerClient {
|
|
|
126
126
|
|
|
127
127
|
get = async (tenant, options = {}) => {
|
|
128
128
|
const { invalidCredentials, retryUntil } = options
|
|
129
|
+
if (invalidCredentials && cacheBindings) delete this._bindingsCache[tenant]
|
|
129
130
|
try {
|
|
130
131
|
const previousFailures = this.failures.has(tenant) ? this.failures.get(tenant).count : 0
|
|
131
132
|
const [binding] = await this._bindings4([tenant], { ...options, tenant, failures: previousFailures, retryUntil })
|
|
@@ -292,9 +293,9 @@ class ServiceManagerClient extends AbstractContainerManagerClient {
|
|
|
292
293
|
}
|
|
293
294
|
fetched.push(...directMatches)
|
|
294
295
|
}
|
|
295
|
-
const cacheMisses = Object.fromEntries(fetched.filter(b => b.labels?.tenant_id).map(b => [b.labels.tenant_id[0], b]))
|
|
296
|
-
Object.assign(this._bindingsCache, cacheMisses)
|
|
297
296
|
if (useCache) {
|
|
297
|
+
const cacheMisses = Object.fromEntries(fetched.filter(b => b.labels?.tenant_id).map(b => [b.labels.tenant_id[0], b]))
|
|
298
|
+
Object.assign(this._bindingsCache, cacheMisses)
|
|
298
299
|
return tenants.map(t => this._bindingsCache[t])
|
|
299
300
|
}
|
|
300
301
|
return fetched
|
|
@@ -17,6 +17,23 @@ class TMSClient extends AbstractContainerManagerClient {
|
|
|
17
17
|
this.tmsHost = credentials.baseurl
|
|
18
18
|
|
|
19
19
|
this.credentialCache = {}
|
|
20
|
+
|
|
21
|
+
// clusterSize > 1 not supported yet for TMS
|
|
22
|
+
const {
|
|
23
|
+
clusterSize
|
|
24
|
+
} = {
|
|
25
|
+
...(cds.env.requires.multitenancy?.jobs ?? {}),
|
|
26
|
+
...(cds.env.requires['cds.xt.SaasProvisioningService']?.jobs ?? {}),
|
|
27
|
+
...(cds.env.requires['cds.xt.SmsProvisioningService']?.jobs ?? {})
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (clusterSize && clusterSize > 1) {
|
|
31
|
+
LOG.warn(`Cluster size of ${clusterSize} is not supported for TMS. Defaulting to 1.`)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
cds.utils.merge(cds.env.requires, { multitenancy: { jobs: { clusterSize: 1 } } })
|
|
35
|
+
cds.utils.merge(cds.env.requires, { 'cds.xt.SaasProvisioningService': { jobs: { clusterSize: 1 } } })
|
|
36
|
+
cds.utils.merge(cds.env.requires, { 'cds.xt.SmsProvisioningService': { jobs: { clusterSize: 1 } } })
|
|
20
37
|
}
|
|
21
38
|
|
|
22
39
|
static defaultInstance() {
|
|
@@ -15,8 +15,6 @@ const resources = new Map()
|
|
|
15
15
|
|
|
16
16
|
const { deepMerge } = require('../../lib/utils')
|
|
17
17
|
|
|
18
|
-
const migration = require('../../lib/migration/migration')
|
|
19
|
-
|
|
20
18
|
if (db?.kind === 'hana') {
|
|
21
19
|
if (!db.credentials?.sm_url && !db.credentials?.baseurl) cds.error('No Service Manager credentials found. Make sure the application is bound to a BTP Service Manager instance.')
|
|
22
20
|
|
|
@@ -89,20 +87,24 @@ if (db?.kind === 'hana') {
|
|
|
89
87
|
})
|
|
90
88
|
ds.on ('tenantsByDb', async req => {
|
|
91
89
|
const tenantsInT0 = await ds.getTenants()
|
|
92
|
-
const
|
|
93
|
-
const tenants = req.data.tenants ?? [...tenantsInT0, ...mtxTenants]
|
|
90
|
+
const tenants = req.data.tenants ?? [...tenantsInT0]
|
|
94
91
|
const hana = require('./hana/hdi-ctnr-mgr').defaultInstance() // TODO tms more generic handling -> new functions hana.toTenantId + hana.toDbId
|
|
95
92
|
const toTenantId = t => t.tenant_id ?? t.labels.tenant_id[0]
|
|
96
93
|
const smTenants = (await hana.getAll(tenants.length > 0 ? tenants : '*')).filter(Boolean).filter(t => toTenantId(t) !== t0)
|
|
94
|
+
const byDb = {}
|
|
97
95
|
if (tenants.length !== smTenants.length) {
|
|
98
96
|
const smSet = new Set(smTenants.map(toTenantId))
|
|
99
97
|
const inconsistent = tenants.filter(t => !smSet.has(t))
|
|
100
98
|
if (!inconsistent.length)
|
|
101
99
|
LOG.warn('Tenants', smTenants.map(toTenantId).join(', '), 'are subscribed in Service Manager but not in t0. Make sure to re-subscribe the tenants.')
|
|
102
|
-
else if (inconsistent.length === 1)
|
|
100
|
+
else if (inconsistent.length === 1) {
|
|
103
101
|
LOG.warn('Warning: Tenant', inconsistent[0], 'does not exist in Service Manager any more and is therefore ignored. Make sure to unsubscribe the tenant.')
|
|
104
|
-
|
|
102
|
+
byDb['no-db'] = inconsistent
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
105
|
LOG.warn('Warning: Tenants', inconsistent.join(', '), 'do not exist in Service Manager any more and are therefore ignored. Make sure to unsubscribe the tenants.')
|
|
106
|
+
byDb['no-db'] = inconsistent
|
|
107
|
+
}
|
|
106
108
|
}
|
|
107
109
|
const tenantToDbUrl = smTenants.reduce((res, t) => {
|
|
108
110
|
const id = toTenantId(t)
|
|
@@ -110,7 +112,7 @@ if (db?.kind === 'hana') {
|
|
|
110
112
|
return { ...res, [id]: `${t.credentials.host}:${t.credentials.port}` }
|
|
111
113
|
}
|
|
112
114
|
, {})
|
|
113
|
-
|
|
115
|
+
|
|
114
116
|
for (const tenant of Object.keys(tenantToDbUrl)) {
|
|
115
117
|
const dbUrl = tenantToDbUrl[tenant]
|
|
116
118
|
if (!byDb[dbUrl]) byDb[dbUrl] = new Set
|
|
@@ -129,11 +131,6 @@ if (db?.kind === 'hana') {
|
|
|
129
131
|
}
|
|
130
132
|
return byDb
|
|
131
133
|
})
|
|
132
|
-
|
|
133
|
-
// check migration before upgrade
|
|
134
|
-
ds.before('upgrade', async (req) => {
|
|
135
|
-
await migration.checkMigration(req)
|
|
136
|
-
})
|
|
137
134
|
})
|
|
138
135
|
})
|
|
139
136
|
|
|
@@ -178,7 +175,11 @@ async function resources4(out) {
|
|
|
178
175
|
throw error
|
|
179
176
|
}
|
|
180
177
|
}
|
|
181
|
-
if (cache)
|
|
178
|
+
if (cache) {
|
|
179
|
+
const p = _resources4(out).catch(e => { resources.delete(out); throw e })
|
|
180
|
+
resources.set(out, p)
|
|
181
|
+
return p
|
|
182
|
+
}
|
|
182
183
|
return _resources4(out)
|
|
183
184
|
}
|
|
184
185
|
module.exports.resources4 = resources4 // required in abstract provisioning service to prepare shared deployment directory
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
# media-typer
|
|
2
2
|
|
|
3
|
-
[![NPM Version][npm-
|
|
4
|
-
[![NPM Downloads][
|
|
3
|
+
[![NPM Version][npm-image]][npm-url]
|
|
4
|
+
[![NPM Downloads][downloads-image]][downloads-url]
|
|
5
5
|
[![Node.js Version][node-version-image]][node-version-url]
|
|
6
|
-
[![Build Status][
|
|
6
|
+
[![Build Status][ci-image]][ci-url]
|
|
7
7
|
[![Test Coverage][coveralls-image]][coveralls-url]
|
|
8
8
|
|
|
9
9
|
Simple RFC 6838 media type parser.
|
|
10
10
|
|
|
11
|
-
This module will parse a given media type into
|
|
11
|
+
This module will parse a given media type into its component parts, like type,
|
|
12
12
|
subtype, and suffix. A formatter is also provided to put them back together and
|
|
13
13
|
the two can be combined to normalize media types into a canonical form.
|
|
14
14
|
|
|
15
|
-
If you are looking to parse the string that represents a media type and
|
|
15
|
+
If you are looking to parse the string that represents a media type and its
|
|
16
16
|
parameters in HTTP (for example, the `Content-Type` header), use the
|
|
17
17
|
[content-type module](https://www.npmjs.com/package/content-type).
|
|
18
18
|
|
|
@@ -75,19 +75,20 @@ If any of the given object values are invalid, then a `TypeError` is thrown.
|
|
|
75
75
|
var valid = typer.test('image/svg+xml')
|
|
76
76
|
```
|
|
77
77
|
|
|
78
|
-
Validate a media type string. This will return `true`
|
|
78
|
+
Validate a media type string. This will return `true` if the string is a well-
|
|
79
79
|
formatted media type, or `false` otherwise.
|
|
80
80
|
|
|
81
81
|
## License
|
|
82
82
|
|
|
83
83
|
[MIT](LICENSE)
|
|
84
84
|
|
|
85
|
-
[
|
|
86
|
-
[
|
|
87
|
-
[
|
|
88
|
-
[node-version-url]: https://nodejs.org/en/download
|
|
89
|
-
[npm-downloads-image]: https://badgen.net/npm/dm/media-typer
|
|
85
|
+
[ci-image]: https://img.shields.io/github/workflow/status/jshttp/media-typer/ci/master?label=ci
|
|
86
|
+
[ci-url]: https://github.com/jshttp/media-typer/actions/workflows/ci.yml
|
|
87
|
+
[npm-image]: https://img.shields.io/npm/v/media-typer.svg
|
|
90
88
|
[npm-url]: https://npmjs.org/package/media-typer
|
|
91
|
-
[
|
|
92
|
-
[
|
|
93
|
-
[
|
|
89
|
+
[node-version-image]: https://img.shields.io/node/v/media-typer.svg
|
|
90
|
+
[node-version-url]: https://nodejs.org/en/
|
|
91
|
+
[coveralls-image]: https://img.shields.io/coveralls/jshttp/media-typer/master.svg
|
|
92
|
+
[coveralls-url]: https://coveralls.io/r/jshttp/media-typer?branch=master
|
|
93
|
+
[downloads-image]: https://img.shields.io/npm/dm/media-typer.svg
|
|
94
|
+
[downloads-url]: https://npmjs.org/package/media-typer
|
|
@@ -83,10 +83,6 @@ function format (obj) {
|
|
|
83
83
|
*/
|
|
84
84
|
|
|
85
85
|
function test (string) {
|
|
86
|
-
if (!string) {
|
|
87
|
-
throw new TypeError('argument string is required')
|
|
88
|
-
}
|
|
89
|
-
|
|
90
86
|
if (typeof string !== 'string') {
|
|
91
87
|
throw new TypeError('argument string is required to be a string')
|
|
92
88
|
}
|
|
@@ -103,10 +99,6 @@ function test (string) {
|
|
|
103
99
|
*/
|
|
104
100
|
|
|
105
101
|
function parse (string) {
|
|
106
|
-
if (!string) {
|
|
107
|
-
throw new TypeError('argument string is required')
|
|
108
|
-
}
|
|
109
|
-
|
|
110
102
|
if (typeof string !== 'string') {
|
|
111
103
|
throw new TypeError('argument string is required to be a string')
|
|
112
104
|
}
|
|
@@ -1,20 +1,24 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "media-typer",
|
|
3
3
|
"description": "Simple RFC 6838 media type parser and formatter",
|
|
4
|
-
"version": "1.1.
|
|
4
|
+
"version": "1.1.1",
|
|
5
5
|
"author": "Douglas Christopher Wilson <doug@somethingdoug.com>",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"repository": "jshttp/media-typer",
|
|
8
|
+
"funding": {
|
|
9
|
+
"type": "opencollective",
|
|
10
|
+
"url": "https://opencollective.com/express"
|
|
11
|
+
},
|
|
8
12
|
"devDependencies": {
|
|
9
|
-
"eslint": "
|
|
10
|
-
"eslint-config-standard": "
|
|
11
|
-
"eslint-plugin-import": "2.
|
|
12
|
-
"eslint-plugin-markdown": "1.0.
|
|
13
|
-
"eslint-plugin-node": "
|
|
14
|
-
"eslint-plugin-promise": "4.
|
|
15
|
-
"eslint-plugin-standard": "4.
|
|
16
|
-
"mocha": "
|
|
17
|
-
"nyc": "
|
|
13
|
+
"eslint": "7.23.0",
|
|
14
|
+
"eslint-config-standard": "14.1.1",
|
|
15
|
+
"eslint-plugin-import": "2.22.1",
|
|
16
|
+
"eslint-plugin-markdown": "1.0.2",
|
|
17
|
+
"eslint-plugin-node": "11.1.0",
|
|
18
|
+
"eslint-plugin-promise": "4.3.1",
|
|
19
|
+
"eslint-plugin-standard": "4.1.0",
|
|
20
|
+
"mocha": "9.2.0",
|
|
21
|
+
"nyc": "15.1.0"
|
|
18
22
|
},
|
|
19
23
|
"files": [
|
|
20
24
|
"LICENSE",
|
|
@@ -27,7 +31,7 @@
|
|
|
27
31
|
"scripts": {
|
|
28
32
|
"lint": "eslint --plugin markdown --ext js,md .",
|
|
29
33
|
"test": "mocha --reporter spec --check-leaks --bail test/",
|
|
30
|
-
"test-
|
|
31
|
-
"test-
|
|
34
|
+
"test-ci": "nyc --reporter=lcov --reporter=text npm test",
|
|
35
|
+
"test-cov": "nyc --reporter=html --reporter=text npm test"
|
|
32
36
|
}
|
|
33
37
|
}
|
|
@@ -381,8 +381,8 @@
|
|
|
381
381
|
|
|
382
382
|
// this really needs to be replaced with character classes.
|
|
383
383
|
// XML allows all manner of ridiculous numbers and digits.
|
|
384
|
-
var
|
|
385
|
-
var
|
|
384
|
+
var CDATAre = /^\[CDATA\[$/i
|
|
385
|
+
var DOCTYPEre = /^DOCTYPE$/i
|
|
386
386
|
var XML_NAMESPACE = 'http://www.w3.org/XML/1998/namespace'
|
|
387
387
|
var XMLNS_NAMESPACE = 'http://www.w3.org/2000/xmlns/'
|
|
388
388
|
var rootNS = { xml: XML_NAMESPACE, xmlns: XMLNS_NAMESPACE }
|
|
@@ -464,15 +464,15 @@
|
|
|
464
464
|
SCRIPT_ENDING: S++, // <script> ... <
|
|
465
465
|
}
|
|
466
466
|
|
|
467
|
-
sax.XML_ENTITIES = {
|
|
467
|
+
sax.XML_ENTITIES = Object.assign(Object.create(null), {
|
|
468
468
|
amp: '&',
|
|
469
469
|
gt: '>',
|
|
470
470
|
lt: '<',
|
|
471
471
|
quot: '"',
|
|
472
472
|
apos: "'",
|
|
473
|
-
}
|
|
473
|
+
})
|
|
474
474
|
|
|
475
|
-
sax.ENTITIES = {
|
|
475
|
+
sax.ENTITIES = Object.assign(Object.create(null), {
|
|
476
476
|
amp: '&',
|
|
477
477
|
gt: '>',
|
|
478
478
|
lt: '<',
|
|
@@ -726,7 +726,7 @@
|
|
|
726
726
|
clubs: 9827,
|
|
727
727
|
hearts: 9829,
|
|
728
728
|
diams: 9830,
|
|
729
|
-
}
|
|
729
|
+
})
|
|
730
730
|
|
|
731
731
|
Object.keys(sax.ENTITIES).forEach(function (key) {
|
|
732
732
|
var e = sax.ENTITIES[key]
|
|
@@ -1137,7 +1137,8 @@
|
|
|
1137
1137
|
isNaN(num) ||
|
|
1138
1138
|
numStr.toLowerCase() !== entity ||
|
|
1139
1139
|
num < 0 ||
|
|
1140
|
-
num > 0x10ffff
|
|
1140
|
+
num > 0x10ffff ||
|
|
1141
|
+
!isXmlChar(num)
|
|
1141
1142
|
) {
|
|
1142
1143
|
strictFail(parser, 'Invalid character entity')
|
|
1143
1144
|
return '&' + parser.entity + ';'
|
|
@@ -1146,6 +1147,23 @@
|
|
|
1146
1147
|
return String.fromCodePoint(num)
|
|
1147
1148
|
}
|
|
1148
1149
|
|
|
1150
|
+
// Returns true if `num` is a code point that matches the XML `Char`
|
|
1151
|
+
// production, false otherwise. Character references that resolve to a
|
|
1152
|
+
// character outside this range (e.g. surrogates or restricted control
|
|
1153
|
+
// characters) are not well-formed.
|
|
1154
|
+
// https://www.w3.org/TR/REC-xml/#NT-Char
|
|
1155
|
+
// https://www.w3.org/TR/REC-xml/#wf-Legalchar
|
|
1156
|
+
function isXmlChar(num) {
|
|
1157
|
+
return (
|
|
1158
|
+
num === 0x9 ||
|
|
1159
|
+
num === 0xa ||
|
|
1160
|
+
num === 0xd ||
|
|
1161
|
+
(num >= 0x20 && num <= 0xd7ff) ||
|
|
1162
|
+
(num >= 0xe000 && num <= 0xfffd) ||
|
|
1163
|
+
(num >= 0x10000 && num <= 0x10ffff)
|
|
1164
|
+
)
|
|
1165
|
+
}
|
|
1166
|
+
|
|
1149
1167
|
function beginWhiteSpace(parser, c) {
|
|
1150
1168
|
if (c === '<') {
|
|
1151
1169
|
parser.state = S.OPEN_WAKA
|
|
@@ -1317,12 +1335,12 @@
|
|
|
1317
1335
|
parser.state = S.DOCTYPE_DTD
|
|
1318
1336
|
parser.doctype += '<!' + parser.sgmlDecl + c
|
|
1319
1337
|
parser.sgmlDecl = ''
|
|
1320
|
-
} else if ((parser.sgmlDecl + c)
|
|
1338
|
+
} else if (CDATAre.test(parser.sgmlDecl + c)) {
|
|
1321
1339
|
emitNode(parser, 'onopencdata')
|
|
1322
1340
|
parser.state = S.CDATA
|
|
1323
1341
|
parser.sgmlDecl = ''
|
|
1324
1342
|
parser.cdata = ''
|
|
1325
|
-
} else if ((parser.sgmlDecl + c)
|
|
1343
|
+
} else if (DOCTYPEre.test(parser.sgmlDecl + c)) {
|
|
1326
1344
|
parser.state = S.DOCTYPE
|
|
1327
1345
|
if (parser.doctype || parser.sawRoot) {
|
|
1328
1346
|
strictFail(
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sap/cds-dk",
|
|
3
|
-
"version": "10.0.
|
|
3
|
+
"version": "10.0.7",
|
|
4
4
|
"description": "Command line client and development toolkit for the SAP Cloud Application Programming Model",
|
|
5
5
|
"homepage": "https://cap.cloud.sap/",
|
|
6
6
|
"keywords": [
|
|
@@ -20,10 +20,10 @@
|
|
|
20
20
|
"@cap-js/asyncapi": "^1.0.0",
|
|
21
21
|
"@cap-js/openapi": "^1.0.0",
|
|
22
22
|
"@cap-js/sqlite": "^3",
|
|
23
|
-
"@sap/cds": "
|
|
24
|
-
"@sap/cds-mtxs": "
|
|
23
|
+
"@sap/cds": "^10",
|
|
24
|
+
"@sap/cds-mtxs": "^4",
|
|
25
25
|
"@sap/hdi-deploy": "^5",
|
|
26
|
-
"express": "^
|
|
26
|
+
"express": "^5",
|
|
27
27
|
"hdb": "^2.0.0",
|
|
28
28
|
"livereload-js": "^4.0.1",
|
|
29
29
|
"mustache": "^4.0.1",
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
# CAP {{ projectName }}
|
|
2
|
-
_out
|
|
3
|
-
*.db
|
|
4
|
-
*.sqlite
|
|
5
|
-
connection.properties
|
|
6
|
-
default-*.json
|
|
7
|
-
.cdsrc-private.json
|
|
8
|
-
gen/
|
|
9
|
-
node_modules/
|
|
10
|
-
target/
|
|
11
|
-
|
|
12
|
-
# Web IDE, App Studio
|
|
13
|
-
.che/
|
|
14
|
-
.gen/
|
|
15
|
-
|
|
16
|
-
# MTA
|
|
17
|
-
*_mta_build_tmp
|
|
18
|
-
*.mtar
|
|
19
|
-
mta_archives/
|
|
20
|
-
|
|
21
|
-
# Other
|
|
22
|
-
.DS_Store
|
|
23
|
-
*.orig
|
|
24
|
-
*.log
|
|
25
|
-
|
|
26
|
-
*.iml
|
|
27
|
-
*.flattened-pom.xml
|
|
28
|
-
|
|
29
|
-
# IDEs
|
|
30
|
-
# .vscode
|
|
31
|
-
# .idea
|
|
32
|
-
|
|
33
|
-
# @cap-js/cds-typer
|
|
34
|
-
@cds-models
|