From 3d39699f59259da0f0f96a17e15f8f3151f8dac2 Mon Sep 17 00:00:00 2001 From: I569192 Date: Tue, 24 Mar 2026 12:31:52 +0100 Subject: [PATCH 01/12] cds connect only once per service --- .../bookshop/srv/annotation-hybrid-service.ts | 3 +- tests/bookshop/srv/programmatic-service.ts | 31 ++++--------------- tests/bookshop/tsconfig.json | 4 +-- .../annotations/lifeCycleAnnotation.test.ts | 2 -- 4 files changed, 10 insertions(+), 30 deletions(-) diff --git a/tests/bookshop/srv/annotation-hybrid-service.ts b/tests/bookshop/srv/annotation-hybrid-service.ts index d1254c41..bb92c04a 100644 --- a/tests/bookshop/srv/annotation-hybrid-service.ts +++ b/tests/bookshop/srv/annotation-hybrid-service.ts @@ -3,9 +3,10 @@ import Annotation_Lifecycle_ProcessService from '#cds-models/eu12/cdsmunich/capp class AnnotationHybridService extends cds.ApplicationService { async init() { + const annotationLifecycleProcess = await cds.connect.to(Annotation_Lifecycle_ProcessService); + this.on('getInstancesByBusinessKey', async (req: cds.Request) => { const { ID, status } = req.data; - const annotationLifecycleProcess = await cds.connect.to(Annotation_Lifecycle_ProcessService); const instances = await annotationLifecycleProcess.getInstancesByBusinessKey({ businessKey: ID, status: status, diff --git a/tests/bookshop/srv/programmatic-service.ts b/tests/bookshop/srv/programmatic-service.ts index dc0f7a3e..17fedd82 100644 --- a/tests/bookshop/srv/programmatic-service.ts +++ b/tests/bookshop/srv/programmatic-service.ts @@ -4,19 +4,19 @@ import Programmatic_Outputs_ProcessService from '#cds-models/eu12/cdsmunich/capp class ProgrammaticService extends cds.ApplicationService { async init() { + const programmaticLifecycleProcess = await cds.connect.to( + Programmatic_Lifecycle_ProcessService, + ); + const programmaticOutputProcess = await cds.connect.to(Programmatic_Outputs_ProcessService); + const processService = await cds.connect.to('ProcessService'); + this.on('startLifeCycleProcess', async (req: cds.Request) => { - const programmaticLifecycleProcess = await cds.connect.to( - Programmatic_Lifecycle_ProcessService, - ); const { ID } = req.data; await programmaticLifecycleProcess.start({ ID }); }); this.on('updateProcess', async (req: cds.Request) => { const { ID, newStatus } = req.data; - const programmaticLifecycleProcess = await cds.connect.to( - Programmatic_Lifecycle_ProcessService, - ); if (newStatus === 'SUSPEND') { await programmaticLifecycleProcess.suspend({ businessKey: ID, @@ -30,17 +30,11 @@ class ProgrammaticService extends cds.ApplicationService { this.on('cancelProcess', async (req: cds.Request) => { const { ID } = req.data; - const programmaticLifecycleProcess = await cds.connect.to( - Programmatic_Lifecycle_ProcessService, - ); await programmaticLifecycleProcess.cancel({ businessKey: ID }); }); this.on('getInstancesByBusinessKey', async (req: cds.Request) => { const { ID, status } = req.data; - const programmaticLifecycleProcess = await cds.connect.to( - Programmatic_Lifecycle_ProcessService, - ); const instances = await programmaticLifecycleProcess.getInstancesByBusinessKey({ businessKey: ID, status: status, @@ -50,9 +44,6 @@ class ProgrammaticService extends cds.ApplicationService { this.on('getAttributes', async (req: cds.Request) => { const { ID, status } = req.data; - const programmaticLifecycleProcess = await cds.connect.to( - Programmatic_Lifecycle_ProcessService, - ); const processInstances = await programmaticLifecycleProcess.getInstancesByBusinessKey({ businessKey: ID, status: status, @@ -73,7 +64,6 @@ class ProgrammaticService extends cds.ApplicationService { this.on('startForGetOutputs', async (req: cds.Request) => { const { ID, mandatory_datetime, mandatory_string, optional_datetime, optional_string } = req.data; - const programmaticOutputProcess = await cds.connect.to(Programmatic_Outputs_ProcessService); await programmaticOutputProcess.start({ ID, mandatory_datetime, @@ -85,7 +75,6 @@ class ProgrammaticService extends cds.ApplicationService { this.on('getInstanceIDForGetOutputs', async (req: cds.Request) => { const { ID, status } = req.data; - const programmaticOutputProcess = await cds.connect.to(Programmatic_Outputs_ProcessService); const processInstances = await programmaticOutputProcess.getInstancesByBusinessKey({ businessKey: ID, status: status, @@ -105,7 +94,6 @@ class ProgrammaticService extends cds.ApplicationService { this.on('getOutputs', async (req: cds.Request) => { const { instanceId } = req.data; - const programmaticOutputProcess = await cds.connect.to(Programmatic_Outputs_ProcessService); const outputs = await programmaticOutputProcess.getOutputs(instanceId); return outputs; }); @@ -113,7 +101,6 @@ class ProgrammaticService extends cds.ApplicationService { // Generic ProcessService handlers (using cds.connect.to('ProcessService')) this.on('genericStart', async (req: cds.Request) => { const { definitionId, businessKey, context } = req.data; - const processService = await cds.connect.to('ProcessService'); const queuedProcessService = cds.queued(processService); const parsedContext = context ? JSON.parse(context) : {}; await queuedProcessService.emit( @@ -125,28 +112,24 @@ class ProgrammaticService extends cds.ApplicationService { this.on('genericCancel', async (req: cds.Request) => { const { businessKey, cascade } = req.data; - const processService = await cds.connect.to('ProcessService'); const queuedProcessService = cds.queued(processService); await queuedProcessService.emit('cancel', { businessKey, cascade: cascade ?? false }); }); this.on('genericSuspend', async (req: cds.Request) => { const { businessKey, cascade } = req.data; - const processService = await cds.connect.to('ProcessService'); const queuedProcessService = cds.queued(processService); await queuedProcessService.emit('suspend', { businessKey, cascade: cascade ?? false }); }); this.on('genericResume', async (req: cds.Request) => { const { businessKey, cascade } = req.data; - const processService = await cds.connect.to('ProcessService'); const queuedProcessService = cds.queued(processService); await queuedProcessService.emit('resume', { businessKey, cascade: cascade ?? false }); }); this.on('genericGetInstancesByBusinessKey', async (req: cds.Request) => { const { businessKey, status } = req.data; - const processService = await cds.connect.to('ProcessService'); const result = await processService.send('getInstancesByBusinessKey', { businessKey, status, @@ -156,14 +139,12 @@ class ProgrammaticService extends cds.ApplicationService { this.on('genericGetAttributes', async (req: cds.Request) => { const { processInstanceId } = req.data; - const processService = await cds.connect.to('ProcessService'); const result = await processService.send('getAttributes', { processInstanceId }); return result; }); this.on('genericGetOutputs', async (req: cds.Request) => { const { processInstanceId } = req.data; - const processService = await cds.connect.to('ProcessService'); const result = await processService.send('getOutputs', { processInstanceId }); return result; }); diff --git a/tests/bookshop/tsconfig.json b/tests/bookshop/tsconfig.json index 634049a0..74bd89d0 100644 --- a/tests/bookshop/tsconfig.json +++ b/tests/bookshop/tsconfig.json @@ -8,10 +8,10 @@ "strict": true, "skipLibCheck": true, "sourceMap": true, - "allowJs": true, "paths": { "@sap/cds": ["./node_modules/@cap-js/cds-types"], "#cds-models/*": ["./@cds-models/*"] } - } + }, + "exclude": ["**/node_modules"] } diff --git a/tests/integration/annotations/lifeCycleAnnotation.test.ts b/tests/integration/annotations/lifeCycleAnnotation.test.ts index 174b1f89..96794a47 100644 --- a/tests/integration/annotations/lifeCycleAnnotation.test.ts +++ b/tests/integration/annotations/lifeCycleAnnotation.test.ts @@ -10,8 +10,6 @@ describe('Integration tests for Process Annotation Combinations', () => { beforeAll(async () => { const db = await cds.connect.to('db'); - // Warmup: ensure DB connection and ProcessService are fully initialized before tests - await cds.connect.to('ProcessService'); db.before('*', (req) => { if (req.event === 'CREATE' && req.target?.name === 'cds.outbox.Messages') { const msg = JSON.parse(req.query?.INSERT?.entries[0].msg); From 687f108416042a862725ec6142bd50135a0a6486 Mon Sep 17 00:00:00 2001 From: I569192 Date: Tue, 24 Mar 2026 15:18:12 +0100 Subject: [PATCH 02/12] move workflows into srv --- .prettierignore | 2 +- README.md | 6 +++--- lib/processImport.ts | 2 +- ...rocesspluginhybridtest.annotation_Lifecycle_Process.json | 0 ...uginhybridtest.importProcess_Attributes_And_Outputs.json | 0 ...rocesspluginhybridtest.importProcess_Complex_Inputs.json | 0 ...processpluginhybridtest.importProcess_Simple_Inputs.json | 0 ...h.capprocesspluginhybridtest.lifecycle_Test_Process.json | 0 ...cesspluginhybridtest.programmatic_Lifecycle_Process.json | 0 ...processpluginhybridtest.programmatic_Output_Process.json | 0 10 files changed, 5 insertions(+), 5 deletions(-) rename tests/bookshop/{ => srv}/workflows/eu12.cdsmunich.capprocesspluginhybridtest.annotation_Lifecycle_Process.json (100%) rename tests/bookshop/{ => srv}/workflows/eu12.cdsmunich.capprocesspluginhybridtest.importProcess_Attributes_And_Outputs.json (100%) rename tests/bookshop/{ => srv}/workflows/eu12.cdsmunich.capprocesspluginhybridtest.importProcess_Complex_Inputs.json (100%) rename tests/bookshop/{ => srv}/workflows/eu12.cdsmunich.capprocesspluginhybridtest.importProcess_Simple_Inputs.json (100%) rename tests/bookshop/{ => srv}/workflows/eu12.cdsmunich.capprocesspluginhybridtest.lifecycle_Test_Process.json (100%) rename tests/bookshop/{ => srv}/workflows/eu12.cdsmunich.capprocesspluginhybridtest.programmatic_Lifecycle_Process.json (100%) rename tests/bookshop/{ => srv}/workflows/eu12.cdsmunich.capprocesspluginhybridtest.programmatic_Output_Process.json (100%) diff --git a/.prettierignore b/.prettierignore index 174f613d..fd053e47 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,2 +1,2 @@ -tests/bookshop/workflows/* +tests/bookshop/srv/workflows/* dist/* \ No newline at end of file diff --git a/README.md b/README.md index 21236237..299b5323 100644 --- a/README.md +++ b/README.md @@ -406,21 +406,21 @@ Import your SBPA process directly from the API: cds bind --exec -- cds-tsx import --from process --name eu12.bpm-horizon-walkme.sdshipmentprocessor.shipmentHandler --no-copy ``` -If you want to have it as a cds instead of a csn you can add --as cds at the end. If you want to reimport the process use the --force flag at the end. The flag `no-copy` is very important, as otherwise the process will be saved locally on both `./workflows`and `./srv/external` folder which would result in cds runtime issues, as the json is not a valid csn model and cannot be stored in the `.srv/external` directory. +If you want to have it as a cds instead of a csn you can add --as cds at the end. If you want to reimport the process use the --force flag at the end. The flag `no-copy` is very important, as otherwise the process will be saved locally on both `./srv/workflows`and `./srv/external` folder which would result in cds runtime issues, as the json is not a valid csn model and cannot be stored in the `.srv/external` directory. ### From Local JSON File If you already have a process definition JSON file (e.g., exported or previously fetched), you can generate the CSN model directly from it without needing credentials: ```bash -cds import --from process ./workflows/eu12.bpm-horizon-walkme.sdshipmentprocessor.shipmentHandler.json --no-copy +cds import --from process ./srv/workflows/eu12.bpm-horizon-walkme.sdshipmentprocessor.shipmentHandler.json --no-copy ``` ### What Gets Generated This will generate: -- A CDS service definition in `./workflows/` +- A CDS service definition in `./srv/workflows/` - Types via `cds-typer` for full TypeScript support - Generic handlers for the actions and functions in the imported service diff --git a/lib/processImport.ts b/lib/processImport.ts index 09f08fb9..1f3dc690 100644 --- a/lib/processImport.ts +++ b/lib/processImport.ts @@ -75,7 +75,7 @@ async function fetchAndSaveProcessDefinition(processName: string): Promise dataTypeCache.set(dt.uid, dt)); } - const outputPath = path.join(cds.root, 'workflows', `${processName}.json`); + const outputPath = path.join(cds.root, 'srv', 'workflows', `${processName}.json`); await fs.promises.mkdir(path.dirname(outputPath), { recursive: true }); await fs.promises.writeFile(outputPath, JSON.stringify(processHeader, null, 2), 'utf8'); diff --git a/tests/bookshop/workflows/eu12.cdsmunich.capprocesspluginhybridtest.annotation_Lifecycle_Process.json b/tests/bookshop/srv/workflows/eu12.cdsmunich.capprocesspluginhybridtest.annotation_Lifecycle_Process.json similarity index 100% rename from tests/bookshop/workflows/eu12.cdsmunich.capprocesspluginhybridtest.annotation_Lifecycle_Process.json rename to tests/bookshop/srv/workflows/eu12.cdsmunich.capprocesspluginhybridtest.annotation_Lifecycle_Process.json diff --git a/tests/bookshop/workflows/eu12.cdsmunich.capprocesspluginhybridtest.importProcess_Attributes_And_Outputs.json b/tests/bookshop/srv/workflows/eu12.cdsmunich.capprocesspluginhybridtest.importProcess_Attributes_And_Outputs.json similarity index 100% rename from tests/bookshop/workflows/eu12.cdsmunich.capprocesspluginhybridtest.importProcess_Attributes_And_Outputs.json rename to tests/bookshop/srv/workflows/eu12.cdsmunich.capprocesspluginhybridtest.importProcess_Attributes_And_Outputs.json diff --git a/tests/bookshop/workflows/eu12.cdsmunich.capprocesspluginhybridtest.importProcess_Complex_Inputs.json b/tests/bookshop/srv/workflows/eu12.cdsmunich.capprocesspluginhybridtest.importProcess_Complex_Inputs.json similarity index 100% rename from tests/bookshop/workflows/eu12.cdsmunich.capprocesspluginhybridtest.importProcess_Complex_Inputs.json rename to tests/bookshop/srv/workflows/eu12.cdsmunich.capprocesspluginhybridtest.importProcess_Complex_Inputs.json diff --git a/tests/bookshop/workflows/eu12.cdsmunich.capprocesspluginhybridtest.importProcess_Simple_Inputs.json b/tests/bookshop/srv/workflows/eu12.cdsmunich.capprocesspluginhybridtest.importProcess_Simple_Inputs.json similarity index 100% rename from tests/bookshop/workflows/eu12.cdsmunich.capprocesspluginhybridtest.importProcess_Simple_Inputs.json rename to tests/bookshop/srv/workflows/eu12.cdsmunich.capprocesspluginhybridtest.importProcess_Simple_Inputs.json diff --git a/tests/bookshop/workflows/eu12.cdsmunich.capprocesspluginhybridtest.lifecycle_Test_Process.json b/tests/bookshop/srv/workflows/eu12.cdsmunich.capprocesspluginhybridtest.lifecycle_Test_Process.json similarity index 100% rename from tests/bookshop/workflows/eu12.cdsmunich.capprocesspluginhybridtest.lifecycle_Test_Process.json rename to tests/bookshop/srv/workflows/eu12.cdsmunich.capprocesspluginhybridtest.lifecycle_Test_Process.json diff --git a/tests/bookshop/workflows/eu12.cdsmunich.capprocesspluginhybridtest.programmatic_Lifecycle_Process.json b/tests/bookshop/srv/workflows/eu12.cdsmunich.capprocesspluginhybridtest.programmatic_Lifecycle_Process.json similarity index 100% rename from tests/bookshop/workflows/eu12.cdsmunich.capprocesspluginhybridtest.programmatic_Lifecycle_Process.json rename to tests/bookshop/srv/workflows/eu12.cdsmunich.capprocesspluginhybridtest.programmatic_Lifecycle_Process.json diff --git a/tests/bookshop/workflows/eu12.cdsmunich.capprocesspluginhybridtest.programmatic_Output_Process.json b/tests/bookshop/srv/workflows/eu12.cdsmunich.capprocesspluginhybridtest.programmatic_Output_Process.json similarity index 100% rename from tests/bookshop/workflows/eu12.cdsmunich.capprocesspluginhybridtest.programmatic_Output_Process.json rename to tests/bookshop/srv/workflows/eu12.cdsmunich.capprocesspluginhybridtest.programmatic_Output_Process.json From 54e160542ce0fa4d2546a9f6fe990ff68f2046a9 Mon Sep 17 00:00:00 2001 From: I569192 Date: Tue, 24 Mar 2026 15:53:54 +0100 Subject: [PATCH 03/12] make cds bind --exec obsolete during import --- README.md | 4 ++-- lib/processImport.ts | 23 +++++++++++++++++++++-- package.json | 12 ++++++------ tsconfig.json | 4 ++-- 4 files changed, 31 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 299b5323..bc189728 100644 --- a/README.md +++ b/README.md @@ -400,10 +400,10 @@ To use the programmatic approach with types, you need to import an existing SBPA Import your SBPA process directly from the API: -**Note:** For remote imports, you must have ProcessService credentials bound. Run with `cds bind --exec` if needed: +**Note:** For remote imports, you must have ProcessService credentials bound (e.g., via `cds bind process -2 `). The plugin will automatically resolve the bindings at import time. ```bash -cds bind --exec -- cds-tsx import --from process --name eu12.bpm-horizon-walkme.sdshipmentprocessor.shipmentHandler --no-copy +cds import --from process --name eu12.bpm-horizon-walkme.sdshipmentprocessor.shipmentHandler --no-copy ``` If you want to have it as a cds instead of a csn you can add --as cds at the end. If you want to reimport the process use the --force flag at the end. The flag `no-copy` is very important, as otherwise the process will be saved locally on both `./srv/workflows`and `./srv/external` folder which would result in cds runtime issues, as the json is not a valid csn model and cannot be stored in the `.srv/external` directory. diff --git a/lib/processImport.ts b/lib/processImport.ts index 1f3dc690..81b49cec 100644 --- a/lib/processImport.ts +++ b/lib/processImport.ts @@ -83,9 +83,28 @@ async function fetchAndSaveProcessDefinition(processName: string): Promise { - const credentials = getServiceCredentials(PROCESS_SERVICE); + let credentials = getServiceCredentials(PROCESS_SERVICE); + + if (!credentials) { + // Try to resolve cloud bindings automatically (same as cds bind --exec does) + // REVISIT: once merged in core + try { + const { env: bindingEnv } = require('@sap/cds-dk/lib/bind/shared'); + process.env.CDS_ENV ??= 'hybrid'; + (cds as any).env = cds.env.for('cds'); + Object.assign(process.env, await bindingEnv()); + (cds as any).env = cds.env.for('cds'); + (cds as any).requires = cds.env.requires; + credentials = getServiceCredentials(PROCESS_SERVICE); + } catch { + // cds-dk not available or binding resolution failed + } + } + if (!credentials) { - throw new Error('No ProcessService credentials found. Run with: cds bind --exec -- ...'); + throw new Error( + 'No ProcessService credentials found. Ensure you have bound a process service instance (e.g., via cds bind process -2 ).', + ); } const apiUrl = credentials.endpoints?.api; diff --git a/package.json b/package.json index 156edce0..45ad826e 100644 --- a/package.json +++ b/package.json @@ -28,12 +28,12 @@ "prettier": "npx -y prettier@3 --write .", "prettier:check": "npx -y prettier@3 --check .", "import:process": "npm run import:process:annotationLifeCycle && npm run import:process:programmaticLifecycle && npm run import:process:programmaticOutput && npm run import:process:importAttributesOutputs && npm run import:process:importComplex && npm run import:process:importSimple", - "import:process:annotationLifeCycle": "cd tests/bookshop && cds bind --exec -- cds-tsx import --from process --name eu12.cdsmunich.capprocesspluginhybridtest.annotation_Lifecycle_Process --force --no-copy --as cds --config kind=process-service", - "import:process:programmaticLifecycle": "cd tests/bookshop && cds bind --exec -- cds-tsx import --from process --name eu12.cdsmunich.capprocesspluginhybridtest.programmatic_Lifecycle_Process --force --no-copy --as cds --config kind=process-service", - "import:process:programmaticOutput": "cd tests/bookshop && cds bind --exec -- cds-tsx import --from process --name eu12.cdsmunich.capprocesspluginhybridtest.programmatic_Output_Process --force --no-copy --as cds --config kind=process-service", - "import:process:importAttributesOutputs": "cd tests/bookshop && cds bind --exec -- cds-tsx import --from process --name eu12.cdsmunich.capprocesspluginhybridtest.importProcess_Attributes_And_Outputs --force --no-copy --as cds --config kind=process-service", - "import:process:importComplex": "cd tests/bookshop && cds bind --exec -- cds-tsx import --from process --name eu12.cdsmunich.capprocesspluginhybridtest.importProcess_Complex_Inputs --force --no-copy --as cds --config kind=process-service", - "import:process:importSimple": "cd tests/bookshop && cds bind --exec -- cds-tsx import --from process --name eu12.cdsmunich.capprocesspluginhybridtest.importProcess_Simple_Inputs --force --no-copy --as cds --config kind=process-service" + "import:process:annotationLifeCycle": "cd tests/bookshop && cds import --from process --name eu12.cdsmunich.capprocesspluginhybridtest.annotation_Lifecycle_Process --force", + "import:process:programmaticLifecycle": "cd tests/bookshop && cds import --from process --name eu12.cdsmunich.capprocesspluginhybridtest.programmatic_Lifecycle_Process --force", + "import:process:programmaticOutput": "cd tests/bookshop && cds import --from process --name eu12.cdsmunich.capprocesspluginhybridtest.programmatic_Output_Process --force", + "import:process:importAttributesOutputs": "cd tests/bookshop && cds import --from process --name eu12.cdsmunich.capprocesspluginhybridtest.importProcess_Attributes_And_Outputs --force", + "import:process:importComplex": "cd tests/bookshop && cds import --from process --name eu12.cdsmunich.capprocesspluginhybridtest.importProcess_Complex_Inputs --force", + "import:process:importSimple": "cd tests/bookshop && cds import --from process --name eu12.cdsmunich.capprocesspluginhybridtest.importProcess_Simple_Inputs --force" }, "keywords": [], "author": "", diff --git a/tsconfig.json b/tsconfig.json index e2d80340..275de97d 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -8,7 +8,6 @@ "strict": true, "skipLibCheck": true, "sourceMap": true, - "allowJs": true, "types": ["jest", "node"], "paths": { "@sap/cds": ["./node_modules/@cap-js/cds-types"], @@ -22,5 +21,6 @@ "./srv/**/*.ts", "./utils/**/*.ts", "./tests/**/*.ts" - ] + ], + "exclude": ["**/node_modules"] } From fed02e4c73a2c544c86e8f3ea7b3ff0f2840c31f Mon Sep 17 00:00:00 2001 From: I569192 Date: Tue, 24 Mar 2026 16:53:21 +0100 Subject: [PATCH 04/12] remove unused var --- tests/bookshop/srv/programmatic-service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/bookshop/srv/programmatic-service.ts b/tests/bookshop/srv/programmatic-service.ts index c6227eb8..d038f650 100644 --- a/tests/bookshop/srv/programmatic-service.ts +++ b/tests/bookshop/srv/programmatic-service.ts @@ -43,7 +43,7 @@ class ProgrammaticService extends cds.ApplicationService { }); this.on('getAttributes', async (req: cds.Request) => { - const { ID, status } = req.data; + const { ID } = req.data; const processInstances = await programmaticLifecycleProcess.getInstancesByBusinessKey({ businessKey: ID, }); From 2bbf2147c461213c551d43e769eafc1e8b159092 Mon Sep 17 00:00:00 2001 From: I569192 Date: Tue, 24 Mar 2026 17:13:47 +0100 Subject: [PATCH 05/12] fix lint --- lib/processImport.ts | 3 +++ lib/processImportRegistration.ts | 8 +++++++- tests/bookshop/eslint.config.mjs | 2 +- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/lib/processImport.ts b/lib/processImport.ts index 81b49cec..2374390b 100644 --- a/lib/processImport.ts +++ b/lib/processImport.ts @@ -89,12 +89,15 @@ async function createApiClient(): Promise { // Try to resolve cloud bindings automatically (same as cds bind --exec does) // REVISIT: once merged in core try { + // eslint-disable-next-line @typescript-eslint/no-require-imports const { env: bindingEnv } = require('@sap/cds-dk/lib/bind/shared'); process.env.CDS_ENV ??= 'hybrid'; + /* eslint-disable @typescript-eslint/no-explicit-any */ (cds as any).env = cds.env.for('cds'); Object.assign(process.env, await bindingEnv()); (cds as any).env = cds.env.for('cds'); (cds as any).requires = cds.env.requires; + /* eslint-enable @typescript-eslint/no-explicit-any */ credentials = getServiceCredentials(PROCESS_SERVICE); } catch { // cds-dk not available or binding resolution failed diff --git a/lib/processImportRegistration.ts b/lib/processImportRegistration.ts index 88a4e33b..d4b777f9 100644 --- a/lib/processImportRegistration.ts +++ b/lib/processImportRegistration.ts @@ -7,7 +7,13 @@ export function registerProcessImport() { // @ts-expect-error: cds type does not exist cds.import.options ??= {}; // @ts-expect-error: cds type does not exist - cds.import.options.process = { no_copy: true, as: 'cds', config: 'kind=process-service' }; + cds.import.options.process = { + no_copy: true, + as: 'cds', + config: 'kind=process-service', + profile: 'hybrid', + 'resolve-bindings': true, + }; // @ts-expect-error: process does not exist on cds.import type cds.import.from ??= {}; // @ts-expect-error: from does not exist on cds.import type diff --git a/tests/bookshop/eslint.config.mjs b/tests/bookshop/eslint.config.mjs index d762606f..d5241e8c 100644 --- a/tests/bookshop/eslint.config.mjs +++ b/tests/bookshop/eslint.config.mjs @@ -1,2 +1,2 @@ import cds from '@sap/cds/eslint.config.mjs'; -export default [...cds.recommended]; +export default [{ ignores: ['gen/**'] }, ...cds.recommended]; From 1a892cb0d62b0db1c919459a6b185e15663dd049 Mon Sep 17 00:00:00 2001 From: I569192 Date: Tue, 24 Mar 2026 17:14:12 +0100 Subject: [PATCH 06/12] fix action to bind ProcessService (revisit later) --- .github/actions/integration-tests/action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/actions/integration-tests/action.yml b/.github/actions/integration-tests/action.yml index 53bd53d2..1391d489 100644 --- a/.github/actions/integration-tests/action.yml +++ b/.github/actions/integration-tests/action.yml @@ -95,7 +95,7 @@ runs: # Bind against BTP services - name: Bind -2 process if: ${{ inputs.PROFILE == 'hana-process' }} - run: cds bind process -2 sbpa-service-instance -o package.json && cd tests/bookshop && cds bind process -2 sbpa-service-instance + run: cds bind ProcessService -2 sbpa-service-instance -o package.json && cd tests/bookshop && cds bind ProcessService -2 sbpa-service-instance shell: bash - name: Import process if: ${{ inputs.PROFILE == 'hana-process' }} From cf73b801e2e991e6c7787f2d64bb5a3355fa81c8 Mon Sep 17 00:00:00 2001 From: I569192 Date: Tue, 24 Mar 2026 17:30:21 +0100 Subject: [PATCH 07/12] update imports --- lib/processImport.ts | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/lib/processImport.ts b/lib/processImport.ts index 2374390b..ee996aee 100644 --- a/lib/processImport.ts +++ b/lib/processImport.ts @@ -1,5 +1,7 @@ import * as path from 'node:path'; import * as fs from 'node:fs'; +import { execSync } from 'node:child_process'; +import { createRequire } from 'node:module'; import cds from '@sap/cds'; import * as csn from './types/csn-extensions'; import { getServiceCredentials, CachingTokenProvider, createXsuaaTokenProvider } from './auth'; @@ -14,6 +16,27 @@ import { PROCESS_LOGGER_PREFIX, PROCESS_SERVICE } from './constants'; const LOG = cds.log(PROCESS_LOGGER_PREFIX); +// ============================================================================ +// HELPERS +// ============================================================================ + +/** + * Requires a module from @sap/cds-dk, trying local node_modules first, + * then falling back to the global npm installation. + */ +// eslint-disable-next-line @typescript-eslint/no-explicit-any +function requireCdsDk(moduleId: string): any { + try { + // eslint-disable-next-line @typescript-eslint/no-require-imports + return require(moduleId); + } catch { + // Not found locally -- try global npm root + const globalRoot = execSync('npm root -g', { encoding: 'utf8' }).trim(); + const globalRequire = createRequire(globalRoot + '/'); + return globalRequire(moduleId); + } +} + // ============================================================================ // TYPES // ============================================================================ @@ -89,8 +112,8 @@ async function createApiClient(): Promise { // Try to resolve cloud bindings automatically (same as cds bind --exec does) // REVISIT: once merged in core try { - // eslint-disable-next-line @typescript-eslint/no-require-imports - const { env: bindingEnv } = require('@sap/cds-dk/lib/bind/shared'); + const bindShared = requireCdsDk('@sap/cds-dk/lib/bind/shared'); + const { env: bindingEnv } = bindShared; process.env.CDS_ENV ??= 'hybrid'; /* eslint-disable @typescript-eslint/no-explicit-any */ (cds as any).env = cds.env.for('cds'); @@ -99,8 +122,8 @@ async function createApiClient(): Promise { (cds as any).requires = cds.env.requires; /* eslint-enable @typescript-eslint/no-explicit-any */ credentials = getServiceCredentials(PROCESS_SERVICE); - } catch { - // cds-dk not available or binding resolution failed + } catch (e) { + LOG.debug('Auto-resolve bindings failed:', e); } } From 1ac8899d346841e470f14673725d2a324cf75fb3 Mon Sep 17 00:00:00 2001 From: I569192 Date: Tue, 24 Mar 2026 17:43:07 +0100 Subject: [PATCH 08/12] . --- .github/actions/integration-tests/action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/actions/integration-tests/action.yml b/.github/actions/integration-tests/action.yml index 1391d489..53bd53d2 100644 --- a/.github/actions/integration-tests/action.yml +++ b/.github/actions/integration-tests/action.yml @@ -95,7 +95,7 @@ runs: # Bind against BTP services - name: Bind -2 process if: ${{ inputs.PROFILE == 'hana-process' }} - run: cds bind ProcessService -2 sbpa-service-instance -o package.json && cd tests/bookshop && cds bind ProcessService -2 sbpa-service-instance + run: cds bind process -2 sbpa-service-instance -o package.json && cd tests/bookshop && cds bind process -2 sbpa-service-instance shell: bash - name: Import process if: ${{ inputs.PROFILE == 'hana-process' }} From 980f0c441a664c00ecbf9da59abe740ed42aab2d Mon Sep 17 00:00:00 2001 From: I569192 Date: Thu, 26 Mar 2026 14:43:59 +0100 Subject: [PATCH 09/12] . --- lib/processImport.ts | 37 +++++++------------------------------ 1 file changed, 7 insertions(+), 30 deletions(-) diff --git a/lib/processImport.ts b/lib/processImport.ts index ee996aee..98c34798 100644 --- a/lib/processImport.ts +++ b/lib/processImport.ts @@ -1,7 +1,5 @@ import * as path from 'node:path'; import * as fs from 'node:fs'; -import { execSync } from 'node:child_process'; -import { createRequire } from 'node:module'; import cds from '@sap/cds'; import * as csn from './types/csn-extensions'; import { getServiceCredentials, CachingTokenProvider, createXsuaaTokenProvider } from './auth'; @@ -16,27 +14,6 @@ import { PROCESS_LOGGER_PREFIX, PROCESS_SERVICE } from './constants'; const LOG = cds.log(PROCESS_LOGGER_PREFIX); -// ============================================================================ -// HELPERS -// ============================================================================ - -/** - * Requires a module from @sap/cds-dk, trying local node_modules first, - * then falling back to the global npm installation. - */ -// eslint-disable-next-line @typescript-eslint/no-explicit-any -function requireCdsDk(moduleId: string): any { - try { - // eslint-disable-next-line @typescript-eslint/no-require-imports - return require(moduleId); - } catch { - // Not found locally -- try global npm root - const globalRoot = execSync('npm root -g', { encoding: 'utf8' }).trim(); - const globalRequire = createRequire(globalRoot + '/'); - return globalRequire(moduleId); - } -} - // ============================================================================ // TYPES // ============================================================================ @@ -112,15 +89,15 @@ async function createApiClient(): Promise { // Try to resolve cloud bindings automatically (same as cds bind --exec does) // REVISIT: once merged in core try { - const bindShared = requireCdsDk('@sap/cds-dk/lib/bind/shared'); - const { env: bindingEnv } = bindShared; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const cdsDk = cds as any; + const resolve = cdsDk._localOrGlobal ?? cdsDk._local ?? require; + const { env: bindingEnv } = resolve('@sap/cds-dk/lib/bind/shared'); process.env.CDS_ENV ??= 'hybrid'; - /* eslint-disable @typescript-eslint/no-explicit-any */ - (cds as any).env = cds.env.for('cds'); + cdsDk.env = cds.env.for('cds'); Object.assign(process.env, await bindingEnv()); - (cds as any).env = cds.env.for('cds'); - (cds as any).requires = cds.env.requires; - /* eslint-enable @typescript-eslint/no-explicit-any */ + cdsDk.env = cds.env.for('cds'); + cdsDk.requires = cds.env.requires; credentials = getServiceCredentials(PROCESS_SERVICE); } catch (e) { LOG.debug('Auto-resolve bindings failed:', e); From 6e163f93eb30d2e264a070de18a579e642d37aaa Mon Sep 17 00:00:00 2001 From: I569192 Date: Thu, 26 Mar 2026 14:47:04 +0100 Subject: [PATCH 10/12] . --- tsconfig.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tsconfig.json b/tsconfig.json index 275de97d..0cecbde2 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -21,6 +21,5 @@ "./srv/**/*.ts", "./utils/**/*.ts", "./tests/**/*.ts" - ], - "exclude": ["**/node_modules"] + ] } From 9de00fb990308b8de6cbe0495e68f0af9f3ae1a4 Mon Sep 17 00:00:00 2001 From: I569192 Date: Thu, 26 Mar 2026 14:48:02 +0100 Subject: [PATCH 11/12] . --- tsconfig.json | 1 + 1 file changed, 1 insertion(+) diff --git a/tsconfig.json b/tsconfig.json index 0cecbde2..e2d80340 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -8,6 +8,7 @@ "strict": true, "skipLibCheck": true, "sourceMap": true, + "allowJs": true, "types": ["jest", "node"], "paths": { "@sap/cds": ["./node_modules/@cap-js/cds-types"], From 450e772f37cd51b21eada1635298694d329d0384 Mon Sep 17 00:00:00 2001 From: I569192 Date: Thu, 26 Mar 2026 15:01:30 +0100 Subject: [PATCH 12/12] debump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 45ad826e..dee5a4a9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@cap-js/process", - "version": "1.0.0", + "version": "0.1.0", "description": "", "main": "cds-plugin.js", "files": [