Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
10ef4f5
refactor: replace axios with fetch in client libs
tylerbutler Oct 1, 2025
34867dc
r11s driver
tylerbutler Oct 1, 2025
03ef6f4
lockfile
tylerbutler Oct 1, 2025
c116e7c
uuid is only used in tests
tylerbutler Oct 1, 2025
6e39e35
pnpm dedupe
tylerbutler Oct 1, 2025
5c66607
rm unneeded types
tylerbutler Oct 1, 2025
7a64c23
code review
tylerbutler Oct 1, 2025
1d8a8f9
rename types
tylerbutler Oct 1, 2025
7c0206a
rm
tylerbutler Oct 1, 2025
c8d9d87
lint
tylerbutler Oct 1, 2025
78f579e
Merge branch 'main' into bt-rm-axios
tylerbutler Oct 2, 2025
e479033
Merge branch 'main' into bt-rm-axios
tylerbutler Oct 7, 2025
36db57f
Merge branch 'main' into bt-rm-axios
tylerbutler Oct 14, 2025
c1bb213
fix: add explicit error handling for fetch responses
tylerbutler Oct 14, 2025
120b4a0
Merge branch 'main' into bt-rm-axios
tylerbutler Dec 4, 2025
32538f0
Merge branch 'main' into bt-rm-axios
tylerbutler Dec 11, 2025
0214113
fixes
tylerbutler Dec 11, 2025
14566af
feedback
tylerbutler Dec 11, 2025
33861b5
Update packages/drivers/routerlicious-driver/src/request.cts
tylerbutler Dec 11, 2025
2408115
Merge branch 'main' into bt-rm-axios
tylerbutler Dec 15, 2025
f471f67
Merge branch 'main' into bt-rm-axios
tylerbutler Dec 16, 2025
7e62db6
Merge branch 'main' into bt-rm-axios
tylerbutler Jan 8, 2026
64d979e
Merge branch 'main' into bt-rm-axios
tylerbutler Jan 12, 2026
4b210b4
Update .gitignore
tylerbutler Jan 12, 2026
4dfe277
Merge branch 'main' into bt-rm-axios
tylerbutler Jan 12, 2026
32be28b
fixes
tylerbutler Jan 12, 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
7 changes: 3 additions & 4 deletions packages/drivers/routerlicious-driver/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -125,8 +125,7 @@
"@fluidframework/telemetry-utils": "workspace:~",
"cross-fetch": "^3.1.5",
"json-stringify-safe": "5.0.1",
"socket.io-client": "~4.7.5",
"uuid": "^11.1.0"
"socket.io-client": "~4.7.5"
},
"devDependencies": {
"@arethetypeswrong/cli": "^0.18.2",
Expand All @@ -142,7 +141,6 @@
"@types/nock": "^9.3.0",
"@types/node": "^18.19.0",
"@types/sinon": "^17.0.3",
"axios": "^1.8.4",
"c8": "^10.1.3",
"concurrently": "^9.2.1",
"copyfiles": "^2.4.1",
Expand All @@ -154,7 +152,8 @@
"nock": "^13.3.3",
"rimraf": "^6.1.2",
"sinon": "^18.0.1",
"typescript": "~5.4.5"
"typescript": "~5.4.5",
"uuid": "^11.1.0"
},
"typeValidation": {
"broken": {},
Expand Down
8 changes: 0 additions & 8 deletions packages/drivers/routerlicious-driver/src/axios.cts

This file was deleted.

32 changes: 32 additions & 0 deletions packages/drivers/routerlicious-driver/src/request.cts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*!
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
* Licensed under the MIT License.
*/

/**
* Request configuration interface compatible with the existing RestWrapper API.
* This replaces the previous axios-based types with native fetch-compatible types.
*
* Note: These interfaces maintain an axios-compatible shape to align with server-side
* RestWrapper implementations, which currently use axios types directly from the axios package.
*/
export interface RequestConfig {
baseURL?: string;
url?: string;
method?: string;
headers?: RawRequestHeaders;
params?: Record<string, any>;
data?: any;
maxBodyLength?: number;
maxContentLength?: number;
}

/**
* Request headers type.
*/
export type RequestHeaders = Record<string, string | number | boolean>;

/**
* Raw request headers type allowing undefined values.
*/
export type RawRequestHeaders = Record<string, string | number | boolean | undefined>;
28 changes: 16 additions & 12 deletions packages/drivers/routerlicious-driver/src/restWrapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,29 +25,29 @@ import {
import fetch from "cross-fetch";
import safeStringify from "json-stringify-safe";

import type { AxiosRequestConfig, RawAxiosRequestHeaders } from "./axios.cjs";
import {
getUrlForTelemetry,
RouterliciousErrorTypes,
throwR11sNetworkError,
} from "./errorUtils.js";
import { pkgVersion as driverVersion } from "./packageVersion.js";
import { addOrUpdateQueryParams, type QueryStringType } from "./queryStringUtils.js";
import type { RequestConfig, RawRequestHeaders } from "./request.cjs";
import { RestWrapper } from "./restWrapperBase.js";
import { ITokenProvider, ITokenResponse } from "./tokens.js";

type AuthorizationHeaderGetter = (token: ITokenResponse) => string;
export type TokenFetcher = (refresh?: boolean) => Promise<ITokenResponse>;

const buildRequestUrl = (requestConfig: AxiosRequestConfig): string =>
const buildRequestUrl = (requestConfig: RequestConfig): string =>
requestConfig.baseURL !== undefined
? `${requestConfig.baseURL ?? ""}${requestConfig.url ?? ""}`
: (requestConfig.url ?? "");

const axiosBuildRequestInitConfig = (requestConfig: AxiosRequestConfig): RequestInit => {
const buildRequestInitConfig = (requestConfig: RequestConfig): RequestInit => {
const requestInit: RequestInit = {
method: requestConfig.method,
// NOTE: I believe that although the Axios type permits non-string values in the header, here we are
// NOTE: Although the RequestHeaders type permits non-string values in the header, here we are
// guaranteed the requestConfig only has string values in its header.
headers: requestConfig.headers as Record<string, string>,
body: requestConfig.data,
Expand Down Expand Up @@ -139,7 +139,7 @@ class RouterliciousRestWrapper extends RestWrapper {
}

protected async request<T>(
requestConfig: AxiosRequestConfig,
requestConfig: RequestConfig,
statusCode: number,
canRetry = true,
): Promise<IR11sResponse<T>> {
Expand All @@ -151,7 +151,7 @@ class RouterliciousRestWrapper extends RestWrapper {
// Build the complete request url including baseUrl, url and query params. (all except 'retry' query param)
let completeRequestUrl = addOrUpdateQueryParams(
buildRequestUrl(requestConfig),
requestConfig.params,
requestConfig.params ?? {},
);

// Check whether this request has been made before or if it is a retry.
Expand All @@ -164,13 +164,17 @@ class RouterliciousRestWrapper extends RestWrapper {
});
}

const config = {
const config: RequestConfig = {
...requestConfig,
headers: await this.generateHeaders(requestConfig.headers),
};

const translatedConfig = this.useRestLess ? this.restLess.translate(config) : config;
const fetchRequestConfig = axiosBuildRequestInitConfig(translatedConfig);
// RestLessClient.translate() returns AxiosRequestConfig (from server-services-client),
// which is structurally compatible with our RequestConfig type.
const translatedConfig: RequestConfig = this.useRestLess
? (this.restLess.translate(config) as RequestConfig)
: config;
const fetchRequestConfig = buildRequestInitConfig(translatedConfig);

const res = await this.rateLimiter.schedule(async () => {
const perfStart = performanceNow();
Expand Down Expand Up @@ -292,11 +296,11 @@ class RouterliciousRestWrapper extends RestWrapper {
}

private async generateHeaders(
requestHeaders?: RawAxiosRequestHeaders | undefined,
): Promise<RawAxiosRequestHeaders> {
requestHeaders?: RawRequestHeaders | undefined,
): Promise<RawRequestHeaders> {
const token = await this.getToken();
assert(token !== undefined, 0x679 /* token should be present */);
const headers: RawAxiosRequestHeaders = {
const headers: RawRequestHeaders = {
...requestHeaders,
[DriverVersionHeaderName]: driverVersion,
// NOTE: If this.authorizationHeader is undefined, should "Authorization" be removed entirely?
Expand Down
28 changes: 14 additions & 14 deletions packages/drivers/routerlicious-driver/src/restWrapperBase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
* Licensed under the MIT License.
*/

import type { AxiosRequestConfig, AxiosRequestHeaders } from "./axios.cjs";
import type { QueryStringType } from "./queryStringUtils.js";
import type { RequestConfig, RequestHeaders } from "./request.cjs";
import { IR11sResponse } from "./restWrapper.js";

export abstract class RestWrapper {
Expand All @@ -24,15 +24,15 @@ export abstract class RestWrapper {
public async get<T>(
url: string,
queryString?: QueryStringType,
headers?: AxiosRequestHeaders,
headers?: RequestHeaders,
additionalOptions?: Partial<
Omit<
AxiosRequestConfig,
RequestConfig,
"baseURL" | "headers" | "maxBodyLength" | "maxContentLength" | "method" | "url"
>
>,
): Promise<IR11sResponse<T>> {
const options: AxiosRequestConfig = {
const options: RequestConfig = {
...additionalOptions,
baseURL: this.baseurl,
headers,
Expand All @@ -56,15 +56,15 @@ export abstract class RestWrapper {
url: string,
requestBody: any,
queryString?: QueryStringType,
headers?: AxiosRequestHeaders,
headers?: RequestHeaders,
additionalOptions?: Partial<
Omit<
AxiosRequestConfig,
RequestConfig,
"baseURL" | "headers" | "maxBodyLength" | "maxContentLength" | "method" | "url"
>
>,
): Promise<IR11sResponse<T>> {
const options: AxiosRequestConfig = {
const options: RequestConfig = {
...additionalOptions,
baseURL: this.baseurl,
data: requestBody,
Expand All @@ -87,15 +87,15 @@ export abstract class RestWrapper {
public async delete<T>(
url: string,
queryString?: QueryStringType,
headers?: AxiosRequestHeaders,
headers?: RequestHeaders,
additionalOptions?: Partial<
Omit<
AxiosRequestConfig,
RequestConfig,
"baseURL" | "headers" | "maxBodyLength" | "maxContentLength" | "method" | "url"
>
>,
): Promise<IR11sResponse<T>> {
const options: AxiosRequestConfig = {
const options: RequestConfig = {
...additionalOptions,
baseURL: this.baseurl,
headers,
Expand All @@ -119,15 +119,15 @@ export abstract class RestWrapper {
url: string,
requestBody: any,
queryString?: QueryStringType,
headers?: AxiosRequestHeaders,
headers?: RequestHeaders,
additionalOptions?: Partial<
Omit<
AxiosRequestConfig,
RequestConfig,
"baseURL" | "headers" | "maxBodyLength" | "maxContentLength" | "method" | "url"
>
>,
): Promise<IR11sResponse<T>> {
const options: AxiosRequestConfig = {
const options: RequestConfig = {
...additionalOptions,
baseURL: this.baseurl,
data: requestBody,
Expand All @@ -142,7 +142,7 @@ export abstract class RestWrapper {
}

protected abstract request<T>(
options: AxiosRequestConfig,
options: RequestConfig,
statusCode: number,
addNetworkCallProps?: boolean,
): Promise<IR11sResponse<T>>;
Expand Down
1 change: 0 additions & 1 deletion packages/loader/driver-utils/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,6 @@
"@fluidframework/core-utils": "workspace:~",
"@fluidframework/driver-definitions": "workspace:~",
"@fluidframework/telemetry-utils": "workspace:~",
"axios": "^1.8.4",
"lz4js": "^0.2.0",
"uuid": "^11.1.0"
},
Expand Down
31 changes: 15 additions & 16 deletions packages/loader/driver-utils/src/insecureUrlResolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import {
IResolvedUrl,
IUrlResolver,
} from "@fluidframework/driver-definitions/internal";
import Axios from "axios";

/**
* As the name implies this is not secure and should not be used in production. It simply makes the example easier
Expand Down Expand Up @@ -66,22 +65,22 @@ export class InsecureUrlResolver implements IUrlResolver {
return maybeResolvedUrl;
}

const headers = {
Authorization: `Bearer ${this.bearer}`,
};
const resolvedP = Axios.post<IResolvedUrl>(
`${this.hostUrl}/apis/load`,
{
url: request.url,
const resolvedP = fetch(`${this.hostUrl}/apis/load`, {
method: "POST",
headers: {
Authorization: `Bearer ${this.bearer}`,
"Content-Type": "application/json",
},
{
headers,
},
);
this.cache.set(
request.url,
resolvedP.then((resolved) => resolved.data),
);
body: JSON.stringify({
url: request.url,
}),
}).then(async (response) => {
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return response.json() as Promise<IResolvedUrl>;
});
this.cache.set(request.url, resolvedP);

return this.cache.get(request.url);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,6 @@
"@fluidframework/test-runtime-utils": "workspace:~",
"@fluidframework/test-utils": "workspace:~",
"@fluidframework/tree": "workspace:~",
"axios": "^1.8.4",
"cross-env": "^10.1.0",
"mocha": "^10.8.2",
"mocha-multi-reporters": "^1.5.1",
Expand Down
Loading
Loading