Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,6 @@ UPCOMING.md
# This is created to later publish its content on the pipeline and do not need to be included on git as
# artifacts or bundleAnalysis folders. See scripts/pack-build-output.sh for more details.
build_output_archive

# AI artifacts
.claude
2 changes: 1 addition & 1 deletion packages/drivers/routerlicious-driver/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@
"@types/nock": "^9.3.0",
"@types/node": "^18.19.0",
"@types/sinon": "^17.0.3",
"axios": "^1.8.4",
"@types/uuid": "^9.0.2",
"c8": "^10.1.3",
"concurrently": "^8.2.1",
"copyfiles": "^2.4.1",
Expand Down
25 changes: 23 additions & 2 deletions packages/drivers/routerlicious-driver/src/axios.cts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,27 @@
* Licensed under the MIT License.
*/

import type { AxiosRequestConfig, AxiosRequestHeaders, RawAxiosRequestHeaders } from "axios";
/**
* Request configuration interface compatible with the existing RestWrapper API.
* This replaces the previous axios-based types with native fetch-compatible types.
*/
export interface AxiosRequestConfig {
baseURL?: string;
url?: string;
method?: string;
headers?: RawAxiosRequestHeaders;
params?: Record<string, any>;
data?: any;
maxBodyLength?: number;
maxContentLength?: number;
}

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

export { AxiosRequestConfig, AxiosRequestHeaders, RawAxiosRequestHeaders };
/**
* Raw request headers type allowing undefined values.
*/
export type RawAxiosRequestHeaders = Record<string, string | number | boolean | undefined>;
6 changes: 3 additions & 3 deletions packages/drivers/routerlicious-driver/src/restWrapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,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 @@ -163,12 +163,12 @@ class RouterliciousRestWrapper extends RestWrapper {
});
}

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

const translatedConfig = this.useRestLess ? this.restLess.translate(config) : config;
const translatedConfig = this.useRestLess ? (this.restLess.translate(config) as AxiosRequestConfig) : config;
const fetchRequestConfig = axiosBuildRequestInitConfig(translatedConfig);

const res = await this.rateLimiter.schedule(async () => {
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 @@ -81,7 +81,6 @@
"@fluidframework/test-runtime-utils": "workspace:~",
"@fluidframework/test-utils": "workspace:~",
"@fluidframework/tree": "workspace:~",
"axios": "^1.8.4",
"cross-env": "^7.0.3",
"mocha": "^10.8.2",
"mocha-multi-reporters": "^1.5.1",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,13 @@ import {
createMultiSinkLogger,
} from "@fluidframework/telemetry-utils/internal";
import { InsecureTokenProvider } from "@fluidframework/test-runtime-utils/internal";
import { default as Axios, type AxiosResponse, type AxiosRequestConfig } from "axios";
import { v4 as uuid } from "uuid";

interface FetchResponse {
status: number;
data: { id?: string } | string;
}

import { createAzureTokenProvider } from "./AzureTokenFactory.js";

// eslint-disable-next-line unicorn/prefer-export-from
Expand Down Expand Up @@ -187,13 +191,13 @@ export function createAzureClientLegacy(
* currently these are mainly fetched from ephemeralSummaryTrees.ts
* @param userID - ID for the user creating the container
* @param userName - Name for the user creating the container
* @returns - An AxiosResponse containing the container ID(response.data.id)
* @returns - A FetchResponse containing the container ID(response.data.id)
*/
export async function createContainerFromPayload(
requestPayload: object,
userID?: string,
userName?: string,
): Promise<AxiosResponse> {
): Promise<FetchResponse> {
const useAzure = process.env.FLUID_CLIENT === "azure";
const tenantId = useAzure
? (process.env.azure__fluid__relay__service__tenantId as string)
Expand All @@ -219,48 +223,54 @@ export async function createContainerFromPayload(
"Content-Type": "application/json",
};

const url = `/documents/${tenantId}`;

const options: AxiosRequestConfig = {
baseURL: endPoint,
data: requestPayload,
headers,
maxBodyLength: 1048576000,
maxContentLength: 1048576000,
method: "POST",
url,
};
const url = `${endPoint}/documents/${tenantId}`;

try {
const response: AxiosResponse = await Axios(options);
const response = await fetch(url, {
method: "POST",
headers,
body: JSON.stringify(requestPayload),
});

if (response.status === 201) {
console.log("Container created successfully");
} else {
throw new Error(`Error creating container. Status code: ${response.status}`);
}

// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
if (response?.data === undefined || (useAzure && response?.data?.id === undefined)) {
const data: { id?: string } | string = (await response.json()) as { id?: string } | string;

if (
data === undefined ||
(useAzure && typeof data === "object" && data.id === undefined)
) {
throw new Error(`ID of the created container is undefined`);
}

return response;
return { status: response.status, data };
} catch (error) {
throw new Error(`An error occurred: ${error}`);
}
}

/**
* This function takes an AxiosResponse returned by the createContainerFromPayload and returns the containerId.
* This function takes a FetchResponse returned by the createContainerFromPayload and returns the containerId.
* A separate function is used for this, since the data path to the containerID is not always the same.
* (Tinylicious has the ID stored at a different path than other services)
*
* @param response - A container creation response returned by createContainerFromPayload
* @returns - The ID of the container that was created by createContainerFromPayload
*/
export function getContainerIdFromPayloadResponse(response: AxiosResponse): string {
export function getContainerIdFromPayloadResponse(response: FetchResponse): string {
const useAzure = process.env.FLUID_CLIENT === "azure";
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
return (useAzure ? response.data.id : response.data) as string;
if (useAzure) {
if (typeof response.data === "object" && response.data.id !== undefined) {
return response.data.id;
}
throw new Error("Invalid response format for Azure");
}
if (typeof response.data === "string") {
return response.data;
}
throw new Error("Invalid response format for local");
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import { ConnectionState } from "@fluidframework/container-loader";
import type { ContainerSchema, IFluidContainer } from "@fluidframework/fluid-static";
import { SharedMap } from "@fluidframework/map/legacy";
import { timeoutPromise } from "@fluidframework/test-utils/internal";
import type { AxiosResponse } from "axios";

import {
createAzureClient,
Expand Down Expand Up @@ -49,7 +48,7 @@ for (const testOpts of testMatrix) {
let container: IFluidContainer;
let services: AzureContainerServices;
if (isEphemeral) {
const containerResponse: AxiosResponse | undefined = await createContainerFromPayload(
const containerResponse = await createContainerFromPayload(
ephemeralSummaryTrees.findOriginalMember,
"test-user-id-1",
"test-user-name-1",
Expand Down Expand Up @@ -94,7 +93,7 @@ for (const testOpts of testMatrix) {
let container: IFluidContainer;
let services: AzureContainerServices;
if (isEphemeral) {
const containerResponse: AxiosResponse | undefined = await createContainerFromPayload(
const containerResponse = await createContainerFromPayload(
ephemeralSummaryTrees.findPartnerMember,
"test-user-id-1",
"test-user-name-1",
Expand Down Expand Up @@ -158,7 +157,7 @@ for (const testOpts of testMatrix) {
let containerId: string;
let container: IFluidContainer;
if (isEphemeral) {
const containerResponse: AxiosResponse | undefined = await createContainerFromPayload(
const containerResponse = await createContainerFromPayload(
ephemeralSummaryTrees.observeMemberLeaving,
"test-user-id-1",
"test-user-name-1",
Expand Down Expand Up @@ -217,7 +216,7 @@ for (const testOpts of testMatrix) {
let container: IFluidContainer;
let services: AzureContainerServices;
if (isEphemeral) {
const containerResponse: AxiosResponse | undefined = await createContainerFromPayload(
const containerResponse = await createContainerFromPayload(
ephemeralSummaryTrees.observeMemberLeaving,
"test-user-id-1",
"test-user-name-1",
Expand Down Expand Up @@ -326,7 +325,7 @@ for (const testOpts of testMatrix) {
let containerId: string;
let container: IFluidContainer;
if (isEphemeral) {
const containerResponse: AxiosResponse | undefined = await createContainerFromPayload(
const containerResponse = await createContainerFromPayload(
ephemeralSummaryTrees.observeMemberLeaving,
"test-user-id-1",
"test-user-name-1",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,6 @@ import { SharedMap } from "@fluidframework/map/legacy";
import { SharedMap as SharedMapLegacy } from "@fluidframework/map-legacy";
import { MockLogger, UsageError } from "@fluidframework/telemetry-utils/internal";
import { timeoutPromise } from "@fluidframework/test-utils/internal";
import { SharedTree } from "@fluidframework/tree/legacy";
import type { AxiosResponse } from "axios";
import type { SinonSandbox } from "sinon";
import { createSandbox } from "sinon";

Expand Down Expand Up @@ -96,7 +94,7 @@ for (const testOpts of testMatrix) {
let containerId: string;
let container: IFluidContainer;
if (isEphemeral) {
const containerResponse: AxiosResponse | undefined = await createContainerFromPayload(
const containerResponse = await createContainerFromPayload(
ephemeralSummaryTrees.canAttachContainer,
"test-user-id-1",
"test-user-name-1",
Expand Down Expand Up @@ -133,7 +131,7 @@ for (const testOpts of testMatrix) {
let containerId: string;
let container: IFluidContainer;
if (isEphemeral) {
const containerResponse: AxiosResponse | undefined = await createContainerFromPayload(
const containerResponse = await createContainerFromPayload(
ephemeralSummaryTrees.cannotAttachContainerTwice,
"test-user-id-1",
"test-user-name-1",
Expand Down Expand Up @@ -175,7 +173,7 @@ for (const testOpts of testMatrix) {
let containerId: string;
let newContainer: IFluidContainer;
if (isEphemeral) {
const containerResponse: AxiosResponse | undefined = await createContainerFromPayload(
const containerResponse = await createContainerFromPayload(
ephemeralSummaryTrees.retrieveExistingAFRContainer,
"test-user-id-1",
"test-user-name-1",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import type { IFluidHandle } from "@fluidframework/core-interfaces";
import type { ContainerSchema, IFluidContainer } from "@fluidframework/fluid-static";
import { type ISharedMap, SharedMap } from "@fluidframework/map/legacy";
import { timeoutPromise } from "@fluidframework/test-utils/internal";
import type { AxiosResponse } from "axios";

import {
createAzureClient,
Expand Down Expand Up @@ -49,7 +48,7 @@ for (const testOpts of testMatrix) {
let containerId: string;
let newContainer: IFluidContainer;
if (isEphemeral) {
const containerResponse: AxiosResponse | undefined = await createContainerFromPayload(
const containerResponse = await createContainerFromPayload(
ephemeralSummaryTrees.setDDSesAsInitialObjectsForContainer,
"test-user-id-1",
"test-user-name-1",
Expand Down Expand Up @@ -92,7 +91,7 @@ for (const testOpts of testMatrix) {
let containerId: string;
let container: IFluidContainer;
if (isEphemeral) {
const containerResponse: AxiosResponse | undefined = await createContainerFromPayload(
const containerResponse = await createContainerFromPayload(
ephemeralSummaryTrees.changeDDSesWithinInitialObjectsValue,
"test-user-id-1",
"test-user-name-1",
Expand Down Expand Up @@ -137,7 +136,7 @@ for (const testOpts of testMatrix) {
let containerId: string;
let container: IFluidContainer;
if (isEphemeral) {
const containerResponse: AxiosResponse | undefined = await createContainerFromPayload(
const containerResponse = await createContainerFromPayload(
ephemeralSummaryTrees.setDataObjectsAsInitialObjectsForContainer,
"test-user-id-1",
"test-user-name-1",
Expand Down Expand Up @@ -200,7 +199,7 @@ for (const testOpts of testMatrix) {
let containerId: string;
let container: IFluidContainer;
if (isEphemeral) {
const containerResponse: AxiosResponse | undefined = await createContainerFromPayload(
const containerResponse = await createContainerFromPayload(
ephemeralSummaryTrees.useMultipleDataObjectsOfSameType,
"test-user-id-1",
"test-user-name-1",
Expand Down Expand Up @@ -268,7 +267,7 @@ for (const testOpts of testMatrix) {
let containerId: string;
let container: IFluidContainer;
if (isEphemeral) {
const containerResponse: AxiosResponse | undefined = await createContainerFromPayload(
const containerResponse = await createContainerFromPayload(
ephemeralSummaryTrees.changeDataObjectsWithinInitialObjectsValue,
"test-user-id-1",
"test-user-name-1",
Expand Down Expand Up @@ -328,7 +327,7 @@ for (const testOpts of testMatrix) {
let containerId: string;
let container: IFluidContainer;
if (isEphemeral) {
const containerResponse: AxiosResponse | undefined = await createContainerFromPayload(
const containerResponse = await createContainerFromPayload(
ephemeralSummaryTrees.createAddLoadableObjectsDynamically,
"test-user-id-1",
"test-user-name-1",
Expand Down
Loading
Loading