Compare commits

..

No commits in common. "main" and "v0.4.2" have entirely different histories.
main ... v0.4.2

4 changed files with 7 additions and 38 deletions

4
package-lock.json generated
View file

@ -1,12 +1,12 @@
{ {
"name": "@uschuster/webapp-scaffold", "name": "@uschuster/webapp-scaffold",
"version": "0.5.0", "version": "0.3.6",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "@uschuster/webapp-scaffold", "name": "@uschuster/webapp-scaffold",
"version": "0.5.0", "version": "0.3.6",
"license": "UNLICENSED", "license": "UNLICENSED",
"bin": { "bin": {
"webapp-scaffold-fetch-openapi": "bin/fetch-openapi.sh", "webapp-scaffold-fetch-openapi": "bin/fetch-openapi.sh",

View file

@ -1,6 +1,6 @@
{ {
"name": "@uschuster/webapp-scaffold", "name": "@uschuster/webapp-scaffold",
"version": "0.5.0", "version": "0.4.2",
"description": "Shared build scripts + Vite config factories for webapp-template-derived projects.", "description": "Shared build scripts + Vite config factories for webapp-template-derived projects.",
"type": "module", "type": "module",
"bin": { "bin": {

View file

@ -173,23 +173,4 @@ describe('createCoreFetch — request shape', () => {
await cf('/v1/x'); await cf('/v1/x');
expect(captured).toBe('https://api.example.com/v1/x'); expect(captured).toBe('https://api.example.com/v1/x');
}); });
it('baseUrl getter is resolved at request time, not factory time', async () => {
const captured: string[] = [];
let dynamicBase = 'https://first.example.com';
const cf = createCoreFetch({
baseUrl: () => dynamicBase,
fetchImpl: ((url: string) => {
captured.push(url);
return Promise.resolve(jsonResponse({}));
}) as unknown as typeof fetch,
});
await cf('/v1/x');
dynamicBase = 'https://second.example.com/';
await cf('/v1/y');
expect(captured).toEqual([
'https://first.example.com/v1/x',
'https://second.example.com/v1/y',
]);
});
}); });

View file

@ -28,16 +28,8 @@ export interface CoreFetchRequest {
} }
export interface CoreFetchOptions { export interface CoreFetchOptions {
/** /** Prefix for every request; strip trailing slash. */
* Prefix for every request; trailing slash stripped at resolve time. baseUrl?: string;
*
* Accepts a string OR a getter so consumers that derive the base from
* `import.meta.env.BASE_URL` (or any other late-bound source) can pass
* the getter form. The getter is invoked at request time, never at
* factory-construction time which keeps orval's CJS bundling of the
* mutator file from blowing up on top-level `import.meta` references.
*/
baseUrl?: string | (() => string);
/** `'body'` returns the parsed body (default); `'wrapped'` returns { data, status, headers }. */ /** `'body'` returns the parsed body (default); `'wrapped'` returns { data, status, headers }. */
responseShape?: ResponseShape; responseShape?: ResponseShape;
@ -105,11 +97,7 @@ export type CoreFetch = CoreFetchWrapped & CoreFetchBody;
const MUTATING = new Set(['POST', 'PUT', 'PATCH', 'DELETE']); const MUTATING = new Set(['POST', 'PUT', 'PATCH', 'DELETE']);
export function createCoreFetch(opts: CoreFetchOptions = {}): CoreFetch { export function createCoreFetch(opts: CoreFetchOptions = {}): CoreFetch {
// Lazy base resolution — see CoreFetchOptions.baseUrl JSDoc. const base = (opts.baseUrl ?? '').replace(/\/$/, '');
const resolveBase = (): string => {
const raw = typeof opts.baseUrl === 'function' ? opts.baseUrl() : (opts.baseUrl ?? '');
return raw.replace(/\/$/, '');
};
// Resolve fetch at call time, not construction time, so tests that // Resolve fetch at call time, not construction time, so tests that
// `vi.stubGlobal('fetch', ...)` after module import see the stub. // `vi.stubGlobal('fetch', ...)` after module import see the stub.
const callFetch: typeof fetch = opts.fetchImpl const callFetch: typeof fetch = opts.fetchImpl
@ -147,7 +135,7 @@ export function createCoreFetch(opts: CoreFetchOptions = {}): CoreFetch {
let r: Response; let r: Response;
try { try {
r = await callFetch(`${resolveBase()}${url}`, { r = await callFetch(`${base}${url}`, {
credentials: 'include', credentials: 'include',
...init, ...init,
headers, headers,