From 99a5fc1c41b8a04e391cf24c05215a4838629491 Mon Sep 17 00:00:00 2001 From: Satnam Singh Brar Date: Fri, 30 Jan 2026 10:27:16 -0800 Subject: [PATCH 1/7] add the new `callWithResult()` method to `Swampyer` class --- src/swampyer.ts | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/src/swampyer.ts b/src/swampyer.ts index 02b7514..51fe7a0 100644 --- a/src/swampyer.ts +++ b/src/swampyer.ts @@ -272,7 +272,7 @@ export class Swampyer { } /** - * Call a WAMP URI and get its result + * Call a WAMP URI and returns the full result * * @param uri The WAMP URI to call * @@ -281,14 +281,40 @@ export class Swampyer { * @param args Positional arguments * @param kwargs Keyword arguments * @param options Settings for how the registration should be done. This may vary between WAMP servers - * @returns Arbitrary data returned by the call operation + * @returns A tuple containing the raw `args`, `kwargs` and the WAMP call `details` */ - async call(uri: string, args: unknown[] = [], kwargs: Object = {}, options: CallOptions = {}): Promise { + async callWithResult( + uri: string, + args: unknown[] = [], + kwargs: Object = {}, + options: CallOptions = {} + ): Promise<[args: unknown[], kwargs: Object, wampCallResponseDetails: Object]> { this.throwIfNotOpen(); const fullUri = options.withoutUriBase ? uri : this.getFullUri(uri); const requestId = this.callRequestId; this.callRequestId += 1; - const [, , resultArray] = await this.sendRequest(MessageTypes.Call, [requestId, options, fullUri, args, kwargs], MessageTypes.Result); + const [, details, resultArgs, resultKwargs] = await this.sendRequest( + MessageTypes.Call, + [requestId, options, fullUri, args, kwargs], + MessageTypes.Result + ); + return [resultArgs, resultKwargs, details]; + } + + /** + * Call a WAMP URI and get its result + * + * @param uri The WAMP URI to call + * + * If the `uriBase` options was defined when opening the connection then `uriBase` will be + * prepended to the provided URI (unless the appropriate value is set in `options`) + * @param args Positional arguments + * @param kwargs Keyword arguments + * @param options Settings for how the registration should be done. This may vary between WAMP servers + * @returns Arbitrary data returned by the call operation + */ + async call(uri: string, args: unknown[] = [], kwargs: Object = {}, options: CallOptions = {}): Promise { + const [resultArray] = await this.callWithResult(uri, args, kwargs, options); return resultArray[0]; } From cb32884397485c6c6b90187b02b9871c621d6d79 Mon Sep 17 00:00:00 2001 From: Satnam Singh Brar Date: Fri, 30 Jan 2026 10:27:30 -0800 Subject: [PATCH 2/7] add tests for the new `callWithResult()` method --- src/swampyer.test.ts | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/swampyer.test.ts b/src/swampyer.test.ts index 830a265..c0916c2 100644 --- a/src/swampyer.test.ts +++ b/src/swampyer.test.ts @@ -741,6 +741,39 @@ describe(`${Swampyer.prototype.call.name}()`, () => { }); }); +describe(`${Swampyer.prototype.callWithResult.name}()`, () => { + const args = ['my_args']; + const kwargs = { my: 'kwargs' }; + + beforeEach(async () => { + await openWamp(); + }); + + it('sends a call request and receives the result', async () => { + const promise = wamp.callWithResult('com.test.something', args, kwargs); + const request = await transportProvider.transport.read(); + expect(request).toEqual([MessageTypes.Call, expect.any(Number), {}, 'com.test.something', args, kwargs]); + transportProvider.sendToLib(MessageTypes.Result, [request[1] as number, { someWampInfo: 'info' }, ['something'], { something: 'else' }]); + expect(await promise).toEqual([['something'], { something: 'else' }, { someWampInfo: 'info' }]); + }); + + it('throws an error if the call request fails', async () => { + const promise = wamp.callWithResult('com.test.something', args, kwargs); + const request = await transportProvider.transport.read(); + expect(request).toEqual([MessageTypes.Call, expect.any(Number), {}, 'com.test.something', args, kwargs]); + transportProvider.sendToLib(MessageTypes.Error, [MessageTypes.Call, request[1] as number, {}, 'something bad', [], {}]); + await expect(promise).rejects.toBeInstanceOf(SwampyerOperationError); + }); + + it('throws an error if a GOODBYE message is received before the call can be finished', async () => { + const promise = wamp.callWithResult('com.test.something', args, kwargs); + const request = await transportProvider.transport.read(); + expect(request).toEqual([MessageTypes.Call, expect.any(Number), {}, 'com.test.something', args, kwargs]); + transportProvider.sendToLib(MessageTypes.Goodbye, [{}, 'com.some.reason']); + await expect(promise).rejects.toBeInstanceOf(ConnectionClosedError); + }); +}); + describe(`${Swampyer.prototype.unregister.name}()`, () => { const regId = 1234; From f783d88884b6f031293f56cfffe7c87f02ebda2f Mon Sep 17 00:00:00 2001 From: Satnam Singh Brar Date: Fri, 30 Jan 2026 10:29:33 -0800 Subject: [PATCH 3/7] update package version to `1.6.0` --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8b3a443..fa65b49 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "swampyer", - "version": "1.5.2", + "version": "1.6.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "swampyer", - "version": "1.5.2", + "version": "1.6.0", "license": "MIT", "devDependencies": { "@types/jest": "^27.0.2", diff --git a/package.json b/package.json index 1957755..a294057 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "swampyer", - "version": "1.5.2", + "version": "1.6.0", "description": "A lightweight WAMP client implementing the WAMP v2 basic profile", "main": "lib/index.js", "module": "lib/index.js", From fa912286b9d9ace2e41c56e342c61d7005c46883 Mon Sep 17 00:00:00 2001 From: Satnam Singh Brar Date: Fri, 30 Jan 2026 10:40:59 -0800 Subject: [PATCH 4/7] update the `publish-npm` CI job to use "Trusted Publisher" OIDC authentication on npm rather than using simple auth tokens - No need to manually manage auth token any more. Only the CI jobs will have the ability to publish to the package - The `--provenance` arg was added to `npm publish` to verify the authenticity of where the package was published from --- .github/workflows/npm-publish.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/npm-publish.yml b/.github/workflows/npm-publish.yml index 2656ac2..3ffa790 100644 --- a/.github/workflows/npm-publish.yml +++ b/.github/workflows/npm-publish.yml @@ -30,6 +30,10 @@ jobs: publish-npm: needs: build runs-on: ubuntu-latest + permissions: + # Required for publishing to npm using "Trusted Publisher" OIDC authentication + contents: read + id-token: write steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -42,6 +46,4 @@ jobs: with: path: ./lib key: ${{ github.sha }} - - run: npm publish - env: - NODE_AUTH_TOKEN: ${{secrets.npm_token}} + - run: npm publish --provenance From 43d91e0f7905d474e752b60ad62ec2c355d74acb Mon Sep 17 00:00:00 2001 From: Satnam Singh Brar Date: Fri, 30 Jan 2026 10:57:51 -0800 Subject: [PATCH 5/7] update some docstrings --- src/swampyer.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/swampyer.ts b/src/swampyer.ts index 51fe7a0..60678b7 100644 --- a/src/swampyer.ts +++ b/src/swampyer.ts @@ -272,7 +272,7 @@ export class Swampyer { } /** - * Call a WAMP URI and returns the full result + * Call a WAMP URI and get the full result * * @param uri The WAMP URI to call * @@ -302,7 +302,10 @@ export class Swampyer { } /** - * Call a WAMP URI and get its result + * Call a WAMP URI and get the `args[0]` value from the result directly. This is convenient + * if the WAMP URI only ever returns useful data via the first positional argument. + * + * If you need access to the full result then use {@link callWithResult callWithResult()} instead. * * @param uri The WAMP URI to call * From 1b61ce1c8e3cd6dd99356816c595749ee486534a Mon Sep 17 00:00:00 2001 From: Satnam Singh Brar Date: Fri, 30 Jan 2026 11:04:47 -0800 Subject: [PATCH 6/7] fix lint issues --- src/swampyer.test.ts | 6 ++++-- src/swampyer.ts | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/swampyer.test.ts b/src/swampyer.test.ts index c0916c2..c01805c 100644 --- a/src/swampyer.test.ts +++ b/src/swampyer.test.ts @@ -745,6 +745,8 @@ describe(`${Swampyer.prototype.callWithResult.name}()`, () => { const args = ['my_args']; const kwargs = { my: 'kwargs' }; + const resultDetails = { someWampInfo: 'info' }; + beforeEach(async () => { await openWamp(); }); @@ -753,8 +755,8 @@ describe(`${Swampyer.prototype.callWithResult.name}()`, () => { const promise = wamp.callWithResult('com.test.something', args, kwargs); const request = await transportProvider.transport.read(); expect(request).toEqual([MessageTypes.Call, expect.any(Number), {}, 'com.test.something', args, kwargs]); - transportProvider.sendToLib(MessageTypes.Result, [request[1] as number, { someWampInfo: 'info' }, ['something'], { something: 'else' }]); - expect(await promise).toEqual([['something'], { something: 'else' }, { someWampInfo: 'info' }]); + transportProvider.sendToLib(MessageTypes.Result, [request[1] as number, resultDetails, ['something'], { something: 'else' }]); + expect(await promise).toEqual([['something'], { something: 'else' }, resultDetails]); }); it('throws an error if the call request fails', async () => { diff --git a/src/swampyer.ts b/src/swampyer.ts index 60678b7..d58c4f7 100644 --- a/src/swampyer.ts +++ b/src/swampyer.ts @@ -304,7 +304,7 @@ export class Swampyer { /** * Call a WAMP URI and get the `args[0]` value from the result directly. This is convenient * if the WAMP URI only ever returns useful data via the first positional argument. - * + * * If you need access to the full result then use {@link callWithResult callWithResult()} instead. * * @param uri The WAMP URI to call From 0223737ba00e2891866994e92a71188211fc06cf Mon Sep 17 00:00:00 2001 From: Satnam Singh Brar Date: Fri, 30 Jan 2026 12:05:16 -0800 Subject: [PATCH 7/7] tweak some docstrings --- src/swampyer.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/swampyer.ts b/src/swampyer.ts index d58c4f7..996e759 100644 --- a/src/swampyer.ts +++ b/src/swampyer.ts @@ -281,14 +281,14 @@ export class Swampyer { * @param args Positional arguments * @param kwargs Keyword arguments * @param options Settings for how the registration should be done. This may vary between WAMP servers - * @returns A tuple containing the raw `args`, `kwargs` and the WAMP call `details` + * @returns A tuple containing the raw `args`, `kwargs` and the WAMP call's result `details` */ async callWithResult( uri: string, args: unknown[] = [], kwargs: Object = {}, options: CallOptions = {} - ): Promise<[args: unknown[], kwargs: Object, wampCallResponseDetails: Object]> { + ): Promise<[args: unknown[], kwargs: Object, wampCallResultDetails: Object]> { this.throwIfNotOpen(); const fullUri = options.withoutUriBase ? uri : this.getFullUri(uri); const requestId = this.callRequestId; @@ -314,7 +314,7 @@ export class Swampyer { * @param args Positional arguments * @param kwargs Keyword arguments * @param options Settings for how the registration should be done. This may vary between WAMP servers - * @returns Arbitrary data returned by the call operation + * @returns Arbitrary data defined at the `args[0]` value in the call operation's result */ async call(uri: string, args: unknown[] = [], kwargs: Object = {}, options: CallOptions = {}): Promise { const [resultArray] = await this.callWithResult(uri, args, kwargs, options);