Skip to content

Commit

Permalink
feat(api): OpenAPI spec update (#6)
Browse files Browse the repository at this point in the history
  • Loading branch information
stainless-app[bot] authored Feb 2, 2024
1 parent 373257c commit 60f9ce3
Show file tree
Hide file tree
Showing 28 changed files with 2,705 additions and 834 deletions.
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

This library provides convenient access to the Metronome REST API from server-side TypeScript or JavaScript.

The API documentation can be found [here](https://docs.metronome.com).
The REST API documentation can be found [on docs.metronome.com](https://docs.metronome.com). The full API of this library can be found in [api.md](api.md).

## Installation

Expand All @@ -16,7 +16,7 @@ yarn add @metronome-industries/metronome

## Usage

The full API of this library can be found in [api.md](https://www.github.com/Metronome-Industries/metronome-node/blob/main/api.md).
The full API of this library can be found in [api.md](api.md).

<!-- prettier-ignore -->
```js
Expand Down Expand Up @@ -211,8 +211,8 @@ import { fetch } from 'undici'; // as one example
import Metronome from '@metronome-industries/metronome';

const client = new Metronome({
fetch: (url: RequestInfo, init?: RequestInfo): Response => {
console.log('About to make request', url, init);
fetch: async (url: RequestInfo, init?: RequestInfo): Promise<Response> => {
console.log('About to make a request', url, init);
const response = await fetch(url, init);
console.log('Got response', response);
return response;
Expand Down
37 changes: 20 additions & 17 deletions api.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,12 @@ Types:

- <code><a href="./src/resources/customer-alerts.ts">CustomerAlert</a></code>
- <code><a href="./src/resources/customer-alerts.ts">CustomerAlertRetrieveResponse</a></code>
- <code><a href="./src/resources/customer-alerts.ts">CustomerAlertListResponse</a></code>

Methods:

- <code title="post /customer-alerts/get">client.customerAlerts.<a href="./src/resources/customer-alerts.ts">retrieve</a>({ ...params }) -> CustomerAlertRetrieveResponse</code>
- <code title="post /customer-alerts/list">client.customerAlerts.<a href="./src/resources/customer-alerts.ts">list</a>({ ...params }) -> CustomerAlertsPage</code>
- <code title="post /customer-alerts/list">client.customerAlerts.<a href="./src/resources/customer-alerts.ts">list</a>({ ...params }) -> CustomerAlertListResponse</code>

# Plans

Expand All @@ -53,10 +54,10 @@ Types:

Methods:

- <code title="get /plans">client.plans.<a href="./src/resources/plans.ts">list</a>({ ...params }) -> PlanListResponsesPage</code>
- <code title="get /plans">client.plans.<a href="./src/resources/plans.ts">list</a>({ ...params }) -> PlanListResponse</code>
- <code title="get /planDetails/{plan_id}">client.plans.<a href="./src/resources/plans.ts">getDetails</a>(planId) -> PlanGetDetailsResponse</code>
- <code title="get /planDetails/{plan_id}/charges">client.plans.<a href="./src/resources/plans.ts">listCharges</a>(planId, { ...params }) -> PlanListChargesResponsesPage</code>
- <code title="get /planDetails/{plan_id}/customers">client.plans.<a href="./src/resources/plans.ts">listCustomers</a>(planId, { ...params }) -> PlanListCustomersResponsesPage</code>
- <code title="get /planDetails/{plan_id}/charges">client.plans.<a href="./src/resources/plans.ts">listCharges</a>(planId, { ...params }) -> PlanListChargesResponse</code>
- <code title="get /planDetails/{plan_id}/customers">client.plans.<a href="./src/resources/plans.ts">listCustomers</a>(planId, { ...params }) -> PlanListCustomersResponse</code>

# Credits

Expand All @@ -72,8 +73,8 @@ Methods:

- <code title="post /credits/createGrant">client.credits.<a href="./src/resources/credits.ts">createGrant</a>({ ...params }) -> CreditCreateGrantResponse</code>
- <code title="post /credits/editGrant">client.credits.<a href="./src/resources/credits.ts">editGrant</a>({ ...params }) -> CreditEditGrantResponse</code>
- <code title="post /credits/listEntries">client.credits.<a href="./src/resources/credits.ts">listEntries</a>({ ...params }) -> CreditListEntriesResponsesPage</code>
- <code title="post /credits/listGrants">client.credits.<a href="./src/resources/credits.ts">listGrants</a>({ ...params }) -> CreditListGrantsResponsesPage</code>
- <code title="post /credits/listEntries">client.credits.<a href="./src/resources/credits.ts">listEntries</a>({ ...params }) -> CreditListEntriesResponse</code>
- <code title="post /credits/listGrants">client.credits.<a href="./src/resources/credits.ts">listGrants</a>({ ...params }) -> CreditListGrantsResponse</code>
- <code title="post /credits/voidGrant">client.credits.<a href="./src/resources/credits.ts">voidGrant</a>({ ...params }) -> CreditVoidGrantResponse</code>

# CreditTypes
Expand All @@ -84,7 +85,7 @@ Types:

Methods:

- <code title="get /credit-types/list">client.creditTypes.<a href="./src/resources/credit-types.ts">list</a>({ ...params }) -> CreditTypeListResponsesPage</code>
- <code title="get /credit-types/list">client.creditTypes.<a href="./src/resources/credit-types.ts">list</a>({ ...params }) -> CreditTypeListResponse</code>

# Customers

Expand All @@ -94,6 +95,7 @@ Types:
- <code><a href="./src/resources/customers/customers.ts">CustomerDetail</a></code>
- <code><a href="./src/resources/customers/customers.ts">CustomerCreateResponse</a></code>
- <code><a href="./src/resources/customers/customers.ts">CustomerRetrieveResponse</a></code>
- <code><a href="./src/resources/customers/customers.ts">CustomerListResponse</a></code>
- <code><a href="./src/resources/customers/customers.ts">CustomerArchiveResponse</a></code>
- <code><a href="./src/resources/customers/customers.ts">CustomerListBillableMetricsResponse</a></code>
- <code><a href="./src/resources/customers/customers.ts">CustomerListCostsResponse</a></code>
Expand All @@ -103,10 +105,10 @@ Methods:

- <code title="post /customers">client.customers.<a href="./src/resources/customers/customers.ts">create</a>({ ...params }) -> CustomerCreateResponse</code>
- <code title="get /customers/{customer_id}">client.customers.<a href="./src/resources/customers/customers.ts">retrieve</a>(customerId) -> CustomerRetrieveResponse</code>
- <code title="get /customers">client.customers.<a href="./src/resources/customers/customers.ts">list</a>({ ...params }) -> CustomerDetailsPage</code>
- <code title="get /customers">client.customers.<a href="./src/resources/customers/customers.ts">list</a>({ ...params }) -> CustomerListResponse</code>
- <code title="post /customers/archive">client.customers.<a href="./src/resources/customers/customers.ts">archive</a>({ ...params }) -> CustomerArchiveResponse</code>
- <code title="get /customers/{customer_id}/billable-metrics">client.customers.<a href="./src/resources/customers/customers.ts">listBillableMetrics</a>(customerId, { ...params }) -> CustomerListBillableMetricsResponsesPage</code>
- <code title="get /customers/{customer_id}/costs">client.customers.<a href="./src/resources/customers/customers.ts">listCosts</a>(customerId, { ...params }) -> CustomerListCostsResponsesPage</code>
- <code title="get /customers/{customer_id}/billable-metrics">client.customers.<a href="./src/resources/customers/customers.ts">listBillableMetrics</a>(customerId, { ...params }) -> CustomerListBillableMetricsResponse</code>
- <code title="get /customers/{customer_id}/costs">client.customers.<a href="./src/resources/customers/customers.ts">listCosts</a>(customerId, { ...params }) -> CustomerListCostsResponse</code>
- <code title="post /customers/{customer_id}/setIngestAliases">client.customers.<a href="./src/resources/customers/customers.ts">setIngestAliases</a>(customerId, { ...params }) -> void</code>
- <code title="post /customers/{customer_id}/setName">client.customers.<a href="./src/resources/customers/customers.ts">setName</a>(customerId, { ...params }) -> CustomerSetNameResponse</code>
- <code title="post /customers/{customer_id}/updateConfig">client.customers.<a href="./src/resources/customers/customers.ts">updateConfig</a>(customerId, { ...params }) -> void</code>
Expand All @@ -122,22 +124,23 @@ Types:

Methods:

- <code title="get /customers/{customer_id}/plans">client.customers.plans.<a href="./src/resources/customers/plans.ts">list</a>(customerId, { ...params }) -> PlanListResponsesPage</code>
- <code title="get /customers/{customer_id}/plans">client.customers.plans.<a href="./src/resources/customers/plans.ts">list</a>(customerId, { ...params }) -> PlanListResponse</code>
- <code title="post /customers/{customer_id}/plans/add">client.customers.plans.<a href="./src/resources/customers/plans.ts">add</a>(customerId, { ...params }) -> PlanAddResponse</code>
- <code title="post /customers/{customer_id}/plans/{customer_plan_id}/end">client.customers.plans.<a href="./src/resources/customers/plans.ts">end</a>(customerId, customerPlanId, { ...params }) -> PlanEndResponse</code>
- <code title="get /customers/{customer_id}/plans/{customer_plan_id}/priceAdjustments">client.customers.plans.<a href="./src/resources/customers/plans.ts">listPriceAdjustments</a>(customerId, customerPlanId, { ...params }) -> PlanListPriceAdjustmentsResponsesPage</code>
- <code title="get /customers/{customer_id}/plans/{customer_plan_id}/priceAdjustments">client.customers.plans.<a href="./src/resources/customers/plans.ts">listPriceAdjustments</a>(customerId, customerPlanId, { ...params }) -> PlanListPriceAdjustmentsResponse</code>

## Invoices

Types:

- <code><a href="./src/resources/customers/invoices.ts">Invoice</a></code>
- <code><a href="./src/resources/customers/invoices.ts">InvoiceRetrieveResponse</a></code>
- <code><a href="./src/resources/customers/invoices.ts">InvoiceListResponse</a></code>

Methods:

- <code title="get /customers/{customer_id}/invoices/{invoice_id}">client.customers.invoices.<a href="./src/resources/customers/invoices.ts">retrieve</a>(customerId, invoiceId) -> InvoiceRetrieveResponse</code>
- <code title="get /customers/{customer_id}/invoices">client.customers.invoices.<a href="./src/resources/customers/invoices.ts">list</a>(customerId, { ...params }) -> InvoicesPage</code>
- <code title="get /customers/{customer_id}/invoices">client.customers.invoices.<a href="./src/resources/customers/invoices.ts">list</a>(customerId, { ...params }) -> InvoiceListResponse</code>

## BillingConfig

Expand Down Expand Up @@ -177,8 +180,8 @@ Types:

Methods:

- <code title="post /usage">client.usage.<a href="./src/resources/usage.ts">list</a>({ ...params }) -> UsageListResponsesPage</code>
- <code title="post /usage/groups">client.usage.<a href="./src/resources/usage.ts">listWithGroups</a>({ ...params }) -> UsageListWithGroupsResponsesPage</code>
- <code title="post /usage">client.usage.<a href="./src/resources/usage.ts">list</a>({ ...params }) -> UsageListResponse</code>
- <code title="post /usage/groups">client.usage.<a href="./src/resources/usage.ts">listWithGroups</a>({ ...params }) -> UsageListWithGroupsResponse</code>

# AuditLogs

Expand All @@ -188,7 +191,7 @@ Types:

Methods:

- <code title="get /auditLogs">client.auditLogs.<a href="./src/resources/audit-logs.ts">list</a>({ ...params }) -> AuditLogListResponsesPage</code>
- <code title="get /auditLogs">client.auditLogs.<a href="./src/resources/audit-logs.ts">list</a>({ ...params }) -> AuditLogListResponse</code>

# CustomFields

Expand All @@ -200,6 +203,6 @@ Methods:

- <code title="post /customFields/addKey">client.customFields.<a href="./src/resources/custom-fields.ts">addKey</a>({ ...params }) -> void</code>
- <code title="post /customFields/deleteValues">client.customFields.<a href="./src/resources/custom-fields.ts">deleteValues</a>({ ...params }) -> void</code>
- <code title="post /customFields/listKeys">client.customFields.<a href="./src/resources/custom-fields.ts">listKeys</a>({ ...params }) -> CustomFieldListKeysResponsesPage</code>
- <code title="post /customFields/listKeys">client.customFields.<a href="./src/resources/custom-fields.ts">listKeys</a>({ ...params }) -> CustomFieldListKeysResponse</code>
- <code title="post /customFields/removeKey">client.customFields.<a href="./src/resources/custom-fields.ts">removeKey</a>({ ...params }) -> void</code>
- <code title="post /customFields/setValues">client.customFields.<a href="./src/resources/custom-fields.ts">setValues</a>({ ...params }) -> void</code>
2 changes: 2 additions & 0 deletions release-please-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
"$schema": "https://raw.githubusercontent.com/stainless-api/release-please/main/schemas/config.json",
"include-v-in-tag": true,
"include-component-in-tag": false,
"versioning": "prerelease",
"prerelease": true,
"bump-minor-pre-major": true,
"bump-patch-for-minor-pre-major": false,
"pull-request-header": "Automated Release PR",
Expand Down
6 changes: 5 additions & 1 deletion scripts/fix-index-exports.cjs
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
const fs = require('fs');
const path = require('path');

const indexJs = path.resolve(__dirname, '..', 'dist', 'index.js');
const indexJs =
process.env['DIST_PATH'] ?
path.resolve(process.env['DIST_PATH'], 'index.js')
: path.resolve(__dirname, '..', 'dist', 'index.js');

let before = fs.readFileSync(indexJs, 'utf8');
let after = before.replace(
/^\s*exports\.default\s*=\s*(\w+)/m,
Expand Down
2 changes: 1 addition & 1 deletion scripts/make-dist-package-json.cjs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const pkgJson = require('../package.json');
const pkgJson = require(process.env['PKG_JSON_PATH'] || '../package.json');

function processExportMap(m) {
for (const key in m) {
Expand Down
11 changes: 8 additions & 3 deletions scripts/postprocess-files.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@ const fs = require('fs');
const path = require('path');
const { parse } = require('@typescript-eslint/parser');

const distDir = path.resolve(__dirname, '..', 'dist');
const pkgImportPath = process.env['PKG_IMPORT_PATH'] ?? '@metronome-industries/metronome/'

const distDir =
process.env['DIST_PATH'] ?
path.resolve(process.env['DIST_PATH'])
: path.resolve(__dirname, '..', 'dist');
const distSrcDir = path.join(distDir, 'src');

/**
Expand Down Expand Up @@ -105,11 +110,11 @@ async function postprocess() {

let transformed = mapModulePaths(code, (importPath) => {
if (file.startsWith(distSrcDir)) {
if (importPath.startsWith('@metronome-industries/metronome/')) {
if (importPath.startsWith(pkgImportPath)) {
// convert self-references in dist/src to relative paths
let relativePath = path.relative(
path.dirname(file),
path.join(distSrcDir, importPath.substring('@metronome-industries/metronome/'.length)),
path.join(distSrcDir, importPath.substring(pkgImportPath.length)),
);
if (!relativePath.startsWith('.')) relativePath = `./${relativePath}`;
return relativePath;
Expand Down
45 changes: 32 additions & 13 deletions src/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,11 @@ export abstract class APIClient {
return reqHeaders;
}

/**
* Used as a callback for mutating the given `FinalRequestOptions` object.
*/
protected async prepareOptions(options: FinalRequestOptions): Promise<void> {}

/**
* Used as a callback for mutating the given `RequestInit` object.
*
Expand Down Expand Up @@ -378,6 +383,8 @@ export abstract class APIClient {
retriesRemaining = options.maxRetries ?? this.maxRetries;
}

await this.prepareOptions(options);

const { req, url, timeout } = this.buildRequest(options);

await this.prepareRequest(req, { url, options });
Expand Down Expand Up @@ -408,14 +415,17 @@ export abstract class APIClient {

if (!response.ok) {
if (retriesRemaining && this.shouldRetry(response)) {
const retryMessage = `retrying, ${retriesRemaining} attempts remaining`;
debug(`response (error; ${retryMessage})`, response.status, url, responseHeaders);
return this.retryRequest(options, retriesRemaining, responseHeaders);
}

const errText = await response.text().catch((e) => castToError(e).message);
const errJSON = safeJSON(errText);
const errMessage = errJSON ? undefined : errText;
const retryMessage = retriesRemaining ? `(error; no more retries left)` : `(error; not retryable)`;

debug('response', response.status, url, responseHeaders, errMessage);
debug(`response (error; ${retryMessage})`, response.status, url, responseHeaders, errMessage);

const err = this.makeStatusError(response.status, errJSON, errMessage, responseHeaders);
throw err;
Expand Down Expand Up @@ -443,8 +453,8 @@ export abstract class APIClient {
query = { ...defaultQuery, ...query } as Req;
}

if (query) {
url.search = this.stringifyQuery(query);
if (typeof query === 'object' && query && !Array.isArray(query)) {
url.search = this.stringifyQuery(query as Record<string, unknown>);
}

return url.toString();
Expand Down Expand Up @@ -520,11 +530,21 @@ export abstract class APIClient {
retriesRemaining: number,
responseHeaders?: Headers | undefined,
): Promise<APIResponseProps> {
// About the Retry-After header: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After
let timeoutMillis: number | undefined;

// Note the `retry-after-ms` header may not be standard, but is a good idea and we'd like proactive support for it.
const retryAfterMillisHeader = responseHeaders?.['retry-after-ms'];
if (retryAfterMillisHeader) {
const timeoutMs = parseFloat(retryAfterMillisHeader);
if (!Number.isNaN(timeoutMs)) {
timeoutMillis = timeoutMs;
}
}

// About the Retry-After header: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After
const retryAfterHeader = responseHeaders?.['retry-after'];
if (retryAfterHeader) {
const timeoutSeconds = parseInt(retryAfterHeader);
if (retryAfterHeader && !timeoutMillis) {
const timeoutSeconds = parseFloat(retryAfterHeader);
if (!Number.isNaN(timeoutSeconds)) {
timeoutMillis = timeoutSeconds * 1000;
} else {
Expand All @@ -534,12 +554,7 @@ export abstract class APIClient {

// If the API asks us to wait a certain amount of time (and it's a reasonable amount),
// just do what it says, but otherwise calculate a default
if (
!timeoutMillis ||
!Number.isInteger(timeoutMillis) ||
timeoutMillis <= 0 ||
timeoutMillis > 60 * 1000
) {
if (!(timeoutMillis && 0 <= timeoutMillis && timeoutMillis < 60 * 1000)) {
const maxRetries = options.maxRetries ?? this.maxRetries;
timeoutMillis = this.calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries);
}
Expand Down Expand Up @@ -708,7 +723,7 @@ export type RequestOptions<Req = unknown | Record<string, unknown> | Readable> =
method?: HTTPMethod;
path?: string;
query?: Req | undefined;
body?: Req | undefined;
body?: Req | null | undefined;
headers?: Headers | undefined;

maxRetries?: number;
Expand Down Expand Up @@ -1122,3 +1137,7 @@ export const toBase64 = (str: string | null | undefined): string => {

throw new MetronomeError('Cannot generate b64 string; Expected `Buffer` or `btoa` to be defined');
};

export function isObj(obj: unknown): obj is Record<string, unknown> {
return obj != null && typeof obj === 'object' && !Array.isArray(obj);
}
Loading

0 comments on commit 60f9ce3

Please sign in to comment.