Skip to content

Commit 5a25ed1

Browse files
committed
Use early init for fetcher
1 parent b6c32c9 commit 5a25ed1

5 files changed

Lines changed: 32 additions & 68 deletions

File tree

Makefile

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,11 @@ npm-test:
3131
npm test
3232

3333
.PHONY: test
34-
test: npm-test example snippets
34+
test: typecheck npm-test example snippets
35+
36+
.PHONY: typecheck
37+
typecheck:
38+
npm run typecheck
3539

3640
.PHONY: cover
3741
cover:

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ const config = new Barcode.Configuration(
5959

6060
async function generateBarcode(api) {
6161
const request = new Barcode.GenerateRequestWrapper(
62-
Barcode.EncodeBarcodeType.Qr,
62+
Barcode.EncodeBarcodeType.Qr,
6363
'Aspose.BarCode for Cloud Sample');
6464

6565
const oneBarcode = await api.generate(request);

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@
133133
},
134134
"scripts": {
135135
"test": "npx jest",
136+
"typecheck": "npx tsc --noEmit",
136137
"cover": "npx jest --coverage",
137138
"lint": "npx eslint src test snippets",
138139
"format": "npx eslint src test snippets eslint.config.mjs --fix",

src/JWTAuth.ts

Lines changed: 10 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,6 @@ import { Configuration } from './Configuration';
22
import { Authentication } from './Authentication';
33
import { ApiErrorResponse } from './models';
44

5-
type StringMap = Record<string, string>;
6-
7-
interface FetchHeaders {
8-
forEach(callback: (value: string, key: string) => void): void;
9-
}
10-
11-
interface FetchResponse {
12-
status: number;
13-
statusText: string;
14-
headers: FetchHeaders;
15-
ok: boolean;
16-
text(): Promise<string>;
17-
}
18-
19-
type Fetcher = (
20-
input: string | URL,
21-
init?: { method?: string; headers?: StringMap; body?: any }
22-
) => Promise<FetchResponse>;
23-
245
type AuthResponse = {
256
statusCode: number;
267
statusMessage: string;
@@ -37,9 +18,16 @@ type AuthRejectType = {
3718
export class JWTAuth implements Authentication {
3819
private _accessToken?: string;
3920
private readonly _configuration: Configuration;
21+
private readonly _fetcher: typeof fetch;
4022

4123
constructor(configuration: Configuration) {
4224
this._configuration = configuration;
25+
const resolvedFetch = (globalThis as { fetch?: typeof fetch }).fetch;
26+
if (!resolvedFetch) {
27+
throw new Error('Global fetch API is not available. Please use Node.js 18+.');
28+
}
29+
30+
this._fetcher = resolvedFetch;
4331

4432
if (configuration.accessToken) {
4533
// Use saved token
@@ -69,15 +57,14 @@ export class JWTAuth implements Authentication {
6957
if (!this._configuration.clientId || !this._configuration.clientSecret) {
7058
throw new Error("Required 'clientId' or 'clientSecret' not specified in configuration.");
7159
}
72-
const fetcher = this.getFetch();
7360
const requestBody = new URLSearchParams({
7461
grant_type: 'client_credentials',
7562
client_id: this._configuration.clientId,
7663
client_secret: this._configuration.clientSecret,
7764
}).toString();
78-
let response: FetchResponse;
65+
let response: Response;
7966
try {
80-
response = await fetcher(this._configuration.tokenUrl, {
67+
response = await this._fetcher(this._configuration.tokenUrl, {
8168
method: 'POST',
8269
headers: {
8370
'Content-Type': 'application/x-www-form-urlencoded',
@@ -125,7 +112,7 @@ export class JWTAuth implements Authentication {
125112
return parsed.access_token;
126113
}
127114

128-
private toHeaderDict(headers: FetchHeaders): NodeJS.Dict<string | string[]> {
115+
private toHeaderDict(headers: Headers): NodeJS.Dict<string | string[]> {
129116
const normalizedHeaders: NodeJS.Dict<string | string[]> = {};
130117

131118
headers.forEach((value, key) => {
@@ -147,15 +134,6 @@ export class JWTAuth implements Authentication {
147134
return normalizedHeaders;
148135
}
149136

150-
private getFetch(): Fetcher {
151-
const fetcher = (globalThis as { fetch?: Fetcher }).fetch;
152-
if (!fetcher) {
153-
throw new Error('Global fetch API is not available. Please use Node.js 18+.');
154-
}
155-
156-
return fetcher;
157-
}
158-
159137
private normalizeFetchError(error: unknown): Error {
160138
if (error instanceof Error) {
161139
const mutableError = error as Error & { code?: string; cause?: unknown; name: string };

src/api.ts

Lines changed: 15 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -67,27 +67,18 @@ type ApiRejectType = {
6767
error: Error;
6868
};
6969

70-
interface FetchHeaders {
71-
forEach(callback: (value: string, key: string) => void): void;
72-
}
73-
74-
interface FetchResponse {
75-
status: number;
76-
statusText: string;
77-
headers: FetchHeaders;
78-
ok: boolean;
79-
arrayBuffer(): Promise<ArrayBuffer>;
80-
}
70+
export class ApiClient {
71+
private readonly _fetcher: typeof fetch;
8172

82-
interface FetchOptions {
83-
method?: string;
84-
headers?: StringMap;
85-
body?: any;
86-
}
73+
constructor() {
74+
const resolvedFetch = (globalThis as { fetch?: typeof fetch }).fetch;
75+
if (!resolvedFetch) {
76+
throw new Error('Global fetch API is not available. Please use Node.js 18+.');
77+
}
8778

88-
type Fetcher = (input: string | URL, options?: FetchOptions) => Promise<FetchResponse>;
79+
this._fetcher = resolvedFetch;
80+
}
8981

90-
export class ApiClient {
9182
public requestAsync(options: ApiRequestOptions): Promise<ApiResult> {
9283
const url: URL = options.qs
9384
? new URL(`?${new URLSearchParams(options.qs).toString()}`, options.uri)
@@ -97,7 +88,7 @@ export class ApiClient {
9788

9889
const responseEncoding: BufferEncoding | null = options.encoding === null ? null : options.encoding || 'utf-8';
9990

100-
const requestOptions: FetchOptions = {
91+
const requestOptions: RequestInit = {
10192
method: options.method || 'GET',
10293
headers: options.headers,
10394
};
@@ -136,13 +127,12 @@ export class ApiClient {
136127

137128
private async doFetchRequest(
138129
url: URL,
139-
requestOptions: FetchOptions,
130+
requestOptions: RequestInit,
140131
responseEncoding: BufferEncoding | null
141132
): Promise<ApiResult> {
142-
const fetcher = this.getFetch();
143-
let response: FetchResponse;
133+
let response: Response;
144134
try {
145-
response = await fetcher(url.toString(), requestOptions);
135+
response = await this._fetcher(url.toString(), requestOptions);
146136
} catch (error) {
147137
return Promise.reject({
148138
response: null,
@@ -188,7 +178,7 @@ export class ApiClient {
188178
}
189179

190180
private async readResponseBody(
191-
response: FetchResponse,
181+
response: Response,
192182
responseEncoding: BufferEncoding | null
193183
): Promise<string | Buffer> {
194184
const arrayBuffer = await response.arrayBuffer();
@@ -201,7 +191,7 @@ export class ApiClient {
201191
return buffer.toString(responseEncoding);
202192
}
203193

204-
private toHeaderDict(headers: FetchHeaders): NodeJS.Dict<string | string[]> {
194+
private toHeaderDict(headers: Headers): NodeJS.Dict<string | string[]> {
205195
const normalizedHeaders: NodeJS.Dict<string | string[]> = {};
206196

207197
headers.forEach((value, key) => {
@@ -223,15 +213,6 @@ export class ApiClient {
223213
return normalizedHeaders;
224214
}
225215

226-
private getFetch(): Fetcher {
227-
const fetcher = (globalThis as { fetch?: Fetcher }).fetch;
228-
if (!fetcher) {
229-
throw new Error('Global fetch API is not available. Please use Node.js 18+.');
230-
}
231-
232-
return fetcher;
233-
}
234-
235216
private normalizeFetchError(error: unknown): Error {
236217
if (error instanceof Error) {
237218
const mutableError = error as Error & { code?: string; cause?: unknown; name: string };

0 commit comments

Comments
 (0)