From 9f9c4e64078f331bf01e944cd565f016df9582b9 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 10 May 2024 00:15:13 +0000 Subject: [PATCH 01/20] feat(api): OpenAPI spec update via Stainless API (#5) --- README.md | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 38fe7ca..ab80e1a 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ This library provides convenient access to the Booklet REST API from server-side TypeScript or JavaScript. -The REST API documentation can be found [on docs.booklet.com](https://docs.booklet.com). The full API of this library can be found in [api.md](api.md). +The REST API documentation can be found [on docs.booklet.group](https://docs.booklet.group). The full API of this library can be found in [api.md](api.md). It is generated with [Stainless](https://www.stainlessapi.com/). diff --git a/package.json b/package.json index 0a3bb40..19c977d 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "bklt", "version": "0.0.1-alpha.1", "description": "The official TypeScript library for the Booklet API", - "author": "Booklet ", + "author": "Booklet ", "types": "dist/index.d.ts", "main": "dist/index.js", "type": "commonjs", From b4832fe2213779d8f59d6f0a7191d46486d4ad93 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 10 May 2024 23:36:17 +0000 Subject: [PATCH 02/20] feat(api): update via SDK Studio (#7) --- SECURITY.md | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 SECURITY.md diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..adf2936 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,27 @@ +# Security Policy + +## Reporting Security Issues + +This SDK is generated by [Stainless Software Inc](http://stainlessapi.com). Stainless takes security seriously, and encourages you to report any security vulnerability promptly so that appropriate action can be taken. + +To report a security issue, please contact the Stainless team at security@stainlessapi.com. + +## Responsible Disclosure + +We appreciate the efforts of security researchers and individuals who help us maintain the security of +SDKs we generate. If you believe you have found a security vulnerability, please adhere to responsible +disclosure practices by allowing us a reasonable amount of time to investigate and address the issue +before making any information public. + +## Reporting Non-SDK Related Security Issues + +If you encounter security issues that are not directly related to SDKs but pertain to the services +or products provided by Booklet please follow the respective company's security reporting guidelines. + +### Booklet Terms and Policies + +Please contact booklet@contraption.co for any questions or concerns regarding security of our services. + +--- + +Thank you for helping us keep the SDKs and systems they interact with secure. From 42c5432581e52d934a3e5bc8828c2e68a8f569ec Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 9 Nov 2024 03:53:15 +0000 Subject: [PATCH 03/20] chore: rebuild project due to codegen change (#8) --- .github/workflows/ci.yml | 28 +++- .github/workflows/release-doctor.yml | 3 + .gitignore | 3 +- CONTRIBUTING.md | 54 +++---- README.md | 50 +++--- bin/check-release-environment | 14 +- bin/publish-npm | 20 ++- package.json | 9 +- scripts/build | 2 +- scripts/format | 8 + scripts/lint | 6 +- scripts/mock | 4 +- scripts/test | 1 - src/_shims/node-runtime.ts | 4 +- src/_shims/node-types.d.ts | 2 +- src/core.ts | 92 ++++++++--- src/error.ts | 6 +- src/index.ts | 42 +++-- src/resources/index.ts | 10 +- src/resources/members.ts | 21 +-- src/uploads.ts | 15 +- tests/api-resources/members.test.ts | 44 +++--- tests/index.test.ts | 116 ++++++++++++++ tests/stringifyQuery.test.ts | 9 +- tests/uploads.test.ts | 8 + tsconfig.deno.json | 11 +- tsconfig.json | 3 +- yarn.lock | 223 ++++++++++++++------------- 28 files changed, 526 insertions(+), 282 deletions(-) create mode 100755 scripts/format diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f6b6073..e3530dc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,6 +6,7 @@ on: pull_request: branches: - main + - next jobs: lint: @@ -21,13 +22,30 @@ jobs: with: node-version: '18' - - name: Install dependencies - run: | - yarn install + - name: Bootstrap + run: ./scripts/bootstrap - name: Check types - run: | - yarn build + run: ./scripts/lint + + build: + name: build + runs-on: ubuntu-latest + + + steps: + - uses: actions/checkout@v4 + + - name: Set up Node + uses: actions/setup-node@v4 + with: + node-version: '18' + + - name: Bootstrap + run: ./scripts/bootstrap + + - name: Check build + run: ./scripts/build test: name: test runs-on: ubuntu-latest diff --git a/.github/workflows/release-doctor.yml b/.github/workflows/release-doctor.yml index 6d38dbe..e7af3f0 100644 --- a/.github/workflows/release-doctor.yml +++ b/.github/workflows/release-doctor.yml @@ -1,6 +1,8 @@ name: Release Doctor on: pull_request: + branches: + - main workflow_dispatch: jobs: @@ -17,3 +19,4 @@ jobs: bash ./bin/check-release-environment env: NPM_TOKEN: ${{ secrets.BOOKLET_NPM_TOKEN || secrets.NPM_TOKEN }} + diff --git a/.gitignore b/.gitignore index 9a5858a..d98d51a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,10 @@ +.prism.log node_modules yarn-error.log codegen.log Brewfile.lock.json dist -/deno +dist-deno /*.tgz .idea/ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 343c268..30d3519 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -5,24 +5,24 @@ Other package managers may work but are not officially supported for development To set up the repository, run: -```bash -yarn -yarn build +```sh +$ yarn +$ yarn build ``` This will install all the required dependencies and build output files to `dist/`. ## Modifying/Adding code -Most of the SDK is generated code, and any modified code will be overridden on the next generation. The -`src/lib/` and `examples/` directories are exceptions and will never be overridden. +Most of the SDK is generated code. Modifications to code will be persisted between generations, but may +result in merge conflicts between manual patches and changes from the generator. The generator will never +modify the contents of the `src/lib/` and `examples/` directories. ## Adding and running examples -All files in the `examples/` directory are not modified by the Stainless generator and can be freely edited or -added to. +All files in the `examples/` directory are not modified by the generator and can be freely edited or added to. -```bash +```ts // add an example to examples/.ts #!/usr/bin/env -S npm run tsn -T @@ -41,38 +41,38 @@ If you’d like to use the repository from source, you can either install from g To install via git: -```bash -npm install git+ssh://git@github.com:contraptionco/booklet-node.git +```sh +$ npm install git+ssh://git@github.com:contraptionco/booklet-node.git ``` Alternatively, to link a local copy of the repo: -```bash +```sh # Clone -git clone https://www.github.com/contraptionco/booklet-node -cd booklet-node +$ git clone https://www.github.com/contraptionco/booklet-node +$ cd booklet-node # With yarn -yarn link -cd ../my-package -yarn link bklt +$ yarn link +$ cd ../my-package +$ yarn link bklt # With pnpm -pnpm link --global -cd ../my-package -pnpm link -—global bklt +$ pnpm link --global +$ cd ../my-package +$ pnpm link -—global bklt ``` ## Running tests Most tests require you to [set up a mock server](https://github.com/stoplightio/prism) against the OpenAPI spec to run the tests. -```bash -npx prism mock path/to/your/openapi.yml +```sh +$ npx prism mock path/to/your/openapi.yml ``` -```bash -yarn run test +```sh +$ yarn run test ``` ## Linting and formatting @@ -82,14 +82,14 @@ This repository uses [prettier](https://www.npmjs.com/package/prettier) and To lint: -```bash -yarn lint +```sh +$ yarn lint ``` To format and fix all lint issues automatically: -```bash -yarn fix +```sh +$ yarn fix ``` ## Publishing and releases diff --git a/README.md b/README.md index ab80e1a..89717d5 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ # Booklet Node API Library -[![NPM version](https://img.shields.io/npm/v/bklt.svg)](https://npmjs.org/package/bklt) +[![NPM version](https://img.shields.io/npm/v/bklt.svg)](https://npmjs.org/package/bklt) ![npm bundle size](https://img.shields.io/bundlephobia/minzip/bklt) This library provides convenient access to the Booklet REST API from server-side TypeScript or JavaScript. -The REST API documentation can be found [on docs.booklet.group](https://docs.booklet.group). The full API of this library can be found in [api.md](api.md). +The REST API documentation can be found on [docs.booklet.group](https://docs.booklet.group). The full API of this library can be found in [api.md](api.md). It is generated with [Stainless](https://www.stainlessapi.com/). @@ -22,14 +22,14 @@ The full API of this library can be found in [api.md](api.md). ```js import Booklet from 'bklt'; -const booklet = new Booklet({ +const client = new Booklet({ apiKey: process.env['BOOKLET_API_KEY'], // This is the default and can be omitted }); async function main() { - const memberRetrieveResponse = await booklet.members.retrieve('REPLACE_ME'); + const member = await client.members.retrieve('REPLACE_ME'); - console.log(memberRetrieveResponse.id); + console.log(member.id); } main(); @@ -43,12 +43,12 @@ This library includes TypeScript definitions for all request params and response ```ts import Booklet from 'bklt'; -const booklet = new Booklet({ +const client = new Booklet({ apiKey: process.env['BOOKLET_API_KEY'], // This is the default and can be omitted }); async function main() { - const memberRetrieveResponse: Booklet.MemberRetrieveResponse = await booklet.members.retrieve('REPLACE_ME'); + const member: Booklet.MemberRetrieveResponse = await client.members.retrieve('REPLACE_ME'); } main(); @@ -65,7 +65,7 @@ a subclass of `APIError` will be thrown: ```ts async function main() { - const memberRetrieveResponse = await booklet.members.retrieve('REPLACE_ME').catch(async (err) => { + const member = await client.members.retrieve('REPLACE_ME').catch(async (err) => { if (err instanceof Booklet.APIError) { console.log(err.status); // 400 console.log(err.name); // BadRequestError @@ -103,12 +103,12 @@ You can use the `maxRetries` option to configure or disable this: ```js // Configure the default for all requests: -const booklet = new Booklet({ +const client = new Booklet({ maxRetries: 0, // default is 2 }); // Or, configure per-request: -await booklet.members.retrieve('REPLACE_ME', { +await client.members.retrieve('REPLACE_ME', { maxRetries: 5, }); ``` @@ -120,12 +120,12 @@ Requests time out after 1 minute by default. You can configure this with a `time ```ts // Configure the default for all requests: -const booklet = new Booklet({ +const client = new Booklet({ timeout: 20 * 1000, // 20 seconds (default is 1 minute) }); // Override per-request: -await booklet.members.retrieve('REPLACE_ME', { +await client.members.retrieve('REPLACE_ME', { timeout: 5 * 1000, }); ``` @@ -144,17 +144,15 @@ You can also use the `.withResponse()` method to get the raw `Response` along wi ```ts -const booklet = new Booklet(); +const client = new Booklet(); -const response = await booklet.members.retrieve('REPLACE_ME').asResponse(); +const response = await client.members.retrieve('REPLACE_ME').asResponse(); console.log(response.headers.get('X-My-Header')); console.log(response.statusText); // access the underlying Response object -const { data: memberRetrieveResponse, response: raw } = await booklet.members - .retrieve('REPLACE_ME') - .withResponse(); +const { data: member, response: raw } = await client.members.retrieve('REPLACE_ME').withResponse(); console.log(raw.headers.get('X-My-Header')); -console.log(memberRetrieveResponse.id); +console.log(member.id); ``` ### Making custom/undocumented requests @@ -253,12 +251,12 @@ import http from 'http'; import { HttpsProxyAgent } from 'https-proxy-agent'; // Configure the default for all requests: -const booklet = new Booklet({ +const client = new Booklet({ httpAgent: new HttpsProxyAgent(process.env.PROXY_URL), }); // Override per-request: -await booklet.members.retrieve('REPLACE_ME', { +await client.members.retrieve('REPLACE_ME', { httpAgent: new http.Agent({ keepAlive: false }), }); ``` @@ -281,14 +279,10 @@ TypeScript >= 4.5 is supported. The following runtimes are supported: -- Node.js 18 LTS or later ([non-EOL](https://endoflife.date/nodejs)) versions. -- Deno v1.28.0 or higher, using `import Booklet from "npm:bklt"`. -- Bun 1.0 or later. -- Cloudflare Workers. -- Vercel Edge Runtime. -- Jest 28 or greater with the `"node"` environment (`"jsdom"` is not supported at this time). -- Nitro v2.6 or greater. - Note that React Native is not supported at this time. If you are interested in other runtime environments, please open or upvote an issue on GitHub. + +## Contributing + +See [the contributing documentation](./CONTRIBUTING.md). diff --git a/bin/check-release-environment b/bin/check-release-environment index 130c14e..429d585 100644 --- a/bin/check-release-environment +++ b/bin/check-release-environment @@ -1,20 +1,9 @@ #!/usr/bin/env bash -warnings=() errors=() if [ -z "${NPM_TOKEN}" ]; then - warnings+=("The BOOKLET_NPM_TOKEN secret has not been set. Please set it in either this repository's secrets or your organization secrets") -fi - -lenWarnings=${#warnings[@]} - -if [[ lenWarnings -gt 0 ]]; then - echo -e "Found the following warnings in the release environment:\n" - - for warning in "${warnings[@]}"; do - echo -e "- $warning\n" - done + errors+=("The BOOKLET_NPM_TOKEN secret has not been set. Please set it in either this repository's secrets or your organization secrets") fi lenErrors=${#errors[@]} @@ -30,3 +19,4 @@ if [[ lenErrors -gt 0 ]]; then fi echo "The environment is ready to push releases!" + diff --git a/bin/publish-npm b/bin/publish-npm index 4d6c9f3..4c21181 100644 --- a/bin/publish-npm +++ b/bin/publish-npm @@ -2,8 +2,24 @@ set -eux -npm config set //registry.npmjs.org/:_authToken $NPM_TOKEN +npm config set '//registry.npmjs.org/:_authToken' "$NPM_TOKEN" +# Build the project yarn build + +# Navigate to the dist directory cd dist -yarn publish --access public + +# Get the version from package.json +VERSION="$(node -p "require('./package.json').version")" + +# Extract the pre-release tag if it exists +if [[ "$VERSION" =~ -([a-zA-Z]+) ]]; then + # Extract the part before any dot in the pre-release identifier + TAG="${BASH_REMATCH[1]}" +else + TAG="latest" +fi + +# Publish with the appropriate tag +yarn publish --access public --tag "$TAG" diff --git a/package.json b/package.json index 19c977d..f5eb2b8 100644 --- a/package.json +++ b/package.json @@ -10,19 +10,18 @@ "license": "Apache-2.0", "packageManager": "yarn@1.22.22", "files": [ - "*" + "**/*" ], "private": false, "scripts": { "test": "./scripts/test", "build": "./scripts/build", - "prepack": "echo 'to pack, run yarn build && (cd dist; yarn pack)' && exit 1", "prepublishOnly": "echo 'to publish, run yarn build && (cd dist; yarn publish)' && exit 1", "format": "prettier --write --cache --cache-strategy metadata . !dist", "prepare": "if ./scripts/utils/check-is-in-git-install.sh; then ./scripts/build; fi", "tsn": "ts-node -r tsconfig-paths/register", "lint": "./scripts/lint", - "fix": "eslint --fix --ext ts,js ." + "fix": "./scripts/format" }, "dependencies": { "@types/node": "^18.11.18", @@ -31,8 +30,7 @@ "agentkeepalive": "^4.2.1", "form-data-encoder": "1.7.2", "formdata-node": "^4.3.2", - "node-fetch": "^2.6.7", - "web-streams-polyfill": "^3.2.1" + "node-fetch": "^2.6.7" }, "devDependencies": { "@swc/core": "^1.3.102", @@ -43,6 +41,7 @@ "eslint": "^8.49.0", "eslint-plugin-prettier": "^5.0.1", "eslint-plugin-unused-imports": "^3.0.0", + "iconv-lite": "^0.6.3", "jest": "^29.4.0", "prettier": "^3.0.0", "ts-jest": "^29.1.0", diff --git a/scripts/build b/scripts/build index f057fa5..37c90a0 100755 --- a/scripts/build +++ b/scripts/build @@ -50,7 +50,7 @@ node scripts/utils/postprocess-files.cjs (cd dist && node -e 'require("bklt")') (cd dist && node -e 'import("bklt")' --input-type=module) -if command -v deno &> /dev/null && [ -e ./scripts/build-deno ] +if [ -e ./scripts/build-deno ] then ./scripts/build-deno fi diff --git a/scripts/format b/scripts/format new file mode 100755 index 0000000..a6bb9d0 --- /dev/null +++ b/scripts/format @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +set -e + +cd "$(dirname "$0")/.." + +echo "==> Running eslint --fix" +ESLINT_USE_FLAT_CONFIG="false" ./node_modules/.bin/eslint --fix --ext ts,js . diff --git a/scripts/lint b/scripts/lint index 4f05d66..6ba75df 100755 --- a/scripts/lint +++ b/scripts/lint @@ -4,4 +4,8 @@ set -e cd "$(dirname "$0")/.." -./node_modules/.bin/eslint --ext ts,js . +echo "==> Running eslint" +ESLINT_USE_FLAT_CONFIG="false" ./node_modules/.bin/eslint --ext ts,js . + +echo "==> Running tsc" +./node_modules/.bin/tsc --noEmit diff --git a/scripts/mock b/scripts/mock index fe89a1d..d2814ae 100755 --- a/scripts/mock +++ b/scripts/mock @@ -21,7 +21,7 @@ echo "==> Starting mock server with URL ${URL}" # Run prism mock on the given spec if [ "$1" == "--daemon" ]; then - npm exec --package=@stoplight/prism-cli@~5.8 -- prism mock "$URL" &> .prism.log & + npm exec --package=@stainless-api/prism-cli@5.8.5 -- prism mock "$URL" &> .prism.log & # Wait for server to come online echo -n "Waiting for server" @@ -37,5 +37,5 @@ if [ "$1" == "--daemon" ]; then echo else - npm exec --package=@stoplight/prism-cli@~5.8 -- prism mock "$URL" + npm exec --package=@stainless-api/prism-cli@5.8.5 -- prism mock "$URL" fi diff --git a/scripts/test b/scripts/test index b62a7cc..2049e31 100755 --- a/scripts/test +++ b/scripts/test @@ -52,6 +52,5 @@ else echo fi -# Run tests echo "==> Running tests" ./node_modules/.bin/jest "$@" diff --git a/src/_shims/node-runtime.ts b/src/_shims/node-runtime.ts index a9c42eb..ab9f2ab 100644 --- a/src/_shims/node-runtime.ts +++ b/src/_shims/node-runtime.ts @@ -13,9 +13,7 @@ import { Readable } from 'node:stream'; import { type RequestOptions } from '../core'; import { MultipartBody } from './MultipartBody'; import { type Shims } from './registry'; - -// @ts-ignore (this package does not have proper export maps for this export) -import { ReadableStream } from 'web-streams-polyfill/dist/ponyfill.es2018.js'; +import { ReadableStream } from 'node:stream/web'; type FileFromPathOptions = Omit; diff --git a/src/_shims/node-types.d.ts b/src/_shims/node-types.d.ts index b31698f..c159e5f 100644 --- a/src/_shims/node-types.d.ts +++ b/src/_shims/node-types.d.ts @@ -7,7 +7,7 @@ import * as fd from 'formdata-node'; export { type Agent } from 'node:http'; export { type Readable } from 'node:stream'; export { type ReadStream as FsReadStream } from 'node:fs'; -export { ReadableStream } from 'web-streams-polyfill'; +export { ReadableStream } from 'node:stream/web'; export const fetch: typeof nf.default; diff --git a/src/core.ts b/src/core.ts index aa88001..cf445b1 100644 --- a/src/core.ts +++ b/src/core.ts @@ -18,7 +18,7 @@ import { type HeadersInit, } from './_shims/index'; export { type Response }; -import { isMultipartBody } from './uploads'; +import { BlobLike, isBlobLike, isMultipartBody } from './uploads'; export { maybeMultipartFormRequestOptions, multipartFormRequestOptions, @@ -84,8 +84,10 @@ export class APIPromise extends Promise { }); } - _thenUnwrap(transform: (data: T) => U): APIPromise { - return new APIPromise(this.responsePromise, async (props) => transform(await this.parseResponse(props))); + _thenUnwrap(transform: (data: T, props: APIResponseProps) => U): APIPromise { + return new APIPromise(this.responsePromise, async (props) => + transform(await this.parseResponse(props), props), + ); } /** @@ -235,7 +237,17 @@ export abstract class APIClient { path: string, opts?: PromiseOrValue>, ): APIPromise { - return this.request(Promise.resolve(opts).then((opts) => ({ method, path, ...opts }))); + return this.request( + Promise.resolve(opts).then(async (opts) => { + const body = + opts && isBlobLike(opts?.body) ? new DataView(await opts.body.arrayBuffer()) + : opts?.body instanceof DataView ? opts.body + : opts?.body instanceof ArrayBuffer ? new DataView(opts.body) + : opts && ArrayBuffer.isView(opts?.body) ? new DataView(opts.body.buffer) + : opts?.body; + return { method, path, ...opts, body }; + }), + ); } getAPIList = AbstractPage>( @@ -257,16 +269,23 @@ export abstract class APIClient { const encoded = encoder.encode(body); return encoded.length.toString(); } + } else if (ArrayBuffer.isView(body)) { + return body.byteLength.toString(); } return null; } - buildRequest(options: FinalRequestOptions): { req: RequestInit; url: string; timeout: number } { + buildRequest( + options: FinalRequestOptions, + { retryCount = 0 }: { retryCount?: number } = {}, + ): { req: RequestInit; url: string; timeout: number } { const { method, path, query, headers: headers = {} } = options; const body = - isMultipartBody(options.body) ? options.body.body + ArrayBuffer.isView(options.body) || (options.__binaryRequest && typeof options.body === 'string') ? + options.body + : isMultipartBody(options.body) ? options.body.body : options.body ? JSON.stringify(options.body, null, 2) : null; const contentLength = this.calculateContentLength(body); @@ -292,7 +311,7 @@ export abstract class APIClient { headers[this.idempotencyHeader] = options.idempotencyKey; } - const reqHeaders = this.buildHeaders({ options, headers, contentLength }); + const reqHeaders = this.buildHeaders({ options, headers, contentLength, retryCount }); const req: RequestInit = { method, @@ -311,10 +330,12 @@ export abstract class APIClient { options, headers, contentLength, + retryCount, }: { options: FinalRequestOptions; headers: Record; contentLength: string | null | undefined; + retryCount: number; }): Record { const reqHeaders: Record = {}; if (contentLength) { @@ -330,6 +351,16 @@ export abstract class APIClient { delete reqHeaders['content-type']; } + // Don't set the retry count header if it was already set or removed through default headers or by the + // caller. We check `defaultHeaders` and `headers`, which can contain nulls, instead of `reqHeaders` to + // account for the removal case. + if ( + getHeader(defaultHeaders, 'x-stainless-retry-count') === undefined && + getHeader(headers, 'x-stainless-retry-count') === undefined + ) { + reqHeaders['x-stainless-retry-count'] = String(retryCount); + } + this.validateHeaders(reqHeaders, headers); return reqHeaders; @@ -365,7 +396,7 @@ export abstract class APIClient { error: Object | undefined, message: string | undefined, headers: Headers | undefined, - ) { + ): APIError { return APIError.generate(status, error, message, headers); } @@ -381,13 +412,14 @@ export abstract class APIClient { retriesRemaining: number | null, ): Promise { const options = await optionsInput; + const maxRetries = options.maxRetries ?? this.maxRetries; if (retriesRemaining == null) { - retriesRemaining = options.maxRetries ?? this.maxRetries; + retriesRemaining = maxRetries; } await this.prepareOptions(options); - const { req, url, timeout } = this.buildRequest(options); + const { req, url, timeout } = this.buildRequest(options, { retryCount: maxRetries - retriesRemaining }); await this.prepareRequest(req, { url, options }); @@ -636,9 +668,9 @@ export abstract class AbstractPage implements AsyncIterable { return await this.#client.requestAPIList(this.constructor as any, nextOptions); } - async *iterPages() { + async *iterPages(): AsyncGenerator { // eslint-disable-next-line @typescript-eslint/no-this-alias - let page: AbstractPage = this; + let page: this = this; yield page; while (page.hasNextPage()) { page = await page.getNextPage(); @@ -646,7 +678,7 @@ export abstract class AbstractPage implements AsyncIterable { } } - async *[Symbol.asyncIterator]() { + async *[Symbol.asyncIterator](): AsyncGenerator { for await (const page of this.iterPages()) { for (const item of page.getPaginatedItems()) { yield item; @@ -689,7 +721,7 @@ export class PagePromise< * console.log(item) * } */ - async *[Symbol.asyncIterator]() { + async *[Symbol.asyncIterator](): AsyncGenerator { const page = await this; for await (const item of page) { yield item; @@ -721,7 +753,9 @@ export type Headers = Record; export type DefaultQuery = Record; export type KeysEnum = { [P in keyof Required]: true }; -export type RequestOptions | Readable> = { +export type RequestOptions< + Req = unknown | Record | Readable | BlobLike | ArrayBufferView | ArrayBuffer, +> = { method?: HTTPMethod; path?: string; query?: Req | undefined; @@ -735,6 +769,7 @@ export type RequestOptions | Readable> = signal?: AbortSignal | undefined | null; idempotencyKey?: string; + __binaryRequest?: boolean | undefined; __binaryResponse?: boolean | undefined; }; @@ -755,6 +790,7 @@ const requestOptionsKeys: KeysEnum = { signal: true, idempotencyKey: true, + __binaryRequest: true, __binaryResponse: true, }; @@ -767,10 +803,11 @@ export const isRequestOptions = (obj: unknown): obj is RequestOptions => { ); }; -export type FinalRequestOptions | Readable> = RequestOptions & { - method: HTTPMethod; - path: string; -}; +export type FinalRequestOptions | Readable | DataView> = + RequestOptions & { + method: HTTPMethod; + path: string; + }; declare const Deno: any; declare const EdgeRuntime: any; @@ -959,6 +996,11 @@ const validatePositiveInteger = (name: string, n: unknown): number => { export const castToError = (err: any): Error => { if (err instanceof Error) return err; + if (typeof err === 'object' && err !== null) { + try { + return new Error(JSON.stringify(err)); + } catch {} + } return new Error(err); }; @@ -1096,7 +1138,15 @@ export const isHeadersProtocol = (headers: any): headers is HeadersProtocol => { return typeof headers?.get === 'function'; }; -export const getRequiredHeader = (headers: HeadersLike, header: string): string => { +export const getRequiredHeader = (headers: HeadersLike | Headers, header: string): string => { + const foundHeader = getHeader(headers, header); + if (foundHeader === undefined) { + throw new Error(`Could not find ${header} header`); + } + return foundHeader; +}; + +export const getHeader = (headers: HeadersLike | Headers, header: string): string | undefined => { const lowerCasedHeader = header.toLowerCase(); if (isHeadersProtocol(headers)) { // to deal with the case where the header looks like Stainless-Event-Id @@ -1122,7 +1172,7 @@ export const getRequiredHeader = (headers: HeadersLike, header: string): string } } - throw new Error(`Could not find ${header} header`); + return undefined; }; /** diff --git a/src/error.ts b/src/error.ts index ce3fb95..d1e8ec5 100644 --- a/src/error.ts +++ b/src/error.ts @@ -47,9 +47,9 @@ export class APIError extends BookletError { errorResponse: Object | undefined, message: string | undefined, headers: Headers | undefined, - ) { + ): APIError { if (!status) { - return new APIConnectionError({ cause: castToError(errorResponse) }); + return new APIConnectionError({ message, cause: castToError(errorResponse) }); } const error = errorResponse as Record; @@ -101,7 +101,7 @@ export class APIUserAbortError extends APIError { export class APIConnectionError extends APIError { override readonly status: undefined = undefined; - constructor({ message, cause }: { message?: string; cause?: Error | undefined }) { + constructor({ message, cause }: { message?: string | undefined; cause?: Error | undefined }) { super(undefined, undefined, message || 'Connection error.', undefined); // in some environments the 'cause' property is already declared // @ts-ignore diff --git a/src/index.ts b/src/index.ts index 1ecc042..d4c845e 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,10 +1,18 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. +import { type Agent } from './_shims/index'; import * as Core from './core'; import * as Errors from './error'; -import { type Agent } from './_shims/index'; import * as Uploads from './uploads'; -import * as API from 'bklt/resources/index'; +import * as API from './resources/index'; +import { + MemberCreateParams, + MemberListParams, + MemberListResponse, + MemberRetrieveResponse, + MemberUpdateParams, + Members, +} from './resources/members'; export interface ClientOptions { /** @@ -69,7 +77,9 @@ export interface ClientOptions { defaultQuery?: Core.DefaultQuery; } -/** API Client for interfacing with the Booklet API. */ +/** + * API Client for interfacing with the Booklet API. + */ export class Booklet extends Core.APIClient { apiKey: string; @@ -111,6 +121,7 @@ export class Booklet extends Core.APIClient { maxRetries: options.maxRetries, fetch: options.fetch, }); + this._options = options; this.apiKey = apiKey; @@ -134,6 +145,7 @@ export class Booklet extends Core.APIClient { } static Booklet = this; + static DEFAULT_TIMEOUT = 60000; // 1 minute static BookletError = Errors.BookletError; static APIError = Errors.APIError; @@ -153,7 +165,7 @@ export class Booklet extends Core.APIClient { static fileFromPath = Uploads.fileFromPath; } -export const { +export { BookletError, APIError, APIConnectionError, @@ -167,20 +179,24 @@ export const { InternalServerError, PermissionDeniedError, UnprocessableEntityError, -} = Errors; +} from './error'; export import toFile = Uploads.toFile; export import fileFromPath = Uploads.fileFromPath; -export namespace Booklet { - export import RequestOptions = Core.RequestOptions; +Booklet.Members = Members; + +export declare namespace Booklet { + export type RequestOptions = Core.RequestOptions; - export import Members = API.Members; - export import MemberRetrieveResponse = API.MemberRetrieveResponse; - export import MemberListResponse = API.MemberListResponse; - export import MemberCreateParams = API.MemberCreateParams; - export import MemberUpdateParams = API.MemberUpdateParams; - export import MemberListParams = API.MemberListParams; + export { + Members as Members, + type MemberRetrieveResponse as MemberRetrieveResponse, + type MemberListResponse as MemberListResponse, + type MemberCreateParams as MemberCreateParams, + type MemberUpdateParams as MemberUpdateParams, + type MemberListParams as MemberListParams, + }; } export default Booklet; diff --git a/src/resources/index.ts b/src/resources/index.ts index dd02aea..4e544c6 100644 --- a/src/resources/index.ts +++ b/src/resources/index.ts @@ -1,10 +1,10 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. export { - MemberRetrieveResponse, - MemberListResponse, - MemberCreateParams, - MemberUpdateParams, - MemberListParams, Members, + type MemberRetrieveResponse, + type MemberListResponse, + type MemberCreateParams, + type MemberUpdateParams, + type MemberListParams, } from './members'; diff --git a/src/resources/members.ts b/src/resources/members.ts index 2e141ca..7889500 100644 --- a/src/resources/members.ts +++ b/src/resources/members.ts @@ -1,9 +1,8 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import * as Core from 'bklt/core'; -import { APIResource } from 'bklt/resource'; -import { isRequestOptions } from 'bklt/core'; -import * as MembersAPI from 'bklt/resources/members'; +import { APIResource } from '../resource'; +import { isRequestOptions } from '../core'; +import * as Core from '../core'; export class Members extends APIResource { /** @@ -170,10 +169,12 @@ export interface MemberListParams { page?: number; } -export namespace Members { - export import MemberRetrieveResponse = MembersAPI.MemberRetrieveResponse; - export import MemberListResponse = MembersAPI.MemberListResponse; - export import MemberCreateParams = MembersAPI.MemberCreateParams; - export import MemberUpdateParams = MembersAPI.MemberUpdateParams; - export import MemberListParams = MembersAPI.MemberListParams; +export declare namespace Members { + export { + type MemberRetrieveResponse as MemberRetrieveResponse, + type MemberListResponse as MemberListResponse, + type MemberCreateParams as MemberCreateParams, + type MemberUpdateParams as MemberUpdateParams, + type MemberListParams as MemberListParams, + }; } diff --git a/src/uploads.ts b/src/uploads.ts index 081827c..8fd2154 100644 --- a/src/uploads.ts +++ b/src/uploads.ts @@ -107,21 +107,28 @@ export async function toFile( // If it's a promise, resolve it. value = await value; - // Use the file's options if there isn't one provided - options ??= isFileLike(value) ? { lastModified: value.lastModified, type: value.type } : {}; + // If we've been given a `File` we don't need to do anything + if (isFileLike(value)) { + return value; + } if (isResponseLike(value)) { const blob = await value.blob(); name ||= new URL(value.url).pathname.split(/[\\/]/).pop() ?? 'unknown_file'; - return new File([blob as any], name, options); + // we need to convert the `Blob` into an array buffer because the `Blob` class + // that `node-fetch` defines is incompatible with the web standard which results + // in `new File` interpreting it as a string instead of binary data. + const data = isBlobLike(blob) ? [(await blob.arrayBuffer()) as any] : [blob]; + + return new File(data, name, options); } const bits = await getBytes(value); name ||= getName(value) ?? 'unknown_file'; - if (!options.type) { + if (!options?.type) { const type = (bits[0] as any)?.type; if (typeof type === 'string') { options = { ...options, type }; diff --git a/tests/api-resources/members.test.ts b/tests/api-resources/members.test.ts index 8f5841d..dbc9d2b 100644 --- a/tests/api-resources/members.test.ts +++ b/tests/api-resources/members.test.ts @@ -3,14 +3,14 @@ import Booklet from 'bklt'; import { Response } from 'node-fetch'; -const booklet = new Booklet({ +const client = new Booklet({ apiKey: 'My API Key', baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', }); describe('resource members', () => { test('create: only required params', async () => { - const responsePromise = booklet.members.create({ email: 'string' }); + const responsePromise = client.members.create({ email: 'email' }); const rawResponse = await responsePromise.asResponse(); expect(rawResponse).toBeInstanceOf(Response); const response = await responsePromise; @@ -21,20 +21,20 @@ describe('resource members', () => { }); test('create: required and optional params', async () => { - const response = await booklet.members.create({ - email: 'string', - about: 'string', - name: 'string', - permission: 'string', - photo: 'string', - quarantined_at: 'string', + const response = await client.members.create({ + email: 'email', + about: 'about', + name: 'name', + permission: 'permission', + photo: 'photo', + quarantined_at: 'quarantined_at', send_welcome: true, subscribed_at: true, }); }); test('retrieve', async () => { - const responsePromise = booklet.members.retrieve('string'); + const responsePromise = client.members.retrieve('id'); const rawResponse = await responsePromise.asResponse(); expect(rawResponse).toBeInstanceOf(Response); const response = await responsePromise; @@ -46,13 +46,13 @@ describe('resource members', () => { test('retrieve: request options instead of params are passed correctly', async () => { // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error - await expect(booklet.members.retrieve('string', { path: '/_stainless_unknown_path' })).rejects.toThrow( + await expect(client.members.retrieve('id', { path: '/_stainless_unknown_path' })).rejects.toThrow( Booklet.NotFoundError, ); }); test('update', async () => { - const responsePromise = booklet.members.update('string'); + const responsePromise = client.members.update('id'); const rawResponse = await responsePromise.asResponse(); expect(rawResponse).toBeInstanceOf(Response); const response = await responsePromise; @@ -64,7 +64,7 @@ describe('resource members', () => { test('update: request options instead of params are passed correctly', async () => { // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error - await expect(booklet.members.update('string', { path: '/_stainless_unknown_path' })).rejects.toThrow( + await expect(client.members.update('id', { path: '/_stainless_unknown_path' })).rejects.toThrow( Booklet.NotFoundError, ); }); @@ -72,16 +72,22 @@ describe('resource members', () => { test('update: request options and params are passed correctly', async () => { // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error await expect( - booklet.members.update( - 'string', - { about: 'string', locked_at: 'string', name: 'string', photo: 'string', quarantined_at: 'string' }, + client.members.update( + 'id', + { + about: 'about', + locked_at: 'locked_at', + name: 'name', + photo: 'photo', + quarantined_at: 'quarantined_at', + }, { path: '/_stainless_unknown_path' }, ), ).rejects.toThrow(Booklet.NotFoundError); }); test('list', async () => { - const responsePromise = booklet.members.list(); + const responsePromise = client.members.list(); const rawResponse = await responsePromise.asResponse(); expect(rawResponse).toBeInstanceOf(Response); const response = await responsePromise; @@ -93,7 +99,7 @@ describe('resource members', () => { test('list: request options instead of params are passed correctly', async () => { // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error - await expect(booklet.members.list({ path: '/_stainless_unknown_path' })).rejects.toThrow( + await expect(client.members.list({ path: '/_stainless_unknown_path' })).rejects.toThrow( Booklet.NotFoundError, ); }); @@ -101,7 +107,7 @@ describe('resource members', () => { test('list: request options and params are passed correctly', async () => { // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error await expect( - booklet.members.list({ items: 0, page: 0 }, { path: '/_stainless_unknown_path' }), + client.members.list({ items: 0, page: 0 }, { path: '/_stainless_unknown_path' }), ).rejects.toThrow(Booklet.NotFoundError); }); }); diff --git a/tests/index.test.ts b/tests/index.test.ts index 8aa2ac1..184cb90 100644 --- a/tests/index.test.ts +++ b/tests/index.test.ts @@ -241,6 +241,122 @@ describe('retries', () => { expect(count).toEqual(3); }); + test('retry count header', async () => { + let count = 0; + let capturedRequest: RequestInit | undefined; + const testFetch = async (url: RequestInfo, init: RequestInit = {}): Promise => { + count++; + if (count <= 2) { + return new Response(undefined, { + status: 429, + headers: { + 'Retry-After': '0.1', + }, + }); + } + capturedRequest = init; + return new Response(JSON.stringify({ a: 1 }), { headers: { 'Content-Type': 'application/json' } }); + }; + + const client = new Booklet({ apiKey: 'My API Key', fetch: testFetch, maxRetries: 4 }); + + expect(await client.request({ path: '/foo', method: 'get' })).toEqual({ a: 1 }); + + expect((capturedRequest!.headers as Headers)['x-stainless-retry-count']).toEqual('2'); + expect(count).toEqual(3); + }); + + test('omit retry count header', async () => { + let count = 0; + let capturedRequest: RequestInit | undefined; + const testFetch = async (url: RequestInfo, init: RequestInit = {}): Promise => { + count++; + if (count <= 2) { + return new Response(undefined, { + status: 429, + headers: { + 'Retry-After': '0.1', + }, + }); + } + capturedRequest = init; + return new Response(JSON.stringify({ a: 1 }), { headers: { 'Content-Type': 'application/json' } }); + }; + const client = new Booklet({ apiKey: 'My API Key', fetch: testFetch, maxRetries: 4 }); + + expect( + await client.request({ + path: '/foo', + method: 'get', + headers: { 'X-Stainless-Retry-Count': null }, + }), + ).toEqual({ a: 1 }); + + expect(capturedRequest!.headers as Headers).not.toHaveProperty('x-stainless-retry-count'); + }); + + test('omit retry count header by default', async () => { + let count = 0; + let capturedRequest: RequestInit | undefined; + const testFetch = async (url: RequestInfo, init: RequestInit = {}): Promise => { + count++; + if (count <= 2) { + return new Response(undefined, { + status: 429, + headers: { + 'Retry-After': '0.1', + }, + }); + } + capturedRequest = init; + return new Response(JSON.stringify({ a: 1 }), { headers: { 'Content-Type': 'application/json' } }); + }; + const client = new Booklet({ + apiKey: 'My API Key', + fetch: testFetch, + maxRetries: 4, + defaultHeaders: { 'X-Stainless-Retry-Count': null }, + }); + + expect( + await client.request({ + path: '/foo', + method: 'get', + }), + ).toEqual({ a: 1 }); + + expect(capturedRequest!.headers as Headers).not.toHaveProperty('x-stainless-retry-count'); + }); + + test('overwrite retry count header', async () => { + let count = 0; + let capturedRequest: RequestInit | undefined; + const testFetch = async (url: RequestInfo, init: RequestInit = {}): Promise => { + count++; + if (count <= 2) { + return new Response(undefined, { + status: 429, + headers: { + 'Retry-After': '0.1', + }, + }); + } + capturedRequest = init; + return new Response(JSON.stringify({ a: 1 }), { headers: { 'Content-Type': 'application/json' } }); + }; + const client = new Booklet({ apiKey: 'My API Key', fetch: testFetch, maxRetries: 4 }); + + expect( + await client.request({ + path: '/foo', + method: 'get', + headers: { 'X-Stainless-Retry-Count': '42' }, + }), + ).toEqual({ a: 1 }); + + expect((capturedRequest!.headers as Headers)['x-stainless-retry-count']).toBe('42'); + }); + test('retry on 429 with retry-after', async () => { let count = 0; const testFetch = async (url: RequestInfo, { signal }: RequestInit = {}): Promise => { diff --git a/tests/stringifyQuery.test.ts b/tests/stringifyQuery.test.ts index 221aa01..b101d0e 100644 --- a/tests/stringifyQuery.test.ts +++ b/tests/stringifyQuery.test.ts @@ -1,8 +1,10 @@ -import { APIClient } from 'bklt/core'; +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -const { stringifyQuery } = APIClient.prototype as any; +import { Booklet } from 'bklt'; -describe('APIClient.stringifyQuery', () => { +const { stringifyQuery } = Booklet.prototype as any; + +describe(stringifyQuery, () => { for (const [input, expected] of [ [{ a: '1', b: 2, c: true }, 'a=1&b=2&c=true'], [{ a: null, b: false, c: undefined }, 'a=&b=false'], @@ -18,6 +20,7 @@ describe('APIClient.stringifyQuery', () => { expect(stringifyQuery(input)).toEqual(expected); }); } + for (const value of [[], {}, new Date()]) { it(`${JSON.stringify(value)} -> `, () => { expect(() => stringifyQuery({ value })).toThrow(`Cannot stringify type ${typeof value}`); diff --git a/tests/uploads.test.ts b/tests/uploads.test.ts index 6a5dd7d..bc168e5 100644 --- a/tests/uploads.test.ts +++ b/tests/uploads.test.ts @@ -54,4 +54,12 @@ describe('toFile', () => { const file = await toFile(input); expect(file.name).toEqual('uploads.test.ts'); }); + + it('does not copy File objects', async () => { + const input = new File(['foo'], 'input.jsonl', { type: 'jsonl' }); + const file = await toFile(input); + expect(file).toBe(input); + expect(file.name).toEqual('input.jsonl'); + expect(file.type).toBe('jsonl'); + }); }); diff --git a/tsconfig.deno.json b/tsconfig.deno.json index 2d00bd0..849e070 100644 --- a/tsconfig.deno.json +++ b/tsconfig.deno.json @@ -1,19 +1,14 @@ { "extends": "./tsconfig.json", - "include": ["deno"], + "include": ["dist-deno"], "exclude": [], "compilerOptions": { - "rootDir": "./deno", + "rootDir": "./dist-deno", "lib": ["es2020", "DOM"], - "paths": { - "bklt/_shims/auto/*": ["deno/_shims/auto/*-deno"], - "bklt/*": ["deno/*"], - "bklt": ["deno/index.ts"], - }, "noEmit": true, "declaration": true, "declarationMap": true, - "outDir": "deno", + "outDir": "dist-deno", "pretty": true, "sourceMap": true } diff --git a/tsconfig.json b/tsconfig.json index bd3ecd0..63d87a2 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -11,7 +11,7 @@ "paths": { "bklt/_shims/auto/*": ["src/_shims/auto/*-node"], "bklt/*": ["src/*"], - "bklt": ["src/index.ts"], + "bklt": ["src/index.ts"] }, "noEmit": true, @@ -32,6 +32,7 @@ "noUncheckedIndexedAccess": true, "noImplicitOverride": true, "noPropertyAccessFromIndexSignature": true, + "isolatedModules": false, "skipLibCheck": true } diff --git a/yarn.lock b/yarn.lock index dda4d2e..14e8a75 100644 --- a/yarn.lock +++ b/yarn.lock @@ -322,9 +322,9 @@ eslint-visitor-keys "^3.3.0" "@eslint-community/regexpp@^4.5.1": - version "4.9.0" - resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.9.0.tgz#7ccb5f58703fa61ffdcbf39e2c604a109e781162" - integrity sha512-zJmuCWj2VLBt4c25CfBIbMZLGLyhkvs7LznyVX5HfpzeocThgIj5XQK4L+g3U36mMcx8bPMhGyPpwCATamC4jQ== + version "4.11.1" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.11.1.tgz#a547badfc719eb3e5f4b556325e542fbe9d7a18f" + integrity sha512-m4DVN9ZqskZoLU5GlWZadwDnYo3vAEydiUayB9widCl9ffWx2IvPnp6n3on5rJmziJSw9Bv+Z3ChDVdMwXCY8Q== "@eslint-community/regexpp@^4.6.1": version "4.6.2" @@ -857,9 +857,9 @@ pretty-format "^29.0.0" "@types/json-schema@^7.0.12": - version "7.0.13" - resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.13.tgz#02c24f4363176d2d18fc8b70b9f3c54aba178a85" - integrity sha512-RbSSoHliUbnXj3ny0CNFOoxrIDV6SUGyStHsvDqosw6CkdPV8TtWGlfecuK4ToyMEAql6pzNxgCFKanovUzlgQ== + version "7.0.15" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" + integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== "@types/node-fetch@^2.6.4": version "2.6.4" @@ -882,9 +882,9 @@ integrity sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA== "@types/semver@^7.5.0": - version "7.5.3" - resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.3.tgz#9a726e116beb26c24f1ccd6850201e1246122e04" - integrity sha512-OxepLK9EuNEIPxWNME+C6WwbRAOOI2o2BaQEGzz5Lu2e4Z5eDnEo+/aVEDMIXywoJitJ7xWd641wrGLZdtwRyw== + version "7.5.8" + resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.8.tgz#8268a8c57a3e4abd25c165ecd36237db7948a55e" + integrity sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ== "@types/stack-utils@^2.0.0": version "2.0.3" @@ -904,15 +904,15 @@ "@types/yargs-parser" "*" "@typescript-eslint/eslint-plugin@^6.7.0": - version "6.7.3" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.7.3.tgz#d98046e9f7102d49a93d944d413c6055c47fafd7" - integrity sha512-vntq452UHNltxsaaN+L9WyuMch8bMd9CqJ3zhzTPXXidwbf5mqqKCVXEuvRZUqLJSTLeWE65lQwyXsRGnXkCTA== + version "6.21.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.21.0.tgz#30830c1ca81fd5f3c2714e524c4303e0194f9cd3" + integrity sha512-oy9+hTPCUFpngkEZUSzbf9MxI65wbKFoQYsgPdILTfbUldp5ovUuphZVe4i30emU9M/kP+T64Di0mxl7dSw3MA== dependencies: "@eslint-community/regexpp" "^4.5.1" - "@typescript-eslint/scope-manager" "6.7.3" - "@typescript-eslint/type-utils" "6.7.3" - "@typescript-eslint/utils" "6.7.3" - "@typescript-eslint/visitor-keys" "6.7.3" + "@typescript-eslint/scope-manager" "6.21.0" + "@typescript-eslint/type-utils" "6.21.0" + "@typescript-eslint/utils" "6.21.0" + "@typescript-eslint/visitor-keys" "6.21.0" debug "^4.3.4" graphemer "^1.4.0" ignore "^5.2.4" @@ -921,71 +921,72 @@ ts-api-utils "^1.0.1" "@typescript-eslint/parser@^6.7.0": - version "6.7.3" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-6.7.3.tgz#aaf40092a32877439e5957e18f2d6a91c82cc2fd" - integrity sha512-TlutE+iep2o7R8Lf+yoer3zU6/0EAUc8QIBB3GYBc1KGz4c4TRm83xwXUZVPlZ6YCLss4r77jbu6j3sendJoiQ== - dependencies: - "@typescript-eslint/scope-manager" "6.7.3" - "@typescript-eslint/types" "6.7.3" - "@typescript-eslint/typescript-estree" "6.7.3" - "@typescript-eslint/visitor-keys" "6.7.3" + version "6.21.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-6.21.0.tgz#af8fcf66feee2edc86bc5d1cf45e33b0630bf35b" + integrity sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ== + dependencies: + "@typescript-eslint/scope-manager" "6.21.0" + "@typescript-eslint/types" "6.21.0" + "@typescript-eslint/typescript-estree" "6.21.0" + "@typescript-eslint/visitor-keys" "6.21.0" debug "^4.3.4" -"@typescript-eslint/scope-manager@6.7.3": - version "6.7.3" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-6.7.3.tgz#07e5709c9bdae3eaf216947433ef97b3b8b7d755" - integrity sha512-wOlo0QnEou9cHO2TdkJmzF7DFGvAKEnB82PuPNHpT8ZKKaZu6Bm63ugOTn9fXNJtvuDPanBc78lGUGGytJoVzQ== +"@typescript-eslint/scope-manager@6.21.0": + version "6.21.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz#ea8a9bfc8f1504a6ac5d59a6df308d3a0630a2b1" + integrity sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg== dependencies: - "@typescript-eslint/types" "6.7.3" - "@typescript-eslint/visitor-keys" "6.7.3" + "@typescript-eslint/types" "6.21.0" + "@typescript-eslint/visitor-keys" "6.21.0" -"@typescript-eslint/type-utils@6.7.3": - version "6.7.3" - resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-6.7.3.tgz#c2c165c135dda68a5e70074ade183f5ad68f3400" - integrity sha512-Fc68K0aTDrKIBvLnKTZ5Pf3MXK495YErrbHb1R6aTpfK5OdSFj0rVN7ib6Tx6ePrZ2gsjLqr0s98NG7l96KSQw== +"@typescript-eslint/type-utils@6.21.0": + version "6.21.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-6.21.0.tgz#6473281cfed4dacabe8004e8521cee0bd9d4c01e" + integrity sha512-rZQI7wHfao8qMX3Rd3xqeYSMCL3SoiSQLBATSiVKARdFGCYSRvmViieZjqc58jKgs8Y8i9YvVVhRbHSTA4VBag== dependencies: - "@typescript-eslint/typescript-estree" "6.7.3" - "@typescript-eslint/utils" "6.7.3" + "@typescript-eslint/typescript-estree" "6.21.0" + "@typescript-eslint/utils" "6.21.0" debug "^4.3.4" ts-api-utils "^1.0.1" -"@typescript-eslint/types@6.7.3": - version "6.7.3" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-6.7.3.tgz#0402b5628a63f24f2dc9d4a678e9a92cc50ea3e9" - integrity sha512-4g+de6roB2NFcfkZb439tigpAMnvEIg3rIjWQ+EM7IBaYt/CdJt6em9BJ4h4UpdgaBWdmx2iWsafHTrqmgIPNw== +"@typescript-eslint/types@6.21.0": + version "6.21.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-6.21.0.tgz#205724c5123a8fef7ecd195075fa6e85bac3436d" + integrity sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg== -"@typescript-eslint/typescript-estree@6.7.3": - version "6.7.3" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-6.7.3.tgz#ec5bb7ab4d3566818abaf0e4a8fa1958561b7279" - integrity sha512-YLQ3tJoS4VxLFYHTw21oe1/vIZPRqAO91z6Uv0Ss2BKm/Ag7/RVQBcXTGcXhgJMdA4U+HrKuY5gWlJlvoaKZ5g== +"@typescript-eslint/typescript-estree@6.21.0": + version "6.21.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz#c47ae7901db3b8bddc3ecd73daff2d0895688c46" + integrity sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ== dependencies: - "@typescript-eslint/types" "6.7.3" - "@typescript-eslint/visitor-keys" "6.7.3" + "@typescript-eslint/types" "6.21.0" + "@typescript-eslint/visitor-keys" "6.21.0" debug "^4.3.4" globby "^11.1.0" is-glob "^4.0.3" + minimatch "9.0.3" semver "^7.5.4" ts-api-utils "^1.0.1" -"@typescript-eslint/utils@6.7.3": - version "6.7.3" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-6.7.3.tgz#96c655816c373135b07282d67407cb577f62e143" - integrity sha512-vzLkVder21GpWRrmSR9JxGZ5+ibIUSudXlW52qeKpzUEQhRSmyZiVDDj3crAth7+5tmN1ulvgKaCU2f/bPRCzg== +"@typescript-eslint/utils@6.21.0": + version "6.21.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-6.21.0.tgz#4714e7a6b39e773c1c8e97ec587f520840cd8134" + integrity sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ== dependencies: "@eslint-community/eslint-utils" "^4.4.0" "@types/json-schema" "^7.0.12" "@types/semver" "^7.5.0" - "@typescript-eslint/scope-manager" "6.7.3" - "@typescript-eslint/types" "6.7.3" - "@typescript-eslint/typescript-estree" "6.7.3" + "@typescript-eslint/scope-manager" "6.21.0" + "@typescript-eslint/types" "6.21.0" + "@typescript-eslint/typescript-estree" "6.21.0" semver "^7.5.4" -"@typescript-eslint/visitor-keys@6.7.3": - version "6.7.3" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-6.7.3.tgz#83809631ca12909bd2083558d2f93f5747deebb2" - integrity sha512-HEVXkU9IB+nk9o63CeICMHxFWbHWr3E1mpilIQBe9+7L/lH97rleFLVtYsfnWB+JVMaiFnEaxvknvmIzX+CqVg== +"@typescript-eslint/visitor-keys@6.21.0": + version "6.21.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz#87a99d077aa507e20e238b11d56cc26ade45fe47" + integrity sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A== dependencies: - "@typescript-eslint/types" "6.7.3" + "@typescript-eslint/types" "6.21.0" eslint-visitor-keys "^3.4.1" abort-controller@^3.0.0: @@ -1200,12 +1201,12 @@ brace-expansion@^2.0.1: dependencies: balanced-match "^1.0.0" -braces@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" - integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== +braces@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" + integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== dependencies: - fill-range "^7.0.1" + fill-range "^7.1.1" browserslist@^4.22.2: version "4.22.2" @@ -1392,13 +1393,20 @@ cross-spawn@^7.0.2, cross-spawn@^7.0.3: shebang-command "^2.0.0" which "^2.0.1" -debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4: +debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2: version "4.3.4" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== dependencies: ms "2.1.2" +debug@^4.3.4: + version "4.3.7" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.7.tgz#87945b4151a011d76d95a198d7111c865c360a52" + integrity sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ== + dependencies: + ms "^2.1.3" + dedent@^1.0.0: version "1.5.1" resolved "https://registry.yarnpkg.com/dedent/-/dedent-1.5.1.tgz#4f3fc94c8b711e9bb2800d185cd6ad20f2a90aff" @@ -1546,12 +1554,7 @@ eslint-scope@^7.2.2: esrecurse "^4.3.0" estraverse "^5.2.0" -eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1: - version "3.4.2" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.2.tgz#8c2095440eca8c933bedcadf16fefa44dbe9ba5f" - integrity sha512-8drBzUEyZ2llkpCA67iYrgEssKDUu68V8ChqqOfFupIaG/LCVPUT+CoGJpT77zJprs4T/W7p07LP7zAIMuweVw== - -eslint-visitor-keys@^3.4.3: +eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4.3: version "3.4.3" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== @@ -1709,18 +1712,7 @@ fast-glob@^3.2.12: merge2 "^1.3.0" micromatch "^4.0.4" -fast-glob@^3.2.9: - version "3.3.1" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.1.tgz#784b4e897340f3dbbef17413b3f11acf03c874c4" - integrity sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg== - dependencies: - "@nodelib/fs.stat" "^2.0.2" - "@nodelib/fs.walk" "^1.2.3" - glob-parent "^5.1.2" - merge2 "^1.3.0" - micromatch "^4.0.4" - -fast-glob@^3.3.0: +fast-glob@^3.2.9, fast-glob@^3.3.0: version "3.3.2" resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129" integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow== @@ -1742,9 +1734,9 @@ fast-levenshtein@^2.0.6: integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== fastq@^1.6.0: - version "1.15.0" - resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.15.0.tgz#d04d07c6a2a68fe4599fea8d2e103a937fae6b3a" - integrity sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw== + version "1.17.1" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.17.1.tgz#2a523f07a4e7b1e81a42b91b8bf2254107753b47" + integrity sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w== dependencies: reusify "^1.0.4" @@ -1762,10 +1754,10 @@ file-entry-cache@^6.0.1: dependencies: flat-cache "^3.0.4" -fill-range@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" - integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== +fill-range@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" + integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== dependencies: to-regex-range "^5.0.1" @@ -1959,10 +1951,17 @@ humanize-ms@^1.2.1: dependencies: ms "^2.0.0" +iconv-lite@^0.6.3: + version "0.6.3" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" + integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== + dependencies: + safer-buffer ">= 2.1.2 < 3.0.0" + ignore@^5.2.0, ignore@^5.2.4: - version "5.2.4" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.4.tgz#a291c0c6178ff1b960befe47fcdec301674a6324" - integrity sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ== + version "5.3.2" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5" + integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g== import-fresh@^3.2.1: version "3.3.0" @@ -2638,11 +2637,11 @@ merge2@^1.3.0, merge2@^1.4.1: integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== micromatch@^4.0.4: - version "4.0.5" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" - integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== + version "4.0.8" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" + integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== dependencies: - braces "^3.0.2" + braces "^3.0.3" picomatch "^2.3.1" mime-db@1.51.0: @@ -2667,6 +2666,13 @@ mimic-fn@^4.0.0: resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-4.0.0.tgz#60a90550d5cb0b239cca65d893b1a53b29871ecc" integrity sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw== +minimatch@9.0.3: + version "9.0.3" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.3.tgz#a6e00c3de44c3a542bfaae70abfc22420a6da825" + integrity sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg== + dependencies: + brace-expansion "^2.0.1" + minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" @@ -2696,7 +2702,7 @@ ms@2.1.2: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -ms@^2.0.0: +ms@^2.0.0, ms@^2.1.3: version "2.1.3" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== @@ -3041,18 +3047,28 @@ safe-buffer@~5.2.0: resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== +"safer-buffer@>= 2.1.2 < 3.0.0": + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + semver@^6.3.0, semver@^6.3.1: version "6.3.1" resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== -semver@^7.5.3, semver@^7.5.4: +semver@^7.5.3: version "7.5.4" resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e" integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== dependencies: lru-cache "^6.0.0" +semver@^7.5.4: + version "7.6.3" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143" + integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== + shebang-command@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" @@ -3249,9 +3265,9 @@ tr46@~0.0.3: integrity sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o= ts-api-utils@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.0.3.tgz#f12c1c781d04427313dbac808f453f050e54a331" - integrity sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg== + version "1.3.0" + resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.3.0.tgz#4b490e27129f1e8e686b45cc4ab63714dc60eea1" + integrity sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ== ts-jest@^29.1.0: version "29.1.1" @@ -3412,11 +3428,6 @@ web-streams-polyfill@4.0.0-beta.1: resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.1.tgz#3b19b9817374b7cee06d374ba7eeb3aeb80e8c95" integrity sha512-3ux37gEX670UUphBF9AMCq8XM6iQ8Ac6A+DSRRjDoRBm1ufCkaCDdNVbaqq60PsEkdNlLKrGtv/YBP4EJXqNtQ== -web-streams-polyfill@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz#71c2718c52b45fd49dbeee88634b3a60ceab42a6" - integrity sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q== - webidl-conversions@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" From 935749842956eda69d60880005b43790945da997 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 12 Nov 2024 03:12:32 +0000 Subject: [PATCH 04/20] chore: rebuild project due to codegen change (#9) --- src/index.ts | 35 ++++++++++++++++------------------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/src/index.ts b/src/index.ts index d4c845e..99c2416 100644 --- a/src/index.ts +++ b/src/index.ts @@ -165,6 +165,21 @@ export class Booklet extends Core.APIClient { static fileFromPath = Uploads.fileFromPath; } +Booklet.Members = Members; +export declare namespace Booklet { + export type RequestOptions = Core.RequestOptions; + + export { + Members as Members, + type MemberRetrieveResponse as MemberRetrieveResponse, + type MemberListResponse as MemberListResponse, + type MemberCreateParams as MemberCreateParams, + type MemberUpdateParams as MemberUpdateParams, + type MemberListParams as MemberListParams, + }; +} + +export { toFile, fileFromPath } from 'bklt/uploads'; export { BookletError, APIError, @@ -179,24 +194,6 @@ export { InternalServerError, PermissionDeniedError, UnprocessableEntityError, -} from './error'; - -export import toFile = Uploads.toFile; -export import fileFromPath = Uploads.fileFromPath; - -Booklet.Members = Members; - -export declare namespace Booklet { - export type RequestOptions = Core.RequestOptions; - - export { - Members as Members, - type MemberRetrieveResponse as MemberRetrieveResponse, - type MemberListResponse as MemberListResponse, - type MemberCreateParams as MemberCreateParams, - type MemberUpdateParams as MemberUpdateParams, - type MemberListParams as MemberListParams, - }; -} +} from 'bklt/error'; export default Booklet; From 21d7ffdf216113e48b5d0ece5ad9ca7768e5bb03 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 15 Nov 2024 02:50:34 +0000 Subject: [PATCH 05/20] chore: rebuild project due to codegen change (#10) --- package.json | 1 - src/index.ts | 4 ++-- yarn.lock | 40 ---------------------------------------- 3 files changed, 2 insertions(+), 43 deletions(-) diff --git a/package.json b/package.json index f5eb2b8..30fbe6e 100644 --- a/package.json +++ b/package.json @@ -45,7 +45,6 @@ "jest": "^29.4.0", "prettier": "^3.0.0", "ts-jest": "^29.1.0", - "ts-morph": "^19.0.0", "ts-node": "^10.5.0", "tsc-multi": "^1.1.0", "tsconfig-paths": "^4.0.0", diff --git a/src/index.ts b/src/index.ts index 99c2416..e3ed2fe 100644 --- a/src/index.ts +++ b/src/index.ts @@ -179,7 +179,7 @@ export declare namespace Booklet { }; } -export { toFile, fileFromPath } from 'bklt/uploads'; +export { toFile, fileFromPath } from './uploads'; export { BookletError, APIError, @@ -194,6 +194,6 @@ export { InternalServerError, PermissionDeniedError, UnprocessableEntityError, -} from 'bklt/error'; +} from './error'; export default Booklet; diff --git a/yarn.lock b/yarn.lock index 14e8a75..bfd47d8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -759,16 +759,6 @@ dependencies: "@swc/counter" "^0.1.3" -"@ts-morph/common@~0.20.0": - version "0.20.0" - resolved "https://registry.yarnpkg.com/@ts-morph/common/-/common-0.20.0.tgz#3f161996b085ba4519731e4d24c35f6cba5b80af" - integrity sha512-7uKjByfbPpwuzkstL3L5MQyuXPSKdoNG93Fmi2JoDcTf3pEP731JdRFAduRVkOs8oqxPsXKA+ScrWkdQ8t/I+Q== - dependencies: - fast-glob "^3.2.12" - minimatch "^7.4.3" - mkdirp "^2.1.6" - path-browserify "^1.0.1" - "@tsconfig/node10@^1.0.7": version "1.0.8" resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.8.tgz#c1e4e80d6f964fbecb3359c43bd48b40f7cadad9" @@ -1315,11 +1305,6 @@ co@^4.6.0: resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" integrity sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ== -code-block-writer@^12.0.0: - version "12.0.0" - resolved "https://registry.yarnpkg.com/code-block-writer/-/code-block-writer-12.0.0.tgz#4dd58946eb4234105aff7f0035977b2afdc2a770" - integrity sha512-q4dMFMlXtKR3XNBHyMHt/3pwYNA69EDk00lloMOaaUMKPUXBw6lpXtbu3MMVG6/uOihGnRDOlkyqsONEUj60+w== - collect-v8-coverage@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz#c0b29bcd33bcd0779a1344c2136051e6afd3d9e9" @@ -2680,23 +2665,11 @@ minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: dependencies: brace-expansion "^1.1.7" -minimatch@^7.4.3: - version "7.4.6" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-7.4.6.tgz#845d6f254d8f4a5e4fd6baf44d5f10c8448365fb" - integrity sha512-sBz8G/YjVniEz6lKPNpKxXwazJe4c19fEfV2GDMX6AjFz+MX9uDWIZW8XreVhkFW3fkIdTv/gxWr/Kks5FFAVw== - dependencies: - brace-expansion "^2.0.1" - minimist@^1.2.6: version "1.2.6" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== -mkdirp@^2.1.6: - version "2.1.6" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-2.1.6.tgz#964fbcb12b2d8c5d6fbc62a963ac95a273e2cc19" - integrity sha512-+hEnITedc8LAtIP9u3HJDFIdcLV2vXP33sqLLIzkv1Db1zO/1OxbvYf0Y1OC/S/Qo5dxHXepofhmxL02PsKe+A== - ms@2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" @@ -2860,11 +2833,6 @@ parse-json@^5.2.0: json-parse-even-better-errors "^2.3.0" lines-and-columns "^1.1.6" -path-browserify@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-1.0.1.tgz#d98454a9c3753d5790860f16f68867b9e46be1fd" - integrity sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g== - path-exists@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" @@ -3283,14 +3251,6 @@ ts-jest@^29.1.0: semver "^7.5.3" yargs-parser "^21.0.1" -ts-morph@^19.0.0: - version "19.0.0" - resolved "https://registry.yarnpkg.com/ts-morph/-/ts-morph-19.0.0.tgz#43e95fb0156c3fe3c77c814ac26b7d0be2f93169" - integrity sha512-D6qcpiJdn46tUqV45vr5UGM2dnIEuTGNxVhg0sk5NX11orcouwj6i1bMqZIz2mZTZB1Hcgy7C3oEVhAT+f6mbQ== - dependencies: - "@ts-morph/common" "~0.20.0" - code-block-writer "^12.0.0" - ts-node@^10.5.0: version "10.7.0" resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.7.0.tgz#35d503d0fab3e2baa672a0e94f4b40653c2463f5" From b8d13794f060c11e57c83f262a5b305ca215f8ed Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 15 Nov 2024 20:09:11 +0000 Subject: [PATCH 06/20] chore: rebuild project due to codegen change (#11) --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index 89717d5..ad300eb 100644 --- a/README.md +++ b/README.md @@ -279,6 +279,15 @@ TypeScript >= 4.5 is supported. The following runtimes are supported: +- Web browsers (Up-to-date Chrome, Firefox, Safari, Edge, and more) +- Node.js 18 LTS or later ([non-EOL](https://endoflife.date/nodejs)) versions. +- Deno v1.28.0 or higher, using `import Booklet from "npm:bklt"`. +- Bun 1.0 or later. +- Cloudflare Workers. +- Vercel Edge Runtime. +- Jest 28 or greater with the `"node"` environment (`"jsdom"` is not supported at this time). +- Nitro v2.6 or greater. + Note that React Native is not supported at this time. If you are interested in other runtime environments, please open or upvote an issue on GitHub. From c23a86fd4ba036653925f16d330093a404e46a80 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 20 Nov 2024 05:28:13 +0000 Subject: [PATCH 07/20] docs: remove suggestion to use `npm` call out (#12) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ad300eb..fbd0653 100644 --- a/README.md +++ b/README.md @@ -281,7 +281,7 @@ The following runtimes are supported: - Web browsers (Up-to-date Chrome, Firefox, Safari, Edge, and more) - Node.js 18 LTS or later ([non-EOL](https://endoflife.date/nodejs)) versions. -- Deno v1.28.0 or higher, using `import Booklet from "npm:bklt"`. +- Deno v1.28.0 or higher. - Bun 1.0 or later. - Cloudflare Workers. - Vercel Edge Runtime. From 7569cd546273316f4de5fad7507aee4c84c9496e Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 20 Nov 2024 05:32:03 +0000 Subject: [PATCH 08/20] chore: remove redundant word in comment (#13) --- scripts/build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/build b/scripts/build index 37c90a0..f69a852 100755 --- a/scripts/build +++ b/scripts/build @@ -32,7 +32,7 @@ npm exec tsc-multi # copy over handwritten .js/.mjs/.d.ts files cp src/_shims/*.{d.ts,js,mjs,md} dist/_shims cp src/_shims/auto/*.{d.ts,js,mjs} dist/_shims/auto -# we need to add exports = module.exports = Booklet Node to index.js; +# we need to add exports = module.exports = Booklet to index.js; # No way to get that from index.ts because it would cause compile errors # when building .mjs node scripts/utils/fix-index-exports.cjs From 7be6b86ff0f49a2dcbdc9c19927770e38004ca3c Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 28 Nov 2024 10:04:58 +0000 Subject: [PATCH 09/20] feat(internal): make git install file structure match npm (#14) --- package.json | 2 +- scripts/utils/check-is-in-git-install.sh | 2 +- scripts/utils/git-swap.sh | 13 +++++++++++++ 3 files changed, 15 insertions(+), 2 deletions(-) create mode 100755 scripts/utils/git-swap.sh diff --git a/package.json b/package.json index 30fbe6e..030103a 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ "build": "./scripts/build", "prepublishOnly": "echo 'to publish, run yarn build && (cd dist; yarn publish)' && exit 1", "format": "prettier --write --cache --cache-strategy metadata . !dist", - "prepare": "if ./scripts/utils/check-is-in-git-install.sh; then ./scripts/build; fi", + "prepare": "if ./scripts/utils/check-is-in-git-install.sh; then ./scripts/build && ./scripts/utils/git-swap.sh; fi", "tsn": "ts-node -r tsconfig-paths/register", "lint": "./scripts/lint", "fix": "./scripts/format" diff --git a/scripts/utils/check-is-in-git-install.sh b/scripts/utils/check-is-in-git-install.sh index 36bcedc..1354eb4 100755 --- a/scripts/utils/check-is-in-git-install.sh +++ b/scripts/utils/check-is-in-git-install.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # Check if you happen to call prepare for a repository that's already in node_modules. [ "$(basename "$(dirname "$PWD")")" = 'node_modules' ] || # The name of the containing directory that 'npm` uses, which looks like diff --git a/scripts/utils/git-swap.sh b/scripts/utils/git-swap.sh new file mode 100755 index 0000000..79d1888 --- /dev/null +++ b/scripts/utils/git-swap.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +set -exuo pipefail +# the package is published to NPM from ./dist +# we want the final file structure for git installs to match the npm installs, so we + +# delete everything except ./dist and ./node_modules +find . -maxdepth 1 -mindepth 1 ! -name 'dist' ! -name 'node_modules' -exec rm -rf '{}' + + +# move everything from ./dist to . +mv dist/* . + +# delete the now-empty ./dist +rmdir dist From fb6add5b2815fa11a00fefb1ec3b6e5f19d5bf89 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 10 Dec 2024 11:25:38 +0000 Subject: [PATCH 10/20] chore(internal): remove unnecessary getRequestClient function (#15) --- src/core.ts | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/core.ts b/src/core.ts index cf445b1..e66c71c 100644 --- a/src/core.ts +++ b/src/core.ts @@ -523,19 +523,13 @@ export abstract class APIClient { const timeout = setTimeout(() => controller.abort(), ms); return ( - this.getRequestClient() - // use undefined this binding; fetch errors if bound to something else in browser/cloudflare - .fetch.call(undefined, url, { signal: controller.signal as any, ...options }) - .finally(() => { - clearTimeout(timeout); - }) + // use undefined this binding; fetch errors if bound to something else in browser/cloudflare + this.fetch.call(undefined, url, { signal: controller.signal as any, ...options }).finally(() => { + clearTimeout(timeout); + }) ); } - protected getRequestClient(): RequestClient { - return { fetch: this.fetch }; - } - private shouldRetry(response: Response): boolean { // Note this is not a standard header. const shouldRetryHeader = response.headers.get('x-should-retry'); From e65eb1996762efc9cbab31ed900dad0ef6a8b71d Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 11 Dec 2024 10:06:44 +0000 Subject: [PATCH 11/20] chore(internal): bump cross-spawn to v7.0.6 (#16) Note: it is a dev transitive dependency. --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index bfd47d8..bb17942 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1370,9 +1370,9 @@ create-require@^1.1.0: integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== cross-spawn@^7.0.2, cross-spawn@^7.0.3: - version "7.0.3" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" - integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== + version "7.0.6" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f" + integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA== dependencies: path-key "^3.1.0" shebang-command "^2.0.0" From 56b53550e582c2b91a99aea3cb8f3460478e6839 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 12 Dec 2024 09:55:26 +0000 Subject: [PATCH 12/20] chore(types): nicer error class types + jsdocs (#17) --- src/error.ts | 64 ++++++++++++++++++++-------------------------------- 1 file changed, 24 insertions(+), 40 deletions(-) diff --git a/src/error.ts b/src/error.ts index d1e8ec5..0f06950 100644 --- a/src/error.ts +++ b/src/error.ts @@ -4,17 +4,19 @@ import { castToError, Headers } from './core'; export class BookletError extends Error {} -export class APIError extends BookletError { - readonly status: number | undefined; - readonly headers: Headers | undefined; - readonly error: Object | undefined; - - constructor( - status: number | undefined, - error: Object | undefined, - message: string | undefined, - headers: Headers | undefined, - ) { +export class APIError< + TStatus extends number | undefined = number | undefined, + THeaders extends Headers | undefined = Headers | undefined, + TError extends Object | undefined = Object | undefined, +> extends BookletError { + /** HTTP status for the response that caused the error */ + readonly status: TStatus; + /** HTTP headers for the response that caused the error */ + readonly headers: THeaders; + /** JSON body of the response that caused the error */ + readonly error: TError; + + constructor(status: TStatus, error: TError, message: string | undefined, headers: THeaders) { super(`${APIError.makeMessage(status, error, message)}`); this.status = status; this.headers = headers; @@ -48,7 +50,7 @@ export class APIError extends BookletError { message: string | undefined, headers: Headers | undefined, ): APIError { - if (!status) { + if (!status || !headers) { return new APIConnectionError({ message, cause: castToError(errorResponse) }); } @@ -90,17 +92,13 @@ export class APIError extends BookletError { } } -export class APIUserAbortError extends APIError { - override readonly status: undefined = undefined; - +export class APIUserAbortError extends APIError { constructor({ message }: { message?: string } = {}) { super(undefined, undefined, message || 'Request was aborted.', undefined); } } -export class APIConnectionError extends APIError { - override readonly status: undefined = undefined; - +export class APIConnectionError extends APIError { constructor({ message, cause }: { message?: string | undefined; cause?: Error | undefined }) { super(undefined, undefined, message || 'Connection error.', undefined); // in some environments the 'cause' property is already declared @@ -115,32 +113,18 @@ export class APIConnectionTimeoutError extends APIConnectionError { } } -export class BadRequestError extends APIError { - override readonly status: 400 = 400; -} +export class BadRequestError extends APIError<400, Headers> {} -export class AuthenticationError extends APIError { - override readonly status: 401 = 401; -} +export class AuthenticationError extends APIError<401, Headers> {} -export class PermissionDeniedError extends APIError { - override readonly status: 403 = 403; -} +export class PermissionDeniedError extends APIError<403, Headers> {} -export class NotFoundError extends APIError { - override readonly status: 404 = 404; -} +export class NotFoundError extends APIError<404, Headers> {} -export class ConflictError extends APIError { - override readonly status: 409 = 409; -} +export class ConflictError extends APIError<409, Headers> {} -export class UnprocessableEntityError extends APIError { - override readonly status: 422 = 422; -} +export class UnprocessableEntityError extends APIError<422, Headers> {} -export class RateLimitError extends APIError { - override readonly status: 429 = 429; -} +export class RateLimitError extends APIError<429, Headers> {} -export class InternalServerError extends APIError {} +export class InternalServerError extends APIError {} From 444c551093f053027d44cafb2fafb7b2f889adcd Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 12 Dec 2024 09:57:50 +0000 Subject: [PATCH 13/20] chore(internal): update isAbsoluteURL (#18) --- src/core.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core.ts b/src/core.ts index e66c71c..3f8d77b 100644 --- a/src/core.ts +++ b/src/core.ts @@ -970,8 +970,8 @@ export const safeJSON = (text: string) => { } }; -// https://stackoverflow.com/a/19709846 -const startsWithSchemeRegexp = new RegExp('^(?:[a-z]+:)?//', 'i'); +// https://url.spec.whatwg.org/#url-scheme-string +const startsWithSchemeRegexp = /^[a-z][a-z0-9+.-]*:/i; const isAbsoluteURL = (url: string): boolean => { return startsWithSchemeRegexp.test(url); }; From a9637a67a5691574b1f9256112e2a07460898751 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 18 Dec 2024 09:50:34 +0000 Subject: [PATCH 14/20] chore(internal): codegen related update (#19) --- src/core.ts | 4 ++-- tests/index.test.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/core.ts b/src/core.ts index 3f8d77b..5e726c5 100644 --- a/src/core.ts +++ b/src/core.ts @@ -163,7 +163,7 @@ export abstract class APIClient { maxRetries = 2, timeout = 60000, // 1 minute httpAgent, - fetch: overridenFetch, + fetch: overriddenFetch, }: { baseURL: string; maxRetries?: number | undefined; @@ -176,7 +176,7 @@ export abstract class APIClient { this.timeout = validatePositiveInteger('timeout', timeout); this.httpAgent = httpAgent; - this.fetch = overridenFetch ?? fetch; + this.fetch = overriddenFetch ?? fetch; } protected authHeaders(opts: FinalRequestOptions): Headers { diff --git a/tests/index.test.ts b/tests/index.test.ts index 184cb90..17b7c86 100644 --- a/tests/index.test.ts +++ b/tests/index.test.ts @@ -177,7 +177,7 @@ describe('instantiate client', () => { expect(client.apiKey).toBe('My API Key'); }); - test('with overriden environment variable arguments', () => { + test('with overridden environment variable arguments', () => { // set options via env var process.env['BOOKLET_API_KEY'] = 'another My API Key'; const client = new Booklet({ apiKey: 'My API Key' }); From d9d12fdd69451ad2ba1a2173d1ed261540835d1b Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 20 Dec 2024 09:48:06 +0000 Subject: [PATCH 15/20] fix(client): normalize method (#20) --- src/core.ts | 12 +++++++++++- tests/index.test.ts | 13 +++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/core.ts b/src/core.ts index 5e726c5..46ea6ac 100644 --- a/src/core.ts +++ b/src/core.ts @@ -522,9 +522,19 @@ export abstract class APIClient { const timeout = setTimeout(() => controller.abort(), ms); + const fetchOptions = { + signal: controller.signal as any, + ...options, + }; + if (fetchOptions.method) { + // Custom methods like 'patch' need to be uppercased + // See https://github.com/nodejs/undici/issues/2294 + fetchOptions.method = fetchOptions.method.toUpperCase(); + } + return ( // use undefined this binding; fetch errors if bound to something else in browser/cloudflare - this.fetch.call(undefined, url, { signal: controller.signal as any, ...options }).finally(() => { + this.fetch.call(undefined, url, fetchOptions).finally(() => { clearTimeout(timeout); }) ); diff --git a/tests/index.test.ts b/tests/index.test.ts index 17b7c86..d55906e 100644 --- a/tests/index.test.ts +++ b/tests/index.test.ts @@ -122,6 +122,19 @@ describe('instantiate client', () => { expect(spy).toHaveBeenCalledTimes(1); }); + test('normalized method', async () => { + let capturedRequest: RequestInit | undefined; + const testFetch = async (url: RequestInfo, init: RequestInit = {}): Promise => { + capturedRequest = init; + return new Response(JSON.stringify({}), { headers: { 'Content-Type': 'application/json' } }); + }; + + const client = new Booklet({ baseURL: 'http://localhost:5000/', apiKey: 'My API Key', fetch: testFetch }); + + await client.patch('/foo'); + expect(capturedRequest?.method).toEqual('PATCH'); + }); + describe('baseUrl', () => { test('trailing slash', () => { const client = new Booklet({ baseURL: 'http://localhost:5000/custom/path/', apiKey: 'My API Key' }); From f6c9ebdb532a7a44740a10c05116a495e1f6d4c2 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 21 Dec 2024 09:37:02 +0000 Subject: [PATCH 16/20] chore(internal): codegen related update (#21) --- CONTRIBUTING.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 30d3519..499e89c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,6 +1,6 @@ ## Setting up the environment -This repository uses [`yarn@v1`](https://classic.yarnpkg.com/lang/en/docs/install/#mac-stable). +This repository uses [`yarn@v1`](https://classic.yarnpkg.com/lang/en/docs/install). Other package managers may work but are not officially supported for development. To set up the repository, run: @@ -29,10 +29,10 @@ All files in the `examples/` directory are not modified by the generator and can … ``` -``` -chmod +x examples/.ts +```sh +$ chmod +x examples/.ts # run the example against your api -yarn tsn -T examples/.ts +$ yarn tsn -T examples/.ts ``` ## Using the repository from source From 1bffa8808e2c5c8df861da259fe448247c5aa532 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 2 Jan 2025 09:23:25 +0000 Subject: [PATCH 17/20] chore(internal): codegen related update (#22) --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index b58ffc0..dd8caad 100644 --- a/LICENSE +++ b/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2024 Booklet + Copyright 2025 Booklet Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. From 7fdb428f3ed4e0ac22a7321ee94bfde4386ad029 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 10 Jan 2025 09:46:20 +0000 Subject: [PATCH 18/20] chore(internal): codegen related update (#23) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fbd0653..1a83127 100644 --- a/README.md +++ b/README.md @@ -266,7 +266,7 @@ await client.members.retrieve('REPLACE_ME', { This package generally follows [SemVer](https://semver.org/spec/v2.0.0.html) conventions, though certain backwards-incompatible changes may be released as minor versions: 1. Changes that only affect static types, without breaking runtime behavior. -2. Changes to library internals which are technically public but not intended or documented for external use. _(Please open a GitHub issue to let us know if you are relying on such internals)_. +2. Changes to library internals which are technically public but not intended or documented for external use. _(Please open a GitHub issue to let us know if you are relying on such internals.)_ 3. Changes that we do not expect to impact the vast majority of users in practice. We take backwards-compatibility seriously and work hard to ensure you can rely on a smooth upgrade experience. From eb451a5a9320d1383221d7772a15d222f7d35c54 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 18 Jan 2025 09:19:26 +0000 Subject: [PATCH 19/20] chore(internal): codegen related update (#24) --- src/index.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/index.ts b/src/index.ts index e3ed2fe..d44607e 100644 --- a/src/index.ts +++ b/src/index.ts @@ -34,7 +34,7 @@ export interface ClientOptions { * Note that request timeouts are retried by default, so in a worst-case scenario you may wait * much longer than this timeout before the promise succeeds or fails. */ - timeout?: number; + timeout?: number | undefined; /** * An HTTP agent used to manage HTTP(S) connections. @@ -42,7 +42,7 @@ export interface ClientOptions { * If not provided, an agent will be constructed by default in the Node.js environment, * otherwise no agent is used. */ - httpAgent?: Agent; + httpAgent?: Agent | undefined; /** * Specify a custom `fetch` function implementation. @@ -58,7 +58,7 @@ export interface ClientOptions { * * @default 2 */ - maxRetries?: number; + maxRetries?: number | undefined; /** * Default headers to include with every request to the API. @@ -66,7 +66,7 @@ export interface ClientOptions { * These can be removed in individual requests by explicitly setting the * header to `undefined` or `null` in request options. */ - defaultHeaders?: Core.Headers; + defaultHeaders?: Core.Headers | undefined; /** * Default query parameters to include with every request to the API. @@ -74,7 +74,7 @@ export interface ClientOptions { * These can be removed in individual requests by explicitly setting the * param to `undefined` in request options. */ - defaultQuery?: Core.DefaultQuery; + defaultQuery?: Core.DefaultQuery | undefined; } /** From 497f0a6f04d5b438c58e2f6bd8aa0093dfa28e17 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 18 Jan 2025 09:19:47 +0000 Subject: [PATCH 20/20] release: 0.1.0-alpha.1 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 38 +++++++++++++++++++++++++++++++++++ package.json | 2 +- src/version.ts | 2 +- 4 files changed, 41 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 063a4ae..d7a8735 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.0.1-alpha.1" + ".": "0.1.0-alpha.1" } diff --git a/CHANGELOG.md b/CHANGELOG.md index 656e9a9..0424898 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,43 @@ # Changelog +## 0.1.0-alpha.1 (2025-01-18) + +Full Changelog: [v0.0.1-alpha.1...v0.1.0-alpha.1](https://github.com/contraptionco/booklet-node/compare/v0.0.1-alpha.1...v0.1.0-alpha.1) + +### Features + +* **api:** OpenAPI spec update via Stainless API ([#5](https://github.com/contraptionco/booklet-node/issues/5)) ([9f9c4e6](https://github.com/contraptionco/booklet-node/commit/9f9c4e64078f331bf01e944cd565f016df9582b9)) +* **api:** update via SDK Studio ([#7](https://github.com/contraptionco/booklet-node/issues/7)) ([b4832fe](https://github.com/contraptionco/booklet-node/commit/b4832fe2213779d8f59d6f0a7191d46486d4ad93)) +* **internal:** make git install file structure match npm ([#14](https://github.com/contraptionco/booklet-node/issues/14)) ([7be6b86](https://github.com/contraptionco/booklet-node/commit/7be6b86ff0f49a2dcbdc9c19927770e38004ca3c)) + + +### Bug Fixes + +* **client:** normalize method ([#20](https://github.com/contraptionco/booklet-node/issues/20)) ([d9d12fd](https://github.com/contraptionco/booklet-node/commit/d9d12fdd69451ad2ba1a2173d1ed261540835d1b)) + + +### Chores + +* **internal:** bump cross-spawn to v7.0.6 ([#16](https://github.com/contraptionco/booklet-node/issues/16)) ([e65eb19](https://github.com/contraptionco/booklet-node/commit/e65eb1996762efc9cbab31ed900dad0ef6a8b71d)) +* **internal:** codegen related update ([#19](https://github.com/contraptionco/booklet-node/issues/19)) ([a9637a6](https://github.com/contraptionco/booklet-node/commit/a9637a67a5691574b1f9256112e2a07460898751)) +* **internal:** codegen related update ([#21](https://github.com/contraptionco/booklet-node/issues/21)) ([f6c9ebd](https://github.com/contraptionco/booklet-node/commit/f6c9ebdb532a7a44740a10c05116a495e1f6d4c2)) +* **internal:** codegen related update ([#22](https://github.com/contraptionco/booklet-node/issues/22)) ([1bffa88](https://github.com/contraptionco/booklet-node/commit/1bffa8808e2c5c8df861da259fe448247c5aa532)) +* **internal:** codegen related update ([#23](https://github.com/contraptionco/booklet-node/issues/23)) ([7fdb428](https://github.com/contraptionco/booklet-node/commit/7fdb428f3ed4e0ac22a7321ee94bfde4386ad029)) +* **internal:** codegen related update ([#24](https://github.com/contraptionco/booklet-node/issues/24)) ([eb451a5](https://github.com/contraptionco/booklet-node/commit/eb451a5a9320d1383221d7772a15d222f7d35c54)) +* **internal:** remove unnecessary getRequestClient function ([#15](https://github.com/contraptionco/booklet-node/issues/15)) ([fb6add5](https://github.com/contraptionco/booklet-node/commit/fb6add5b2815fa11a00fefb1ec3b6e5f19d5bf89)) +* **internal:** update isAbsoluteURL ([#18](https://github.com/contraptionco/booklet-node/issues/18)) ([444c551](https://github.com/contraptionco/booklet-node/commit/444c551093f053027d44cafb2fafb7b2f889adcd)) +* rebuild project due to codegen change ([#10](https://github.com/contraptionco/booklet-node/issues/10)) ([21d7ffd](https://github.com/contraptionco/booklet-node/commit/21d7ffdf216113e48b5d0ece5ad9ca7768e5bb03)) +* rebuild project due to codegen change ([#11](https://github.com/contraptionco/booklet-node/issues/11)) ([b8d1379](https://github.com/contraptionco/booklet-node/commit/b8d13794f060c11e57c83f262a5b305ca215f8ed)) +* rebuild project due to codegen change ([#8](https://github.com/contraptionco/booklet-node/issues/8)) ([42c5432](https://github.com/contraptionco/booklet-node/commit/42c5432581e52d934a3e5bc8828c2e68a8f569ec)) +* rebuild project due to codegen change ([#9](https://github.com/contraptionco/booklet-node/issues/9)) ([9357498](https://github.com/contraptionco/booklet-node/commit/935749842956eda69d60880005b43790945da997)) +* remove redundant word in comment ([#13](https://github.com/contraptionco/booklet-node/issues/13)) ([7569cd5](https://github.com/contraptionco/booklet-node/commit/7569cd546273316f4de5fad7507aee4c84c9496e)) +* **types:** nicer error class types + jsdocs ([#17](https://github.com/contraptionco/booklet-node/issues/17)) ([56b5355](https://github.com/contraptionco/booklet-node/commit/56b53550e582c2b91a99aea3cb8f3460478e6839)) + + +### Documentation + +* remove suggestion to use `npm` call out ([#12](https://github.com/contraptionco/booklet-node/issues/12)) ([c23a86f](https://github.com/contraptionco/booklet-node/commit/c23a86fd4ba036653925f16d330093a404e46a80)) + ## 0.0.1-alpha.1 (2024-05-09) Full Changelog: [v0.0.1-alpha.0...v0.0.1-alpha.1](https://github.com/contraptionco/booklet-node/compare/v0.0.1-alpha.0...v0.0.1-alpha.1) diff --git a/package.json b/package.json index 030103a..d162ca5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "bklt", - "version": "0.0.1-alpha.1", + "version": "0.1.0-alpha.1", "description": "The official TypeScript library for the Booklet API", "author": "Booklet ", "types": "dist/index.d.ts", diff --git a/src/version.ts b/src/version.ts index 2c77b51..b0bfd9e 100644 --- a/src/version.ts +++ b/src/version.ts @@ -1 +1 @@ -export const VERSION = '0.0.1-alpha.1'; // x-release-please-version +export const VERSION = '0.1.0-alpha.1'; // x-release-please-version