Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions .eslintignore

This file was deleted.

26 changes: 0 additions & 26 deletions .eslintrc.js

This file was deleted.

17 changes: 12 additions & 5 deletions .github/workflows/cloudflare-workers.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,23 @@ jobs:

strategy:
matrix:
node-version: [18.x]
node-version: [22.x, 24.x]
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/

steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v2
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
cache: 'yarn'
- run: yarn install
- run: corepack enable
- name: Locate Yarn cache
id: yarn-cache
run: echo "dir=$(yarn config get cacheFolder)" >> "$GITHUB_OUTPUT"
- uses: actions/cache@v4
with:
path: ${{ steps.yarn-cache.outputs.dir }}
key: ${{ runner.os }}-node-${{ matrix.node-version }}-yarn-${{ hashFiles('yarn.lock') }}
- run: yarn install --immutable
- run: yarn lint
- run: yarn test-workers
13 changes: 10 additions & 3 deletions .github/workflows/node.js.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:

strategy:
matrix:
node-version: [18.x]
node-version: [22.x, 24.x]
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/

steps:
Expand All @@ -25,7 +25,14 @@ jobs:
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
cache: 'yarn'
- run: yarn install
- run: corepack enable
- name: Locate Yarn cache
id: yarn-cache
run: echo "dir=$(yarn config get cacheFolder)" >> "$GITHUB_OUTPUT"
- uses: actions/cache@v4
with:
path: ${{ steps.yarn-cache.outputs.dir }}
key: ${{ runner.os }}-node-${{ matrix.node-version }}-yarn-${{ hashFiles('yarn.lock') }}
- run: yarn install --immutable
- run: yarn lint
- run: yarn test-node
10 changes: 4 additions & 6 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,12 @@ cache:
directories:
- node_modules
node_js:
- '10'
- '12'
- '14'
- '15'
- '16'
- '22'
- '24'
sudo: false
install:
- yarn install
- corepack enable
- yarn install --immutable
script:
- yarn lint
- yarn test
13,180 changes: 481 additions & 12,699 deletions README.md

Large diffs are not rendered by default.

25 changes: 25 additions & 0 deletions eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
const js = require('@eslint/js');

module.exports = [
{ ignores: ['examples/**', '**/*.node*.js'] },
js.configs.recommended,
{
files: ['**/*.js'],
languageOptions: {
ecmaVersion: 2021,
sourceType: 'commonjs',
globals: {
console: 'readonly',
URL: 'readonly',
URLSearchParams: 'readonly',
__dirname: 'readonly',
},
},
},
{
files: ['**/*ForWorkers*.js'],
languageOptions: {
globals: { fetch: 'readonly', Response: 'readonly' },
},
},
];
23 changes: 11 additions & 12 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
{
"name": "podcast-api",
"version": "2.0.4",
"version": "3.0.0",
"description": "JavaScript bindings for the Listen Notes Podcast API",
"main": "src/PodcastApiClient.js",
"scripts": {
"clean": "rm -rf ./.nyc_output ./node_modules/.cache",
"lint": "eslint --ext .js,.jsx .",
"lint": "eslint .",
"test": "jest --config jest.config.node.json && jest --config jest.config.minifare.json",
"test-node": "jest --config jest.config.node.json",
"test-workers": "jest --config jest.config.minifare.json"
Expand All @@ -24,7 +24,7 @@
"Node.js"
],
"engines": {
"node": ">=10.*"
"node": ">=22"
},
"author": "Listen Notes, Inc. <hello@listennotes.com> (https://www.listennotes.com/)",
"license": "MIT",
Expand All @@ -33,15 +33,14 @@
},
"homepage": "https://www.listennotes.com/api/",
"dependencies": {
"axios": "^0.21.1"
"axios": "1.19.0"
},
"devDependencies": {
"eslint": "^7.25.0",
"eslint-plugin-import": "^2.22.1",
"eslint-plugin-jsx-a11y": "^6.4.1",
"jest": "^26.6.3",
"jest-environment-miniflare": "^2.10.0",
"mocha": "^8.3.2",
"prettier": "^2.2.1"
}
"@eslint/js": "10.0.1",
"eslint": "10.10.0",
"jest": "30.5.1",
"jest-environment-miniflare": "2.14.3",
"prettier": "3.9.8"
},
"packageManager": "yarn@3.3.1"
}
25 changes: 13 additions & 12 deletions src/PodcastApiClientForNode.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,25 @@ const { addApiMethodsToClient } = require('./PodcastApiMethods');

const ClientForNode = (config = {}) => {
const axios = require('axios');

axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
this.httpClient = axios.create({
const httpClient = axios.create({
baseURL: config.apiKey ? API_BASE_PROD : API_BASE_TEST,
timeout: 30000,
headers: {
'X-ListenAPI-Key': config.apiKey || '',
'User-Agent': config.userAgent || defaultUserAgent,
},
// Use the same standard encoding as the Workers transport.
paramsSerializer: (params) => new URLSearchParams(params).toString(),
});

this.httpClient._get = (path, params) => this.httpClient.get(path, { params });
this.httpClient._post = (path, params) => this.httpClient.post(path, new URLSearchParams(params).toString());
this.httpClient._delete = (path) => this.httpClient.delete(path);

return addApiMethodsToClient(this);
const formConfig = (params) => ({
params,
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
});
httpClient._get = (path, params) => httpClient.get(path, { params });
httpClient._post = (path, params, query) => httpClient.post(path, new URLSearchParams(params).toString(), formConfig(query));
httpClient._put = (path, params, query) => httpClient.put(path, new URLSearchParams(params).toString(), formConfig(query));
httpClient._delete = (path, params) => httpClient.delete(path, { params });
return addApiMethodsToClient({ httpClient });
};

module.exports = {
ClientForNode,
};
module.exports = { ClientForNode };
98 changes: 27 additions & 71 deletions src/PodcastApiClientForWorkers.js
Original file line number Diff line number Diff line change
@@ -1,85 +1,41 @@
const {API_BASE_PROD, API_BASE_TEST, defaultUserAgent} = require('./Constants');
const {addApiMethodsToClient} = require('./PodcastApiMethods');
const { API_BASE_PROD, API_BASE_TEST, defaultUserAgent } = require('./Constants');
const { addApiMethodsToClient } = require('./PodcastApiMethods');

const _fetch = (path, config, method = 'GET', queryParams = {}, formParams = null) => {
const _fetch = async (path, config, method, queryParams = {}, formParams = null) => {
let url = `${config.apiKey ? API_BASE_PROD : API_BASE_TEST}${path}`;
const headers = {
'X-ListenAPI-Key': config.apiKey || '',
'User-Agent': config.userAgent || defaultUserAgent,
};
const fetchConfig = {
method,
headers,
};
let formParamsString = null;
if (formParams) {
fetchConfig.body = formParams;
formParamsString = [...formParams.entries()].map(
x => `${encodeURIComponent(x[0])}=${encodeURIComponent(x[1])}`).join('&');
const query = new URLSearchParams(queryParams).toString();
if (query) url += `?${query}`;
const body = formParams === null ? null : new URLSearchParams(formParams).toString();
const fetchConfig = { method, headers };
if (body !== null) {
fetchConfig.body = body;
headers['Content-Type'] = 'application/x-www-form-urlencoded';
}
if (queryParams) {
url = `${url}?${new URLSearchParams(queryParams).toString()}`
const responseConfig = { params: queryParams, data: body, url: path, method: method.toLowerCase() };
const response = await fetch(url, fetchConfig);
const responseHeaders = Object.fromEntries(response.headers.entries());
if (!response.ok) {
const error = new Error(`HTTP ${response.status}`);
error.response = { status: response.status, config: responseConfig, headers: responseHeaders };
throw error;
}
const responseConfig = {
params: queryParams,
data: formParamsString,
url: path,
method: method.toLowerCase(),
};
const responseHeaders = {};
return fetch(url, fetchConfig).then((response) => {
if (response.headers) {
for (const pair of response.headers.entries()) {
responseHeaders[pair[0]] = pair[1];
}
}

if (response.ok) {
return response;
} else {
const err = new Error(`HTTP ${response.status}`);
err.response = {
status: response.status,
config: responseConfig,
headers: responseHeaders,
};
throw err;
}
}).then((response) => {
return response.json();
}).then((data) => {
return {
config: responseConfig,
headers: responseHeaders,
data,
}
});
return { config: responseConfig, headers: responseHeaders, data: await response.json() };
};

const ClientForWorkers = (config = {}) => {
this.httpClient = {
_get: (path, params) => {
return _fetch(path, config, 'GET', params);
},

_post: (path, params) => {
let formData = null;
if (params && Object.keys(params).length > 0) {
formData = new FormData();
Object.keys(params).forEach(function (key) {
formData.append(key, params[key]);
});
}
return _fetch(path, config, 'POST', {}, formData)
},

_delete: (path) => {
return _fetch(path, config, 'DELETE')
},
// Snapshot configuration so later clients or caller mutations cannot change it.
const settings = { ...config };
const httpClient = {
_get: (path, params) => _fetch(path, settings, 'GET', params),
_post: (path, params, query) => _fetch(path, settings, 'POST', query, params),
_put: (path, params, query) => _fetch(path, settings, 'PUT', query, params),
_delete: (path, params) => _fetch(path, settings, 'DELETE', params),
};
return addApiMethodsToClient(this);
return addApiMethodsToClient({ httpClient });
};

module.exports = {
ClientForWorkers,
};
module.exports = { ClientForWorkers };
Loading
Loading