Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
b5891d2
fix(client): avoid memory leak with abort signals
stainless-app[bot] Feb 3, 2026
5f852e5
chore(client): do not parse responses with empty content-length
stainless-app[bot] Feb 3, 2026
09b3c0f
chore(client): restructure abort controller binding
stainless-app[bot] Feb 5, 2026
971bc60
fix(client): avoid removing abort listener too early
stainless-app[bot] Feb 6, 2026
8f10069
chore(internal): avoid type checking errors with ts-reset
stainless-app[bot] Feb 12, 2026
112a9ed
chore: format all `api.md` files
stainless-app[bot] Feb 13, 2026
645d7f8
chore(internal/client): fix form-urlencoded requests
stainless-app[bot] Feb 18, 2026
004672e
chore: update mock server docs
stainless-app[bot] Feb 20, 2026
0fba230
fix(docs/contributing): correct pnpm link command
stainless-app[bot] Feb 24, 2026
2cf4c15
chore(internal): move stringifyQuery implementation to internal function
stainless-app[bot] Feb 27, 2026
f66750f
chore(internal): codegen related update
stainless-app[bot] Mar 3, 2026
ffdc333
chore(internal): codegen related update
stainless-app[bot] Mar 6, 2026
3b3f3ed
chore(test): do not count install time for mock server timeout
stainless-app[bot] Mar 6, 2026
4d15af4
chore(ci): skip uploading artifacts on stainless-internal branches
stainless-app[bot] Mar 7, 2026
0aa4a14
fix(client): preserve URL params already embedded in path
stainless-app[bot] Mar 7, 2026
8b8c04d
feat(api): sync openapi spec
stainless-app[bot] Mar 9, 2026
88ffc07
feat(api): add betas back in for search
stainless-app[bot] Mar 9, 2026
2260057
release: 0.3.2
stainless-app[bot] Mar 9, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,14 +55,18 @@ jobs:
run: ./scripts/build

- name: Get GitHub OIDC Token
if: github.repository == 'stainless-sdks/parallel-sdk-typescript'
if: |-
github.repository == 'stainless-sdks/parallel-sdk-typescript' &&
!startsWith(github.ref, 'refs/heads/stl/')
id: github-oidc
uses: actions/github-script@v8
with:
script: core.setOutput('github_token', await core.getIDToken());

- name: Upload tarball
if: github.repository == 'stainless-sdks/parallel-sdk-typescript'
if: |-
github.repository == 'stainless-sdks/parallel-sdk-typescript' &&
!startsWith(github.ref, 'refs/heads/stl/')
env:
URL: https://pkg.stainless.com/s
AUTH: ${{ steps.github-oidc.outputs.github_token }}
Expand Down
2 changes: 1 addition & 1 deletion .release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
".": "0.3.1"
".": "0.3.2"
}
4 changes: 2 additions & 2 deletions .stats.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
configured_endpoints: 22
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/parallel-web%2Fparallel-sdk-31ff2f5e2e00191b8f376bd9648d8305d224493bf40dd9f0e73e6668f2558504.yml
openapi_spec_hash: de646907ddb63402755855b7e78ccbac
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/parallel-web%2Fparallel-sdk-970b780e86490322cc3c7e2b57f140ca6766a3d9f6e0d3402837ebaf7c2183fc.yml
openapi_spec_hash: 34f784ce2dec796048e6780924bae08f
config_hash: a398d153133d8884bed4e5256a0ae818
32 changes: 32 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,37 @@
# Changelog

## 0.3.2 (2026-03-09)

Full Changelog: [v0.3.1...v0.3.2](https://github.com/parallel-web/parallel-sdk-typescript/compare/v0.3.1...v0.3.2)

### Features

* **api:** add betas back in for search ([88ffc07](https://github.com/parallel-web/parallel-sdk-typescript/commit/88ffc0723b8ad725b626d47d95d45cc088a97bd9))
* **api:** sync openapi spec ([8b8c04d](https://github.com/parallel-web/parallel-sdk-typescript/commit/8b8c04d813a6f29274cb0e0a416539e0ec7aa5d4))


### Bug Fixes

* **client:** avoid memory leak with abort signals ([b5891d2](https://github.com/parallel-web/parallel-sdk-typescript/commit/b5891d2e289ba683e2f977cf52199b8185d1a375))
* **client:** avoid removing abort listener too early ([971bc60](https://github.com/parallel-web/parallel-sdk-typescript/commit/971bc60f78633e423d4434cc64cbf56a3fe2a08d))
* **client:** preserve URL params already embedded in path ([0aa4a14](https://github.com/parallel-web/parallel-sdk-typescript/commit/0aa4a148cf3bfc956a1d9de358695df75dbd214e))
* **docs/contributing:** correct pnpm link command ([0fba230](https://github.com/parallel-web/parallel-sdk-typescript/commit/0fba230efc58ec8db7e3b97e498c970e9d5a42f3))


### Chores

* **ci:** skip uploading artifacts on stainless-internal branches ([4d15af4](https://github.com/parallel-web/parallel-sdk-typescript/commit/4d15af4c852abb1422cb3b79579e4f76b837c1d4))
* **client:** do not parse responses with empty content-length ([5f852e5](https://github.com/parallel-web/parallel-sdk-typescript/commit/5f852e53c6d293dcdd940bcb1fc741b2215c5023))
* **client:** restructure abort controller binding ([09b3c0f](https://github.com/parallel-web/parallel-sdk-typescript/commit/09b3c0fdd35a41325408f2304488c41c4fcf44e4))
* format all `api.md` files ([112a9ed](https://github.com/parallel-web/parallel-sdk-typescript/commit/112a9ede4af725999c475e62a590a2273abc6dfe))
* **internal/client:** fix form-urlencoded requests ([645d7f8](https://github.com/parallel-web/parallel-sdk-typescript/commit/645d7f8e772f781bf86a77b1f35b2ddb6cd215eb))
* **internal:** avoid type checking errors with ts-reset ([8f10069](https://github.com/parallel-web/parallel-sdk-typescript/commit/8f100690328b09531482ec54e4cf38e0b0d59a9b))
* **internal:** codegen related update ([ffdc333](https://github.com/parallel-web/parallel-sdk-typescript/commit/ffdc333a95868e11c587facb0ffb3b4f68e2fbad))
* **internal:** codegen related update ([f66750f](https://github.com/parallel-web/parallel-sdk-typescript/commit/f66750f2632f5e9f32dc2e334c9472fb7aebc7a5))
* **internal:** move stringifyQuery implementation to internal function ([2cf4c15](https://github.com/parallel-web/parallel-sdk-typescript/commit/2cf4c156bfa74dd29369f77b60ab5fc4281fe1be))
* **test:** do not count install time for mock server timeout ([3b3f3ed](https://github.com/parallel-web/parallel-sdk-typescript/commit/3b3f3ed79c2ce888d831ed7a26c3a8dcde085ce0))
* update mock server docs ([004672e](https://github.com/parallel-web/parallel-sdk-typescript/commit/004672ea0157df3c026277c5d892849bb0b9a9fe))

## 0.3.1 (2026-01-28)

Full Changelog: [v0.3.0...v0.3.1](https://github.com/parallel-web/parallel-sdk-typescript/compare/v0.3.0...v0.3.1)
Expand Down
4 changes: 2 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,15 +60,15 @@ $ yarn link parallel-web
# With pnpm
$ pnpm link --global
$ cd ../my-package
$ pnpm link -global parallel-web
$ pnpm link --global parallel-web
```

## 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.

```sh
$ npx prism mock path/to/your/openapi.yml
$ ./scripts/mock
```

```sh
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ const taskRun = await client.taskRun.create({
processor: 'base',
});

console.log(taskRun.run_id);
console.log(taskRun.interaction_id);
```

### Request & Response types
Expand Down Expand Up @@ -155,7 +155,7 @@ const { data: taskRun, response: raw } = await client.taskRun
.create({ input: 'What was the GDP of France in 2023?', processor: 'base' })
.withResponse();
console.log(raw.headers.get('X-My-Header'));
console.log(taskRun.run_id);
console.log(taskRun.interaction_id);
```

### Logging
Expand Down
85 changes: 1 addition & 84 deletions api.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,87 +29,4 @@ Methods:
- <code title="get /v1/tasks/runs/{run_id}">client.taskRun.<a href="./src/resources/task-run.ts">retrieve</a>(runID) -> TaskRun</code>
- <code title="get /v1/tasks/runs/{run_id}/result">client.taskRun.<a href="./src/resources/task-run.ts">result</a>(runID, { ...params }) -> TaskRunResult</code>

# Beta

Types:

- <code><a href="./src/resources/beta/beta.ts">ExcerptSettings</a></code>
- <code><a href="./src/resources/beta/beta.ts">ExtractError</a></code>
- <code><a href="./src/resources/beta/beta.ts">ExtractResponse</a></code>
- <code><a href="./src/resources/beta/beta.ts">ExtractResult</a></code>
- <code><a href="./src/resources/beta/beta.ts">FetchPolicy</a></code>
- <code><a href="./src/resources/beta/beta.ts">SearchResult</a></code>
- <code><a href="./src/resources/beta/beta.ts">UsageItem</a></code>
- <code><a href="./src/resources/beta/beta.ts">WebSearchResult</a></code>

Methods:

- <code title="post /v1beta/extract">client.beta.<a href="./src/resources/beta/beta.ts">extract</a>({ ...params }) -> ExtractResponse</code>
- <code title="post /v1beta/search">client.beta.<a href="./src/resources/beta/beta.ts">search</a>({ ...params }) -> SearchResult</code>

## TaskRun

Types:

- <code><a href="./src/resources/beta/task-run.ts">BetaRunInput</a></code>
- <code><a href="./src/resources/beta/task-run.ts">BetaTaskRunResult</a></code>
- <code><a href="./src/resources/beta/task-run.ts">ErrorEvent</a></code>
- <code><a href="./src/resources/beta/task-run.ts">McpServer</a></code>
- <code><a href="./src/resources/beta/task-run.ts">McpToolCall</a></code>
- <code><a href="./src/resources/beta/task-run.ts">ParallelBeta</a></code>
- <code><a href="./src/resources/beta/task-run.ts">TaskRunEvent</a></code>
- <code><a href="./src/resources/beta/task-run.ts">Webhook</a></code>
- <code><a href="./src/resources/beta/task-run.ts">TaskRunEventsResponse</a></code>

Methods:

- <code title="post /v1/tasks/runs?beta=true">client.beta.taskRun.<a href="./src/resources/beta/task-run.ts">create</a>({ ...params }) -> TaskRun</code>
- <code title="get /v1beta/tasks/runs/{run_id}/events">client.beta.taskRun.<a href="./src/resources/beta/task-run.ts">events</a>(runID) -> TaskRunEventsResponse</code>
- <code title="get /v1/tasks/runs/{run_id}/result?beta=true">client.beta.taskRun.<a href="./src/resources/beta/task-run.ts">result</a>(runID, { ...params }) -> BetaTaskRunResult</code>

## TaskGroup

Types:

- <code><a href="./src/resources/beta/task-group.ts">TaskGroup</a></code>
- <code><a href="./src/resources/beta/task-group.ts">TaskGroupRunResponse</a></code>
- <code><a href="./src/resources/beta/task-group.ts">TaskGroupStatus</a></code>
- <code><a href="./src/resources/beta/task-group.ts">TaskGroupEventsResponse</a></code>
- <code><a href="./src/resources/beta/task-group.ts">TaskGroupGetRunsResponse</a></code>

Methods:

- <code title="post /v1beta/tasks/groups">client.beta.taskGroup.<a href="./src/resources/beta/task-group.ts">create</a>({ ...params }) -> TaskGroup</code>
- <code title="get /v1beta/tasks/groups/{taskgroup_id}">client.beta.taskGroup.<a href="./src/resources/beta/task-group.ts">retrieve</a>(taskGroupID) -> TaskGroup</code>
- <code title="post /v1beta/tasks/groups/{taskgroup_id}/runs">client.beta.taskGroup.<a href="./src/resources/beta/task-group.ts">addRuns</a>(taskGroupID, { ...params }) -> TaskGroupRunResponse</code>
- <code title="get /v1beta/tasks/groups/{taskgroup_id}/events">client.beta.taskGroup.<a href="./src/resources/beta/task-group.ts">events</a>(taskGroupID, { ...params }) -> TaskGroupEventsResponse</code>
- <code title="get /v1beta/tasks/groups/{taskgroup_id}/runs">client.beta.taskGroup.<a href="./src/resources/beta/task-group.ts">getRuns</a>(taskGroupID, { ...params }) -> TaskGroupGetRunsResponse</code>

## FindAll

Types:

- <code><a href="./src/resources/beta/findall.ts">FindAllCandidateMatchStatusEvent</a></code>
- <code><a href="./src/resources/beta/findall.ts">FindAllEnrichInput</a></code>
- <code><a href="./src/resources/beta/findall.ts">FindAllExtendInput</a></code>
- <code><a href="./src/resources/beta/findall.ts">FindAllRun</a></code>
- <code><a href="./src/resources/beta/findall.ts">FindAllRunInput</a></code>
- <code><a href="./src/resources/beta/findall.ts">FindAllRunResult</a></code>
- <code><a href="./src/resources/beta/findall.ts">FindAllRunStatusEvent</a></code>
- <code><a href="./src/resources/beta/findall.ts">FindAllSchema</a></code>
- <code><a href="./src/resources/beta/findall.ts">FindAllSchemaUpdatedEvent</a></code>
- <code><a href="./src/resources/beta/findall.ts">IngestInput</a></code>
- <code><a href="./src/resources/beta/findall.ts">FindAllCancelResponse</a></code>
- <code><a href="./src/resources/beta/findall.ts">FindAllEventsResponse</a></code>

Methods:

- <code title="post /v1beta/findall/runs">client.beta.findall.<a href="./src/resources/beta/findall.ts">create</a>({ ...params }) -> FindAllRun</code>
- <code title="get /v1beta/findall/runs/{findall_id}">client.beta.findall.<a href="./src/resources/beta/findall.ts">retrieve</a>(findallID, { ...params }) -> FindAllRun</code>
- <code title="post /v1beta/findall/runs/{findall_id}/cancel">client.beta.findall.<a href="./src/resources/beta/findall.ts">cancel</a>(findallID, { ...params }) -> unknown</code>
- <code title="post /v1beta/findall/runs/{findall_id}/enrich">client.beta.findall.<a href="./src/resources/beta/findall.ts">enrich</a>(findallID, { ...params }) -> FindAllSchema</code>
- <code title="get /v1beta/findall/runs/{findall_id}/events">client.beta.findall.<a href="./src/resources/beta/findall.ts">events</a>(findallID, { ...params }) -> FindAllEventsResponse</code>
- <code title="post /v1beta/findall/runs/{findall_id}/extend">client.beta.findall.<a href="./src/resources/beta/findall.ts">extend</a>(findallID, { ...params }) -> FindAllSchema</code>
- <code title="post /v1beta/findall/ingest">client.beta.findall.<a href="./src/resources/beta/findall.ts">ingest</a>({ ...params }) -> FindAllSchema</code>
- <code title="get /v1beta/findall/runs/{findall_id}/result">client.beta.findall.<a href="./src/resources/beta/findall.ts">result</a>(findallID, { ...params }) -> FindAllRunResult</code>
- <code title="get /v1beta/findall/runs/{findall_id}/schema">client.beta.findall.<a href="./src/resources/beta/findall.ts">schema</a>(findallID, { ...params }) -> FindAllSchema</code>
# [Beta](src/resources/beta/api.md)
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "parallel-web",
"version": "0.3.1",
"version": "0.3.2",
"description": "The official TypeScript library for the Parallel API",
"author": "Parallel <support@parallel.ai>",
"types": "dist/index.d.ts",
Expand Down
13 changes: 12 additions & 1 deletion scripts/mock
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,22 @@ echo "==> Starting mock server with URL ${URL}"

# Run prism mock on the given spec
if [ "$1" == "--daemon" ]; then
# Pre-install the package so the download doesn't eat into the startup timeout
npm exec --package=@stainless-api/prism-cli@5.15.0 -- prism --version

npm exec --package=@stainless-api/prism-cli@5.15.0 -- prism mock "$URL" &> .prism.log &

# Wait for server to come online
# Wait for server to come online (max 30s)
echo -n "Waiting for server"
attempts=0
while ! grep -q "✖ fatal\|Prism is listening" ".prism.log" ; do
attempts=$((attempts + 1))
if [ "$attempts" -ge 300 ]; then
echo
echo "Timed out waiting for Prism server to start"
cat .prism.log
exit 1
fi
echo -n "."
sleep 0.1
done
Expand Down
56 changes: 32 additions & 24 deletions src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import type { APIResponseProps } from './internal/parse';
import { getPlatformHeaders } from './internal/detect-platform';
import * as Shims from './internal/shims';
import * as Opts from './internal/request-options';
import { stringifyQuery } from './internal/utils/query';
import { VERSION } from './version';
import * as Errors from './core/error';
import * as Uploads from './core/uploads';
Expand Down Expand Up @@ -228,21 +229,8 @@ export class Parallel {
/**
* Basic re-implementation of `qs.stringify` for primitive types.
*/
protected stringifyQuery(query: Record<string, unknown>): string {
return Object.entries(query)
.filter(([_, value]) => typeof value !== 'undefined')
.map(([key, value]) => {
if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
return `${encodeURIComponent(key)}=${encodeURIComponent(value)}`;
}
if (value === null) {
return `${encodeURIComponent(key)}=`;
}
throw new Errors.ParallelError(
`Cannot stringify type ${typeof value}; Expected string, number, boolean, or null. If you need to pass nested query parameters, you can manually encode them, e.g. { query: { 'foo[key1]': value1, 'foo[key2]': value2 } }, and please open a GitHub issue requesting better support for your use case.`,
);
})
.join('&');
protected stringifyQuery(query: object | Record<string, unknown>): string {
return stringifyQuery(query);
}

private getUserAgent(): string {
Expand Down Expand Up @@ -274,12 +262,13 @@ export class Parallel {
: new URL(baseURL + (baseURL.endsWith('/') && path.startsWith('/') ? path.slice(1) : path));

const defaultQuery = this.defaultQuery();
if (!isEmptyObj(defaultQuery)) {
query = { ...defaultQuery, ...query };
const pathQuery = Object.fromEntries(url.searchParams);
if (!isEmptyObj(defaultQuery) || !isEmptyObj(pathQuery)) {
query = { ...pathQuery, ...defaultQuery, ...query };
}

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

return url.toString();
Expand Down Expand Up @@ -463,7 +452,7 @@ export class Parallel {
loggerFor(this).info(`${responseInfo} - ${retryMessage}`);

const errText = await response.text().catch((err: any) => castToError(err).message);
const errJSON = safeJSON(errText);
const errJSON = safeJSON(errText) as any;
const errMessage = errJSON ? undefined : errText;

loggerFor(this).debug(
Expand Down Expand Up @@ -504,9 +493,10 @@ export class Parallel {
controller: AbortController,
): Promise<Response> {
const { signal, method, ...options } = init || {};
if (signal) signal.addEventListener('abort', () => controller.abort());
const abort = this._makeAbort(controller);
if (signal) signal.addEventListener('abort', abort, { once: true });

const timeout = setTimeout(() => controller.abort(), ms);
const timeout = setTimeout(abort, ms);

const isReadableBody =
((globalThis as any).ReadableStream && options.body instanceof (globalThis as any).ReadableStream) ||
Expand Down Expand Up @@ -583,9 +573,9 @@ export class Parallel {
}
}

// If the API asks us to wait a certain amount of time (and it's a reasonable amount),
// just do what it says, but otherwise calculate a default
if (!(timeoutMillis && 0 <= timeoutMillis && timeoutMillis < 60 * 1000)) {
// If the API asks us to wait a certain amount of time, just do what it
// says, but otherwise calculate a default
if (timeoutMillis === undefined) {
const maxRetries = options.maxRetries ?? this.maxRetries;
timeoutMillis = this.calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries);
}
Expand Down Expand Up @@ -673,6 +663,12 @@ export class Parallel {
return headers.values;
}

private _makeAbort(controller: AbortController) {
// note: we can't just inline this method inside `fetchWithTimeout()` because then the closure
// would capture all request options, and cause a memory leak.
return () => controller.abort();
}

private buildBody({ options: { body, headers: rawHeaders } }: { options: FinalRequestOptions }): {
bodyHeaders: HeadersLike;
body: BodyInit | undefined;
Expand Down Expand Up @@ -705,6 +701,14 @@ export class Parallel {
(Symbol.iterator in body && 'next' in body && typeof body.next === 'function'))
) {
return { bodyHeaders: undefined, body: Shims.ReadableStreamFrom(body as AsyncIterable<Uint8Array>) };
} else if (
typeof body === 'object' &&
headers.values.get('content-type') === 'application/x-www-form-urlencoded'
) {
return {
bodyHeaders: { 'content-type': 'application/x-www-form-urlencoded' },
body: this.stringifyQuery(body),
};
} else {
return this.#encoder({ body, headers });
}
Expand All @@ -729,6 +733,10 @@ export class Parallel {

static toFile = Uploads.toFile;

/**
* The Task API executes web research and extraction tasks. Clients submit a natural-language objective with an optional input schema; the service plans retrieval, fetches relevant URLs, and returns outputs that conform to a provided or inferred JSON schema. Supports deep research style queries and can return rich structured JSON outputs. Processors trade-off between cost, latency, and quality. Each processor supports calibrated confidences.
* - Output metadata: citations, excerpts, reasoning, and confidence per field
*/
taskRun: API.TaskRun = new API.TaskRun(this);
beta: API.Beta = new API.Beta(this);
}
Expand Down
4 changes: 2 additions & 2 deletions src/core/streaming.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export class Stream<Item> implements AsyncIterable<Item> {
try {
for await (const sse of _iterSSEMessages(response, controller)) {
try {
yield JSON.parse(sse.data);
yield JSON.parse(sse.data) as Item;
} catch (e) {
logger.error(`Could not parse message into JSON:`, sse.data);
logger.error(`From chunk:`, sse.raw);
Expand Down Expand Up @@ -102,7 +102,7 @@ export class Stream<Item> implements AsyncIterable<Item> {
try {
for await (const line of iterLines()) {
if (done) continue;
if (line) yield JSON.parse(line);
if (line) yield JSON.parse(line) as Item;
}
done = true;
} catch (e) {
Expand Down
6 changes: 6 additions & 0 deletions src/internal/parse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,12 @@ export async function defaultParseResponse<T>(client: Parallel, props: APIRespon
const mediaType = contentType?.split(';')[0]?.trim();
const isJSON = mediaType?.includes('application/json') || mediaType?.endsWith('+json');
if (isJSON) {
const contentLength = response.headers.get('content-length');
if (contentLength === '0') {
// if there is no content we can't do anything
return undefined as T;
}

const json = await response.json();
return json as T;
}
Expand Down
1 change: 1 addition & 0 deletions src/internal/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ export * from './utils/env';
export * from './utils/log';
export * from './utils/uuid';
export * from './utils/sleep';
export * from './utils/query';
Loading