From 511814eab7d96e97d601f692755661183740680e Mon Sep 17 00:00:00 2001 From: Nathan Lie Date: Tue, 26 Sep 2023 13:27:05 -0700 Subject: [PATCH 1/8] feat: add wallet address to subresource requests --- openapi/resource-server.yaml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/openapi/resource-server.yaml b/openapi/resource-server.yaml index 37e1dfe5..3a567175 100644 --- a/openapi/resource-server.yaml +++ b/openapi/resource-server.yaml @@ -137,6 +137,9 @@ paths: type: object additionalProperties: false properties: + walletAddress: + type: string + description: The URL of the wallet address that should receive the incoming payment. incomingAmount: $ref: ./schemas.yaml#/components/schemas/amount description: The maximum amount that should be paid into the wallet address under this incoming payment. @@ -334,6 +337,9 @@ paths: schema: type: object properties: + walletAddress: + type: string + description: The URL of the wallet address that should receive the outgoing payment. quoteId: type: string format: uri @@ -650,6 +656,7 @@ paths: description: A client can fetch the latest state of an incoming payment to determine the amount received into the wallet address. parameters: - $ref: '#/components/parameters/id' + - $ref: '#/components/parameters/walletAddress' '/incoming-payments/{id}/complete': post: summary: Complete an Incoming Payment @@ -699,6 +706,7 @@ paths: - $ref: '#/components/parameters/signature' parameters: - $ref: '#/components/parameters/id' + - $ref: '#/components/parameters/walletAddress' '/outgoing-payments/{id}': get: summary: Get an Outgoing Payment @@ -748,6 +756,7 @@ paths: - $ref: '#/components/parameters/signature' parameters: - $ref: '#/components/parameters/id' + - $ref: '#/components/parameters/walletAddress' '/quotes/{id}': get: summary: Get a Quote @@ -1282,6 +1291,12 @@ components: type: string description: Sub-resource identifier required: true + walletAddress: + name: wallet-address + in: query + schema: + type: string + description: URL signature: name: Signature in: header From 75c35f03ec3e8dc7697a4ee456c91adb4ca45873 Mon Sep 17 00:00:00 2001 From: Nathan Lie Date: Tue, 26 Sep 2023 13:54:11 -0700 Subject: [PATCH 2/8] feat: add examples, add walletAddress to /incoming-payments/complete --- openapi/resource-server.yaml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/openapi/resource-server.yaml b/openapi/resource-server.yaml index 3a567175..817a7f5d 100644 --- a/openapi/resource-server.yaml +++ b/openapi/resource-server.yaml @@ -154,6 +154,7 @@ paths: examples: Create incoming payment for $25 to pay invoice INV2022-02-0137: value: + walletAddress: 'https://openpayments.guide/alice/' incomingAmount: value: '2500' assetCode: USD @@ -697,6 +698,20 @@ paths: $ref: '#/components/responses/403' '404': description: Incoming Payment Not Found + requestBody: + content: + application/json: + schema: + type: object + additionalProperties: false + properties: + walletAddress: + type: string + description: The URL of the wallet address that should receive the incoming payment. + examples: + Complete incoming payment for https://openpayments.guide/alice: + value: + walletAddress: 'https://openpayments.guide/alice/' description: |- A client with the appropriate permissions MAY mark a non-expired **incoming payment** as `completed` indicating that the client is not going to make any further payments toward this **incoming payment**, even though the full `incomingAmount` may not have been received. From 7b24784163ed2d09963539921519e7144aee85d3 Mon Sep 17 00:00:00 2001 From: Nathan Lie Date: Tue, 26 Sep 2023 14:04:39 -0700 Subject: [PATCH 3/8] fix: remove wallet-address from /complete query params, add description to component --- openapi/resource-server.yaml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/openapi/resource-server.yaml b/openapi/resource-server.yaml index 817a7f5d..caaa240b 100644 --- a/openapi/resource-server.yaml +++ b/openapi/resource-server.yaml @@ -721,7 +721,6 @@ paths: - $ref: '#/components/parameters/signature' parameters: - $ref: '#/components/parameters/id' - - $ref: '#/components/parameters/walletAddress' '/outgoing-payments/{id}': get: summary: Get an Outgoing Payment @@ -1311,7 +1310,7 @@ components: in: query schema: type: string - description: URL + description: 'URL of a wallet address hosted by a Rafiki instance.' signature: name: Signature in: header From dea540efec5ad606c48d09f7582480f28e8b2976 Mon Sep 17 00:00:00 2001 From: Nathan Lie Date: Tue, 26 Sep 2023 14:28:27 -0700 Subject: [PATCH 4/8] feat: add wallet-address to list endpoints --- openapi/resource-server.yaml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/openapi/resource-server.yaml b/openapi/resource-server.yaml index caaa240b..fad49e11 100644 --- a/openapi/resource-server.yaml +++ b/openapi/resource-server.yaml @@ -279,6 +279,7 @@ paths: $ref: '#/components/responses/403' description: List all incoming payments on the wallet address parameters: + - $ref: '#/components/parameters/wallet-address' - $ref: '#/components/parameters/cursor' - $ref: '#/components/parameters/first' - $ref: '#/components/parameters/last' @@ -489,6 +490,7 @@ paths: $ref: '#/components/responses/403' description: List all outgoing payments on the wallet address parameters: + - $ref: '#/components/parameters/wallet-address' - $ref: '#/components/parameters/cursor' - $ref: '#/components/parameters/first' - $ref: '#/components/parameters/last' @@ -657,7 +659,7 @@ paths: description: A client can fetch the latest state of an incoming payment to determine the amount received into the wallet address. parameters: - $ref: '#/components/parameters/id' - - $ref: '#/components/parameters/walletAddress' + - $ref: '#/components/parameters/wallet-address' '/incoming-payments/{id}/complete': post: summary: Complete an Incoming Payment @@ -770,7 +772,7 @@ paths: - $ref: '#/components/parameters/signature' parameters: - $ref: '#/components/parameters/id' - - $ref: '#/components/parameters/walletAddress' + - $ref: '#/components/parameters/wallet-address' '/quotes/{id}': get: summary: Get a Quote @@ -1305,7 +1307,7 @@ components: type: string description: Sub-resource identifier required: true - walletAddress: + wallet-address: name: wallet-address in: query schema: From 250d95d4917b342e16d9724e8031b126dc7ecf3d Mon Sep 17 00:00:00 2001 From: Nathan Lie Date: Wed, 27 Sep 2023 08:06:23 -0700 Subject: [PATCH 5/8] feat: add changeset --- .changeset/clean-mice-sparkle.md | 5 +++ .../generated/resource-server-types.ts | 34 +++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 .changeset/clean-mice-sparkle.md diff --git a/.changeset/clean-mice-sparkle.md b/.changeset/clean-mice-sparkle.md new file mode 100644 index 00000000..6ad5938d --- /dev/null +++ b/.changeset/clean-mice-sparkle.md @@ -0,0 +1,5 @@ +--- +'@interledger/open-payments': minor +--- + +Added "walletAddress" field to resource POST request bodies, added "wallet-address" query parameter to resource GET requests. diff --git a/packages/open-payments/src/openapi/generated/resource-server-types.ts b/packages/open-payments/src/openapi/generated/resource-server-types.ts index 3a23ed59..9a2818cc 100644 --- a/packages/open-payments/src/openapi/generated/resource-server-types.ts +++ b/packages/open-payments/src/openapi/generated/resource-server-types.ts @@ -60,6 +60,10 @@ export interface paths { /** Sub-resource identifier */ id: components["parameters"]["id"]; }; + query: { + /** URL of a wallet address hosted by a Rafiki instance. */ + "wallet-address"?: components["parameters"]["wallet-address"]; + }; }; }; "/incoming-payments/{id}/complete": { @@ -84,6 +88,10 @@ export interface paths { /** Sub-resource identifier */ id: components["parameters"]["id"]; }; + query: { + /** URL of a wallet address hosted by a Rafiki instance. */ + "wallet-address"?: components["parameters"]["wallet-address"]; + }; }; }; "/quotes/{id}": { @@ -302,6 +310,8 @@ export interface components { last: number; /** @description Sub-resource identifier */ id: string; + /** @description URL of a wallet address hosted by a Rafiki instance. */ + "wallet-address": string; /** @description The signature generated based on the Signature-Input, using the signing algorithm specified in the "alg" field of the JWK. */ signature: components["parameters"]["optional-signature"]; /** @description The Signature-Input field is a Dictionary structured field containing the metadata for one or more message signatures generated from components within the HTTP message. Each member describes a single message signature. The member's key is the label that uniquely identifies the message signature within the context of the HTTP message. The member's value is the serialization of the covered components Inner List plus all signature metadata parameters identified by the label. The following components MUST be included: - "@method" - "@target-uri" - "authorization". When the message contains a request body, the covered components MUST also include the following: - "content-digest" The keyid parameter of the signature MUST be set to the kid value of the JWK. See [ietf-httpbis-message-signatures](https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-message-signatures#section-4.1) for more details. */ @@ -350,6 +360,8 @@ export interface operations { "list-incoming-payments": { parameters: { query: { + /** URL of a wallet address hosted by a Rafiki instance. */ + "wallet-address"?: components["parameters"]["wallet-address"]; /** The cursor key to list from. */ cursor?: components["parameters"]["cursor"]; /** The number of items to return after the cursor. */ @@ -413,6 +425,8 @@ export interface operations { requestBody: { content: { "application/json": { + /** @description The URL of the wallet address that should receive the incoming payment. */ + walletAddress?: string; /** @description The maximum amount that should be paid into the wallet address under this incoming payment. */ incomingAmount?: external["schemas.yaml"]["components"]["schemas"]["amount"]; /** @@ -430,6 +444,8 @@ export interface operations { "list-outgoing-payments": { parameters: { query: { + /** URL of a wallet address hosted by a Rafiki instance. */ + "wallet-address"?: components["parameters"]["wallet-address"]; /** The cursor key to list from. */ cursor?: components["parameters"]["cursor"]; /** The number of items to return after the cursor. */ @@ -490,6 +506,8 @@ export interface operations { requestBody: { content: { "application/json": { + /** @description The URL of the wallet address that should receive the outgoing payment. */ + walletAddress?: string; /** * Format: uri * @description The URL of the quote defining this payment's amounts. @@ -557,6 +575,10 @@ export interface operations { /** Sub-resource identifier */ id: components["parameters"]["id"]; }; + query: { + /** URL of a wallet address hosted by a Rafiki instance. */ + "wallet-address"?: components["parameters"]["wallet-address"]; + }; header: { /** The Signature-Input field is a Dictionary structured field containing the metadata for one or more message signatures generated from components within the HTTP message. Each member describes a single message signature. The member's key is the label that uniquely identifies the message signature within the context of the HTTP message. The member's value is the serialization of the covered components Inner List plus all signature metadata parameters identified by the label. The following components MUST be included: - "@method" - "@target-uri" - "authorization". When the message contains a request body, the covered components MUST also include the following: - "content-digest" The keyid parameter of the signature MUST be set to the kid value of the JWK. See [ietf-httpbis-message-signatures](https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-message-signatures#section-4.1) for more details. */ "Signature-Input"?: components["parameters"]["optional-signature-input"]; @@ -610,6 +632,14 @@ export interface operations { /** Incoming Payment Not Found */ 404: unknown; }; + requestBody: { + content: { + "application/json": { + /** @description The URL of the wallet address that should receive the incoming payment. */ + walletAddress?: string; + }; + }; + }; }; /** A client can fetch the latest state of an outgoing payment. */ "get-outgoing-payment": { @@ -618,6 +648,10 @@ export interface operations { /** Sub-resource identifier */ id: components["parameters"]["id"]; }; + query: { + /** URL of a wallet address hosted by a Rafiki instance. */ + "wallet-address"?: components["parameters"]["wallet-address"]; + }; header: { /** The Signature-Input field is a Dictionary structured field containing the metadata for one or more message signatures generated from components within the HTTP message. Each member describes a single message signature. The member's key is the label that uniquely identifies the message signature within the context of the HTTP message. The member's value is the serialization of the covered components Inner List plus all signature metadata parameters identified by the label. The following components MUST be included: - "@method" - "@target-uri" - "authorization". When the message contains a request body, the covered components MUST also include the following: - "content-digest" The keyid parameter of the signature MUST be set to the kid value of the JWK. See [ietf-httpbis-message-signatures](https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-message-signatures#section-4.1) for more details. */ "Signature-Input": components["parameters"]["signature-input"]; From bdb2f565c8e60499a9347651e5035b9543697c5b Mon Sep 17 00:00:00 2001 From: Nathan Lie Date: Wed, 4 Oct 2023 14:47:35 -0700 Subject: [PATCH 6/8] feat: make wallet addresses required in requests; update open payments client --- openapi/resource-server.yaml | 25 +++- openapi/schemas.yaml | 5 + packages/open-payments/src/client/grant.ts | 16 +-- .../src/client/incoming-payment.test.ts | 116 ++++++++++++------ .../src/client/incoming-payment.ts | 71 ++++++----- packages/open-payments/src/client/index.ts | 13 +- .../src/client/outgoing-payment.test.ts | 91 ++++++++++---- .../src/client/outgoing-payment.ts | 50 ++++---- packages/open-payments/src/client/quote.ts | 19 ++- packages/open-payments/src/client/token.ts | 14 +-- .../src/client/wallet-address.ts | 10 +- .../openapi/generated/auth-server-types.ts | 6 + .../generated/resource-server-types.ts | 30 +++-- 13 files changed, 296 insertions(+), 170 deletions(-) diff --git a/openapi/resource-server.yaml b/openapi/resource-server.yaml index fad49e11..2a9bcf04 100644 --- a/openapi/resource-server.yaml +++ b/openapi/resource-server.yaml @@ -138,8 +138,8 @@ paths: additionalProperties: false properties: walletAddress: - type: string - description: The URL of the wallet address that should receive the incoming payment. + $ref: ./schemas.yaml#/components/schemas/walletAddress + required: true incomingAmount: $ref: ./schemas.yaml#/components/schemas/amount description: The maximum amount that should be paid into the wallet address under this incoming payment. @@ -340,8 +340,8 @@ paths: type: object properties: walletAddress: - type: string - description: The URL of the wallet address that should receive the outgoing payment. + $ref: ./schemas.yaml#/components/schemas/walletAddress + required: true quoteId: type: string format: uri @@ -540,10 +540,12 @@ paths: examples: Create quote for an `receiver` that is an Incoming Payment with an `incomingAmount`: value: + walletAddress: 'https://ilp.rafiki.money/alice' receiver: 'https://ilp.rafiki.money/incoming-payments/37a0d0ee-26dc-4c66-89e0-01fbf93156f7' method: ilp Create fixed-send amount quote for $25: value: + walletAddress: 'https://ilp.rafiki.money/alice' receiver: 'https://ilp.rafiki.money/incoming-payments/37a0d0ee-26dc-4c66-89e0-01fbf93156f7' method: ilp debitAmount: @@ -552,6 +554,7 @@ paths: assetScale: 2 Create fixed-receive amount quote for $25: value: + walletAddress: 'https://ilp.rafiki.money/alice' receiver: 'https://ilp.rafiki.money/incoming-payments/37a0d0ee-26dc-4c66-89e0-01fbf93156f7' method: ilp receiveAmount: @@ -562,16 +565,21 @@ paths: oneOf: - description: Create quote for an `receiver` that is an Incoming Payment with an `incomingAmount` properties: + walletAddress: + $ref: ./schemas.yaml#/components/schemas/walletAddress receiver: $ref: ./schemas.yaml#/components/schemas/receiver method: $ref: '#/components/schemas/payment-method' required: + - walletAddress - receiver - method additionalProperties: false - description: Create a quote with a fixed-receive amount properties: + walletAddress: + $ref: ./schemas.yaml#/components/schemas/walletAddress receiver: $ref: ./schemas.yaml#/components/schemas/receiver method: @@ -580,12 +588,15 @@ paths: description: The fixed amount that would be paid into the receiving wallet address given a successful outgoing payment. $ref: ./schemas.yaml#/components/schemas/amount required: + - walletAddress - receiver - method - receiveAmount additionalProperties: false - description: Create a quote with a fixed-send amount properties: + walletAddress: + $ref: ./schemas.yaml#/components/schemas/walletAddress receiver: $ref: ./schemas.yaml#/components/schemas/receiver method: @@ -594,6 +605,7 @@ paths: description: The fixed amount that would be sent from the sending wallet address given a successful outgoing payment. $ref: ./schemas.yaml#/components/schemas/amount required: + - walletAddress - receiver - method - debitAmount @@ -708,8 +720,8 @@ paths: additionalProperties: false properties: walletAddress: - type: string - description: The URL of the wallet address that should receive the incoming payment. + $ref: ./schemas.yaml#/components/schemas/walletAddress + required: true examples: Complete incoming payment for https://openpayments.guide/alice: value: @@ -1313,6 +1325,7 @@ components: schema: type: string description: 'URL of a wallet address hosted by a Rafiki instance.' + required: true signature: name: Signature in: header diff --git a/openapi/schemas.yaml b/openapi/schemas.yaml index 0216faa4..fc0bce44 100644 --- a/openapi/schemas.yaml +++ b/openapi/schemas.yaml @@ -46,3 +46,8 @@ components: examples: - 'https://ilp.rafiki.money/incoming-payments/08394f02-7b7b-45e2-b645-51d04e7c330c' - 'https://ilp.rafiki.money/connections/016da9d5-c9a4-4c80-a354-86b915a04ff8' + walletAddress: + title: Wallet Address + type: string + description: 'URL of a wallet address hosted by a Rafiki instance.' + format: uri diff --git a/packages/open-payments/src/client/grant.ts b/packages/open-payments/src/client/grant.ts index 6be99e6a..83cda8d5 100644 --- a/packages/open-payments/src/client/grant.ts +++ b/packages/open-payments/src/client/grant.ts @@ -1,8 +1,8 @@ import { HttpMethod } from '@interledger/openapi' import { - ResourceRequestArgs, + GrantOrTokenRequestArgs, RouteDeps, - UnauthenticatedResourceRequestArgs + UnauthenticatedRequestArgs } from '.' import { getASPath, @@ -19,14 +19,14 @@ export interface GrantRouteDeps extends RouteDeps { export interface GrantRoutes { request( - postArgs: UnauthenticatedResourceRequestArgs, + postArgs: UnauthenticatedRequestArgs, args: Omit ): Promise continue( - postArgs: ResourceRequestArgs, + postArgs: GrantOrTokenRequestArgs, args: GrantContinuationRequest ): Promise - cancel(postArgs: ResourceRequestArgs): Promise + cancel(postArgs: GrantOrTokenRequestArgs): Promise } export const createGrantRoutes = (deps: GrantRouteDeps): GrantRoutes => { @@ -47,7 +47,7 @@ export const createGrantRoutes = (deps: GrantRouteDeps): GrantRoutes => { return { request: ( - { url }: UnauthenticatedResourceRequestArgs, + { url }: UnauthenticatedRequestArgs, args: Omit ) => post( @@ -62,7 +62,7 @@ export const createGrantRoutes = (deps: GrantRouteDeps): GrantRoutes => { requestGrantValidator ), continue: ( - { url, accessToken }: ResourceRequestArgs, + { url, accessToken }: GrantOrTokenRequestArgs, args: GrantContinuationRequest ) => post( @@ -74,7 +74,7 @@ export const createGrantRoutes = (deps: GrantRouteDeps): GrantRoutes => { }, continueGrantValidator ), - cancel: ({ url, accessToken }: ResourceRequestArgs) => + cancel: ({ url, accessToken }: GrantOrTokenRequestArgs) => deleteRequest( deps, { diff --git a/packages/open-payments/src/client/incoming-payment.test.ts b/packages/open-payments/src/client/incoming-payment.test.ts index bcc86f07..554cd19b 100644 --- a/packages/open-payments/src/client/incoming-payment.test.ts +++ b/packages/open-payments/src/client/incoming-payment.test.ts @@ -54,15 +54,17 @@ describe('incoming-payment', (): void => { test('returns incoming payment if passes validation', async (): Promise => { const incomingPayment = mockIncomingPaymentWithPaymentMethods() - nock(walletAddress) + nock(serverAddress) .get('/incoming-payments/1') + .query({ 'wallet-address': walletAddress }) .reply(200, incomingPayment) const result = await getIncomingPayment( { axiosInstance, logger }, { - url: `${walletAddress}/incoming-payments/1`, - accessToken + url: `${serverAddress}/incoming-payments/1`, + accessToken, + walletAddress }, openApiValidators.successfulValidator ) @@ -83,8 +85,9 @@ describe('incoming-payment', (): void => { } }) - nock(walletAddress) + nock(serverAddress) .get('/incoming-payments/1') + .query({ 'wallet-address': walletAddress }) .reply(200, incomingPayment) await expect( @@ -94,8 +97,9 @@ describe('incoming-payment', (): void => { logger }, { - url: `${walletAddress}/incoming-payments/1`, - accessToken + url: `${serverAddress}/incoming-payments/1`, + accessToken, + walletAddress }, openApiValidators.successfulValidator ) @@ -105,8 +109,9 @@ describe('incoming-payment', (): void => { test('throws if incoming payment does not pass open api validation', async (): Promise => { const incomingPayment = mockIncomingPaymentWithPaymentMethods() - nock(walletAddress) + nock(serverAddress) .get('/incoming-payments/1') + .query({ 'wallet-address': walletAddress }) .reply(200, incomingPayment) await expect( @@ -116,8 +121,9 @@ describe('incoming-payment', (): void => { logger }, { - url: `${walletAddress}/incoming-payments/1`, - accessToken + url: `${serverAddress}/incoming-payments/1`, + accessToken, + walletAddress }, openApiValidators.failedValidator ) @@ -179,13 +185,13 @@ describe('incoming-payment', (): void => { metadata }) - const scope = nock(walletAddress) + const scope = nock(serverAddress) .post('/incoming-payments') .reply(200, incomingPayment) const result = await createIncomingPayment( { axiosInstance, logger }, - { walletAddress, accessToken }, + { url: serverAddress, walletAddress, accessToken }, openApiValidators.successfulValidator, { incomingAmount, @@ -212,14 +218,14 @@ describe('incoming-payment', (): void => { completed: false }) - const scope = nock(walletAddress) + const scope = nock(serverAddress) .post('/incoming-payments') .reply(200, incomingPayment) await expect( createIncomingPayment( { axiosInstance, logger }, - { walletAddress, accessToken }, + { url: serverAddress, walletAddress, accessToken }, openApiValidators.successfulValidator, {} ) @@ -230,14 +236,14 @@ describe('incoming-payment', (): void => { test('throws if the created incoming payment does not pass open api validation', async (): Promise => { const incomingPayment = mockIncomingPaymentWithPaymentMethods() - const scope = nock(walletAddress) + const scope = nock(serverAddress) .post('/incoming-payments') .reply(200, incomingPayment) await expect( createIncomingPayment( { axiosInstance, logger }, - { walletAddress, accessToken }, + { url: serverAddress, walletAddress, accessToken }, openApiValidators.failedValidator, {} ) @@ -260,7 +266,8 @@ describe('incoming-payment', (): void => { { axiosInstance, logger }, { url: `${serverAddress}/incoming-payments/${incomingPayment.id}`, - accessToken + accessToken, + walletAddress }, openApiValidators.successfulValidator ) @@ -275,7 +282,7 @@ describe('incoming-payment', (): void => { completed: false }) - const scope = nock(walletAddress) + const scope = nock(serverAddress) .post(`/incoming-payments/${incomingPayment.id}/complete`) .reply(200, incomingPayment) @@ -283,8 +290,9 @@ describe('incoming-payment', (): void => { completeIncomingPayment( { axiosInstance, logger }, { - url: `${walletAddress}/incoming-payments/${incomingPayment.id}`, - accessToken + url: `${serverAddress}/incoming-payments/${incomingPayment.id}`, + accessToken, + walletAddress }, openApiValidators.successfulValidator ) @@ -298,7 +306,7 @@ describe('incoming-payment', (): void => { completed: true }) - const scope = nock(walletAddress) + const scope = nock(serverAddress) .post(`/incoming-payments/${incomingPayment.id}/complete`) .reply(200, incomingPayment) @@ -306,8 +314,9 @@ describe('incoming-payment', (): void => { completeIncomingPayment( { axiosInstance, logger }, { - url: `${walletAddress}/incoming-payments/${incomingPayment.id}`, - accessToken + url: `${serverAddress}/incoming-payments/${incomingPayment.id}`, + accessToken, + walletAddress }, openApiValidators.failedValidator ) @@ -332,9 +341,10 @@ describe('incoming-payment', (): void => { result: Array(first).fill(mockIncomingPayment()) }) - const scope = nock(walletAddress) + const scope = nock(serverAddress) .get('/incoming-payments') .query({ + 'wallet-address': walletAddress, ...(first ? { first } : {}), ...(cursor ? { cursor } : {}) }) @@ -346,11 +356,13 @@ describe('incoming-payment', (): void => { logger }, { + url: serverAddress, walletAddress, accessToken }, openApiValidators.successfulValidator, { + 'wallet-address': walletAddress, first, cursor } @@ -375,9 +387,10 @@ describe('incoming-payment', (): void => { result: Array(last).fill(mockIncomingPayment()) }) - const scope = nock(walletAddress) + const scope = nock(serverAddress) .get('/incoming-payments') .query({ + 'wallet-address': walletAddress, ...(last ? { last } : {}), cursor }) @@ -389,11 +402,13 @@ describe('incoming-payment', (): void => { logger }, { + url: serverAddress, walletAddress, accessToken }, openApiValidators.successfulValidator, { + 'wallet-address': walletAddress, last, cursor } @@ -424,8 +439,9 @@ describe('incoming-payment', (): void => { result: [incomingPayment] }) - const scope = nock(walletAddress) + const scope = nock(serverAddress) .get('/incoming-payments') + .query({ 'wallet-address': walletAddress }) .reply(200, incomingPaymentPaginationResult) await expect( @@ -435,6 +451,7 @@ describe('incoming-payment', (): void => { logger }, { + url: serverAddress, walletAddress, accessToken }, @@ -449,14 +466,15 @@ describe('incoming-payment', (): void => { const incomingPaymentPaginationResult = mockIncomingPaymentPaginationResult() - const scope = nock(walletAddress) + const scope = nock(serverAddress) .get('/incoming-payments') + .query({ 'wallet-address': walletAddress }) .reply(200, incomingPaymentPaginationResult) await expect( listIncomingPayment( { axiosInstance, logger }, - { walletAddress, accessToken }, + { url: serverAddress, walletAddress, accessToken }, openApiValidators.failedValidator ) ).rejects.toThrowError() @@ -637,7 +655,7 @@ describe('incoming-payment', (): void => { const mockResponseValidator = ({ path, method }) => path === '/incoming-payments/{id}' && method === HttpMethod.GET - const url = `${walletAddress}/incoming-payments/1` + const url = `${serverAddress}/incoming-payments/1` jest .spyOn(openApi, 'createResponseValidator') @@ -652,14 +670,21 @@ describe('incoming-payment', (): void => { openApi, axiosInstance, logger - }).get({ url, accessToken }) + }).get({ url, accessToken, walletAddress }) expect(getSpy).toHaveBeenCalledWith( { axiosInstance, logger }, - { url, accessToken }, + { + url, + accessToken, + walletAddress, + queryParams: { + 'wallet-address': walletAddress + } + }, true ) }) @@ -709,7 +734,7 @@ describe('incoming-payment', (): void => { mockIncomingPaymentPaginationResult({ result: [mockIncomingPayment()] }) - const url = `${walletAddress}${getRSPath('/incoming-payments')}` + const url = `${serverAddress}${getRSPath('/incoming-payments')}` jest .spyOn(openApi, 'createResponseValidator') @@ -724,14 +749,20 @@ describe('incoming-payment', (): void => { openApi, axiosInstance, logger - }).list({ walletAddress, accessToken }) + }).list({ url: serverAddress, walletAddress, accessToken }) expect(getSpy).toHaveBeenCalledWith( { axiosInstance, logger }, - { url, accessToken }, + { + url, + accessToken, + queryParams: { + 'wallet-address': walletAddress + } + }, true ) }) @@ -742,7 +773,7 @@ describe('incoming-payment', (): void => { const mockResponseValidator = ({ path, method }) => path === '/incoming-payments' && method === HttpMethod.POST - const url = `${walletAddress}/incoming-payments` + const url = `${serverAddress}/incoming-payments` const incomingPaymentCreateArgs = { description: 'Invoice', incomingAmount: { assetCode: 'USD', assetScale: 2, value: '10' } @@ -761,7 +792,10 @@ describe('incoming-payment', (): void => { openApi, axiosInstance, logger - }).create({ walletAddress, accessToken }, incomingPaymentCreateArgs) + }).create( + { url: serverAddress, walletAddress, accessToken }, + incomingPaymentCreateArgs + ) expect(postSpy).toHaveBeenCalledWith( { @@ -780,7 +814,7 @@ describe('incoming-payment', (): void => { path === '/incoming-payments/{id}/complete' && method === HttpMethod.POST - const incomingPaymentUrl = `${walletAddress}/incoming-payments/1` + const incomingPaymentUrl = `${serverAddress}/incoming-payments/1` jest .spyOn(openApi, 'createResponseValidator') @@ -795,14 +829,20 @@ describe('incoming-payment', (): void => { openApi, axiosInstance, logger - }).complete({ url: incomingPaymentUrl, accessToken }) + }).complete({ url: incomingPaymentUrl, accessToken, walletAddress }) expect(postSpy).toHaveBeenCalledWith( { axiosInstance, logger }, - { url: `${incomingPaymentUrl}/complete`, accessToken }, + { + url: `${incomingPaymentUrl}/complete`, + accessToken, + body: { + walletAddress + } + }, true ) }) diff --git a/packages/open-payments/src/client/incoming-payment.ts b/packages/open-payments/src/client/incoming-payment.ts index b64bcbdf..abe94c13 100644 --- a/packages/open-payments/src/client/incoming-payment.ts +++ b/packages/open-payments/src/client/incoming-payment.ts @@ -1,10 +1,9 @@ import { HttpMethod, ResponseValidator } from '@interledger/openapi' import { BaseDeps, - CollectionRequestArgs, - ResourceRequestArgs, + ResourceOrCollectionRequestArgs, RouteDeps, - UnauthenticatedResourceRequestArgs + UnauthenticatedRequestArgs } from '.' import { IncomingPayment, @@ -20,15 +19,19 @@ import { get, post } from './requests' type AnyIncomingPayment = IncomingPayment | IncomingPaymentWithPaymentMethods export interface IncomingPaymentRoutes { - get(args: ResourceRequestArgs): Promise - getPublic(args: ResourceRequestArgs): Promise + get( + args: ResourceOrCollectionRequestArgs + ): Promise + getPublic( + args: ResourceOrCollectionRequestArgs + ): Promise create( - args: CollectionRequestArgs, + args: ResourceOrCollectionRequestArgs, createArgs: CreateIncomingPaymentArgs ): Promise - complete(args: ResourceRequestArgs): Promise + complete(args: ResourceOrCollectionRequestArgs): Promise list( - args: CollectionRequestArgs, + args: ResourceOrCollectionRequestArgs, pagination?: PaginationArgs ): Promise } @@ -69,13 +72,13 @@ export const createIncomingPaymentRoutes = ( }) return { - get: (args: ResourceRequestArgs) => + get: (args: ResourceOrCollectionRequestArgs) => getIncomingPayment( { axiosInstance, logger }, args, getIncomingPaymentOpenApiValidator ), - getPublic: (args: ResourceRequestArgs) => { + getPublic: (args: ResourceOrCollectionRequestArgs) => { // eslint-disable-next-line @typescript-eslint/no-unused-vars const { accessToken, ...argsWithoutAccessToken } = args return getPublicIncomingPayment( @@ -85,7 +88,7 @@ export const createIncomingPaymentRoutes = ( ) }, create: ( - requestArgs: CollectionRequestArgs, + requestArgs: ResourceOrCollectionRequestArgs, createArgs: CreateIncomingPaymentArgs ) => createIncomingPayment( @@ -94,13 +97,16 @@ export const createIncomingPaymentRoutes = ( createIncomingPaymentOpenApiValidator, createArgs ), - complete: (args: ResourceRequestArgs) => + complete: (args: ResourceOrCollectionRequestArgs) => completeIncomingPayment( { axiosInstance, logger }, args, completeIncomingPaymentOpenApiValidator ), - list: (args: CollectionRequestArgs, pagination?: PaginationArgs) => + list: ( + args: ResourceOrCollectionRequestArgs, + pagination?: PaginationArgs + ) => listIncomingPayment( { axiosInstance, logger }, args, @@ -111,7 +117,7 @@ export const createIncomingPaymentRoutes = ( } export interface UnauthenticatedIncomingPaymentRoutes { - get(args: UnauthenticatedResourceRequestArgs): Promise + get(args: UnauthenticatedRequestArgs): Promise } export const createUnauthenticatedIncomingPaymentRoutes = ( @@ -126,7 +132,7 @@ export const createUnauthenticatedIncomingPaymentRoutes = ( }) return { - get: (args: UnauthenticatedResourceRequestArgs) => + get: (args: UnauthenticatedRequestArgs) => getPublicIncomingPayment( { axiosInstance, logger }, args, @@ -137,15 +143,20 @@ export const createUnauthenticatedIncomingPaymentRoutes = ( export const getIncomingPayment = async ( deps: BaseDeps, - args: ResourceRequestArgs, + args: ResourceOrCollectionRequestArgs, validateOpenApiResponse: ResponseValidator ) => { const { axiosInstance, logger } = deps - const { url } = args + const { url, walletAddress } = args const incomingPayment = await get( { axiosInstance, logger }, - args, + { + ...args, + queryParams: { + 'wallet-address': walletAddress + } + }, validateOpenApiResponse ) @@ -164,7 +175,7 @@ export const getIncomingPayment = async ( export const getPublicIncomingPayment = async ( deps: BaseDeps, - args: UnauthenticatedResourceRequestArgs, + args: UnauthenticatedRequestArgs, validateOpenApiResponse: ResponseValidator ) => { const { axiosInstance, logger } = deps @@ -173,13 +184,13 @@ export const getPublicIncomingPayment = async ( export const createIncomingPayment = async ( deps: BaseDeps, - requestArgs: CollectionRequestArgs, + requestArgs: ResourceOrCollectionRequestArgs, validateOpenApiResponse: ResponseValidator, createArgs: CreateIncomingPaymentArgs ) => { const { axiosInstance, logger } = deps - const { walletAddress, accessToken } = requestArgs - const url = `${walletAddress}${getRSPath('/incoming-payments')}` + const { url: baseUrl, accessToken } = requestArgs + const url = `${baseUrl}${getRSPath('/incoming-payments')}` const incomingPayment = await post( { axiosInstance, logger }, @@ -202,16 +213,16 @@ export const createIncomingPayment = async ( export const completeIncomingPayment = async ( deps: BaseDeps, - args: ResourceRequestArgs, + args: ResourceOrCollectionRequestArgs, validateOpenApiResponse: ResponseValidator ) => { const { axiosInstance, logger } = deps - const { url: incomingPaymentUrl, accessToken } = args + const { url: incomingPaymentUrl, accessToken, walletAddress } = args const url = `${incomingPaymentUrl}/complete` const incomingPayment = await post( { axiosInstance, logger }, - { url, accessToken }, + { url, accessToken, body: { walletAddress } }, validateOpenApiResponse ) @@ -230,21 +241,23 @@ export const completeIncomingPayment = async ( export const listIncomingPayment = async ( deps: BaseDeps, - args: CollectionRequestArgs, + args: ResourceOrCollectionRequestArgs, validateOpenApiResponse: ResponseValidator, pagination?: PaginationArgs ) => { const { axiosInstance, logger } = deps - const { accessToken, walletAddress } = args + const { url: baseUrl, accessToken, walletAddress } = args - const url = `${walletAddress}${getRSPath('/incoming-payments')}` + const url = `${baseUrl}${getRSPath('/incoming-payments')}` const incomingPayments = await get( { axiosInstance, logger }, { url, accessToken, - ...(pagination ? { queryParams: { ...pagination } } : {}) + ...(pagination + ? { queryParams: { ...pagination, 'wallet-address': walletAddress } } + : { queryParams: { 'wallet-address': walletAddress } }) }, validateOpenApiResponse ) diff --git a/packages/open-payments/src/client/index.ts b/packages/open-payments/src/client/index.ts index 987b9ddf..c79dfb17 100644 --- a/packages/open-payments/src/client/index.ts +++ b/packages/open-payments/src/client/index.ts @@ -39,13 +39,13 @@ export interface RouteDeps extends BaseDeps { logger: Logger } -export interface UnauthenticatedResourceRequestArgs { +export interface UnauthenticatedRequestArgs { /** * The full URL of the requested resource. * * For example, if the requested resource is an incoming payment: * ``` - * https://openpayments.guide/alice/incoming-payments/08394f02-7b7b-45e2-b645-51d04e7c330c` + * https://openpayments.guide/incoming-payments/08394f02-7b7b-45e2-b645-51d04e7c330c` * ``` */ url: string @@ -60,11 +60,14 @@ interface AuthenticatedRequestArgs { */ accessToken: string } -export interface ResourceRequestArgs - extends UnauthenticatedResourceRequestArgs, + +export interface GrantOrTokenRequestArgs + extends UnauthenticatedRequestArgs, AuthenticatedRequestArgs {} -export interface CollectionRequestArgs extends AuthenticatedRequestArgs { +export interface ResourceOrCollectionRequestArgs + extends UnauthenticatedRequestArgs, + AuthenticatedRequestArgs { /** * The wallet address URL of the requested collection. * diff --git a/packages/open-payments/src/client/outgoing-payment.test.ts b/packages/open-payments/src/client/outgoing-payment.test.ts index d3f83bd7..89dce783 100644 --- a/packages/open-payments/src/client/outgoing-payment.test.ts +++ b/packages/open-payments/src/client/outgoing-payment.test.ts @@ -38,21 +38,24 @@ describe('outgoing-payment', (): void => { const axiosInstance = defaultAxiosInstance const logger = silentLogger const walletAddress = `http://localhost:1000/.well-known/pay` + const serverAddress = 'http://localhost:1000' const openApiValidators = mockOpenApiResponseValidators() describe('getOutgoingPayment', (): void => { test('returns outgoing payment if passes validation', async (): Promise => { const outgoingPayment = mockOutgoingPayment() - const scope = nock(walletAddress) + const scope = nock(serverAddress) .get('/outgoing-payments/1') + .query({ 'wallet-address': walletAddress }) .reply(200, outgoingPayment) const result = await getOutgoingPayment( { axiosInstance, logger }, { - url: `${walletAddress}/outgoing-payments/1`, - accessToken: 'accessToken' + url: `${serverAddress}/outgoing-payments/1`, + accessToken: 'accessToken', + walletAddress }, openApiValidators.successfulValidator ) @@ -74,16 +77,18 @@ describe('outgoing-payment', (): void => { } }) - const scope = nock(walletAddress) + const scope = nock(serverAddress) .get('/outgoing-payments/1') + .query({ 'wallet-address': walletAddress }) .reply(200, outgoingPayment) await expect( getOutgoingPayment( { axiosInstance, logger }, { - url: `${walletAddress}/outgoing-payments/1`, - accessToken: 'accessToken' + url: `${serverAddress}/outgoing-payments/1`, + accessToken: 'accessToken', + walletAddress }, openApiValidators.successfulValidator ) @@ -94,16 +99,18 @@ describe('outgoing-payment', (): void => { test('throws if outgoing payment does not pass open api validation', async (): Promise => { const outgoingPayment = mockOutgoingPayment() - const scope = nock(walletAddress) + const scope = nock(serverAddress) .get('/outgoing-payments/1') + .query({ 'wallet-address': walletAddress }) .reply(200, outgoingPayment) await expect( getOutgoingPayment( { axiosInstance, logger }, { - url: `${walletAddress}/outgoing-payments/1`, - accessToken: 'accessToken' + url: `${serverAddress}/outgoing-payments/1`, + accessToken: 'accessToken', + walletAddress }, openApiValidators.failedValidator ) @@ -127,9 +134,10 @@ describe('outgoing-payment', (): void => { result: Array(first).fill(mockOutgoingPayment()) }) - const scope = nock(walletAddress) + const scope = nock(serverAddress) .get('/outgoing-payments') .query({ + 'wallet-address': walletAddress, ...(first ? { first } : {}), ...(cursor ? { cursor } : {}) }) @@ -138,11 +146,13 @@ describe('outgoing-payment', (): void => { const result = await listOutgoingPayments( { axiosInstance, logger }, { + url: serverAddress, walletAddress, accessToken: 'accessToken' }, openApiValidators.successfulValidator, { + 'wallet-address': walletAddress, first, cursor } @@ -166,9 +176,13 @@ describe('outgoing-payment', (): void => { result: Array(last).fill(mockOutgoingPayment()) }) - const scope = nock(walletAddress) + const scope = nock(serverAddress) .get('/outgoing-payments') - .query({ ...(last ? { last } : {}), cursor }) + .query({ + 'wallet-address': walletAddress, + ...(last ? { last } : {}), + cursor + }) .reply(200, outgoingPaymentPaginationResult) const result = await listOutgoingPayments( @@ -177,11 +191,13 @@ describe('outgoing-payment', (): void => { logger }, { + url: serverAddress, walletAddress, accessToken: 'accessToken' }, openApiValidators.successfulValidator, { + 'wallet-address': walletAddress, last, cursor } @@ -211,8 +227,9 @@ describe('outgoing-payment', (): void => { result: [invalidOutgoingPayment] }) - const scope = nock(walletAddress) + const scope = nock(serverAddress) .get('/outgoing-payments') + .query({ 'wallet-address': walletAddress }) .reply(200, outgoingPaymentPaginationResult) await expect( @@ -222,6 +239,7 @@ describe('outgoing-payment', (): void => { logger }, { + url: serverAddress, walletAddress, accessToken: 'accessToken' }, @@ -235,8 +253,9 @@ describe('outgoing-payment', (): void => { const outgoingPaymentPaginationResult = mockOutgoingPaymentPaginationResult() - const scope = nock(walletAddress) + const scope = nock(serverAddress) .get('/outgoing-payments') + .query({ 'wallet-address': walletAddress }) .reply(200, outgoingPaymentPaginationResult) await expect( @@ -246,6 +265,7 @@ describe('outgoing-payment', (): void => { logger }, { + url: serverAddress, walletAddress, accessToken: 'accessToken' }, @@ -257,7 +277,7 @@ describe('outgoing-payment', (): void => { }) describe('createOutgoingPayment', (): void => { - const quoteId = `${walletAddress}/quotes/${uuid()}` + const quoteId = `${serverAddress}/quotes/${uuid()}` test.each` metadata @@ -269,13 +289,14 @@ describe('outgoing-payment', (): void => { metadata }) - const scope = nock(walletAddress) + const scope = nock(serverAddress) .post('/outgoing-payments') .reply(200, outgoingPayment) const result = await createOutgoingPayment( { axiosInstance, logger }, { + url: serverAddress, walletAddress, accessToken: 'accessToken' }, @@ -303,7 +324,7 @@ describe('outgoing-payment', (): void => { } }) - const scope = nock(walletAddress) + const scope = nock(serverAddress) .post('/outgoing-payments') .reply(200, outgoingPayment) @@ -311,6 +332,7 @@ describe('outgoing-payment', (): void => { createOutgoingPayment( { axiosInstance, logger }, { + url: serverAddress, walletAddress, accessToken: 'accessToken' }, @@ -326,7 +348,7 @@ describe('outgoing-payment', (): void => { test('throws if outgoing payment does not pass open api validation', async (): Promise => { const outgoingPayment = mockOutgoingPayment() - const scope = nock(walletAddress) + const scope = nock(serverAddress) .post('/outgoing-payments') .reply(200, outgoingPayment) @@ -337,6 +359,7 @@ describe('outgoing-payment', (): void => { logger }, { + url: serverAddress, walletAddress, accessToken: 'accessToken' }, @@ -443,7 +466,7 @@ describe('outgoing-payment', (): void => { const mockResponseValidator = ({ path, method }) => path === '/outgoing-payments/{id}' && method === HttpMethod.GET - const url = `${walletAddress}/outgoing-payments/1` + const url = `${serverAddress}/outgoing-payments/1` jest .spyOn(openApi, 'createResponseValidator') @@ -458,14 +481,20 @@ describe('outgoing-payment', (): void => { openApi, axiosInstance, logger - }).get({ url, accessToken: 'accessToken' }) + }).get({ url, accessToken: 'accessToken', walletAddress }) expect(getSpy).toHaveBeenCalledWith( { axiosInstance, logger }, - { url, accessToken: 'accessToken' }, + { + url, + accessToken: 'accessToken', + queryParams: { + 'wallet-address': walletAddress + } + }, true ) }) @@ -480,7 +509,7 @@ describe('outgoing-payment', (): void => { mockOutgoingPaymentPaginationResult({ result: [mockOutgoingPayment()] }) - const url = `${walletAddress}/outgoing-payments` + const url = `${serverAddress}/outgoing-payments` jest .spyOn(openApi, 'createResponseValidator') @@ -495,14 +524,24 @@ describe('outgoing-payment', (): void => { openApi, axiosInstance, logger - }).list({ walletAddress, accessToken: 'accessToken' }) + }).list({ + url: serverAddress, + walletAddress, + accessToken: 'accessToken' + }) expect(getSpy).toHaveBeenCalledWith( { axiosInstance, logger }, - { url, accessToken: 'accessToken' }, + { + url, + accessToken: 'accessToken', + queryParams: { + 'wallet-address': walletAddress + } + }, true ) }) @@ -513,7 +552,7 @@ describe('outgoing-payment', (): void => { const mockResponseValidator = ({ path, method }) => path === '/outgoing-payments' && method === HttpMethod.POST - const url = `${walletAddress}/outgoing-payments` + const url = `${serverAddress}/outgoing-payments` const outgoingPaymentCreateArgs = { quoteId: uuid() } @@ -532,7 +571,7 @@ describe('outgoing-payment', (): void => { axiosInstance, logger }).create( - { walletAddress, accessToken: 'accessToken' }, + { url: serverAddress, walletAddress, accessToken: 'accessToken' }, outgoingPaymentCreateArgs ) diff --git a/packages/open-payments/src/client/outgoing-payment.ts b/packages/open-payments/src/client/outgoing-payment.ts index 76d1038a..93478f40 100644 --- a/packages/open-payments/src/client/outgoing-payment.ts +++ b/packages/open-payments/src/client/outgoing-payment.ts @@ -1,10 +1,5 @@ import { HttpMethod, ResponseValidator } from '@interledger/openapi' -import { - BaseDeps, - CollectionRequestArgs, - ResourceRequestArgs, - RouteDeps -} from '.' +import { BaseDeps, ResourceOrCollectionRequestArgs, RouteDeps } from '.' import { CreateOutgoingPaymentArgs, getRSPath, @@ -15,13 +10,13 @@ import { import { get, post } from './requests' export interface OutgoingPaymentRoutes { - get(args: ResourceRequestArgs): Promise + get(args: ResourceOrCollectionRequestArgs): Promise list( - args: CollectionRequestArgs, + args: ResourceOrCollectionRequestArgs, pagination?: PaginationArgs ): Promise create( - requestArgs: CollectionRequestArgs, + requestArgs: ResourceOrCollectionRequestArgs, createArgs: CreateOutgoingPaymentArgs ): Promise } @@ -50,13 +45,16 @@ export const createOutgoingPaymentRoutes = ( }) return { - get: (requestArgs: ResourceRequestArgs) => + get: (requestArgs: ResourceOrCollectionRequestArgs) => getOutgoingPayment( { axiosInstance, logger }, requestArgs, getOutgoingPaymentOpenApiValidator ), - list: (requestArgs: CollectionRequestArgs, pagination?: PaginationArgs) => + list: ( + requestArgs: ResourceOrCollectionRequestArgs, + pagination?: PaginationArgs + ) => listOutgoingPayments( { axiosInstance, logger }, requestArgs, @@ -64,7 +62,7 @@ export const createOutgoingPaymentRoutes = ( pagination ), create: ( - requestArgs: CollectionRequestArgs, + requestArgs: ResourceOrCollectionRequestArgs, createArgs: CreateOutgoingPaymentArgs ) => createOutgoingPayment( @@ -78,15 +76,21 @@ export const createOutgoingPaymentRoutes = ( export const getOutgoingPayment = async ( deps: BaseDeps, - requestArgs: ResourceRequestArgs, + requestArgs: ResourceOrCollectionRequestArgs, validateOpenApiResponse: ResponseValidator ) => { const { axiosInstance, logger } = deps - const { url, accessToken } = requestArgs + const { url, walletAddress, accessToken } = requestArgs const outgoingPayment = await get( { axiosInstance, logger }, - { url, accessToken }, + { + url, + accessToken, + queryParams: { + 'wallet-address': walletAddress + } + }, validateOpenApiResponse ) @@ -105,13 +109,13 @@ export const getOutgoingPayment = async ( export const createOutgoingPayment = async ( deps: BaseDeps, - requestArgs: CollectionRequestArgs, + requestArgs: ResourceOrCollectionRequestArgs, validateOpenApiResponse: ResponseValidator, createArgs: CreateOutgoingPaymentArgs ) => { const { axiosInstance, logger } = deps - const { walletAddress, accessToken } = requestArgs - const url = `${walletAddress}${getRSPath('/outgoing-payments')}` + const { url: baseUrl, accessToken } = requestArgs + const url = `${baseUrl}${getRSPath('/outgoing-payments')}` const outgoingPayment = await post( { axiosInstance, logger }, @@ -134,20 +138,22 @@ export const createOutgoingPayment = async ( export const listOutgoingPayments = async ( deps: BaseDeps, - requestArgs: CollectionRequestArgs, + requestArgs: ResourceOrCollectionRequestArgs, validateOpenApiResponse: ResponseValidator, pagination?: PaginationArgs ) => { const { axiosInstance, logger } = deps - const { accessToken, walletAddress } = requestArgs - const url = `${walletAddress}${getRSPath('/outgoing-payments')}` + const { url: baseUrl, accessToken, walletAddress } = requestArgs + const url = `${baseUrl}${getRSPath('/outgoing-payments')}` const outgoingPayments = await get( { axiosInstance, logger }, { url, accessToken, - ...(pagination ? { queryParams: { ...pagination } } : {}) + ...(pagination + ? { queryParams: { ...pagination, 'wallet-address': walletAddress } } + : { queryParams: { 'wallet-address': walletAddress } }) }, validateOpenApiResponse ) diff --git a/packages/open-payments/src/client/quote.ts b/packages/open-payments/src/client/quote.ts index 13f2deeb..f2439ecf 100644 --- a/packages/open-payments/src/client/quote.ts +++ b/packages/open-payments/src/client/quote.ts @@ -1,17 +1,12 @@ import { HttpMethod, ResponseValidator } from '@interledger/openapi' -import { - ResourceRequestArgs, - CollectionRequestArgs, - BaseDeps, - RouteDeps -} from '.' +import { ResourceOrCollectionRequestArgs, BaseDeps, RouteDeps } from '.' import { CreateQuoteArgs, getRSPath, Quote } from '../types' import { get, post } from './requests' export interface QuoteRoutes { - get(args: ResourceRequestArgs): Promise + get(args: ResourceOrCollectionRequestArgs): Promise create( - createArgs: CollectionRequestArgs, + createArgs: ResourceOrCollectionRequestArgs, createQuoteArgs: CreateQuoteArgs ): Promise } @@ -30,10 +25,10 @@ export const createQuoteRoutes = (deps: RouteDeps): QuoteRoutes => { }) return { - get: (args: ResourceRequestArgs) => + get: (args: ResourceOrCollectionRequestArgs) => getQuote({ axiosInstance, logger }, args, getQuoteOpenApiValidator), create: ( - createArgs: CollectionRequestArgs, + createArgs: ResourceOrCollectionRequestArgs, createQuoteArgs: CreateQuoteArgs ) => createQuote( @@ -47,7 +42,7 @@ export const createQuoteRoutes = (deps: RouteDeps): QuoteRoutes => { export const getQuote = async ( deps: BaseDeps, - args: ResourceRequestArgs, + args: ResourceOrCollectionRequestArgs, validateOpenApiResponse: ResponseValidator ) => { const { axiosInstance, logger } = deps @@ -63,7 +58,7 @@ export const getQuote = async ( export const createQuote = async ( deps: BaseDeps, - createArgs: CollectionRequestArgs, + createArgs: ResourceOrCollectionRequestArgs, validateOpenApiResponse: ResponseValidator, createQuoteArgs: CreateQuoteArgs ) => { diff --git a/packages/open-payments/src/client/token.ts b/packages/open-payments/src/client/token.ts index aafea3df..ea4a8729 100644 --- a/packages/open-payments/src/client/token.ts +++ b/packages/open-payments/src/client/token.ts @@ -1,16 +1,16 @@ import { HttpMethod, ResponseValidator } from '@interledger/openapi' -import { ResourceRequestArgs, RouteDeps } from '.' +import { GrantOrTokenRequestArgs, RouteDeps } from '.' import { getASPath, AccessToken } from '../types' import { deleteRequest, post } from './requests' export interface TokenRoutes { - rotate(args: ResourceRequestArgs): Promise - revoke(args: ResourceRequestArgs): Promise + rotate(args: GrantOrTokenRequestArgs): Promise + revoke(args: GrantOrTokenRequestArgs): Promise } export const rotateToken = async ( deps: RouteDeps, - args: ResourceRequestArgs, + args: GrantOrTokenRequestArgs, validateOpenApiResponse: ResponseValidator ) => { const { axiosInstance, logger } = deps @@ -31,7 +31,7 @@ export const rotateToken = async ( export const revokeToken = async ( deps: RouteDeps, - args: ResourceRequestArgs, + args: GrantOrTokenRequestArgs, validateOpenApiResponse: ResponseValidator ) => { const { axiosInstance, logger } = deps @@ -63,9 +63,9 @@ export const createTokenRoutes = (deps: RouteDeps): TokenRoutes => { }) return { - rotate: (args: ResourceRequestArgs) => + rotate: (args: GrantOrTokenRequestArgs) => rotateToken(deps, args, rotateTokenValidator), - revoke: (args: ResourceRequestArgs) => + revoke: (args: GrantOrTokenRequestArgs) => revokeToken(deps, args, revokeTokenValidator) } } diff --git a/packages/open-payments/src/client/wallet-address.ts b/packages/open-payments/src/client/wallet-address.ts index b1297e97..eaf60875 100644 --- a/packages/open-payments/src/client/wallet-address.ts +++ b/packages/open-payments/src/client/wallet-address.ts @@ -1,11 +1,11 @@ import { HttpMethod } from '@interledger/openapi' -import { RouteDeps, UnauthenticatedResourceRequestArgs } from '.' +import { RouteDeps, UnauthenticatedRequestArgs } from '.' import { JWKS, WalletAddress, getRSPath } from '../types' import { get } from './requests' export interface WalletAddressRoutes { - get(args: UnauthenticatedResourceRequestArgs): Promise - getKeys(args: UnauthenticatedResourceRequestArgs): Promise + get(args: UnauthenticatedRequestArgs): Promise + getKeys(args: UnauthenticatedRequestArgs): Promise } export const createWalletAddressRoutes = ( @@ -25,9 +25,9 @@ export const createWalletAddressRoutes = ( }) return { - get: (args: UnauthenticatedResourceRequestArgs) => + get: (args: UnauthenticatedRequestArgs) => get({ axiosInstance, logger }, args, getPaymentPaymentValidator), - getKeys: (args: UnauthenticatedResourceRequestArgs) => + getKeys: (args: UnauthenticatedRequestArgs) => get( { axiosInstance, logger }, { diff --git a/packages/open-payments/src/openapi/generated/auth-server-types.ts b/packages/open-payments/src/openapi/generated/auth-server-types.ts index 68c05a25..3a2e6c65 100644 --- a/packages/open-payments/src/openapi/generated/auth-server-types.ts +++ b/packages/open-payments/src/openapi/generated/auth-server-types.ts @@ -340,6 +340,12 @@ export interface external { * @description The URL of the incoming payment or ILP STREAM connection that is being paid. */ receiver: string; + /** + * Wallet Address + * Format: uri + * @description URL of a wallet address hosted by a Rafiki instance. + */ + walletAddress: string; }; }; operations: {}; diff --git a/packages/open-payments/src/openapi/generated/resource-server-types.ts b/packages/open-payments/src/openapi/generated/resource-server-types.ts index 9a2818cc..91fa50f0 100644 --- a/packages/open-payments/src/openapi/generated/resource-server-types.ts +++ b/packages/open-payments/src/openapi/generated/resource-server-types.ts @@ -62,7 +62,7 @@ export interface paths { }; query: { /** URL of a wallet address hosted by a Rafiki instance. */ - "wallet-address"?: components["parameters"]["wallet-address"]; + "wallet-address": components["parameters"]["wallet-address"]; }; }; }; @@ -90,7 +90,7 @@ export interface paths { }; query: { /** URL of a wallet address hosted by a Rafiki instance. */ - "wallet-address"?: components["parameters"]["wallet-address"]; + "wallet-address": components["parameters"]["wallet-address"]; }; }; }; @@ -361,7 +361,7 @@ export interface operations { parameters: { query: { /** URL of a wallet address hosted by a Rafiki instance. */ - "wallet-address"?: components["parameters"]["wallet-address"]; + "wallet-address": components["parameters"]["wallet-address"]; /** The cursor key to list from. */ cursor?: components["parameters"]["cursor"]; /** The number of items to return after the cursor. */ @@ -425,8 +425,7 @@ export interface operations { requestBody: { content: { "application/json": { - /** @description The URL of the wallet address that should receive the incoming payment. */ - walletAddress?: string; + walletAddress?: external["schemas.yaml"]["components"]["schemas"]["walletAddress"]; /** @description The maximum amount that should be paid into the wallet address under this incoming payment. */ incomingAmount?: external["schemas.yaml"]["components"]["schemas"]["amount"]; /** @@ -445,7 +444,7 @@ export interface operations { parameters: { query: { /** URL of a wallet address hosted by a Rafiki instance. */ - "wallet-address"?: components["parameters"]["wallet-address"]; + "wallet-address": components["parameters"]["wallet-address"]; /** The cursor key to list from. */ cursor?: components["parameters"]["cursor"]; /** The number of items to return after the cursor. */ @@ -506,8 +505,7 @@ export interface operations { requestBody: { content: { "application/json": { - /** @description The URL of the wallet address that should receive the outgoing payment. */ - walletAddress?: string; + walletAddress?: external["schemas.yaml"]["components"]["schemas"]["walletAddress"]; /** * Format: uri * @description The URL of the quote defining this payment's amounts. @@ -550,16 +548,19 @@ export interface operations { content: { "application/json": | { + walletAddress: external["schemas.yaml"]["components"]["schemas"]["walletAddress"]; receiver: external["schemas.yaml"]["components"]["schemas"]["receiver"]; method: components["schemas"]["payment-method"]; } | { + walletAddress: external["schemas.yaml"]["components"]["schemas"]["walletAddress"]; receiver: external["schemas.yaml"]["components"]["schemas"]["receiver"]; method: components["schemas"]["payment-method"]; /** @description The fixed amount that would be paid into the receiving wallet address given a successful outgoing payment. */ receiveAmount: external["schemas.yaml"]["components"]["schemas"]["amount"]; } | { + walletAddress: external["schemas.yaml"]["components"]["schemas"]["walletAddress"]; receiver: external["schemas.yaml"]["components"]["schemas"]["receiver"]; method: components["schemas"]["payment-method"]; /** @description The fixed amount that would be sent from the sending wallet address given a successful outgoing payment. */ @@ -577,7 +578,7 @@ export interface operations { }; query: { /** URL of a wallet address hosted by a Rafiki instance. */ - "wallet-address"?: components["parameters"]["wallet-address"]; + "wallet-address": components["parameters"]["wallet-address"]; }; header: { /** The Signature-Input field is a Dictionary structured field containing the metadata for one or more message signatures generated from components within the HTTP message. Each member describes a single message signature. The member's key is the label that uniquely identifies the message signature within the context of the HTTP message. The member's value is the serialization of the covered components Inner List plus all signature metadata parameters identified by the label. The following components MUST be included: - "@method" - "@target-uri" - "authorization". When the message contains a request body, the covered components MUST also include the following: - "content-digest" The keyid parameter of the signature MUST be set to the kid value of the JWK. See [ietf-httpbis-message-signatures](https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-message-signatures#section-4.1) for more details. */ @@ -635,8 +636,7 @@ export interface operations { requestBody: { content: { "application/json": { - /** @description The URL of the wallet address that should receive the incoming payment. */ - walletAddress?: string; + walletAddress?: external["schemas.yaml"]["components"]["schemas"]["walletAddress"]; }; }; }; @@ -650,7 +650,7 @@ export interface operations { }; query: { /** URL of a wallet address hosted by a Rafiki instance. */ - "wallet-address"?: components["parameters"]["wallet-address"]; + "wallet-address": components["parameters"]["wallet-address"]; }; header: { /** The Signature-Input field is a Dictionary structured field containing the metadata for one or more message signatures generated from components within the HTTP message. Each member describes a single message signature. The member's key is the label that uniquely identifies the message signature within the context of the HTTP message. The member's value is the serialization of the covered components Inner List plus all signature metadata parameters identified by the label. The following components MUST be included: - "@method" - "@target-uri" - "authorization". When the message contains a request body, the covered components MUST also include the following: - "content-digest" The keyid parameter of the signature MUST be set to the kid value of the JWK. See [ietf-httpbis-message-signatures](https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-message-signatures#section-4.1) for more details. */ @@ -732,6 +732,12 @@ export interface external { * @description The URL of the incoming payment or ILP STREAM connection that is being paid. */ receiver: string; + /** + * Wallet Address + * Format: uri + * @description URL of a wallet address hosted by a Rafiki instance. + */ + walletAddress: string; }; }; operations: {}; From e860b726ff28ffc2779813bf59f1c7d34b800974 Mon Sep 17 00:00:00 2001 From: Nathan Lie Date: Thu, 5 Oct 2023 13:40:09 -0700 Subject: [PATCH 7/8] fix: openapi package tests --- openapi/resource-server.yaml | 7 ++++--- .../src/openapi/generated/resource-server-types.ts | 4 ++-- packages/openapi/src/middleware.test.ts | 11 ++++++++--- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/openapi/resource-server.yaml b/openapi/resource-server.yaml index 2a9bcf04..8feb6a16 100644 --- a/openapi/resource-server.yaml +++ b/openapi/resource-server.yaml @@ -139,7 +139,6 @@ paths: properties: walletAddress: $ref: ./schemas.yaml#/components/schemas/walletAddress - required: true incomingAmount: $ref: ./schemas.yaml#/components/schemas/amount description: The maximum amount that should be paid into the wallet address under this incoming payment. @@ -333,6 +332,7 @@ paths: examples: Create an outgoing payment based on a quote: value: + walletAddress: 'https://ilp.rafiki.money/alice/' quoteId: 'https://ilp.rafiki.money/quotes/ab03296b-0c8b-4776-b94e-7ee27d868d4d' metadata: externalRef: INV2022-02-0137 @@ -341,7 +341,6 @@ paths: properties: walletAddress: $ref: ./schemas.yaml#/components/schemas/walletAddress - required: true quoteId: type: string format: uri @@ -352,6 +351,7 @@ paths: description: Additional metadata associated with the outgoing payment. (Optional) required: - quoteId + - walletAddress additionalProperties: false description: |- A subset of the outgoing payments schema is accepted as input to create a new outgoing payment. @@ -721,7 +721,8 @@ paths: properties: walletAddress: $ref: ./schemas.yaml#/components/schemas/walletAddress - required: true + required: + - walletAddress examples: Complete incoming payment for https://openpayments.guide/alice: value: diff --git a/packages/open-payments/src/openapi/generated/resource-server-types.ts b/packages/open-payments/src/openapi/generated/resource-server-types.ts index 91fa50f0..af6c385a 100644 --- a/packages/open-payments/src/openapi/generated/resource-server-types.ts +++ b/packages/open-payments/src/openapi/generated/resource-server-types.ts @@ -505,7 +505,7 @@ export interface operations { requestBody: { content: { "application/json": { - walletAddress?: external["schemas.yaml"]["components"]["schemas"]["walletAddress"]; + walletAddress: external["schemas.yaml"]["components"]["schemas"]["walletAddress"]; /** * Format: uri * @description The URL of the quote defining this payment's amounts. @@ -636,7 +636,7 @@ export interface operations { requestBody: { content: { "application/json": { - walletAddress?: external["schemas.yaml"]["components"]["schemas"]["walletAddress"]; + walletAddress: external["schemas.yaml"]["components"]["schemas"]["walletAddress"]; }; }; }; diff --git a/packages/openapi/src/middleware.test.ts b/packages/openapi/src/middleware.test.ts index f7482884..cefaec06 100644 --- a/packages/openapi/src/middleware.test.ts +++ b/packages/openapi/src/middleware.test.ts @@ -37,6 +37,7 @@ export function createContext( const PATH = '/incoming-payments' const SPEC = path.resolve(__dirname, '../../../openapi/resource-server.yaml') +const WALLET_ADDRESS = 'https://openpayments.guide/alice' describe('OpenAPI Validator', (): void => { let openApi: OpenAPI @@ -75,7 +76,7 @@ describe('OpenAPI Validator', (): void => { const ctx = createContext( { headers: { Accept: 'application/json' }, - url: `${PATH}?first=${first}` + url: `${PATH}?first=${first}&wallet-address=${WALLET_ADDRESS}` }, {} ) @@ -88,7 +89,7 @@ describe('OpenAPI Validator', (): void => { const ctx = createContext( { headers: { Accept: 'application/json' }, - url: `${PATH}?first=NaN` + url: `${PATH}?first=NaN&wallet-address=${WALLET_ADDRESS}` }, {} ) @@ -145,6 +146,8 @@ describe('OpenAPI Validator', (): void => { ) addTestSignatureHeaders(ctx) ctx.request.body = body + ? { ...body, walletAddress: WALLET_ADDRESS } + : body await expect(validatePostMiddleware(ctx, next)).rejects.toMatchObject({ status: 400, message @@ -161,10 +164,12 @@ describe('OpenAPI Validator', (): void => { {} ) addTestSignatureHeaders(ctx) + ctx.request.query = { 'wallet-address': WALLET_ADDRESS } const next = jest.fn().mockImplementation(() => { expect(ctx.request.query).toEqual({ first: 10, - last: 10 + last: 10, + 'wallet-address': WALLET_ADDRESS }) ctx.response.body = {} }) From 0f67aafc4900a538cde6a8a8f7c9cd4910b457e3 Mon Sep 17 00:00:00 2001 From: Nathan Lie Date: Wed, 11 Oct 2023 14:05:13 -0700 Subject: [PATCH 8/8] feat: remove query param from paths already with unique id --- openapi/resource-server.yaml | 17 ------ packages/open-payments/src/client/grant.ts | 6 +- .../src/client/incoming-payment.test.ts | 55 +++++++----------- .../src/client/incoming-payment.ts | 58 ++++++++----------- packages/open-payments/src/client/index.ts | 12 ++-- .../src/client/outgoing-payment.test.ts | 36 +++++------- .../src/client/outgoing-payment.ts | 35 ++++++----- .../open-payments/src/client/quote.test.ts | 20 +++---- packages/open-payments/src/client/quote.ts | 18 +++--- .../src/client/wallet-address.ts | 10 ++-- .../generated/resource-server-types.ts | 23 -------- packages/open-payments/src/types.ts | 1 + 12 files changed, 113 insertions(+), 178 deletions(-) diff --git a/openapi/resource-server.yaml b/openapi/resource-server.yaml index 8feb6a16..ac42d585 100644 --- a/openapi/resource-server.yaml +++ b/openapi/resource-server.yaml @@ -671,7 +671,6 @@ paths: description: A client can fetch the latest state of an incoming payment to determine the amount received into the wallet address. parameters: - $ref: '#/components/parameters/id' - - $ref: '#/components/parameters/wallet-address' '/incoming-payments/{id}/complete': post: summary: Complete an Incoming Payment @@ -712,21 +711,6 @@ paths: $ref: '#/components/responses/403' '404': description: Incoming Payment Not Found - requestBody: - content: - application/json: - schema: - type: object - additionalProperties: false - properties: - walletAddress: - $ref: ./schemas.yaml#/components/schemas/walletAddress - required: - - walletAddress - examples: - Complete incoming payment for https://openpayments.guide/alice: - value: - walletAddress: 'https://openpayments.guide/alice/' description: |- A client with the appropriate permissions MAY mark a non-expired **incoming payment** as `completed` indicating that the client is not going to make any further payments toward this **incoming payment**, even though the full `incomingAmount` may not have been received. @@ -785,7 +769,6 @@ paths: - $ref: '#/components/parameters/signature' parameters: - $ref: '#/components/parameters/id' - - $ref: '#/components/parameters/wallet-address' '/quotes/{id}': get: summary: Get a Quote diff --git a/packages/open-payments/src/client/grant.ts b/packages/open-payments/src/client/grant.ts index 83cda8d5..420f2d07 100644 --- a/packages/open-payments/src/client/grant.ts +++ b/packages/open-payments/src/client/grant.ts @@ -2,7 +2,7 @@ import { HttpMethod } from '@interledger/openapi' import { GrantOrTokenRequestArgs, RouteDeps, - UnauthenticatedRequestArgs + UnauthenticatedResourceRequestArgs } from '.' import { getASPath, @@ -19,7 +19,7 @@ export interface GrantRouteDeps extends RouteDeps { export interface GrantRoutes { request( - postArgs: UnauthenticatedRequestArgs, + postArgs: UnauthenticatedResourceRequestArgs, args: Omit ): Promise continue( @@ -47,7 +47,7 @@ export const createGrantRoutes = (deps: GrantRouteDeps): GrantRoutes => { return { request: ( - { url }: UnauthenticatedRequestArgs, + { url }: UnauthenticatedResourceRequestArgs, args: Omit ) => post( diff --git a/packages/open-payments/src/client/incoming-payment.test.ts b/packages/open-payments/src/client/incoming-payment.test.ts index 554cd19b..bcf773d2 100644 --- a/packages/open-payments/src/client/incoming-payment.test.ts +++ b/packages/open-payments/src/client/incoming-payment.test.ts @@ -56,15 +56,13 @@ describe('incoming-payment', (): void => { nock(serverAddress) .get('/incoming-payments/1') - .query({ 'wallet-address': walletAddress }) .reply(200, incomingPayment) const result = await getIncomingPayment( { axiosInstance, logger }, { url: `${serverAddress}/incoming-payments/1`, - accessToken, - walletAddress + accessToken }, openApiValidators.successfulValidator ) @@ -87,7 +85,6 @@ describe('incoming-payment', (): void => { nock(serverAddress) .get('/incoming-payments/1') - .query({ 'wallet-address': walletAddress }) .reply(200, incomingPayment) await expect( @@ -98,8 +95,7 @@ describe('incoming-payment', (): void => { }, { url: `${serverAddress}/incoming-payments/1`, - accessToken, - walletAddress + accessToken }, openApiValidators.successfulValidator ) @@ -122,8 +118,7 @@ describe('incoming-payment', (): void => { }, { url: `${serverAddress}/incoming-payments/1`, - accessToken, - walletAddress + accessToken }, openApiValidators.failedValidator ) @@ -191,9 +186,10 @@ describe('incoming-payment', (): void => { const result = await createIncomingPayment( { axiosInstance, logger }, - { url: serverAddress, walletAddress, accessToken }, + { url: serverAddress, accessToken }, openApiValidators.successfulValidator, { + walletAddress, incomingAmount, expiresAt, metadata @@ -225,9 +221,9 @@ describe('incoming-payment', (): void => { await expect( createIncomingPayment( { axiosInstance, logger }, - { url: serverAddress, walletAddress, accessToken }, + { url: serverAddress, accessToken }, openApiValidators.successfulValidator, - {} + { walletAddress } ) ).rejects.toThrowError() scope.done() @@ -243,9 +239,9 @@ describe('incoming-payment', (): void => { await expect( createIncomingPayment( { axiosInstance, logger }, - { url: serverAddress, walletAddress, accessToken }, + { url: serverAddress, accessToken }, openApiValidators.failedValidator, - {} + { walletAddress } ) ).rejects.toThrowError() scope.done() @@ -266,8 +262,7 @@ describe('incoming-payment', (): void => { { axiosInstance, logger }, { url: `${serverAddress}/incoming-payments/${incomingPayment.id}`, - accessToken, - walletAddress + accessToken }, openApiValidators.successfulValidator ) @@ -291,8 +286,7 @@ describe('incoming-payment', (): void => { { axiosInstance, logger }, { url: `${serverAddress}/incoming-payments/${incomingPayment.id}`, - accessToken, - walletAddress + accessToken }, openApiValidators.successfulValidator ) @@ -315,8 +309,7 @@ describe('incoming-payment', (): void => { { axiosInstance, logger }, { url: `${serverAddress}/incoming-payments/${incomingPayment.id}`, - accessToken, - walletAddress + accessToken }, openApiValidators.failedValidator ) @@ -670,7 +663,7 @@ describe('incoming-payment', (): void => { openApi, axiosInstance, logger - }).get({ url, accessToken, walletAddress }) + }).get({ url, accessToken }) expect(getSpy).toHaveBeenCalledWith( { @@ -679,11 +672,7 @@ describe('incoming-payment', (): void => { }, { url, - accessToken, - walletAddress, - queryParams: { - 'wallet-address': walletAddress - } + accessToken }, true ) @@ -695,7 +684,7 @@ describe('incoming-payment', (): void => { const mockResponseValidator = ({ path, method }) => path === '/incoming-payments/{id}' && method === HttpMethod.GET - const url = `${walletAddress}/incoming-payments/1` + const url = `${serverAddress}/incoming-payments/1` jest .spyOn(openApi, 'createResponseValidator') @@ -712,7 +701,7 @@ describe('incoming-payment', (): void => { openApi, axiosInstance, logger - }).getPublic({ accessToken, url }) + }).getPublic({ url }) expect(getSpy).toHaveBeenCalledWith( { @@ -775,6 +764,7 @@ describe('incoming-payment', (): void => { const url = `${serverAddress}/incoming-payments` const incomingPaymentCreateArgs = { + walletAddress, description: 'Invoice', incomingAmount: { assetCode: 'USD', assetScale: 2, value: '10' } } @@ -793,7 +783,7 @@ describe('incoming-payment', (): void => { axiosInstance, logger }).create( - { url: serverAddress, walletAddress, accessToken }, + { url: serverAddress, accessToken }, incomingPaymentCreateArgs ) @@ -829,7 +819,7 @@ describe('incoming-payment', (): void => { openApi, axiosInstance, logger - }).complete({ url: incomingPaymentUrl, accessToken, walletAddress }) + }).complete({ url: incomingPaymentUrl, accessToken }) expect(postSpy).toHaveBeenCalledWith( { @@ -838,10 +828,7 @@ describe('incoming-payment', (): void => { }, { url: `${incomingPaymentUrl}/complete`, - accessToken, - body: { - walletAddress - } + accessToken }, true ) @@ -854,7 +841,7 @@ describe('incoming-payment', (): void => { const mockResponseValidator = ({ path, method }) => path === '/incoming-payments/{id}' && method === HttpMethod.GET - const url = `${walletAddress}/incoming-payments/1` + const url = `${serverAddress}/incoming-payments/1` jest .spyOn(openApi, 'createResponseValidator') diff --git a/packages/open-payments/src/client/incoming-payment.ts b/packages/open-payments/src/client/incoming-payment.ts index abe94c13..36c847d5 100644 --- a/packages/open-payments/src/client/incoming-payment.ts +++ b/packages/open-payments/src/client/incoming-payment.ts @@ -1,9 +1,10 @@ import { HttpMethod, ResponseValidator } from '@interledger/openapi' import { BaseDeps, - ResourceOrCollectionRequestArgs, + ResourceRequestArgs, + CollectionRequestArgs, RouteDeps, - UnauthenticatedRequestArgs + UnauthenticatedResourceRequestArgs } from '.' import { IncomingPayment, @@ -19,19 +20,17 @@ import { get, post } from './requests' type AnyIncomingPayment = IncomingPayment | IncomingPaymentWithPaymentMethods export interface IncomingPaymentRoutes { - get( - args: ResourceOrCollectionRequestArgs - ): Promise + get(args: ResourceRequestArgs): Promise getPublic( - args: ResourceOrCollectionRequestArgs + args: UnauthenticatedResourceRequestArgs ): Promise create( - args: ResourceOrCollectionRequestArgs, + args: ResourceRequestArgs, createArgs: CreateIncomingPaymentArgs ): Promise - complete(args: ResourceOrCollectionRequestArgs): Promise + complete(args: ResourceRequestArgs): Promise list( - args: ResourceOrCollectionRequestArgs, + args: CollectionRequestArgs, pagination?: PaginationArgs ): Promise } @@ -72,23 +71,22 @@ export const createIncomingPaymentRoutes = ( }) return { - get: (args: ResourceOrCollectionRequestArgs) => + get: (args: ResourceRequestArgs) => getIncomingPayment( { axiosInstance, logger }, args, getIncomingPaymentOpenApiValidator ), - getPublic: (args: ResourceOrCollectionRequestArgs) => { + getPublic: (args: UnauthenticatedResourceRequestArgs) => { // eslint-disable-next-line @typescript-eslint/no-unused-vars - const { accessToken, ...argsWithoutAccessToken } = args return getPublicIncomingPayment( { axiosInstance, logger }, - argsWithoutAccessToken, + args, getPublicIncomingPaymentOpenApiValidator ) }, create: ( - requestArgs: ResourceOrCollectionRequestArgs, + requestArgs: ResourceRequestArgs, createArgs: CreateIncomingPaymentArgs ) => createIncomingPayment( @@ -97,16 +95,13 @@ export const createIncomingPaymentRoutes = ( createIncomingPaymentOpenApiValidator, createArgs ), - complete: (args: ResourceOrCollectionRequestArgs) => + complete: (args: ResourceRequestArgs) => completeIncomingPayment( { axiosInstance, logger }, args, completeIncomingPaymentOpenApiValidator ), - list: ( - args: ResourceOrCollectionRequestArgs, - pagination?: PaginationArgs - ) => + list: (args: CollectionRequestArgs, pagination?: PaginationArgs) => listIncomingPayment( { axiosInstance, logger }, args, @@ -117,7 +112,7 @@ export const createIncomingPaymentRoutes = ( } export interface UnauthenticatedIncomingPaymentRoutes { - get(args: UnauthenticatedRequestArgs): Promise + get(args: UnauthenticatedResourceRequestArgs): Promise } export const createUnauthenticatedIncomingPaymentRoutes = ( @@ -132,7 +127,7 @@ export const createUnauthenticatedIncomingPaymentRoutes = ( }) return { - get: (args: UnauthenticatedRequestArgs) => + get: (args: UnauthenticatedResourceRequestArgs) => getPublicIncomingPayment( { axiosInstance, logger }, args, @@ -143,19 +138,16 @@ export const createUnauthenticatedIncomingPaymentRoutes = ( export const getIncomingPayment = async ( deps: BaseDeps, - args: ResourceOrCollectionRequestArgs, + args: ResourceRequestArgs, validateOpenApiResponse: ResponseValidator ) => { const { axiosInstance, logger } = deps - const { url, walletAddress } = args + const { url } = args const incomingPayment = await get( { axiosInstance, logger }, { - ...args, - queryParams: { - 'wallet-address': walletAddress - } + ...args }, validateOpenApiResponse ) @@ -175,7 +167,7 @@ export const getIncomingPayment = async ( export const getPublicIncomingPayment = async ( deps: BaseDeps, - args: UnauthenticatedRequestArgs, + args: UnauthenticatedResourceRequestArgs, validateOpenApiResponse: ResponseValidator ) => { const { axiosInstance, logger } = deps @@ -184,7 +176,7 @@ export const getPublicIncomingPayment = async ( export const createIncomingPayment = async ( deps: BaseDeps, - requestArgs: ResourceOrCollectionRequestArgs, + requestArgs: ResourceRequestArgs, validateOpenApiResponse: ResponseValidator, createArgs: CreateIncomingPaymentArgs ) => { @@ -213,16 +205,16 @@ export const createIncomingPayment = async ( export const completeIncomingPayment = async ( deps: BaseDeps, - args: ResourceOrCollectionRequestArgs, + args: ResourceRequestArgs, validateOpenApiResponse: ResponseValidator ) => { const { axiosInstance, logger } = deps - const { url: incomingPaymentUrl, accessToken, walletAddress } = args + const { url: incomingPaymentUrl, accessToken } = args const url = `${incomingPaymentUrl}/complete` const incomingPayment = await post( { axiosInstance, logger }, - { url, accessToken, body: { walletAddress } }, + { url, accessToken }, validateOpenApiResponse ) @@ -241,7 +233,7 @@ export const completeIncomingPayment = async ( export const listIncomingPayment = async ( deps: BaseDeps, - args: ResourceOrCollectionRequestArgs, + args: CollectionRequestArgs, validateOpenApiResponse: ResponseValidator, pagination?: PaginationArgs ) => { diff --git a/packages/open-payments/src/client/index.ts b/packages/open-payments/src/client/index.ts index c79dfb17..a0737faf 100644 --- a/packages/open-payments/src/client/index.ts +++ b/packages/open-payments/src/client/index.ts @@ -39,7 +39,7 @@ export interface RouteDeps extends BaseDeps { logger: Logger } -export interface UnauthenticatedRequestArgs { +export interface UnauthenticatedResourceRequestArgs { /** * The full URL of the requested resource. * @@ -62,11 +62,15 @@ interface AuthenticatedRequestArgs { } export interface GrantOrTokenRequestArgs - extends UnauthenticatedRequestArgs, + extends UnauthenticatedResourceRequestArgs, AuthenticatedRequestArgs {} -export interface ResourceOrCollectionRequestArgs - extends UnauthenticatedRequestArgs, +export interface ResourceRequestArgs + extends UnauthenticatedResourceRequestArgs, + AuthenticatedRequestArgs {} + +export interface CollectionRequestArgs + extends UnauthenticatedResourceRequestArgs, AuthenticatedRequestArgs { /** * The wallet address URL of the requested collection. diff --git a/packages/open-payments/src/client/outgoing-payment.test.ts b/packages/open-payments/src/client/outgoing-payment.test.ts index 89dce783..ab195c94 100644 --- a/packages/open-payments/src/client/outgoing-payment.test.ts +++ b/packages/open-payments/src/client/outgoing-payment.test.ts @@ -47,15 +47,13 @@ describe('outgoing-payment', (): void => { const scope = nock(serverAddress) .get('/outgoing-payments/1') - .query({ 'wallet-address': walletAddress }) .reply(200, outgoingPayment) const result = await getOutgoingPayment( { axiosInstance, logger }, { url: `${serverAddress}/outgoing-payments/1`, - accessToken: 'accessToken', - walletAddress + accessToken: 'accessToken' }, openApiValidators.successfulValidator ) @@ -79,7 +77,6 @@ describe('outgoing-payment', (): void => { const scope = nock(serverAddress) .get('/outgoing-payments/1') - .query({ 'wallet-address': walletAddress }) .reply(200, outgoingPayment) await expect( @@ -87,8 +84,7 @@ describe('outgoing-payment', (): void => { { axiosInstance, logger }, { url: `${serverAddress}/outgoing-payments/1`, - accessToken: 'accessToken', - walletAddress + accessToken: 'accessToken' }, openApiValidators.successfulValidator ) @@ -101,7 +97,6 @@ describe('outgoing-payment', (): void => { const scope = nock(serverAddress) .get('/outgoing-payments/1') - .query({ 'wallet-address': walletAddress }) .reply(200, outgoingPayment) await expect( @@ -109,8 +104,7 @@ describe('outgoing-payment', (): void => { { axiosInstance, logger }, { url: `${serverAddress}/outgoing-payments/1`, - accessToken: 'accessToken', - walletAddress + accessToken: 'accessToken' }, openApiValidators.failedValidator ) @@ -297,13 +291,13 @@ describe('outgoing-payment', (): void => { { axiosInstance, logger }, { url: serverAddress, - walletAddress, accessToken: 'accessToken' }, openApiValidators.successfulValidator, { quoteId, - metadata + metadata, + walletAddress } ) expect(result).toEqual(outgoingPayment) @@ -333,12 +327,12 @@ describe('outgoing-payment', (): void => { { axiosInstance, logger }, { url: serverAddress, - walletAddress, accessToken: 'accessToken' }, openApiValidators.successfulValidator, { - quoteId: uuid() + quoteId: uuid(), + walletAddress } ) ).rejects.toThrowError() @@ -360,12 +354,12 @@ describe('outgoing-payment', (): void => { }, { url: serverAddress, - walletAddress, accessToken: 'accessToken' }, openApiValidators.failedValidator, { - quoteId: uuid() + quoteId: uuid(), + walletAddress } ) ).rejects.toThrowError() @@ -481,7 +475,7 @@ describe('outgoing-payment', (): void => { openApi, axiosInstance, logger - }).get({ url, accessToken: 'accessToken', walletAddress }) + }).get({ url, accessToken: 'accessToken' }) expect(getSpy).toHaveBeenCalledWith( { @@ -490,10 +484,7 @@ describe('outgoing-payment', (): void => { }, { url, - accessToken: 'accessToken', - queryParams: { - 'wallet-address': walletAddress - } + accessToken: 'accessToken' }, true ) @@ -554,7 +545,8 @@ describe('outgoing-payment', (): void => { const url = `${serverAddress}/outgoing-payments` const outgoingPaymentCreateArgs = { - quoteId: uuid() + quoteId: uuid(), + walletAddress } jest @@ -571,7 +563,7 @@ describe('outgoing-payment', (): void => { axiosInstance, logger }).create( - { url: serverAddress, walletAddress, accessToken: 'accessToken' }, + { url: serverAddress, accessToken: 'accessToken' }, outgoingPaymentCreateArgs ) diff --git a/packages/open-payments/src/client/outgoing-payment.ts b/packages/open-payments/src/client/outgoing-payment.ts index 93478f40..48301d4e 100644 --- a/packages/open-payments/src/client/outgoing-payment.ts +++ b/packages/open-payments/src/client/outgoing-payment.ts @@ -1,5 +1,10 @@ import { HttpMethod, ResponseValidator } from '@interledger/openapi' -import { BaseDeps, ResourceOrCollectionRequestArgs, RouteDeps } from '.' +import { + BaseDeps, + ResourceRequestArgs, + CollectionRequestArgs, + RouteDeps +} from '.' import { CreateOutgoingPaymentArgs, getRSPath, @@ -10,13 +15,13 @@ import { import { get, post } from './requests' export interface OutgoingPaymentRoutes { - get(args: ResourceOrCollectionRequestArgs): Promise + get(args: ResourceRequestArgs): Promise list( - args: ResourceOrCollectionRequestArgs, + args: CollectionRequestArgs, pagination?: PaginationArgs ): Promise create( - requestArgs: ResourceOrCollectionRequestArgs, + requestArgs: ResourceRequestArgs, createArgs: CreateOutgoingPaymentArgs ): Promise } @@ -45,16 +50,13 @@ export const createOutgoingPaymentRoutes = ( }) return { - get: (requestArgs: ResourceOrCollectionRequestArgs) => + get: (requestArgs: ResourceRequestArgs) => getOutgoingPayment( { axiosInstance, logger }, requestArgs, getOutgoingPaymentOpenApiValidator ), - list: ( - requestArgs: ResourceOrCollectionRequestArgs, - pagination?: PaginationArgs - ) => + list: (requestArgs: CollectionRequestArgs, pagination?: PaginationArgs) => listOutgoingPayments( { axiosInstance, logger }, requestArgs, @@ -62,7 +64,7 @@ export const createOutgoingPaymentRoutes = ( pagination ), create: ( - requestArgs: ResourceOrCollectionRequestArgs, + requestArgs: ResourceRequestArgs, createArgs: CreateOutgoingPaymentArgs ) => createOutgoingPayment( @@ -76,20 +78,17 @@ export const createOutgoingPaymentRoutes = ( export const getOutgoingPayment = async ( deps: BaseDeps, - requestArgs: ResourceOrCollectionRequestArgs, + requestArgs: ResourceRequestArgs, validateOpenApiResponse: ResponseValidator ) => { const { axiosInstance, logger } = deps - const { url, walletAddress, accessToken } = requestArgs + const { url, accessToken } = requestArgs const outgoingPayment = await get( { axiosInstance, logger }, { url, - accessToken, - queryParams: { - 'wallet-address': walletAddress - } + accessToken }, validateOpenApiResponse ) @@ -109,7 +108,7 @@ export const getOutgoingPayment = async ( export const createOutgoingPayment = async ( deps: BaseDeps, - requestArgs: ResourceOrCollectionRequestArgs, + requestArgs: ResourceRequestArgs, validateOpenApiResponse: ResponseValidator, createArgs: CreateOutgoingPaymentArgs ) => { @@ -138,7 +137,7 @@ export const createOutgoingPayment = async ( export const listOutgoingPayments = async ( deps: BaseDeps, - requestArgs: ResourceOrCollectionRequestArgs, + requestArgs: CollectionRequestArgs, validateOpenApiResponse: ResponseValidator, pagination?: PaginationArgs ) => { diff --git a/packages/open-payments/src/client/quote.test.ts b/packages/open-payments/src/client/quote.test.ts index 7d5421c8..10cea754 100644 --- a/packages/open-payments/src/client/quote.test.ts +++ b/packages/open-payments/src/client/quote.test.ts @@ -75,25 +75,25 @@ describe('quote', (): void => { describe('createQuote', (): void => { test('returns the quote if it passes open api validation', async (): Promise => { - const scope = nock(walletAddress).post(`/quotes`).reply(200, quote) + const scope = nock(baseUrl).post(`/quotes`).reply(200, quote) const result = await createQuote( { axiosInstance, logger }, { - walletAddress, + url: baseUrl, accessToken }, openApiValidators.successfulValidator, - { receiver: quote.receiver, method: 'ilp' } + { receiver: quote.receiver, method: 'ilp', walletAddress } ) expect(result).toStrictEqual(quote) scope.done() }) test('throws if quote does not pass open api validation', async (): Promise => { - const scope = nock(walletAddress).post(`/quotes`).reply(200, quote) + const scope = nock(baseUrl).post(`/quotes`).reply(200, quote) await expect(() => createQuote( { @@ -101,11 +101,11 @@ describe('quote', (): void => { logger }, { - walletAddress, + url: baseUrl, accessToken }, openApiValidators.failedValidator, - { receiver: quote.receiver, method: 'ilp' } + { receiver: quote.receiver, method: 'ilp', walletAddress } ) ).rejects.toThrowError() scope.done() @@ -161,7 +161,7 @@ describe('quote', (): void => { const postSpy = jest .spyOn(requestors, 'post') .mockResolvedValueOnce(quote) - const url = `${walletAddress}${getRSPath('/quotes')}` + const url = `${baseUrl}${getRSPath('/quotes')}` await createQuoteRoutes({ openApi, @@ -169,10 +169,10 @@ describe('quote', (): void => { logger }).create( { - walletAddress, + url: baseUrl, accessToken }, - { receiver: quote.receiver, method: 'ilp' } + { receiver: quote.receiver, method: 'ilp', walletAddress } ) expect(postSpy).toHaveBeenCalledWith( @@ -183,7 +183,7 @@ describe('quote', (): void => { { url, accessToken, - body: { receiver: quote.receiver, method: 'ilp' } + body: { receiver: quote.receiver, method: 'ilp', walletAddress } }, true ) diff --git a/packages/open-payments/src/client/quote.ts b/packages/open-payments/src/client/quote.ts index f2439ecf..275f9272 100644 --- a/packages/open-payments/src/client/quote.ts +++ b/packages/open-payments/src/client/quote.ts @@ -1,12 +1,12 @@ import { HttpMethod, ResponseValidator } from '@interledger/openapi' -import { ResourceOrCollectionRequestArgs, BaseDeps, RouteDeps } from '.' +import { ResourceRequestArgs, BaseDeps, RouteDeps } from '.' import { CreateQuoteArgs, getRSPath, Quote } from '../types' import { get, post } from './requests' export interface QuoteRoutes { - get(args: ResourceOrCollectionRequestArgs): Promise + get(args: ResourceRequestArgs): Promise create( - createArgs: ResourceOrCollectionRequestArgs, + createArgs: ResourceRequestArgs, createQuoteArgs: CreateQuoteArgs ): Promise } @@ -25,10 +25,10 @@ export const createQuoteRoutes = (deps: RouteDeps): QuoteRoutes => { }) return { - get: (args: ResourceOrCollectionRequestArgs) => + get: (args: ResourceRequestArgs) => getQuote({ axiosInstance, logger }, args, getQuoteOpenApiValidator), create: ( - createArgs: ResourceOrCollectionRequestArgs, + createArgs: ResourceRequestArgs, createQuoteArgs: CreateQuoteArgs ) => createQuote( @@ -42,7 +42,7 @@ export const createQuoteRoutes = (deps: RouteDeps): QuoteRoutes => { export const getQuote = async ( deps: BaseDeps, - args: ResourceOrCollectionRequestArgs, + args: ResourceRequestArgs, validateOpenApiResponse: ResponseValidator ) => { const { axiosInstance, logger } = deps @@ -58,13 +58,13 @@ export const getQuote = async ( export const createQuote = async ( deps: BaseDeps, - createArgs: ResourceOrCollectionRequestArgs, + createArgs: ResourceRequestArgs, validateOpenApiResponse: ResponseValidator, createQuoteArgs: CreateQuoteArgs ) => { const { axiosInstance, logger } = deps - const { accessToken, walletAddress } = createArgs - const url = `${walletAddress}${getRSPath('/quotes')}` + const { accessToken, url: baseUrl } = createArgs + const url = `${baseUrl}${getRSPath('/quotes')}` const quote = await post( { axiosInstance, logger }, diff --git a/packages/open-payments/src/client/wallet-address.ts b/packages/open-payments/src/client/wallet-address.ts index eaf60875..b1297e97 100644 --- a/packages/open-payments/src/client/wallet-address.ts +++ b/packages/open-payments/src/client/wallet-address.ts @@ -1,11 +1,11 @@ import { HttpMethod } from '@interledger/openapi' -import { RouteDeps, UnauthenticatedRequestArgs } from '.' +import { RouteDeps, UnauthenticatedResourceRequestArgs } from '.' import { JWKS, WalletAddress, getRSPath } from '../types' import { get } from './requests' export interface WalletAddressRoutes { - get(args: UnauthenticatedRequestArgs): Promise - getKeys(args: UnauthenticatedRequestArgs): Promise + get(args: UnauthenticatedResourceRequestArgs): Promise + getKeys(args: UnauthenticatedResourceRequestArgs): Promise } export const createWalletAddressRoutes = ( @@ -25,9 +25,9 @@ export const createWalletAddressRoutes = ( }) return { - get: (args: UnauthenticatedRequestArgs) => + get: (args: UnauthenticatedResourceRequestArgs) => get({ axiosInstance, logger }, args, getPaymentPaymentValidator), - getKeys: (args: UnauthenticatedRequestArgs) => + getKeys: (args: UnauthenticatedResourceRequestArgs) => get( { axiosInstance, logger }, { diff --git a/packages/open-payments/src/openapi/generated/resource-server-types.ts b/packages/open-payments/src/openapi/generated/resource-server-types.ts index af6c385a..7f4e2858 100644 --- a/packages/open-payments/src/openapi/generated/resource-server-types.ts +++ b/packages/open-payments/src/openapi/generated/resource-server-types.ts @@ -60,10 +60,6 @@ export interface paths { /** Sub-resource identifier */ id: components["parameters"]["id"]; }; - query: { - /** URL of a wallet address hosted by a Rafiki instance. */ - "wallet-address": components["parameters"]["wallet-address"]; - }; }; }; "/incoming-payments/{id}/complete": { @@ -88,10 +84,6 @@ export interface paths { /** Sub-resource identifier */ id: components["parameters"]["id"]; }; - query: { - /** URL of a wallet address hosted by a Rafiki instance. */ - "wallet-address": components["parameters"]["wallet-address"]; - }; }; }; "/quotes/{id}": { @@ -576,10 +568,6 @@ export interface operations { /** Sub-resource identifier */ id: components["parameters"]["id"]; }; - query: { - /** URL of a wallet address hosted by a Rafiki instance. */ - "wallet-address": components["parameters"]["wallet-address"]; - }; header: { /** The Signature-Input field is a Dictionary structured field containing the metadata for one or more message signatures generated from components within the HTTP message. Each member describes a single message signature. The member's key is the label that uniquely identifies the message signature within the context of the HTTP message. The member's value is the serialization of the covered components Inner List plus all signature metadata parameters identified by the label. The following components MUST be included: - "@method" - "@target-uri" - "authorization". When the message contains a request body, the covered components MUST also include the following: - "content-digest" The keyid parameter of the signature MUST be set to the kid value of the JWK. See [ietf-httpbis-message-signatures](https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-message-signatures#section-4.1) for more details. */ "Signature-Input"?: components["parameters"]["optional-signature-input"]; @@ -633,13 +621,6 @@ export interface operations { /** Incoming Payment Not Found */ 404: unknown; }; - requestBody: { - content: { - "application/json": { - walletAddress: external["schemas.yaml"]["components"]["schemas"]["walletAddress"]; - }; - }; - }; }; /** A client can fetch the latest state of an outgoing payment. */ "get-outgoing-payment": { @@ -648,10 +629,6 @@ export interface operations { /** Sub-resource identifier */ id: components["parameters"]["id"]; }; - query: { - /** URL of a wallet address hosted by a Rafiki instance. */ - "wallet-address": components["parameters"]["wallet-address"]; - }; header: { /** The Signature-Input field is a Dictionary structured field containing the metadata for one or more message signatures generated from components within the HTTP message. Each member describes a single message signature. The member's key is the label that uniquely identifies the message signature within the context of the HTTP message. The member's value is the serialization of the covered components Inner List plus all signature metadata parameters identified by the label. The following components MUST be included: - "@method" - "@target-uri" - "authorization". When the message contains a request body, the covered components MUST also include the following: - "content-digest" The keyid parameter of the signature MUST be set to the kid value of the JWK. See [ietf-httpbis-message-signatures](https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-message-signatures#section-4.1) for more details. */ "Signature-Input": components["parameters"]["signature-input"]; diff --git a/packages/open-payments/src/types.ts b/packages/open-payments/src/types.ts index eedadf3a..c9495b4c 100644 --- a/packages/open-payments/src/types.ts +++ b/packages/open-payments/src/types.ts @@ -51,6 +51,7 @@ export type JWK = RSComponents['schemas']['json-web-key'] export type JWKS = RSComponents['schemas']['json-web-key-set'] export type Quote = RSComponents['schemas']['quote'] type QuoteArgsBase = { + walletAddress: RSOperations['create-quote']['requestBody']['content']['application/json']['walletAddress'] receiver: RSOperations['create-quote']['requestBody']['content']['application/json']['receiver'] method: RSComponents['schemas']['payment-method'] }