Skip to content

Commit bfab3ac

Browse files
committed
fix: prefer global fetch for Cloudflare Workers compatibility (Issue 215)
- Updated fetch selection logic to prefer globalThis.fetch when available. - Replaced cross-fetch imports with a new fetch utility in src/util/fetch.ts. - Updated integration tests to use the new fetch utility. - Added documentation and a unit test for Cloudflare Workers support.
1 parent 1942d42 commit bfab3ac

30 files changed

Lines changed: 3967 additions & 3844 deletions

dist/account.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { fetch } from 'cross-fetch';
21
import { DAVAccount } from './types/models';
2+
import { fetch } from './util/fetch';
33
export declare const serviceDiscovery: (params: {
44
account: DAVAccount;
55
headers?: Record<string, string>;

dist/client.d.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ export declare const createDAVClient: (params: {
2828
headers?: Record<string, string>;
2929
headersToExclude?: string[];
3030
fetchOptions?: RequestInit;
31-
fetch?: typeof import("cross-fetch").fetch;
31+
fetch?: typeof import("./util/fetch").fetch;
3232
}) => Promise<DAVResponse[]>;
3333
createAccount: (params0: {
3434
account: Optional<DAVAccount, "serverUrl">;
@@ -43,7 +43,7 @@ export declare const createDAVClient: (params: {
4343
headers?: Record<string, string>;
4444
headersToExclude?: string[];
4545
fetchOptions?: RequestInit;
46-
fetch?: typeof import("cross-fetch").fetch;
46+
fetch?: typeof import("./util/fetch").fetch;
4747
}) => Promise<Response>;
4848
updateObject: (params: {
4949
url: string;
@@ -52,15 +52,15 @@ export declare const createDAVClient: (params: {
5252
headers?: Record<string, string>;
5353
headersToExclude?: string[];
5454
fetchOptions?: RequestInit;
55-
fetch?: typeof import("cross-fetch").fetch;
55+
fetch?: typeof import("./util/fetch").fetch;
5656
}) => Promise<Response>;
5757
deleteObject: (params: {
5858
url: string;
5959
etag?: string;
6060
headers?: Record<string, string>;
6161
headersToExclude?: string[];
6262
fetchOptions?: RequestInit;
63-
fetch?: typeof import("cross-fetch").fetch;
63+
fetch?: typeof import("./util/fetch").fetch;
6464
}) => Promise<Response>;
6565
calendarQuery: (params: {
6666
url: string;

dist/index.d.ts

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,12 @@ declare const _default: {
3030
getBearerAuthHeaders: (credentials: import("./types/models").DAVCredentials) => {
3131
authorization?: string;
3232
};
33-
fetchOauthTokens: (credentials: import("./types/models").DAVCredentials, fetchOptions?: RequestInit, fetchOverride?: typeof import("cross-fetch").fetch) => Promise<import("./types/DAVTypes").DAVTokens>;
34-
refreshAccessToken: (credentials: import("./types/models").DAVCredentials, fetchOptions?: RequestInit, fetchOverride?: typeof import("cross-fetch").fetch) => Promise<{
33+
fetchOauthTokens: (credentials: import("./types/models").DAVCredentials, fetchOptions?: RequestInit, fetchOverride?: typeof import("./util/fetch").fetch) => Promise<import("./types/DAVTypes").DAVTokens>;
34+
refreshAccessToken: (credentials: import("./types/models").DAVCredentials, fetchOptions?: RequestInit, fetchOverride?: typeof import("./util/fetch").fetch) => Promise<{
3535
access_token?: string;
3636
expires_in?: number;
3737
}>;
38-
getOauthHeaders: (credentials: import("./types/models").DAVCredentials, fetchOptions?: RequestInit, fetchOverride?: typeof import("cross-fetch").fetch) => Promise<{
38+
getOauthHeaders: (credentials: import("./types/models").DAVCredentials, fetchOptions?: RequestInit, fetchOverride?: typeof import("./util/fetch").fetch) => Promise<{
3939
tokens: import("./types/DAVTypes").DAVTokens;
4040
headers: {
4141
authorization?: string;
@@ -207,21 +207,21 @@ declare const _default: {
207207
headers?: Record<string, string>;
208208
headersToExclude?: string[];
209209
fetchOptions?: RequestInit;
210-
fetch?: typeof import("cross-fetch").fetch;
210+
fetch?: typeof import("./util/fetch").fetch;
211211
}) => Promise<string>;
212212
fetchPrincipalUrl: (params: {
213213
account: import("./types/models").DAVAccount;
214214
headers?: Record<string, string>;
215215
headersToExclude?: string[];
216216
fetchOptions?: RequestInit;
217-
fetch?: typeof import("cross-fetch").fetch;
217+
fetch?: typeof import("./util/fetch").fetch;
218218
}) => Promise<string>;
219219
fetchHomeUrl: (params: {
220220
account: import("./types/models").DAVAccount;
221221
headers?: Record<string, string>;
222222
headersToExclude?: string[];
223223
fetchOptions?: RequestInit;
224-
fetch?: typeof import("cross-fetch").fetch;
224+
fetch?: typeof import("./util/fetch").fetch;
225225
}) => Promise<string>;
226226
createAccount: (params: {
227227
account: import("./types/models").DAVAccount;
@@ -230,7 +230,7 @@ declare const _default: {
230230
loadCollections?: boolean;
231231
loadObjects?: boolean;
232232
fetchOptions?: RequestInit;
233-
fetch?: typeof import("cross-fetch").fetch;
233+
fetch?: typeof import("./util/fetch").fetch;
234234
}) => Promise<import("./types/models").DAVAccount>;
235235
collectionQuery: (params: {
236236
url: string;
@@ -285,7 +285,7 @@ declare const _default: {
285285
convertIncoming?: boolean;
286286
parseOutgoing?: boolean;
287287
fetchOptions?: RequestInit;
288-
fetch?: typeof import("cross-fetch").fetch;
288+
fetch?: typeof import("./util/fetch").fetch;
289289
}) => Promise<import("./types/DAVTypes").DAVResponse[]>;
290290
propfind: (params: {
291291
url: string;
@@ -294,15 +294,15 @@ declare const _default: {
294294
headers?: Record<string, string>;
295295
headersToExclude?: string[];
296296
fetchOptions?: RequestInit;
297-
fetch?: typeof import("cross-fetch").fetch;
297+
fetch?: typeof import("./util/fetch").fetch;
298298
}) => Promise<import("./types/DAVTypes").DAVResponse[]>;
299299
createObject: (params: {
300300
url: string;
301301
data: BodyInit;
302302
headers?: Record<string, string>;
303303
headersToExclude?: string[];
304304
fetchOptions?: RequestInit;
305-
fetch?: typeof import("cross-fetch").fetch;
305+
fetch?: typeof import("./util/fetch").fetch;
306306
}) => Promise<Response>;
307307
updateObject: (params: {
308308
url: string;
@@ -311,15 +311,15 @@ declare const _default: {
311311
headers?: Record<string, string>;
312312
headersToExclude?: string[];
313313
fetchOptions?: RequestInit;
314-
fetch?: typeof import("cross-fetch").fetch;
314+
fetch?: typeof import("./util/fetch").fetch;
315315
}) => Promise<Response>;
316316
deleteObject: (params: {
317317
url: string;
318318
etag?: string;
319319
headers?: Record<string, string>;
320320
headersToExclude?: string[];
321321
fetchOptions?: RequestInit;
322-
fetch?: typeof import("cross-fetch").fetch;
322+
fetch?: typeof import("./util/fetch").fetch;
323323
}) => Promise<Response>;
324324
createDAVClient: (params: {
325325
serverUrl: string;
@@ -343,7 +343,7 @@ declare const _default: {
343343
headers?: Record<string, string>;
344344
headersToExclude?: string[];
345345
fetchOptions?: RequestInit;
346-
fetch?: typeof import("cross-fetch").fetch;
346+
fetch?: typeof import("./util/fetch").fetch;
347347
}) => Promise<import("./types/DAVTypes").DAVResponse[]>;
348348
createAccount: (params0: {
349349
account: import("./util/typeHelpers").Optional<import("./types/models").DAVAccount, "serverUrl">;
@@ -358,7 +358,7 @@ declare const _default: {
358358
headers?: Record<string, string>;
359359
headersToExclude?: string[];
360360
fetchOptions?: RequestInit;
361-
fetch?: typeof import("cross-fetch").fetch;
361+
fetch?: typeof import("./util/fetch").fetch;
362362
}) => Promise<Response>;
363363
updateObject: (params: {
364364
url: string;
@@ -367,15 +367,15 @@ declare const _default: {
367367
headers?: Record<string, string>;
368368
headersToExclude?: string[];
369369
fetchOptions?: RequestInit;
370-
fetch?: typeof import("cross-fetch").fetch;
370+
fetch?: typeof import("./util/fetch").fetch;
371371
}) => Promise<Response>;
372372
deleteObject: (params: {
373373
url: string;
374374
etag?: string;
375375
headers?: Record<string, string>;
376376
headersToExclude?: string[];
377377
fetchOptions?: RequestInit;
378-
fetch?: typeof import("cross-fetch").fetch;
378+
fetch?: typeof import("./util/fetch").fetch;
379379
}) => Promise<Response>;
380380
calendarQuery: (params: {
381381
url: string;

dist/request.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import { fetch } from 'cross-fetch';
21
import { ElementCompact } from 'xml-js';
32
import { DAVDepth, DAVRequest, DAVResponse } from './types/DAVTypes';
3+
import { fetch } from './util/fetch';
44
export declare const davRequest: (params: {
55
url: string;
66
init: DAVRequest;

dist/tsdav.cjs

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22

33
Object.defineProperty(exports, '__esModule', { value: true });
44

5-
var crossFetch = require('cross-fetch');
65
var getLogger = require('debug');
76
var convert = require('xml-js');
7+
var crossFetch = require('cross-fetch');
88
var base64 = require('base-64');
99

1010
exports.DAVNamespace = void 0;
@@ -42,6 +42,19 @@ var ICALObjects;
4242

4343
const camelCase = (str) => str.replace(/([-_]\w)/g, (g) => g[1].toUpperCase());
4444

45+
/**
46+
* Cloudflare Workers and some modern environments have a native fetch on globalThis.
47+
* We prefer it over cross-fetch to avoid compatibility issues with the polyfill.
48+
*/
49+
const getFetch = () => {
50+
if (typeof globalThis !== 'undefined' && typeof globalThis.fetch === 'function') {
51+
return globalThis.fetch.bind(globalThis);
52+
}
53+
// Fallback to cross-fetch
54+
return crossFetch;
55+
};
56+
const fetch = getFetch();
57+
4558
const nativeType = (value) => {
4659
const nValue = Number(value);
4760
if (!Number.isNaN(nValue)) {
@@ -124,7 +137,7 @@ const debug$5 = getLogger('tsdav:request');
124137
const davRequest = async (params) => {
125138
var _a;
126139
const { url, init, convertIncoming = true, parseOutgoing = true, fetchOptions = {}, fetch: fetchOverride, } = params;
127-
const requestFetch = fetchOverride !== null && fetchOverride !== void 0 ? fetchOverride : crossFetch.fetch;
140+
const requestFetch = fetchOverride !== null && fetchOverride !== void 0 ? fetchOverride : fetch;
128141
const { headers = {}, body, namespace, method, attributes } = init;
129142
const xmlBody = convertIncoming
130143
? convert.js2xml({
@@ -284,7 +297,7 @@ const propfind = async (params) => {
284297
};
285298
const createObject = async (params) => {
286299
const { url, data, headers, headersToExclude, fetchOptions = {}, fetch: fetchOverride } = params;
287-
const requestFetch = fetchOverride !== null && fetchOverride !== void 0 ? fetchOverride : crossFetch.fetch;
300+
const requestFetch = fetchOverride !== null && fetchOverride !== void 0 ? fetchOverride : fetch;
288301
return requestFetch(url, {
289302
method: 'PUT',
290303
body: data,
@@ -294,7 +307,7 @@ const createObject = async (params) => {
294307
};
295308
const updateObject = async (params) => {
296309
const { url, data, etag, headers, headersToExclude, fetchOptions = {}, fetch: fetchOverride, } = params;
297-
const requestFetch = fetchOverride !== null && fetchOverride !== void 0 ? fetchOverride : crossFetch.fetch;
310+
const requestFetch = fetchOverride !== null && fetchOverride !== void 0 ? fetchOverride : fetch;
298311
return requestFetch(url, {
299312
method: 'PUT',
300313
body: data,
@@ -304,7 +317,7 @@ const updateObject = async (params) => {
304317
};
305318
const deleteObject = async (params) => {
306319
const { url, headers, etag, headersToExclude, fetchOptions = {}, fetch: fetchOverride } = params;
307-
const requestFetch = fetchOverride !== null && fetchOverride !== void 0 ? fetchOverride : crossFetch.fetch;
320+
const requestFetch = fetchOverride !== null && fetchOverride !== void 0 ? fetchOverride : fetch;
308321
return requestFetch(url, {
309322
method: 'DELETE',
310323
headers: excludeHeaders(cleanupFalsy({ 'If-Match': etag, ...headers }), headersToExclude),
@@ -1278,7 +1291,7 @@ const serviceDiscovery = async (params) => {
12781291
var _a, _b;
12791292
debug$1('Service discovery...');
12801293
const { account, headers, headersToExclude, fetchOptions = {}, fetch: fetchOverride } = params;
1281-
const requestFetch = fetchOverride !== null && fetchOverride !== void 0 ? fetchOverride : crossFetch.fetch;
1294+
const requestFetch = fetchOverride !== null && fetchOverride !== void 0 ? fetchOverride : fetch;
12821295
const endpoint = new URL(account.serverUrl);
12831296
const uri = new URL(`/.well-known/${account.accountType}`, endpoint);
12841297
uri.protocol = (_a = endpoint.protocol) !== null && _a !== void 0 ? _a : 'http';
@@ -1489,7 +1502,7 @@ const fetchOauthTokens = async (credentials, fetchOptions, fetchOverride) => {
14891502
});
14901503
debug(credentials.tokenUrl);
14911504
debug(param.toString());
1492-
const requestFetch = fetchOverride !== null && fetchOverride !== void 0 ? fetchOverride : crossFetch.fetch;
1505+
const requestFetch = fetchOverride !== null && fetchOverride !== void 0 ? fetchOverride : fetch;
14931506
const response = await requestFetch(credentials.tokenUrl, {
14941507
method: 'POST',
14951508
body: param.toString(),
@@ -1522,7 +1535,7 @@ const refreshAccessToken = async (credentials, fetchOptions, fetchOverride) => {
15221535
refresh_token: credentials.refreshToken,
15231536
grant_type: 'refresh_token',
15241537
});
1525-
const requestFetch = fetchOverride !== null && fetchOverride !== void 0 ? fetchOverride : crossFetch.fetch;
1538+
const requestFetch = fetchOverride !== null && fetchOverride !== void 0 ? fetchOverride : fetch;
15261539
const response = await requestFetch(credentials.tokenUrl, {
15271540
method: 'POST',
15281541
body: param.toString(),

dist/tsdav.cjs.js

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22

33
Object.defineProperty(exports, '__esModule', { value: true });
44

5-
var crossFetch = require('cross-fetch');
65
var getLogger = require('debug');
76
var convert = require('xml-js');
7+
var crossFetch = require('cross-fetch');
88
var base64 = require('base-64');
99

1010
exports.DAVNamespace = void 0;
@@ -42,6 +42,19 @@ var ICALObjects;
4242

4343
const camelCase = (str) => str.replace(/([-_]\w)/g, (g) => g[1].toUpperCase());
4444

45+
/**
46+
* Cloudflare Workers and some modern environments have a native fetch on globalThis.
47+
* We prefer it over cross-fetch to avoid compatibility issues with the polyfill.
48+
*/
49+
const getFetch = () => {
50+
if (typeof globalThis !== 'undefined' && typeof globalThis.fetch === 'function') {
51+
return globalThis.fetch.bind(globalThis);
52+
}
53+
// Fallback to cross-fetch
54+
return crossFetch;
55+
};
56+
const fetch = getFetch();
57+
4558
const nativeType = (value) => {
4659
const nValue = Number(value);
4760
if (!Number.isNaN(nValue)) {
@@ -124,7 +137,7 @@ const debug$5 = getLogger('tsdav:request');
124137
const davRequest = async (params) => {
125138
var _a;
126139
const { url, init, convertIncoming = true, parseOutgoing = true, fetchOptions = {}, fetch: fetchOverride, } = params;
127-
const requestFetch = fetchOverride !== null && fetchOverride !== void 0 ? fetchOverride : crossFetch.fetch;
140+
const requestFetch = fetchOverride !== null && fetchOverride !== void 0 ? fetchOverride : fetch;
128141
const { headers = {}, body, namespace, method, attributes } = init;
129142
const xmlBody = convertIncoming
130143
? convert.js2xml({
@@ -284,7 +297,7 @@ const propfind = async (params) => {
284297
};
285298
const createObject = async (params) => {
286299
const { url, data, headers, headersToExclude, fetchOptions = {}, fetch: fetchOverride } = params;
287-
const requestFetch = fetchOverride !== null && fetchOverride !== void 0 ? fetchOverride : crossFetch.fetch;
300+
const requestFetch = fetchOverride !== null && fetchOverride !== void 0 ? fetchOverride : fetch;
288301
return requestFetch(url, {
289302
method: 'PUT',
290303
body: data,
@@ -294,7 +307,7 @@ const createObject = async (params) => {
294307
};
295308
const updateObject = async (params) => {
296309
const { url, data, etag, headers, headersToExclude, fetchOptions = {}, fetch: fetchOverride, } = params;
297-
const requestFetch = fetchOverride !== null && fetchOverride !== void 0 ? fetchOverride : crossFetch.fetch;
310+
const requestFetch = fetchOverride !== null && fetchOverride !== void 0 ? fetchOverride : fetch;
298311
return requestFetch(url, {
299312
method: 'PUT',
300313
body: data,
@@ -304,7 +317,7 @@ const updateObject = async (params) => {
304317
};
305318
const deleteObject = async (params) => {
306319
const { url, headers, etag, headersToExclude, fetchOptions = {}, fetch: fetchOverride } = params;
307-
const requestFetch = fetchOverride !== null && fetchOverride !== void 0 ? fetchOverride : crossFetch.fetch;
320+
const requestFetch = fetchOverride !== null && fetchOverride !== void 0 ? fetchOverride : fetch;
308321
return requestFetch(url, {
309322
method: 'DELETE',
310323
headers: excludeHeaders(cleanupFalsy({ 'If-Match': etag, ...headers }), headersToExclude),
@@ -1278,7 +1291,7 @@ const serviceDiscovery = async (params) => {
12781291
var _a, _b;
12791292
debug$1('Service discovery...');
12801293
const { account, headers, headersToExclude, fetchOptions = {}, fetch: fetchOverride } = params;
1281-
const requestFetch = fetchOverride !== null && fetchOverride !== void 0 ? fetchOverride : crossFetch.fetch;
1294+
const requestFetch = fetchOverride !== null && fetchOverride !== void 0 ? fetchOverride : fetch;
12821295
const endpoint = new URL(account.serverUrl);
12831296
const uri = new URL(`/.well-known/${account.accountType}`, endpoint);
12841297
uri.protocol = (_a = endpoint.protocol) !== null && _a !== void 0 ? _a : 'http';
@@ -1489,7 +1502,7 @@ const fetchOauthTokens = async (credentials, fetchOptions, fetchOverride) => {
14891502
});
14901503
debug(credentials.tokenUrl);
14911504
debug(param.toString());
1492-
const requestFetch = fetchOverride !== null && fetchOverride !== void 0 ? fetchOverride : crossFetch.fetch;
1505+
const requestFetch = fetchOverride !== null && fetchOverride !== void 0 ? fetchOverride : fetch;
14931506
const response = await requestFetch(credentials.tokenUrl, {
14941507
method: 'POST',
14951508
body: param.toString(),
@@ -1522,7 +1535,7 @@ const refreshAccessToken = async (credentials, fetchOptions, fetchOverride) => {
15221535
refresh_token: credentials.refreshToken,
15231536
grant_type: 'refresh_token',
15241537
});
1525-
const requestFetch = fetchOverride !== null && fetchOverride !== void 0 ? fetchOverride : crossFetch.fetch;
1538+
const requestFetch = fetchOverride !== null && fetchOverride !== void 0 ? fetchOverride : fetch;
15261539
const response = await requestFetch(credentials.tokenUrl, {
15271540
method: 'POST',
15281541
body: param.toString(),

0 commit comments

Comments
 (0)