From 8a2dcb0a49ccbf4c9fc2c0c8f0b3391713f676dd Mon Sep 17 00:00:00 2001 From: Gregor Becker Date: Sun, 19 Jul 2026 23:19:20 +0200 Subject: [PATCH] fix(axios): apply global plugin config on first repository use AxiosRepository captured the axios instance and global plugin config in its constructor, but ORM plugins only run after the repository has been constructed. On the first useAxiosRepo() call of an app the repository therefore saw an empty global config and options like baseURL and dataKey were silently dropped. The axios instance and global config are now resolved lazily from the plugin config the repository receives during plugin registration. fixes #1987 --- packages/axios/src/api/Request.ts | 6 +- .../axios/src/repository/AxiosRepository.ts | 34 ++++++---- .../test/feature/Request_GlobalConfig.spec.ts | 66 +++++++++++++++++++ 3 files changed, 92 insertions(+), 14 deletions(-) create mode 100644 packages/axios/test/feature/Request_GlobalConfig.spec.ts diff --git a/packages/axios/src/api/Request.ts b/packages/axios/src/api/Request.ts index a595adf30..0ad749c52 100644 --- a/packages/axios/src/api/Request.ts +++ b/packages/axios/src/api/Request.ts @@ -34,14 +34,14 @@ export class Request { * Get the axios client. */ get axios (): AxiosInstance { - this.repository.axios = this.repository.axios ?? this.repository.config.axiosApi.axios - if (!this.repository.axios) { + const axios = this.repository.axios + if (!axios) { throw new Error( '[Pinia ORM Axios] The axios instance is not registered. Please register the axios instance to the repository.', ) } - return this.repository.axios + return axios } /** diff --git a/packages/axios/src/repository/AxiosRepository.ts b/packages/axios/src/repository/AxiosRepository.ts index 6902d8a8b..8cd8afbad 100644 --- a/packages/axios/src/repository/AxiosRepository.ts +++ b/packages/axios/src/repository/AxiosRepository.ts @@ -1,20 +1,32 @@ -import type { Database, Model } from 'pinia-orm' -import type { Pinia } from 'pinia' -import { Repository, config } from 'pinia-orm' +import type { Model } from 'pinia-orm' +import { Repository } from 'pinia-orm' import type { AxiosInstance } from 'axios' import { useAxiosApi } from '../index' import type { Config, GlobalConfig } from '../types/config' export class AxiosRepository extends Repository { - axios: AxiosInstance - globalApiConfig: GlobalConfig - apiConfig: Config + apiConfig: Config = {} - constructor (database: Database, pinia?: Pinia) { - super(database, pinia) - this.axios = config?.axiosApi?.axios || null - this.globalApiConfig = config?.axiosApi || {} - this.apiConfig = {} + protected axiosInstance: AxiosInstance | null = null + + /** + * The axios instance from the plugin config, unless an instance was set + * explicitly via `setAxios`. The plugin config is resolved lazily because + * plugins are registered after the repository has been constructed. + */ + get axios (): AxiosInstance | null { + return this.axiosInstance ?? this.globalApiConfig.axios ?? null + } + + set axios (axios: AxiosInstance | null) { + this.axiosInstance = axios + } + + /** + * The global plugin config passed to `createPiniaOrmAxios`. + */ + get globalApiConfig (): GlobalConfig { + return this.config.axiosApi ?? {} } api () { diff --git a/packages/axios/test/feature/Request_GlobalConfig.spec.ts b/packages/axios/test/feature/Request_GlobalConfig.spec.ts new file mode 100644 index 000000000..0f49a7625 --- /dev/null +++ b/packages/axios/test/feature/Request_GlobalConfig.spec.ts @@ -0,0 +1,66 @@ +import axios from 'axios' +import MockAdapter from 'axios-mock-adapter' +import { createPinia, setActivePinia } from 'pinia' +import { createApp } from 'vue' +import { Model, config, createORM } from 'pinia-orm' +import { afterEach, beforeEach, describe, expect, it } from 'vitest' +import { assertState } from '../helpers' +import { createPiniaOrmAxios, useAxiosRepo } from '../../src' + +describe('Feature - Request - Global Config', () => { + let mock: MockAdapter + + class User extends Model { + static entity = 'users' + + static fields () { + return { + id: this.attr(null), + name: this.attr(''), + } + } + } + + beforeEach(() => { + mock = new MockAdapter(axios) + }) + afterEach(() => { + mock.reset() + }) + + it('applies global plugin options like baseURL and dataKey on first repository use', async () => { + // Simulate a freshly booted app where no repository has been used yet, + // so the axios plugin has not been applied to the global config. + delete config.axiosApi + + const app = createApp({}) + const pinia = createPinia() + pinia.use(createORM({ + plugins: [ + createPiniaOrmAxios({ + axios, + baseURL: 'https://example.com/api', + dataKey: 'data', + }), + ], + })) + app.use(pinia) + setActivePinia(pinia) + + mock.onGet('https://example.com/api/users').reply(200, { + data: [{ id: 1, name: 'John Doe' }], + }) + + const userStore = useAxiosRepo(User) + + await userStore.api().get('/users') + + expect(mock.history.get[0].baseURL).toBe('https://example.com/api') + + assertState({ + users: { + 1: { id: 1, name: 'John Doe' }, + }, + }) + }) +})