Skip to content

Commit

Permalink
feat: update aio-lib-networking library (#34)
Browse files Browse the repository at this point in the history
---------

Co-authored-by: Nicola Dardanis <[email protected]>
Co-authored-by: Shazron Abdullah <[email protected]>
  • Loading branch information
3 people authored Aug 15, 2023
1 parent f999796 commit bfb5e17
Show file tree
Hide file tree
Showing 7 changed files with 50 additions and 72 deletions.
39 changes: 10 additions & 29 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<!--
Copyright 2020 Adobe. All rights reserved.
Copyright 2019 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Expand All @@ -13,14 +13,11 @@ governing permissions and limitations under the License.
[![Version](https://img.shields.io/npm/v/@adobe/aio-lib-events.svg)](https://npmjs.org/package/@adobe/aio-lib-events)
[![Downloads/week](https://img.shields.io/npm/dw/@adobe/aio-lib-events.svg)](https://npmjs.org/package/@adobe/aio-lib-events)
[![Build Status](https://travis-ci.com/adobe/aio-lib-events.svg?branch=master)](https://travis-ci.com/adobe/aio-lib-events)
[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
[![Greenkeeper badge](https://badges.greenkeeper.io/adobe/aio-lib-events.svg)](https://greenkeeper.io/)
[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) [![Greenkeeper badge](https://badges.greenkeeper.io/adobe/aio-lib-events.svg)](https://greenkeeper.io/)
[![Codecov Coverage](https://img.shields.io/codecov/c/github/adobe/aio-lib-events/master.svg?style=flat-square)](https://codecov.io/gh/adobe/aio-lib-events/)

# Adobe I/O Events Lib

Node Javascript API wrapping the [Adobe I/O Events API](https://www.adobe.io/apis/experienceplatform/events.html).

### Installing

```bash
Expand Down Expand Up @@ -50,7 +47,7 @@ async function sdkTest() {

// call methods
try {
// use one of the get methods
// get profiles by custom filters
const result = await client.getSomething({})
console.log(result)

Expand Down Expand Up @@ -129,8 +126,6 @@ and max number of retries</p>
<dd></dd>
<dt><a href="#EventsJournalPollingOptions">EventsJournalPollingOptions</a> : <code>object</code></dt>
<dd></dd>
<dt><a href="#SignatureOptions">SignatureOptions</a> : <code>object</code></dt>
<dd></dd>
</dl>

<a name="EventsCoreAPI"></a>
Expand Down Expand Up @@ -170,7 +165,7 @@ and max number of retries
* [.publishEvent(cloudEvent)](#EventsCoreAPI+publishEvent) ⇒ <code>Promise.&lt;string&gt;</code>
* [.getEventsFromJournal(journalUrl, [eventsJournalOptions], [fetchResponseHeaders])](#EventsCoreAPI+getEventsFromJournal) ⇒ <code>Promise.&lt;object&gt;</code>
* [.getEventsObservableFromJournal(journalUrl, [eventsJournalOptions], [eventsJournalPollingOptions])](#EventsCoreAPI+getEventsObservableFromJournal) ⇒ <code>Observable</code>
* [.verifyDigitalSignatureForEvent(event, recipientClientId, [signatureOptions])](#EventsCoreAPI+verifyDigitalSignatureForEvent) ⇒ <code>boolean</code>
* [.verifyDigitalSignatureForEvent(event, recipientClientId, signatureOptions)](#EventsCoreAPI+verifyDigitalSignatureForEvent) ⇒ <code>boolean</code>

<a name="EventsCoreAPI+httpOptions"></a>

Expand Down Expand Up @@ -514,18 +509,17 @@ and leverage the various <a href="https://rxjs-dev.firebaseapp.com/guide/operato

<a name="EventsCoreAPI+verifyDigitalSignatureForEvent"></a>

### eventsCoreAPI.verifyDigitalSignatureForEvent(event, recipientClientId, [signatureOptions]) ⇒ <code>boolean</code>
### eventsCoreAPI.verifyDigitalSignatureForEvent(event, recipientClientId, signatureOptions) ⇒ <code>boolean</code>
Authenticating events by verifying digital signature

**Kind**: instance method of [<code>EventsCoreAPI</code>](#EventsCoreAPI)
**Returns**: <code>boolean</code> - If signature matches return true else return false

| Param | Type | Description |
| --- | --- | --- |
| event | <code>object</code> | JSON payload delivered to the registered webhook URL |
| recipientClientId | <code>string</code> | Target recipient client id retrieved from the Adobe I/O Console integration |
| [signatureOptions] | [<code>SignatureOptions</code>](#SignatureOptions) | Map of digital signature header fields defined in SignatureOptions |

| event | <code>\*</code> | JSON payload delivered to the registered webhook URL |
| recipientClientId | <code>\*</code> | Target recipient client id retrieved from the Adobe I/O Console integration |
| signatureOptions | <code>\*</code> | map of all digital signature header values consisting fields as below digiSignature1 : Value of digital signature retrieved from the x-adobe-digital-signature1 header in each POST request to webhook digiSignature2 : Value of digital signature retrieved from the x-adobe-digital-signature2 header in each POST request to webhook publicKeyPath1 : Relative path of ioevents public key retrieved from the x-adobe-public-key1-path header in each POST request to webhook publicKeyPath2 : Relative path of ioevents public key retrieved from the x-adobe-public-key2-path header in each POST request to webhook |

<a name="init"></a>

Expand Down Expand Up @@ -627,7 +621,7 @@ Returns a Promise that resolves with a new EventsCoreAPI object.
| description | <code>string</code> | The description of the registration |
| [webhook_url] | <code>string</code> | A valid webhook url where the events would be delivered for webhook or webhook_batch delivery_type |
| events_of_interest | [<code>Array.&lt;EventsOfInterest&gt;</code>](#EventsOfInterest) | The events for which the registration is to be subscribed to |
| delivery_type | <code>string</code> | Delivery type can either be webhook, webhook_batch or journal. |
| delivery_type | <code>string</code> | Delivery type can either be webhook|webhook_batch|journal. |
| [enabled] | <code>string</code> | Enable or disable the registration. Default true. |

<a name="RegistrationUpdateModel"></a>
Expand All @@ -642,7 +636,7 @@ Returns a Promise that resolves with a new EventsCoreAPI object.
| description | <code>string</code> | The description of the registration |
| [webhook_url] | <code>string</code> | A valid webhook url where the events would be delivered for webhook or webhook_batch delivery_type |
| events_of_interest | [<code>Array.&lt;EventsOfInterest&gt;</code>](#EventsOfInterest) | The events for which the registration is to be subscribed to |
| delivery_type | <code>string</code> | Delivery type can either be webhook, webhook_batch or journal. |
| delivery_type | <code>string</code> | Delivery type can either be webhook|webhook_batch|journal. |
| [enabled] | <code>string</code> | Enable or disable the registration. Default true. |

<a name="Page"></a>
Expand Down Expand Up @@ -678,19 +672,6 @@ Returns a Promise that resolves with a new EventsCoreAPI object.
| --- | --- | --- |
| [interval] | <code>number</code> | Interval at which to poll the journal; If not provided, a default value will be used (optional) |

<a name="SignatureOptions"></a>

## SignatureOptions : <code>object</code>
**Kind**: global typedef
**Properties**

| Name | Type | Description |
| --- | --- | --- |
| [digiSignature1] | <code>string</code> | Value of digital signature retrieved from the x-adobe-digital-signature1 header |
| [digiSignature2] | <code>string</code> | Value of digital signature retrieved from the x-adobe-digital-signature2 header |
| [publicKeyPath1] | <code>string</code> | Relative path of ioevents public key retrieved from the x-adobe-public-key1-path header |
| [publicKeyPath2] | <code>string</code> | Relative path of ioevents public key retrieved from the x-adobe-public-key2-path header |

### Debug Logs

```bash
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"dependencies": {
"@adobe/aio-lib-core-errors": "^3.1.1",
"@adobe/aio-lib-core-logging": "^2.0.0",
"@adobe/aio-lib-core-networking": "^3.0.0",
"@adobe/aio-lib-core-networking": "^4.1.0",
"@adobe/aio-lib-state": "^2.0.1",
"crypto-js": "^4.0.0",
"http-link-header": "^1.0.2",
Expand Down
16 changes: 0 additions & 16 deletions src/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,21 +64,6 @@ function parseLinkHeader (base, header) {
return result
}

/**
* Parse the Retry-After header
* Spec: {@link https://tools.ietf.org/html/rfc7231#section-7.1.3}
*
* @param {string} header Retry-After header value
* @returns {number} Number of milliseconds to sleep until the next call to getEventsFromJournal
*/
function parseRetryAfterHeader (header) {
if (header.match(/^[0-9]+$/)) {
return parseInt(header, 10) * 1000
} else {
return Date.parse(header) - Date.now()
}
}

/**
* Wrapper to check the event received by webhook
* and return decoded (if encoded) payload
Expand Down Expand Up @@ -128,7 +113,6 @@ const exportFunctions = {
reduceError,
appendQueryParams,
parseLinkHeader,
parseRetryAfterHeader,
getProperPayload,
genErrorResponse
}
Expand Down
4 changes: 2 additions & 2 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ const loggerNamespace = '@adobe/aio-lib-events'
const logger = require('@adobe/aio-lib-core-logging')(loggerNamespace,
{ level: process.env.LOG_LEVEL })
const { codes } = require('./SDKErrors')
const { HttpExponentialBackoff } = require('@adobe/aio-lib-core-networking')
const { HttpExponentialBackoff, parseRetryAfterHeader } = require('@adobe/aio-lib-core-networking')
const fetchRetryClient = new HttpExponentialBackoff()

const EventsConsumerFromJournal = require('./journalling')
Expand Down Expand Up @@ -561,7 +561,7 @@ class EventsCoreAPI {
result.link = helpers.parseLinkHeader(journalUrl, linkHeader)
}
if (retryAfterHeader) {
result.retryAfter = helpers.parseRetryAfterHeader(retryAfterHeader)
result.retryAfter = parseRetryAfterHeader(retryAfterHeader) || undefined
}
if (fetchResponseHeaders) {
result.responseHeaders = response.headers.raw()
Expand Down
17 changes: 14 additions & 3 deletions test/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,13 @@ const mockHttpExponentialBackoff = jest.fn(() => ({
exponentialBackoff: mockExponentialBackoff
}))

jest.mock('@adobe/aio-lib-core-networking', () => ({
HttpExponentialBackoff: mockHttpExponentialBackoff
}))
jest.mock('@adobe/aio-lib-core-networking', () => {
const originalModule = jest.requireActual('@adobe/aio-lib-core-networking')
return {
...originalModule,
HttpExponentialBackoff: mockHttpExponentialBackoff
}
})

const sdk = require('../src')
const mock = require('./mock')
Expand Down Expand Up @@ -637,6 +641,13 @@ describe('Fetch from journalling', () => {
expect(res2.link.next).toBe('http://journal-url/events-fast/organizations/orgId/integrations/integId/regId?since=position-1')
expect(res2.retryAfter).toBe(10000)
})
it('204 response on fetch from journal with invalid retry after', async () => {
const sdkClient = await createSdkClient()
exponentialBackoffMockReturnValue(undefined, mock.data.journalResponseHeader204InvalidTime)
const res2 = await sdkClient.getEventsFromJournal(journalUrl)
expect(res2.link.next).toBe('http://journal-url/events-fast/organizations/orgId/integrations/integId/regId?since=position-1')
expect(res2.retryAfter).toBe(undefined)
})
it('204 response on fetch from journal with retry after as date time string', async () => {
const sdkClient = await createSdkClient()
const realDateNow = Date.now.bind(global.Date)
Expand Down
17 changes: 17 additions & 0 deletions test/mock.js
Original file line number Diff line number Diff line change
Expand Up @@ -750,6 +750,22 @@ const journalResponseHeader204 = {
}
}

const journalResponseHeader204InvalidTime = {
status: 204,
headers: {
link: [
'</events/organizations/orgId/integrations/integId/regId>; rel="events"',
'</events-fast/organizations/orgId/integrations/integId/regId?since=position-1>; rel="next"',
'</count/organizations/orgId/integrations/integId/regId?since=position-1>; rel="count"',
'</events/organizations/orgId/integrations/integId/regId?latest=true>; rel="latest"',
'</events/organizations/orgId/integrations/integId/regId?since={position}&limit={count}>; rel="page"',
'</events/organizations/orgId/integrations/integId/regId?seek={duration}&limit={count}>; rel="seek"',
'</events-validate/organizations/orgId/integrations/integId/regId?since=position-1>; rel="validate"'
],
'retry-after': 'not::a::valid::date'
}
}

const journalResponseHeader204MissingLinks = {
status: 204,
headers: {
Expand Down Expand Up @@ -903,6 +919,7 @@ const data = {
journalResponseHeader204,
journalResponseHeader204MissingLinks,
journalResponseHeader204DateTime,
journalResponseHeader204InvalidTime,
journalPollerResponse,
journalPollerNoContentResponse,
journalPollerNoContentMissingRetryAfter,
Expand Down
27 changes: 6 additions & 21 deletions types.d.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import {Observable} from "rxjs";

/**
* @property [timeout] - Http request timeout in ms (optional)
* @property [retries] - Number of retries in case of 5xx errors. Default 0 (optional)
Expand Down Expand Up @@ -42,19 +40,19 @@ declare class EventsCoreAPI {
/**
* Http options {retries, timeout}
*/
httpOptions: EventsCoreAPIOptions;
httpOptions: any;
/**
* The organization id from your integration
*/
organizationId: string;
organizationId: any;
/**
* The api key from your integration
*/
apiKey: string;
apiKey: any;
/**
* The JWT Token for the integration with IO Management API scope
*/
accessToken: string;
accessToken: any;
/**
* Fetch all the providers
* @param consumerOrgId - Consumer Org Id from the console
Expand Down Expand Up @@ -234,7 +232,7 @@ declare class EventsCoreAPI {
* @param [eventsJournalPollingOptions] - Journal polling options
* @returns observable to which the user can subscribe to in order to listen to events
*/
getEventsObservableFromJournal(journalUrl: string, eventsJournalOptions?: EventsJournalOptions, eventsJournalPollingOptions?: EventsJournalPollingOptions): Observable<object>;
getEventsObservableFromJournal(journalUrl: string, eventsJournalOptions?: EventsJournalOptions, eventsJournalPollingOptions?: EventsJournalPollingOptions): Observable;
/**
* Authenticating events by verifying digital signature
* @param event - JSON payload delivered to the registered webhook URL
Expand All @@ -246,7 +244,7 @@ declare class EventsCoreAPI {
* publicKeyPath2 : Relative path of ioevents public key retrieved from the x-adobe-public-key2-path header in each POST request to webhook
* @returns If signature matches return true else return false
*/
verifyDigitalSignatureForEvent(event: any, recipientClientId: string, signatureOptions?: SignatureOptions): boolean;
verifyDigitalSignatureForEvent(event: any, recipientClientId: any, signatureOptions: any): boolean;
}

/**
Expand Down Expand Up @@ -365,16 +363,3 @@ declare type EventsJournalPollingOptions = {
interval?: number;
};

/**
* @typedef {object} SignatureOptions
* @property [digiSignature1] - Value of digital signature retrieved from the x-adobe-digital-signature1 header in each POST request to webhook
* @property [digiSignature2] - Value of digital signature retrieved from the x-adobe-digital-signature2 header in each POST request to webhook
* @property [publicKeyUrl1] - Value of public key url retrieved from the x-adobe-public-key1-url header in each POST request to webhook
* @property [publicKeyUrl2] - Value of public key url retrieved from the x-adobe-public-key2-url header in each POST request to webhook
*/
declare type SignatureOptions = {
digiSignature1: string;
digiSignature2: string;
publicKeyUrl1: string;
publicKeyUrl2: string;
};

0 comments on commit bfb5e17

Please sign in to comment.