Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@equinor/fusion-framework-module-http

Package Overview
Dependencies
Maintainers
4
Versions
126
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@equinor/fusion-framework-module-http - npm Package Compare versions

Comparing version 5.2.3 to 6.0.0

92

CHANGELOG.md
# Change Log
## 6.0.0
### Major Changes
- [#2181](https://github.com/equinor/fusion-framework/pull/2181) [`ba2379b`](https://github.com/equinor/fusion-framework/commit/ba2379b177f23ccc023894e36e50d7fc56c929c8) Thanks [@odinr](https://github.com/odinr)! - The `blob` and `blob# Change Log methods in the `HttpClient` class have been updated to provide a more robust and flexible API for fetching blob resources.
1. The `blob` and `blob# Change Log methods now accept an optional `args`parameter of type`FetchRequestInit<T, TRequest, TResponse>`, where `T` is the type of the expected blob result. This allows consumers to customize the fetch request and response handling.
2. The `blob` and `blob# Change Log methods now return a `Promise<T>`and`StreamResponse<T>`respectively, where`T` is the type of the expected blob result. This allows consumers to handle the blob data in a more type-safe manner.
3. The `blobSelector` function has been updated to extract the filename (if available) from the `content-disposition` header and return it along with the blob data in a `BlobResult` object.
4. If you were previously using the `blob` or `blob# Change Log methods and expecting a `Blob`result, you must now use the new`BlobResult` type, which includes the filename (if available) and the blob data.
> [!WARNING]
> This alters the return type of the `blob` and `blob# Change Log methods, which is a **breaking change**.
Example:
```typescript
const blobResult = await httpClient.blob('/path/to/blob');
console.log(blobResult.filename); // 'example.pdf'
console.log(blobResult.blob); // Blob instance
```
1. If you were providing a custom selector function to the `blob` or `blob# Change Log methods, you can now use the new `BlobResult` type in your selector function.
Example:
```typescript
const customBlobSelector = async (
response: Response,
): Promise<{ filename: string; blob: Blob }> => {
// Extract filename and blob from the response
const { filename, blob } = await blobSelector(response);
return { filename, blob };
};
const blobResult = await httpClient.blob('/path/to/blob', { selector: customBlobSelector });
console.log(blobResult.filename); // 'example.pdf'
console.log(blobResult.blob); // Blob instance
```
3. If you were using the `blob# Change Log method and expecting a `StreamResponse<Blob>`, you can now use the new `StreamResponse<T>`type, where`T` is the type of the expected blob result.
Example:
```typescript
const blobStream = httpClient.blob$('/path/to/blob');
blobStream.subscribe((blobResult) => {
console.log(blobResult.filename); // 'example.pdf'
console.log(blobResult.blob); // Blob instance
});
```
### Patch Changes
- [#2196](https://github.com/equinor/fusion-framework/pull/2196) [`1e60919`](https://github.com/equinor/fusion-framework/commit/1e60919e83fb65528c88f604d7bd43299ec412e1) Thanks [@odinr](https://github.com/odinr)! - The `jsonSelector` function was not checking the error type in the `catch` block.
This lead to not throwing the error with parsed data, but always throwing a parser error, where the correct error was `cause` in the `ErrorOptions`
**BREAKING CHANGE:**
If for some reason developers has catched the error and assumed the `cause` property would give the proper error data, this will no longer be the case.
```ts
try {
await jsonSelector(response);
} catch (error) {
if (error instanceof HttpJsonResponseError) {
const { data, cause } = error;
if (data) {
console.error('the request was not `ok`, see provided error data', data);
} else {
console.error('failed to parse data from response, see provided cause', cause);
}
}
}
```
```diff
try {
await jsonSelector(response);
} catch (error) {
if(error instanceof HttpJsonResponseError) {
- const data = error.cause instanceof HttpJsonResponseError ? err.cause.data : null;
+ const data = error instanceof HttpJsonResponseError ? error.data : null;
if(data) {
console.error('the request was not `ok`, see provided error data', data);
} else {
console.error('failed to parse data from response, see provided cause', error.cause);
}
}
}
```
## 5.2.3

@@ -4,0 +96,0 @@

3

dist/esm/lib/client/client.js

@@ -62,3 +62,4 @@ var __rest = (this && this.__rest) || function (s, e) {

const selector = (_a = args === null || args === void 0 ? void 0 : args.selector) !== null && _a !== void 0 ? _a : blobSelector;
return this.fetch$(path, Object.assign(Object.assign({}, args), { selector }));
const init = Object.assign(Object.assign({}, args), { selector });
return this.fetch$(path, init);
}

@@ -65,0 +66,0 @@ blob(path, args) {

@@ -1,2 +0,12 @@

export const blobSelector = (response) => {
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
export const blobSelector = (response) => __awaiter(void 0, void 0, void 0, function* () {
var _a, _b, _c;
if (!response.ok) {

@@ -8,4 +18,7 @@ throw new Error('network response was not OK');

}
const filename = (_c = (_b = (_a = response.headers
.get('content-disposition')) === null || _a === void 0 ? void 0 : _a.split(';').find((n) => n.includes('filename='))) === null || _b === void 0 ? void 0 : _b.replace('filename=', '')) === null || _c === void 0 ? void 0 : _c.trim();
try {
return response.blob();
const blob = yield response.blob();
return { filename, blob };
}

@@ -15,4 +28,4 @@ catch (err) {

}
};
});
export default blobSelector;
//# sourceMappingURL=blob-selector.js.map

@@ -23,2 +23,5 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {

catch (cause) {
if (cause instanceof HttpJsonResponseError) {
throw cause;
}
throw new HttpJsonResponseError('failed to parse response', response, { cause });

@@ -25,0 +28,0 @@ }

@@ -1,2 +0,2 @@

export const version = '5.2.3';
export const version = '6.0.0';
//# sourceMappingURL=version.js.map
import { Subject } from 'rxjs';
import type { Observable, ObservableInput } from 'rxjs';
import type { IHttpRequestHandler, IHttpResponseHandler } from '../operators';
import type { FetchRequest, FetchRequestInit, FetchResponse, IHttpClient, JsonRequest, StreamResponse } from '.';
import type { BlobResult, FetchRequest, FetchRequestInit, FetchResponse, IHttpClient, JsonRequest, StreamResponse } from './types';
export type HttpClientCreateOptions<TRequest extends FetchRequest = FetchRequest, TResponse = Response> = {

@@ -25,4 +25,4 @@ requestHandler: IHttpRequestHandler<TRequest>;

json<T = unknown>(path: string, args?: FetchRequestInit<T, JsonRequest<TRequest>, TResponse>): Promise<T>;
blob$(path: string, args?: FetchRequestInit<Blob, TRequest, TResponse>): StreamResponse<Blob>;
blob(path: string, args?: FetchRequestInit<Blob, TRequest, TResponse>): Promise<Blob>;
blob$<T = BlobResult>(path: string, args?: FetchRequestInit<T, TRequest, TResponse>): StreamResponse<T>;
blob<T = BlobResult>(path: string, args?: FetchRequestInit<T, TRequest, TResponse>): Promise<T>;
jsonAsync<T = unknown>(path: string, args?: FetchRequestInit<T, JsonRequest<TRequest>, TResponse>): Promise<T>;

@@ -29,0 +29,0 @@ execute<T = TResponse, TMethod extends 'fetch' | 'fetch$' | 'json' | 'json$' = 'fetch'>(method: TMethod, path: string, init?: FetchRequestInit<T, TRequest, TResponse>): ReturnType<IHttpClient[TMethod]>;

@@ -11,2 +11,6 @@ import type { ObservableInput, Observable } from 'rxjs';

};
export type BlobResult = {
filename?: string;
blob: Blob;
};
export type FetchResponse<T = unknown> = Response & {

@@ -34,5 +38,5 @@ json(): Promise<T>;

jsonAsync<T = unknown>(path: string, args?: FetchRequestInit<T, JsonRequest<TRequest>, TResponse>): Promise<T>;
blob(path: string, args?: FetchRequestInit<Blob, JsonRequest<TRequest>, TResponse>): Promise<Blob>;
blob$(path: string, args?: FetchRequestInit<Blob, JsonRequest<TRequest>, TResponse>): StreamResponse<Blob>;
blob<T = BlobResult>(path: string, args?: FetchRequestInit<T, JsonRequest<TRequest>, TResponse>): Promise<T>;
blob$<T = BlobResult>(path: string, args?: FetchRequestInit<T, JsonRequest<TRequest>, TResponse>): StreamResponse<T>;
abort(): void;
}

@@ -1,2 +0,3 @@

export declare const blobSelector: <TResponse extends Response = Response>(response: TResponse) => Promise<Blob>;
import { type BlobResult } from '../client/types';
export declare const blobSelector: <TResponse extends Response = Response>(response: TResponse) => Promise<BlobResult>;
export default blobSelector;

@@ -1,1 +0,1 @@

export declare const version = "5.2.3";
export declare const version = "6.0.0";
{
"name": "@equinor/fusion-framework-module-http",
"version": "5.2.3",
"version": "6.0.0",
"description": "",

@@ -5,0 +5,0 @@ "main": "dist/esm/index.js",

@@ -11,2 +11,3 @@ import { firstValueFrom, of, Subject } from 'rxjs';

import type {
BlobResult,
FetchRequest,

@@ -18,3 +19,3 @@ FetchRequestInit,

StreamResponse,
} from '.';
} from './types';
import { HttpResponseError } from '../../errors';

@@ -116,14 +117,37 @@

public blob$(
/**
* Fetches a blob resource from the specified path and returns a stream response.
*
* @param path - The path to the blob resource.
* @param args - Optional request initialization options, including a custom selector function.
* @returns A stream response containing the fetched blob data.
*/
public blob$<T = BlobResult>(
path: string,
args?: FetchRequestInit<Blob, TRequest, TResponse>,
): StreamResponse<Blob> {
args?: FetchRequestInit<T, TRequest, TResponse>,
): StreamResponse<T> {
// Get the selector value from the provided args, or use the default blobSelector
const selector = args?.selector ?? blobSelector;
return this.fetch$(path, {
// Create the FetchRequestInit object with the provided args and the selector
const init = {
...args,
selector,
} as FetchRequestInit<Blob, TRequest, TResponse>);
} as FetchRequestInit<T, TRequest, TResponse>;
// Call the fetch$ method with the provided path and the constructed init object
return this.fetch$(path, init);
}
public blob(path: string, args?: FetchRequestInit<Blob, TRequest, TResponse>): Promise<Blob> {
/**
* Fetches a blob from the specified path and returns a Promise that resolves to the blob result.
*
* @param path - The path to fetch the blob from.
* @param args - Optional arguments for the fetch request, including request body, headers, and response type.
* @returns A Promise that resolves to the blob result.
*/
public blob<T = BlobResult>(
path: string,
args?: FetchRequestInit<T, TRequest, TResponse>,
): Promise<T> {
return firstValueFrom(this.blob$(path, args));

@@ -130,0 +154,0 @@ }

@@ -15,2 +15,9 @@ import type { ObservableInput, Observable } from 'rxjs';

/**
* Represents the result of a blob operation, including the filename (if available) and the blob itself.
* @property {string} [filename] - The filename of the blob, if available.
* @property {Blob} blob - The blob data.
*/
export type BlobResult = { filename?: string; blob: Blob };
export type FetchResponse<T = unknown> = Response & {

@@ -153,11 +160,25 @@ json(): Promise<T>;

blob(
/**
* Fetches a blob resource from the specified path.
*
* @param path - The path to the blob resource.
* @param args - Optional arguments for the fetch request, including the request body, headers, and response type.
* @returns A Promise that resolves to the fetched blob data.
*/
blob<T = BlobResult>(
path: string,
args?: FetchRequestInit<Blob, JsonRequest<TRequest>, TResponse>,
): Promise<Blob>;
args?: FetchRequestInit<T, JsonRequest<TRequest>, TResponse>,
): Promise<T>;
blob$(
/**
* Fetches a blob from the specified path and returns a stream response.
*
* @param path - The path to fetch the blob from.
* @param args - Optional arguments for the fetch request, including the request body, headers, and response type.
* @returns A stream response containing the fetched blob.
*/
blob$<T = BlobResult>(
path: string,
args?: FetchRequestInit<Blob, JsonRequest<TRequest>, TResponse>,
): StreamResponse<Blob>;
args?: FetchRequestInit<T, JsonRequest<TRequest>, TResponse>,
): StreamResponse<T>;

@@ -164,0 +185,0 @@ /**

@@ -1,8 +0,19 @@

export const blobSelector = <TResponse extends Response = Response>(
import { type BlobResult } from '../client/types';
/**
* Extracts a blob and filename from a successful HTTP response.
*
* @param response - The HTTP response to extract the blob and filename from.
* @returns A promise that resolves to an object containing the extracted blob and filename.
* @throws {Error} If the response is not successful or if there is an error parsing the response.
*/
export const blobSelector = async <TResponse extends Response = Response>(
response: TResponse,
): Promise<Blob> => {
): Promise<BlobResult> => {
if (!response.ok) {
// Throw an error if the network response is not successful
throw new Error('network response was not OK');
}
//Status code 204 is no content
// Status code 204 indicates no content, so throw an error
if (response.status === 204) {

@@ -12,5 +23,16 @@ throw new Error('no content');

// Extract the filename from the 'content-disposition' header
const filename = response.headers
.get('content-disposition')
?.split(';')
.find((n) => n.includes('filename='))
?.replace('filename=', '')
?.trim();
try {
return response.blob();
// Convert the response to a Blob and return the filename and Blob
const blob = await response.blob();
return { filename, blob };
} catch (err) {
// Throw an error if there's a problem parsing the response
throw Error('failed to parse response');

@@ -17,0 +39,0 @@ }

import { HttpJsonResponseError } from '../../errors';
/**
* Converts the JSON response from an HTTP request into the specified type.
* If the response is not OK or if there is an error parsing the response, an error is thrown.
* If the response has a status code of 204 (No Content), a resolved Promise is returned.
* Asynchronously parses the JSON data from a given HTTP response.
*
* @param response The HTTP response object.
* @returns A Promise that resolves to the parsed JSON data.
* @throws {Error} If the network response is not OK.
* @throws {HttpJsonResponseError} If there is an error parsing the response.
* If the response has a status code of 204 (No Content), this function will resolve with `undefined`.
*
* If the response is not successful (i.e. `response.ok` is `false`), this function will throw an `HttpJsonResponseError` with the response details and the parsed data (if any).
*
* If there is an error parsing the JSON data, this function will throw an `HttpJsonResponseError` with the parsing error and the original response.
*
* @template TType - The expected type of the parsed JSON data.
* @template TResponse - The type of the HTTP response object.
* @param response - The HTTP response to parse.
* @returns A promise that resolves with the parsed JSON data, or rejects with an `HttpJsonResponseError`.
*/

@@ -16,3 +20,3 @@ export const jsonSelector = async <TType = unknown, TResponse extends Response = Response>(

): Promise<TType> => {
/** Status code 204 is no content */
/** Status code 204 indicates no content in the response */
if (response.status === 204) {

@@ -23,8 +27,20 @@ return Promise.resolve() as Promise<TType>;

try {
// Parse the response JSON data
const data = await response.json();
// Check if the response was successful
if (!response.ok) {
// Throw an error with the response details
throw new HttpJsonResponseError('network response was not OK', response, { data });
}
// Return the parsed data
return data;
} catch (cause) {
// If the cause is an HttpJsonResponseError, rethrow it
if (cause instanceof HttpJsonResponseError) {
throw cause;
}
// Otherwise, throw a new HttpJsonResponseError with the parsing error
throw new HttpJsonResponseError('failed to parse response', response, { cause });

@@ -31,0 +47,0 @@ }

// Generated by genversion.
export const version = '5.2.3';
export const version = '6.0.0';

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc