diff --git a/package.json b/package.json index 2acec7a0..f505100f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@duffel/api", - "version": "3.3.0", + "version": "4.0.0", "description": "Javascript client library for the Duffel API", "main": "dist/index.js", "module": "dist/index.es.js", diff --git a/src/Vault/Cards/Cards.spec.ts b/src/Payments/Cards/Cards.spec.ts similarity index 78% rename from src/Vault/Cards/Cards.spec.ts rename to src/Payments/Cards/Cards.spec.ts index e5318801..e42dd9e6 100644 --- a/src/Vault/Cards/Cards.spec.ts +++ b/src/Payments/Cards/Cards.spec.ts @@ -10,8 +10,8 @@ describe('Cards', () => { it('should create a card record when `create` is called', async () => { const MOCK_ID = 'tcd_00009hthhsUZ8W4LxQgkjb' nock(/(.*)/) - .post('/vault/cards') - .reply(200, { data: { id: MOCK_ID, liveMode: false } }) + .post('/payments/cards') + .reply(200, { data: { id: MOCK_ID, liveMode: false, unavailableAt: '2024-01-01T00:00:00', brand: 'visa', multiUse: false, last4Digits: '4242' } }) const response = await duffel.cards.create({ address_city: 'London', @@ -25,6 +25,7 @@ describe('Cards', () => { name: 'Neil Armstrong', number: '4242424242424242', cvc: '123', + multi_use: false, }) expect(response.data.id).toBe(MOCK_ID) }) diff --git a/src/Vault/Cards/Cards.ts b/src/Payments/Cards/Cards.ts similarity index 87% rename from src/Vault/Cards/Cards.ts rename to src/Payments/Cards/Cards.ts index 07f02b5a..5c231a8a 100644 --- a/src/Vault/Cards/Cards.ts +++ b/src/Payments/Cards/Cards.ts @@ -56,11 +56,19 @@ interface CardParameters { * The card verification code */ cvc: string + /** + * Set to true to indicate that this card can be used multiple times + */ + multi_use: boolean } interface CardRecord { id: string live_mode: boolean + multi_use: boolean + unavailble_at: string + brand: string + last_4_digits: string } export class Cards extends Resource { @@ -72,7 +80,7 @@ export class Cards extends Resource { // basePath must be 'https://api.duffel.cards' constructor(client: Client) { super(client) - this.path = 'vault/cards' + this.path = 'payments/cards' } /** diff --git a/src/Vault/Cards/index.ts b/src/Payments/Cards/index.ts similarity index 100% rename from src/Vault/Cards/index.ts rename to src/Payments/Cards/index.ts diff --git a/src/Payments/ThreeDSecureSessions/ThreeDSecureSessions.spec.ts b/src/Payments/ThreeDSecureSessions/ThreeDSecureSessions.spec.ts new file mode 100644 index 00000000..09451037 --- /dev/null +++ b/src/Payments/ThreeDSecureSessions/ThreeDSecureSessions.spec.ts @@ -0,0 +1,24 @@ +import nock from 'nock' +import { Duffel } from '../../index' + +const duffel = new Duffel({ token: 'mockToken' }) +describe('ThreeDSecureSessions', () => { + afterEach(() => { + nock.cleanAll() + }) + + it('should create a 3DS session record when `create` is called', async () => { + const MOCK_ID = '3ds_00009hthhsUZ8W4LxQgkjb' + nock(/(.*)/) + .post('/payments/three_d_secure_sessions') + .reply(200, { data: { id: MOCK_ID, liveMode: false, expiresAt: '2024-01-01T00:00:00', status: 'ready_for_payment', resourceId: 'off_00009hthhsUZ8W4LxQgkjb', clientId: 'tds_57aa862f8bf7', cardID: 'tcd_00009hthhsUZ8W4LxQgkjb'} }) + + const response = await duffel.cards.create({ + resource_id: 'off_00009hthhsUZ8W4LxQgkjb', + card_id: 'tcd_00009hthhsUZ8W4LxQgkjb' + services: [{quantity: 1, id: 'ser_00009UhD4ongolulWd9123'}], + exception: null, + }) + expect(response.data.id).toBe(MOCK_ID) + }) +}) diff --git a/src/Payments/ThreeDSecureSessions/ThreeDSecureSessions.ts b/src/Payments/ThreeDSecureSessions/ThreeDSecureSessions.ts new file mode 100644 index 00000000..d3cc5243 --- /dev/null +++ b/src/Payments/ThreeDSecureSessions/ThreeDSecureSessions.ts @@ -0,0 +1,66 @@ +import { Client } from '../../Client' +import { Resource } from '../../Resource' +import { DuffelResponse } from '../../types' + +interface Service { + /** + * The quantity of the service ID to pay for + */ + quantity: number + /** + * The ID of the service to pay for + */ + id: string +} + +interface ThreeDSecureSessionParameters { + /** + * The offer ID, order ID, order change ID or quote ID intended to pay + */ + resource_id: string + + /** + * The services inteded to pay + */ + services: Service[] + + /** + * The card ID + */ + card_id: string + + /** + * The exception name for the 3DS session + */ + exception: string +} + +interface ThreeDSecureSessionRecord { + id: string + resource_id: string + card_id: string + live_mode: boolean + expires_at: string + status: string + client_id: string +} + +export class ThreeDSecureSession extends Resource { + /** + * Endpoint path + */ + path: string + + constructor(args: any) { + super(args) + this.path = 'payments/three_d_secure_sessions' + } + + /** + * Create a Duffel ThreeDSecureSession record + */ + public create = async ( + data: ThreeDSecureSessionParameters, + ): Promise> => + this.request({ method: 'POST', path: this.path, data }) +} diff --git a/src/Payments/ThreeDSecureSessions/index.ts b/src/Payments/ThreeDSecureSessions/index.ts new file mode 100644 index 00000000..28ba9018 --- /dev/null +++ b/src/Payments/ThreeDSecureSessions/index.ts @@ -0,0 +1 @@ +export * from './ThreeDSecureSessions' diff --git a/src/Payments/index.ts b/src/Payments/index.ts new file mode 100644 index 00000000..59c836e0 --- /dev/null +++ b/src/Payments/index.ts @@ -0,0 +1,2 @@ +export * from './Cards' +export * from './ThreeDSecureSessions' diff --git a/src/Vault/index.ts b/src/Vault/index.ts deleted file mode 100644 index 90016471..00000000 --- a/src/Vault/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './Cards' diff --git a/src/index.ts b/src/index.ts index 85859804..41bbab31 100644 --- a/src/index.ts +++ b/src/index.ts @@ -19,7 +19,8 @@ import { Refunds } from './DuffelPayments/Refunds' import { Sessions } from './Links' import { Webhooks } from './notifications' import { Stays } from './Stays/Stays' -import { Cards } from './Vault/Cards' +import { Cards } from './Payments/Cards' +import { ThreeDSecureSessions } from './Payments/ThreeDSecureSessions' export interface DuffelAPIClient { aircraft: Aircraft @@ -34,6 +35,7 @@ export interface DuffelAPIClient { orderCancellations: OrderCancellations payments: Payments seatMaps: SeatMaps + threeDSecureSessions: ThreeDSecureSessions } export class Duffel { @@ -58,6 +60,7 @@ export class Duffel { public refunds: Refunds public webhooks: Webhooks public stays: Stays + public three_d_secure_sessions: ThreeDSecureSessions private cardsClient: Client public cards: Cards @@ -85,6 +88,7 @@ export class Duffel { this.refunds = new Refunds(this.client) this.webhooks = new Webhooks(this.client) this.stays = new Stays(this.client) + this.three_d_secure_sessions = new ThreeDSecureSessions(this.client) this.cardsClient = new Client({ ...config,