Socket
Socket
Sign inDemoInstall

@sap/cds-mtxs

Package Overview
Dependencies
Maintainers
1
Versions
61
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@sap/cds-mtxs - npm Package Compare versions

Comparing version 1.2.0 to 1.3.0

srv/jobs/async.js

37

bin/cds-mtx.js
#!/usr/bin/env node
/* eslint-disable no-console */
const cds = require('@sap/cds')
const { _import, isfile, local, path } = cds.utils
const cmd = process.argv[2]
const SUPPORTED = ['subscribe', 'unsubscribe', 'upgrade']
const SUPPORTED = ['subscribe', 'unsubscribe']
async function runAction(action, tenant) {
if (!action) _usage()
if (!SUPPORTED.includes(action)) _usage(`Unknown command ${cmd}.`)
if (!_hasMtEnv()) _handleError(`cds ${action} operation can only be run inside a multitenant application environment using @sap/cds-mtxs.`)
if (!tenant) _handleError(`Please provide a tenant: cds ${action} <tenant id>`)
async function cds_mtx(cmd, tenant) {
if (!cmd) _usage()
if (!SUPPORTED.includes(cmd)) _usage(`Unknown command ${cmd}.`)
if (!_hasMtEnv()) _handleError(`cds ${cmd} operation can only be run inside a multitenant application environment using @sap/cds-mtxs.`)
if (!tenant) _handleError(`Please provide a tenant: cds ${cmd} <tenant>`)
const { 'cds.xt.DeploymentService':ds } = await cds.serve ([

@@ -17,7 +18,18 @@ '@sap/cds-mtxs/srv/deployment-service',

])
await _local_server_js()
await cds.emit('served')
if (action === 'unsubscribe') { await cds.connect('db') }
return await ds[action](tenant)
if (cmd === 'unsubscribe') { await cds.connect() }
return await ds[cmd](tenant)
}
// copied from cds.serve
async function _local_server_js() {
const _local = file => isfile(file) || isfile (path.join(cds.env.folders.srv,file))
let cli_js = process.env.CDS_TYPESCRIPT && _local('cli.ts') || _local('cli.js')
if (cli_js) {
console.log ('[cds] - loading server from', { file: local(cli_js) })
let fn = await _import(cli_js)
}
}
// check for application environment

@@ -53,4 +65,3 @@ // fails for edge cases (ignored for now):

// eslint-disable-next-line no-console
runAction(cmd, process.argv.slice(3)[0]).catch(console.error)
const [,,cmd,tenant] = process.argv
cds_mtx(cmd, tenant).catch(console.error)

@@ -9,2 +9,25 @@ # Change Log

## Version 1.3.0 - 2022-10-28
### Added
- `cds.requires.multitenancy.for` lets you define tenant-specific creation and deployment configuration.
- `cds.xt.DeploymentService`: The `t0` tenant is now onboarded on startup.
- `POST /-/cds/deployment/subscribe` saves onboarding metadata in `t0`.
- `POST /-/cds/deployment/unsubscribe` removes onboarding metadata for `t0`.
- Parameters for `t0` tenant onboarding can now be specified via `cds.requires.multitenancy.for.t0`. Analogous to the configuraiton in `cds.xt.DeploymentService` you can specify options for `hdi` and `create`.
### Changed
- `@sap/instance-manager` has been replaced by a custom Service Manager client, which is now the default. You can switch back to the `@sap/instance-manager`-based client by setting `cds.requires['cds.xt.DeploymentService']['old-instance-manager']` to `true`.
## Version 1.2.1 - tbd
### Added
- [BETA] Command line tool `cds-mtx` now also allows to run `upgrade` in an application environment, e. g. `npx cds-mtx upgrade tenant1` or `cds-mtx upgrade tenant1` if you have installed `@sap/cds-mtxs` globally. This redeploys the current application model. Potential service handlers can be registered in `cli.js` (`server.js` is not loaded)
### Fixed
- `/-/cds/saas-provisioning/upgrade` now also runs with DwC
## Version 1.2.0 - 2022-10-06

@@ -50,3 +73,4 @@

- `GET /-/cds/deployment/getTables(tenant='<tenantId>)` returns all deployed tables for a tenant.
- Command line tool `cds-mtx` allows to run `subscribe and unsubscribe` in an application environment, e. g. `npx cds-mtx subscribe tenant1` or `cds-mtx subscribe tenant1` if you have installed `@sap/cds-mtxs` globally
- [BETA] Command line tool `cds-mtx` allows to run `subscribe and unsubscribe` in an application environment, e. g. `npx cds-mtx subscribe tenant1` or `cds-mtx subscribe tenant1` if you have installed `@sap/cds-mtxs` globally
### Changed

@@ -56,3 +80,3 @@

- `POST /-/cds/saas-provisioning/upgrade` accepts a list of tenants like `upgrade(['t1', 't2'])`.
- `upgrade(['*'])` upgrades all tenants.
+ `upgrade(['*'])` upgrades all tenants.
- `POST /-/cds/saas-provisioning/upgrade` gets its tenants from the `t0` cache instead of the `saas-registry` service.

@@ -59,0 +83,0 @@ - `POST /-/cds/saas-provisioning/upgradeAll` has been deprecated and will be removed.

@@ -114,10 +114,2 @@ const fs = require('fs')

const exists = async fileOrDir => {
try {
return await fs.promises.stat(fileOrDir)
} catch (_) {
return false
}
}
module.exports = {

@@ -131,4 +123,3 @@ EXT_BACK_PACK,

getCompilerError,
collectFiles,
exists
collectFiles
}
{
"name": "@sap/cds-mtxs",
"version": "1.2.0",
"version": "1.3.0",
"description": "SAP Cloud Application Programming Model - Multitenancy library",

@@ -22,5 +22,5 @@ "homepage": "https://cap.cloud.sap/",

"dependencies": {
"@sap/hdi-deploy": "^4",
"axios": ">=0.27.2",
"@sap/instance-manager": "^3",
"axios": "^0.27.2"
"@sap/hdi-deploy": "^4"
},

@@ -27,0 +27,0 @@ "peerDependencies": {

@@ -1,6 +0,7 @@

const cds = require('@sap/cds/lib')//, { axios } = cds.utils
const cds = require('@sap/cds/lib')
const LOG = cds.log('mtx')
const { submit, getStatus, diagnose } = require('./jobs/async')
const { asyncPool } = require('./jobs/parallel')
const { submit, getStatus, diagnose } = require('../jobs/async')
const { asyncPool } = require('../jobs/parallel')
const SaasRegistryUtil = require('./saas-registry-util')
const Tenants = 'cds.xt.Tenants'

@@ -28,4 +29,2 @@ // TODO: Implement/validate scope/tenant ID checks

await super.init() // ensure to call super.init()
cds.once('served', () => this._resubscribeT0IfNeeded())
}

@@ -39,3 +38,3 @@

async _subscribe(context) {
const { subscribedTenantId: tenant } = context.data
const tenant = this._getSubscribedTenant(context)
LOG.info(`Subscribing tenant ${tenant}`)

@@ -46,6 +45,3 @@

const tx = deploymentService.tx(context)
await tx.subscribe(tenant, this._options(context.data))
await cds.tx({ tenant: this._t0 }, tx =>
tx.run(`INSERT INTO CDS_XT_TENANTS(ID, metadata) VALUES (?, ?)`, [tenant, JSON.stringify(context.data)])
)
await tx.subscribe(tenant, context.data, this._options(context.data))
LOG.info(`Successfully subscribed tenant ${tenant}`)

@@ -75,8 +71,9 @@ await this.emit('succeeded', { task: 'subscribe', result: await this._getAppUrl(context.data, context.headers) })

async _unsubscribe(context) {
const { subscribedTenantId: tenant } = context.data
const tenant = this._getSubscribedTenant(context)
LOG.info(`Unsubscribing tenant ${tenant}`)
const [{ metadata, METADATA } = {}] = await (async () => { try { return await cds.tx({ tenant: this._t0 }, tx =>
tx.run(`SELECT metadata FROM CDS_XT_TENANTS WHERE ID=?`, [tenant])
)} catch (error) { return [] }})() // REVISIT: What if there's no subdomain (currently silently ignored)? (e.g. tenant was onboarded via DeploymentService)
// REVISIT: What if there's no subdomain (currently silently ignored)? (e.g. tenant was onboarded via DeploymentService)
const { metadata } = (await cds.tx({ tenant: this._t0 }, tx =>
tx.run(SELECT.one.from(Tenants, { ID: tenant }, tenant => { tenant.metadata }))
)) ?? {}

@@ -86,6 +83,3 @@ const ds = await cds.connect.to('cds.xt.DeploymentService')

try {
await tx.unsubscribe(tenant, { metadata: JSON.parse(metadata ?? METADATA ?? '{}') })
await cds.tx({ tenant: this._t0 }, tx =>
tx.run(`DELETE FROM CDS_XT_TENANTS WHERE ID=?`, [tenant])
)
await tx.unsubscribe(tenant, { metadata: JSON.parse(metadata ?? '{}') })
LOG.info(`Successfully unsubscribed tenant ${tenant}`)

@@ -102,2 +96,7 @@ await this.emit('succeeded', { task: 'unsubscribe' })

get _t0() {
return cds.env.requires.multitenancy.t0 ?? 't0'
}
getJobStatus(context) {

@@ -137,14 +136,23 @@ const { jobID } = context.data

const { subscribedTenantId: tenant } = context.data
const tenant = this._getSubscribedTenant(context)
return submit(tenant, this._subscribe.bind(this), context, { context })
}
_getSubscribedTenant(context) {
const { data: { subscribedTenantId }, params } = context
return (params && params[0]?.subscribedTenantId) ?? subscribedTenantId
}
async read(context) { // TODO check params for get
const { subscribedTenantId: tenant } = context.data
const tenants = (await cds.tx({ tenant: this._t0 }, tx =>
tenant ? tx.run(`SELECT ID, metadata FROM CDS_XT_TENANTS WHERE ID=?`, [tenant])
: tx.run(`SELECT ID, metadata FROM CDS_XT_TENANTS`)
)).map(tenant => (JSON.parse(tenant.metadata ?? tenant.METADATA))) // some DBs (HANA) upper-case field names
if (tenant && !tenants[0]) cds.error(`Tenant ${tenant} not found`, { status: 404 })
return tenant ? tenants[0] : tenants
const tenantId = this._getSubscribedTenant(context)
if (tenantId) {
const tenant = await cds.tx({ tenant: this._t0 }, tx =>
tx.run(SELECT.one.from(Tenants, { ID: tenantId }, tenant => { tenant.metadata }))
)
if (!tenant) cds.error(`Tenant ${tenantId} not found`, { status: 404 })
return JSON.parse(tenant.metadata)
}
return (await cds.tx({ tenant: this._t0 }, tx =>
tx.run(SELECT.from(Tenants, tenant => { tenant.ID, tenant.metadata }))
)).map(tenant => JSON.parse(tenant.metadata))
}

@@ -160,3 +168,3 @@

const { subscribedTenantId: tenant } = context.data
const tenant = this._getSubscribedTenant(context)
return submit(tenant, this._unsubscribe.bind(this), context, { context })

@@ -166,5 +174,3 @@ }

async getDependencies() {
return cds.env.requires['cds.xt.SaasProvisioningService']?.dependencies?.map(
d => ({ 'xsappname': d })
) ?? []
return cds.env.requires['cds.xt.SaasProvisioningService']?.dependencies?.map(d => ({ xsappname: d })) ?? []
}

@@ -182,8 +188,10 @@

const tenants = tenantList ?? (await cds.tx({ tenant: this._t0 }, tx =>
tx.run(`SELECT ID FROM CDS_XT_TENANTS`)
tx.run(SELECT.from(Tenants, tenant => { tenant.ID }))
)).map(({ ID }) => ID)
const { isSync } = SaasRegistryUtil.getCallbackUrlsFromHeaders(context._.req)
if (isSync) return this._updateAll(tenants, context)
// REVISIT: Which tenant ID here? - used request tenant but it is not matching what we use in subscribe
return submit(context.tenant, this._updateAll.bind(this), [tenants, context], { context })
// REVISIT: Which tenant ID here?
// use tenant from context if available
// use constant if not (dwc use case)
return submit(context.tenant ?? 'provider', this._updateAll.bind(this), [tenants, context], { context })
}

@@ -205,3 +213,4 @@

if (!isSync && !noCallback) {
const { subscribedTenantId: tenant } = originalRequest.body // TODO evaluate params for new rest adapter
/// TODO evaluate params for new rest adapter
const tenant = this._getSubscribedTenant(originalRequest.body)

@@ -226,16 +235,2 @@ const payload = { status, message, subscriptionUrl }

}
get _t0() {
return process.env.CDS_REQUIRES_MULTITENANCY_T0 ?? 't0'
}
async _resubscribeT0IfNeeded() {
const ds = await cds.connect.to('cds.xt.DeploymentService')
await ds.tx({ tenant: this._t0 }, async tx => {
if (!await tx.needsT0Redeployment()) return
const csn = await cds.load(`${__dirname}/../../db/t0.cds`)
await tx.subscribe({ tenant: this._t0, options: { csn }})
})
}
}

@@ -242,0 +237,0 @@

@@ -140,7 +140,2 @@ const { URL } = require('url')

// TODO find out purpose of this method (currently unused)
static getAuthFromHeaders(req) {
return req?.headers?.mtx_status_callback && req?.headers?.authorization
}
static get SUBDOMAIN_PLACEHOLDER() {

@@ -147,0 +142,0 @@ return 'tenant_subdomain'

@@ -16,2 +16,4 @@ const cds = require ('@sap/cds/lib')

plugins.unshift(path.join(dir,'common','metadata.js'))
const loaded = plugins.map(each => ({ file:each, module:require(each) }))

@@ -18,0 +20,0 @@

@@ -10,12 +10,16 @@ const cds = require('@sap/cds/lib'), { fs, path, tar, rimraf } = cds.utils

const _compileProject = async function (extension, req) {
const _compileProject = async function (extension) {
const root = await fs.promises.mkdtemp(`${TEMP_DIR}${path.sep}extension-`)
try {
let files = (await tar.xvz(extension).to(root)) .filter (f => f.match(/\.(cds|csn)$/))
let csn = await cds.compile (files, { cwd: root, flavor: 'parsed' })
if (csn.requires) delete csn.requires
return { csn, files }
} catch (err) {
if (err.messages) req.reject(422, getCompilerError(err.messages))
else throw err
await tar.xvz(extension).to(root)
let extCsn
try { extCsn = await cds.utils.read(path.join(root, 'extension.csn')) }
catch(e) { if (e.code !== 'ENOENT') throw e }
let bundles
try { bundles = await cds.utils.read(path.join(root, 'i18n', 'i18n.json')) }
catch(e) { if (e.code !== 'ENOENT') throw e }
return { extCsn: extCsn && JSON.parse(extCsn), bundles }
} finally {

@@ -62,3 +66,3 @@ rimraf (root)

const sources = typeof extension === 'string' ? Buffer.from(extension, 'base64') : extension
const { csn: extCsn } = await _compileProject(sources, req)
const { extCsn, bundles } = await _compileProject(sources, req)
if (!extCsn) req.reject(400, 'Missing or bad extension')

@@ -95,2 +99,3 @@ if (!tag) tag = null

csn: JSON.stringify(extCsn),
i18n: bundles ? JSON.stringify(bundles) : null,
sources,

@@ -97,0 +102,0 @@ activated: 'database',

const { URL } = require('url')
const util = require('util');
const cds = require('@sap/cds/lib')

@@ -50,13 +51,12 @@ const LOG = cds.log()

} catch (error) {
const rootCause = error.response?.data ? JSON.stringify(error.response?.data) : error.message
error.message = `Authentication failed with root cause '${rootCause}'. Passcode URL: https://${parsedUrl.hostname}/passcode`
const {
constructor: { name },
message
} = error
const status = name in { JwtRequestError: 1, IncompleteJwtResponseError: 1 } ? 401 : error.response.status ?? 500
LOG.error(message)
response.status(status).send({ message, status })
const data = error.response?.data
const reason = data?.error /* RFC 6749 */ ?? error.message
const details = data ? (` Details: '${data.error_description /* RFC 6749 */ || util.inspect(data)}'.`) : ''
const message = `Authentication failed: ${reason}.${details} Passcode URL: https://${parsedUrl.hostname}/passcode`
const status = error.response?.status ?? 500
Object.assign(error, { message })
LOG.error(error)
response.status(status).send(error)
}
}
}

@@ -56,7 +56,9 @@ const fs = require('fs').promises

const { res } = req._; if (res) res.set('Content-Type', 'application/xml')
const { service, locale, flavor } = req.data
const { service, model, locale, flavor } = req.data
delete req.data.flavor // we need to delete the OData 'flavor' argument, as getCsn has a different CSN `flavor` argument
const csn = await _getCsn(req)
const csn = model ? model : await _getCsn(req)
const edmx = cds.compile.to.edmx(csn, { service, flavor })
return cds.localize(csn, locale, edmx)
const extBundle = await _getExtI18n(req)
return cds.localize(csn, locale, edmx, extBundle)
})

@@ -108,4 +110,4 @@

async function _getCsn (req, checkExt) {
const { tenant, toggles, base, flavor, for:javaornode } = req.data
const extensions = !base && await _getExtensions4 (req.data.tenant, req.data.activated)
const { tenant, toggles, base, flavor, for:javaornode, activated } = req.data
const extensions = !base && await _getExtensions4 (tenant, activated)
if (!extensions && checkExt) req.reject(404, 'Missing extensions')

@@ -130,16 +132,44 @@

if (!main.requires.extensibility || !tenant && main.requires.multitenancy) return
const cqn = SELECT('csn').from('cds.xt.Extensions')
if (activated) cqn.where('activated=', 'database')
const exts = await cds.db.run(cqn)
if (!exts.length) return
try {
const cqn = SELECT('csn').from('cds.xt.Extensions')
if (activated) cqn.where('activated=', 'database')
const exts = await cds.db.run(cqn)
if (!exts.length) return
const merged = { extensions: [], definitions: {} }
for (let each of exts) {
let {definitions,extensions} = JSON.parse(each.csn)
if (definitions) Object.assign (merged.definitions, definitions)
if (extensions) merged.extensions.push (...extensions)
const merged = { extensions: [], definitions: {} }
for (let each of exts) {
let {definitions,extensions} = JSON.parse(each.csn)
if (definitions) Object.assign (merged.definitions, definitions)
if (extensions) merged.extensions.push (...extensions)
}
return merged
} catch (error) {
DEBUG && DEBUG('cds.xt.Extensions not yet deployed', error)
return
}
return merged
}
async function _getExtI18n (req) {
if (!main.requires.extensibility) return
const { tenant, locale } = req.data
if (!tenant && main.requires.multitenancy) return
const cqn = SELECT('i18n').from('cds.xt.Extensions').where('i18n !=', null).orderBy('timestamp')
const extBundles = await cds.db.run(cqn)
let extBundle
if (extBundles && extBundles.length) {
extBundle = extBundles.reduce((acc, cur) => {
const bundle = JSON.parse(cur.i18n)
if (locale && bundle[locale]) acc[locale] = Object.assign(acc[locale] || {}, bundle[locale])
acc[''] = Object.assign(acc[''] || {}, bundle['']) // default locale
return acc
}, {})
extBundle = extBundle[locale] || extBundle['']
}
return extBundle
}
}

@@ -146,0 +176,0 @@

@@ -15,10 +15,10 @@ const cds = require('@sap/cds/lib'), {db} = cds.requires

cds.on ('served', () => {
const hana = require('./hana/inst-mgr')
const { 'cds.xt.DeploymentService': ds } = cds.services
const useOldIm = cds.env.requires['cds.xt.DeploymentService']?.['old-instance-manager']
const hana = useOldIm ? require('./hana/inst-mgr') : require('./hana/srv-mgr')
ds.on ('subscribe', async req => {
ds.on ('subscribe', req => {
const { tenant:t, options: { _: params, csn } = {} } = req.data
// REVISIT: in which scenarios do we need to get the tenant _before_ the subscription (e.g. shared service manager/domain concept)
return prepareAndDeploy (t, hana.getOrCreate(t, _imCreateParams(params)), params, csn ?? csn4(), csn ? undefined : resources4(t))
return prepareAndDeploy (t, hana.acquire(t, _imCreateParams(t, params)), params, csn ?? csn4(), csn ? undefined : resources4(t))
})

@@ -42,22 +42,5 @@ ds.on ('upgrade', async req => {

})
ds.on ('needsT0Redeployment', async function() {
const tables = await this.getTables(_t0())
return !(tables.includes('CDS_XT_JOBS') && tables.includes('CDS_XT_TENANTS'))
})
ds.on ('hasTenant', async req => {
const { tenant:t } = req.data
try {
return await hana.get(t) !== null
} catch (e) {
if (e.code === 404) return false
throw e
}
})
ds.on ('getTenantDb', req => {
const { tenant:t } = req.data
return hana.get(t)
})
ds.on ('getTables', async req => {
const { tenant:t } = req.data
const { schema } = (t === _t0() ? await hana.getOrCreate(t) : await hana.get(t)).credentials
const { schema } = (t === _t0() ? await hana.acquire(t, _imCreateParams(t)) : await hana.get(t)).credentials
return (await cds.tx({ tenant: t }, async tx =>

@@ -67,3 +50,2 @@ await tx.run('SELECT TABLE_NAME FROM TABLES WHERE SCHEMA_NAME = ?', [schema])

})
})

@@ -74,8 +56,9 @@

function _t0() {
return process.env.CDS_REQUIRES_MULTITENANCY_T0 ?? 't0'
return cds.env.requires.multitenancy.t0 ?? 't0'
}
function _imCreateParams(params = {}) {
const paramsFromEnv = cds.env.requires['cds.xt.DeploymentService']?.hdi?.create || {}
return { ...paramsFromEnv, ...params?.hdi?.create }
function _imCreateParams(tenant, params = {}) {
const paramsFromEnv = cds.env.requires['cds.xt.DeploymentService']?.hdi?.create ?? {}
const paramsFromTenantOptions = cds.env.requires.multitenancy.for?.[tenant]?.hdi?.create ?? {}
return { ...paramsFromEnv, ...paramsFromTenantOptions, ...params?.hdi?.create }
}

@@ -168,3 +151,4 @@ function _hdiDeployParams(params = {}) {

try {
const hana = require('./hana/inst-mgr')
const useOldIm = cds.env.requires['cds.xt.DeploymentService']?.['old-instance-manager']
const hana = useOldIm ? require('./hana/inst-mgr') : require('./hana/srv-mgr')
await hana.deploy (container, tenant, out, options)

@@ -171,0 +155,0 @@ LOG.info(`Successfully finished HANA deployment for tenant ${tenant}`)

module.exports = new class InstanceManager {
async create (t, _) { return (await _im()).create(t, _) }
async delete (t) { try { return await (await _im()).delete(t) } catch (e) { if (e.statusCode !== 404) throw e } }
async get (t) { return (await _im()).get(t) }
async getOrCreate(t, _) { return await (await _im()).get(t) ?? (await _im()).create(t, _) }
async getAll () { return (await _im()).getAll() }
get deploy () { return super.deploy = require('./hdi').deploy } //> tunnelling this to provide a simpler API to users
async create (t, _) { return (await _im()).create(t, _) }
async delete (t) { try { return await (await _im()).delete(t) } catch (e) { if (e.statusCode !== 404) throw e } }
async get (t) { return (await _im()).get(t) }
async acquire(t, _) { return await (await _im()).get(t) ?? (await _im()).create(t, _) }
async getAll () { return (await _im()).getAll() }
get deploy () { return super.deploy = require('./hdi').deploy } //> tunnelling this to provide a simpler API to users
}

@@ -9,0 +9,0 @@

@@ -38,30 +38,2 @@ const cds = require('@sap/cds/lib'), {db} = cds.requires, {fs} = cds.utils

})
// REVISIT: I think we should have a review on these creeping APIs ;)
ds.on ('needsT0Redeployment', async function (req) {
const tables = await this.getTables(_t0())
if (!(tables.includes('cds_xt_Jobs') && tables.includes('cds_xt_Tenants'))) {
return true
}
// REVISIT: Don't informn when everything is as expected
// LOG.info(`No redeployment for ${_t0()} needed`)
return false
})
ds.on ('hasTenant', async req => {
const { tenant:t } = req.data
const [{ 'count(*)': count }] = await cds.tx({ tenant: t }, tx =>
tx.run(`SELECT count(*) FROM sqlite_master WHERE type = 'table'`)
)
return count > 0
})
ds.on ('getTenantDb', req => {
const { tenant:t } = req.data
return cds.tx({ tenant: t }, tx =>
tx.run(`SELECT count(*) FROM sqlite_master WHERE type = 'table'`)
) > 0 ? {} : null // TODO: What would be a sensible response here?
})
ds.on ('getTables', async req => {

@@ -74,3 +46,2 @@ const { tenant:t } = req.data

async function csn4 (tenant) {

@@ -81,8 +52,4 @@ const { 'cds.xt.ModelProviderService': mp } = cds.services

function _t0() {
return process.env.CDS_REQUIRES_MULTITENANCY_T0 ?? 't0'
}
// workaround for SQLite:
if (!cds.env.requires.multitenancy) cds.env.requires.multitenancy = true
})

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc