From 7c2f383bd03999e99dab2bc8323bd6bd2a4fdc0b Mon Sep 17 00:00:00 2001 From: Pier Roberto Lucisano Date: Tue, 29 Oct 2024 17:08:49 +0100 Subject: [PATCH] Remove redis, axios, got, flydrive, memcached dependencies --- README.md | 8 - package.json | 42 +-- src/Buffer.test.ts | 15 -- src/Buffer.ts | 40 --- src/Cache.test.ts | 91 ------- src/Cache.ts | 107 -------- src/Http.test.ts | 94 ------- src/Http.ts | 275 -------------------- src/Stream.ts | 33 --- src/cache/Memcached.test.ts | 79 ------ src/cache/Memcached.ts | 87 ------- src/cache/Memory.ts | 47 ---- src/cache/Redis.test.ts | 111 -------- src/cache/Redis.ts | 106 -------- src/cache/Storage.test.ts | 104 -------- src/cache/Storage.ts | 84 ------ src/http/Axios.test.ts | 112 -------- src/http/Axios.ts | 78 ------ src/http/Fetch.test.ts | 83 ------ src/http/Fetch.ts | 101 -------- src/http/Got.test.ts | 47 ---- src/http/Got.ts | 74 ------ src/http/Mock.ts | 46 ---- src/index.ts | 8 - src/storage/Flydrive.test.ts | 130 ---------- src/storage/Flydrive.ts | 112 -------- src/storage/Fs.ts | 38 --- yarn.lock | 487 +---------------------------------- 28 files changed, 4 insertions(+), 2635 deletions(-) delete mode 100644 src/Buffer.test.ts delete mode 100644 src/Buffer.ts delete mode 100644 src/Cache.test.ts delete mode 100644 src/Cache.ts delete mode 100644 src/Http.test.ts delete mode 100644 src/Http.ts delete mode 100644 src/Stream.ts delete mode 100644 src/cache/Memcached.test.ts delete mode 100644 src/cache/Memcached.ts delete mode 100644 src/cache/Memory.ts delete mode 100644 src/cache/Redis.test.ts delete mode 100644 src/cache/Redis.ts delete mode 100644 src/cache/Storage.test.ts delete mode 100644 src/cache/Storage.ts delete mode 100644 src/http/Axios.test.ts delete mode 100644 src/http/Axios.ts delete mode 100644 src/http/Fetch.test.ts delete mode 100644 src/http/Fetch.ts delete mode 100644 src/http/Got.test.ts delete mode 100644 src/http/Got.ts delete mode 100644 src/http/Mock.ts delete mode 100644 src/storage/Flydrive.test.ts delete mode 100644 src/storage/Flydrive.ts delete mode 100644 src/storage/Fs.ts diff --git a/README.md b/README.md index e1b5dc6..0372533 100644 --- a/README.md +++ b/README.md @@ -23,13 +23,6 @@ The package is available via [npm](https://www.npmjs.com/package/fortepiano), an npm install fortepiano fp-ts io-ts io-ts-types ``` -Additional packages are required, shall you want to use specific abstractions: - -- [`memcached`](https://www.npmjs.com/package/memcached) and [`@types/memcached`](https://www.npmjs.com/package/@types/memcached) (`cache/Memcached`) -- [`redis`](https://www.npmjs.com/package/redis) and [`@types/redis`](https://www.npmjs.com/package/@types/redis) (`cache/Redis`) -- [`axios`](https://www.npmjs.com/package/axios) (`http/Axios`) -- [`@slynova/flydrive`](https://www.npmjs.com/package/@slynova/flydrive) (`storage/Flydrive`) - ### Usage Import modules (e.g., values) from package index and types from specific modules. "Function" module and abstraction implementations are an exception: @@ -38,7 +31,6 @@ Import modules (e.g., values) from package index and types from specific modules import { $type } from 'fortepiano' import { Struct } from 'fortepiano/struct' import { curry } from 'fortepiano/function' -import { $axios } from 'fortepiano/http/Axios' ``` ## Contributing diff --git a/package.json b/package.json index ba59e62..0beff5a 100644 --- a/package.json +++ b/package.json @@ -39,66 +39,26 @@ }, "devDependencies": { "@rushstack/eslint-patch": "^1.1.3", - "@slynova/flydrive": "^1.0.0", "@types/jest": "^26.0.24", - "@types/memcached": "^2.0.0", "@types/node-fetch": "^2.5.12", - "@types/redis": "^2.0.0", - "@types/redis-mock": "^0.17.0", - "axios": "^0.28.0", "eslint": "^8.16.0", "eslint-config-facile": "^0.5.0", "fp-ts": "^2.0.0", - "got": "^11.0.0", "io-ts": "^2.0.0", "io-ts-types": "^0.5.0", "jest": "^26.6.3", - "memcached": "^2.0.0", - "memcached-mock": "^0.1.0", "monocle-ts": "^2.3.10", "newtype-ts": "^0.3.4", "node-fetch": "^2.6.7", "prettier": "^2.6.2", - "redis": "^3.0.0", - "redis-mock": "^0.56.3", "ts-jest": "^26.5.6", "ts-node": "^10.9.2", "typescript": "^4.6.4" }, "peerDependencies": { - "@slynova/flydrive": "^1.0.0", - "@types/memcached": "^2.0.0", - "@types/redis": "^2.0.0", - "axios": "^0.21.2 || ^0.28.0", "fp-ts": "^2.0.0", - "got": "^11.0.0", "io-ts": "^2.0.0", - "io-ts-types": "^0.5.0", - "memcached": "^2.0.0", - "redis": "^3.0.0" - }, - "peerDependenciesMeta": { - "@slynova/flydrive": { - "optional": true - }, - "@types/memcached": { - "optional": true - }, - "@types/redis": { - "optional": true - }, - "axios": { - "optional": true - }, - "got": { - "optional": true - }, - "memcached": { - "optional": true - }, - "redis": { - "optional": true - } + "io-ts-types": "^0.5.0" }, "packageManager": "yarn@3.2.3" } diff --git a/src/Buffer.test.ts b/src/Buffer.test.ts deleted file mode 100644 index d066c9e..0000000 --- a/src/Buffer.test.ts +++ /dev/null @@ -1,15 +0,0 @@ -import * as E from 'fp-ts/Either' -import { pipe } from 'fp-ts/function' -import { BufferFromStringC } from './Buffer' - -describe('Buffer', () => { - describe('BufferFromStringC', () => { - it('should encode buffers into strings', () => { - const buffer = Buffer.from('foo') - - expect( - pipe(buffer, BufferFromStringC.encode, BufferFromStringC.decode), - ).toStrictEqual(E.right(buffer)) - }) - }) -}) diff --git a/src/Buffer.ts b/src/Buffer.ts deleted file mode 100644 index 97f1a28..0000000 --- a/src/Buffer.ts +++ /dev/null @@ -1,40 +0,0 @@ -import * as t from 'io-ts' -import * as $E from './Error' -import * as $TE from './TaskEither' - -const is = (u: unknown): u is Buffer => u instanceof Buffer - -export const BufferC = new t.Type( - 'Buffer', - is, - (u, c) => (is(u) ? t.success(u) : t.failure(u, c)), - (b) => b.toString('base64'), -) - -export const BufferFromStringC = new t.Type( - 'BufferFromString', - is, - (u, c) => { - try { - return t.string.is(u) - ? t.success(Buffer.from(u, 'base64')) - : t.failure(u, c) - } catch (_) { - return t.failure(u, c) - } - }, - BufferC.encode, -) - -export const fromStream = (stream: NodeJS.ReadableStream) => - $TE.tryCatch( - () => - new Promise((resolve, reject) => { - const buffer: Array = [] - stream - .on('error', reject) - .on('data', (data) => buffer.push(data)) - .on('end', () => resolve(Buffer.concat(buffer))) - }), - $E.fromUnknown(Error('Cannot read stream into buffer')), - ) diff --git a/src/Cache.test.ts b/src/Cache.test.ts deleted file mode 100644 index 6be99e3..0000000 --- a/src/Cache.test.ts +++ /dev/null @@ -1,91 +0,0 @@ -import * as E from 'fp-ts/Either' -import { constUndefined, pipe } from 'fp-ts/function' -import * as T from 'fp-ts/Task' -import * as TE from 'fp-ts/TaskEither' -import * as t from 'io-ts' -import { chain, memory } from './Cache' - -describe('Cache', () => { - describe('chain', () => { - const c0 = memory() - const c1 = memory() - const c = chain(c0, c1) - - describe('get', () => { - it('should fail when no cache is warm', async () => { - await expect( - pipe(c.get('foo', t.number), T.map(E.isLeft))(), - ).resolves.toBe(true) - }) - it('should succeed when first level cache is warm', async () => { - await expect( - pipe( - c0.set('foo', t.string)('bar'), - TE.chain(() => c.get('foo', t.string)), - )(), - ).resolves.toStrictEqual(E.right('bar')) - }) - it('should succeed when second level cache is warm', async () => { - await expect( - pipe( - c1.set('foo', t.string)('bar'), - TE.chain(() => c.get('foo', t.string)), - )(), - ).resolves.toStrictEqual(E.right('bar')) - }) - it('should resist to a cache level failure', async () => { - await expect( - pipe( - c.set('foo', t.string)('bar'), - TE.chainFirst(() => c0.clear), - TE.bind('c', () => c.get('foo', t.string)), - TE.bind('c1', () => c1.get('foo', t.string)), - )(), - ).resolves.toStrictEqual(E.right({ c: 'bar', c1: 'bar' })) - }) - }) - - describe('set', () => { - it('should warm up all cache levels', async () => { - await expect( - pipe( - c.set('foo', t.string)('bar'), - TE.bind('c', () => c.get('foo', t.string)), - TE.bind('c0', () => c0.get('foo', t.string)), - TE.bind('c1', () => c1.get('foo', t.string)), - )(), - ).resolves.toStrictEqual(E.right({ c: 'bar', c0: 'bar', c1: 'bar' })) - }) - }) - - describe('delete', () => { - it('should delete an item from all cache levels', async () => { - await expect( - pipe( - c.set('foo', t.string)('bar'), - T.chainFirst(() => c.delete('foo')), - T.map(constUndefined), - T.bind('c', () => pipe(c.get('foo', t.string), T.map(E.isLeft))), - T.bind('c0', () => pipe(c0.get('foo', t.string), T.map(E.isLeft))), - T.bind('c1', () => pipe(c1.get('foo', t.string), T.map(E.isLeft))), - )(), - ).resolves.toStrictEqual({ c: true, c0: true, c1: true }) - }) - }) - - describe('clear', () => { - it('should clear all cache levels', async () => { - await expect( - pipe( - c.set('foo', t.string)('bar'), - T.chainFirst(() => c.clear), - T.map(constUndefined), - T.bind('c', () => pipe(c.get('foo', t.string), T.map(E.isLeft))), - T.bind('c0', () => pipe(c0.get('foo', t.string), T.map(E.isLeft))), - T.bind('c1', () => pipe(c1.get('foo', t.string), T.map(E.isLeft))), - )(), - ).resolves.toStrictEqual({ c: true, c0: true, c1: true }) - }) - }) - }) -}) diff --git a/src/Cache.ts b/src/Cache.ts deleted file mode 100644 index 76a79c5..0000000 --- a/src/Cache.ts +++ /dev/null @@ -1,107 +0,0 @@ -import { constVoid, Endomorphism, pipe } from 'fp-ts/function' -import * as J from 'fp-ts/Json' -import * as R from 'fp-ts/Random' -import * as RNEA from 'fp-ts/ReadonlyNonEmptyArray' -import * as TE from 'fp-ts/TaskEither' -import * as t from 'io-ts' -import { memory } from './cache/Memory' -import { storage } from './cache/Storage' -import * as $L from './Log' -import * as $R from './Random' - -export interface Cache { - readonly get: ( - key: string, - codec: t.Type, - ) => TE.TaskEither - readonly set: ( - key: string, - codec: t.Type, - ttl?: number, - ) => (value: A) => TE.TaskEither - readonly delete: (key: string) => TE.TaskEither - readonly clear: TE.TaskEither -} - -export const chain = (...caches: RNEA.ReadonlyNonEmptyArray): Cache => ({ - get: (key, codec) => - pipe( - caches, - RNEA.reduce(TE.left(Error()), (value, { get }) => - TE.Alt.alt(value, () => get(key, codec)), - ), - ), - set: (key, codec, ttl) => (value) => - pipe( - caches, - TE.traverseArray(({ set }) => set(key, codec, ttl)(value)), - TE.map(constVoid), - ), - delete: (key) => - pipe( - caches, - TE.traverseArray(({ delete: _delete }) => _delete(key)), - TE.map(constVoid), - ), - clear: pipe( - caches, - TE.traverseArray(({ clear }) => clear), - TE.map(constVoid), - ), -}) - -// eslint-disable-next-line @typescript-eslint/unified-signatures -export function log(logStart: $L.Logger, logEnd: $L.Logger): Endomorphism -export function log(log: $L.Logger): Endomorphism -export function log(log0: $L.Logger, log1?: $L.Logger) { - const logStart = undefined !== log1 ? log0 : $L.void - const logEnd = log1 || log0 - - return (cache: Cache): Cache => ({ - get: (key, codec) => - $R.salt(TE.MonadIO)(R.randomInt(0, Number.MAX_SAFE_INTEGER), (salt) => - pipe( - logStart(`[${salt}] \rItem "${key}" retrieved from cache`), - TE.fromIO, - TE.chain(() => cache.get(key, codec)), - TE.chainFirstIOK(() => - logEnd(`[${salt}] \rItem "${key}" retrieved from cache`), - ), - ), - ), - set: (key, codec, ttl) => (value) => - $R.salt(TE.MonadIO)(R.randomInt(0, Number.MAX_SAFE_INTEGER), (salt) => - pipe( - logStart(`[${salt}] \rItem "${key}" saved to cache`), - TE.fromIO, - TE.chain(() => cache.set(key, codec, ttl)(value)), - TE.chainFirstIOK(() => - logEnd(`[${salt}] \rItem "${key}" saved to cache`), - ), - ), - ), - delete: (key) => - $R.salt(TE.MonadIO)(R.randomInt(0, Number.MAX_SAFE_INTEGER), (salt) => - pipe( - logStart(`[${salt}] \rItem "${key}" deleted from cache`), - TE.fromIO, - TE.chain(() => cache.delete(key)), - TE.chainFirstIOK(() => - logEnd(`[${salt}] \rItem "${key}" deleted from cache`), - ), - ), - ), - clear: $R.salt(TE.MonadIO)( - R.randomInt(0, Number.MAX_SAFE_INTEGER), - (salt) => - pipe( - logStart(`[${salt}] \rCache cleared`), - TE.fromIO, - TE.chain(() => cache.clear), - TE.chainFirstIOK(() => logEnd(`[${salt}] \rCache cleared`)), - ), - ), - }) -} - -export { memory, storage } diff --git a/src/Http.test.ts b/src/Http.test.ts deleted file mode 100644 index 2760e15..0000000 --- a/src/Http.test.ts +++ /dev/null @@ -1,94 +0,0 @@ -import { either } from 'fp-ts' -import * as E from 'fp-ts/Either' -import { identity } from 'io-ts' -import * as $C from './Cache' -import { cache, HttpError, HttpErrorC, HttpResponse, mock } from './Http' - -jest.useFakeTimers() - -describe('Http', () => { - describe('cache', () => { - const _cache = $C.memory() - const http = cache(_cache)(mock) - - describe('get', () => { - it('should return the same successful result', async () => { - const h = await http.get('foo')() - const c = await http.get('foo')() - - if (E.isRight(h)) { - expect(c).toStrictEqual(h) - } else { - expect(h).not.toStrictEqual(c) - } - }) - it('should return different results when the cache is cleared', async () => { - const h = await http.get('foo')() - await _cache.clear() - const c = await http.get('foo')() - - expect(c).not.toStrictEqual(h) - }) - }) - }) - - describe('HttpErrorC', () => { - const response: HttpResponse = { - url: 'https://example.com/', - status: 500, - headers: { - 'access-control-allow-origin': '*', - charset: 'utf-8', - 'content-type': 'application/json', - }, - body: '', - } - describe('without type given', () => { - const codec = HttpErrorC() - describe('given "Error" instance', () => { - it('should not match type', async () => { - const obj = new Error('Error messsage') - expect(codec.is(obj)).toBeFalsy() - expect(codec.validate(obj, [])._tag).toStrictEqual('Left') - }) - }) - describe('given object with "HttpResponse" property', () => { - it('should not match type', async () => { - const obj = { response } - expect(codec.is(obj)).toBeFalsy() - expect(codec.validate(obj, [])._tag).toStrictEqual('Left') - }) - }) - describe('given "HttpError" instance', () => { - it('should match type successfully', async () => { - const obj = new HttpError(response) - expect(codec.is(obj)).toBeTruthy() - expect(codec.validate(obj, [])._tag).toStrictEqual('Right') - expect( - either.match(identity, identity)(codec.validate(obj, [])), - ).toStrictEqual(obj) - }) - }) - }) - describe('given "BadRequest" type', () => { - const codec = HttpErrorC('BadRequest') - describe('given "HttpError" instance with "500" status code', () => { - it('should match type successfully', async () => { - const obj = new HttpError(response) - expect(codec.is(obj)).toBeFalsy() - expect(codec.validate(obj, [])._tag).toStrictEqual('Left') - }) - }) - describe('given "HttpError" instance with "400" status code', () => { - it('should match type successfully', async () => { - const obj = new HttpError({ ...response, status: 400 }) - expect(codec.is(obj)).toBeTruthy() - expect(codec.validate(obj, [])._tag).toStrictEqual('Right') - expect( - either.match(identity, identity)(codec.validate(obj, [])), - ).toStrictEqual(obj) - }) - }) - }) - }) -}) diff --git a/src/Http.ts b/src/Http.ts deleted file mode 100644 index 61638d2..0000000 --- a/src/Http.ts +++ /dev/null @@ -1,275 +0,0 @@ -import * as Ei from 'fp-ts/Either' -import { constant, identity, pipe } from 'fp-ts/function' -import * as J from 'fp-ts/Json' -import * as O from 'fp-ts/Option' -import * as R from 'fp-ts/Random' -import * as RR from 'fp-ts/ReadonlyRecord' -import * as TE from 'fp-ts/TaskEither' -import * as t from 'io-ts' -import { Json } from 'io-ts-types' -import * as $C from './Cache' -import * as $Er from './Error' -import { mock } from './http/Mock' -import * as $L from './Log' -import * as $R from './Random' -import * as $Stri from './string' -import * as $Stru from './struct' -import * as $T from './Type' - -const ERRORS = { - BadRequest: 400, - Unauthorized: 401, - PaymentRequired: 402, - Forbidden: 403, - NotFound: 404, - MethodNotAllowed: 405, - NotAcceptable: 406, - ProxyAuthenticationRequired: 407, - RequestTimeout: 408, - Conflict: 409, - Gone: 410, - LengthRequired: 411, - PreconditionFailed: 412, - PayloadTooLarge: 413, - RequestUriTooLong: 414, - UnsupportedMediaType: 415, - RequestedRangeNotSatisfiable: 416, - ExpectationFailed: 417, - ImATeapot: 418, - MisdirectedRequest: 421, - UnprocessableEntity: 422, - Locked: 423, - FailedDependency: 424, - UpgradeRequired: 426, - PreconditionRequired: 428, - TooManyRequests: 429, - RequestHeaderFieldsTooLarge: 431, - ConnectionClosedWithoutResponse: 444, - UnavailableForLegalReasons: 451, - ClientClosedRequest: 499, - InternalServerError: 500, - NotImplemented: 501, - BadGateway: 502, - ServiceUnavailable: 503, - GatewayTimeout: 504, - HttpVersionNotSupported: 505, - VariantAlsoNegotiates: 506, - InsufficientStorage: 507, - LoopDetected: 508, - NotExtended: 510, - NetworkAuthenticationRequired: 511, - NetworkConnectTimeoutError: 599, -} as const - -export interface Http { - readonly delete: HttpRequest<'body'> - readonly get: HttpRequest<'body'> - readonly patch: HttpRequest - readonly post: HttpRequest - readonly put: HttpRequest - readonly head: HttpRequest<'body'> - readonly options: HttpRequest<'body'> -} - -export interface HttpResponse { - readonly url: string - readonly status: number - readonly headers: RR.ReadonlyRecord> - readonly body: A -} - -export class HttpError extends Error { - constructor(readonly response: HttpResponse, message?: string) { - super(message) - } -} - -export interface HttpOptions { - readonly body?: $Stru.Struct | Buffer - readonly headers?: RR.ReadonlyRecord - readonly json?: boolean - readonly buffer?: boolean - readonly query?: RR.ReadonlyRecord -} - -export interface HttpRequest { - (url: string, options?: Omit): TE.TaskEither< - Error | HttpError, - HttpResponse - > -} - -const HttpMethods = [ - 'delete', - 'get', - 'head', - 'options', - 'patch', - 'post', - 'put', -] as const -export const HttpMethodC = $T.literalUnion(HttpMethods, 'HttpMethod') -export type HttpMethod = t.TypeOf - -export const HttpResponseC = (codec: C) => - t.type( - { - url: t.string, - status: t.number, - headers: t.readonly( - t.record(t.string, t.union([t.string, t.readonlyArray(t.string)])), - ), - body: codec, - }, - `HttpResponse(${codec.name})`, - ) - -const is = - (type?: A) => - (u: unknown): u is HttpError => - $Er.ErrorC.is(u) && - t - .type({ - response: t.intersection([ - HttpResponseC(t.unknown), - t.type({ status: type ? t.literal(ERRORS[type]) : t.number }), - ]), - }) - .is({ ...u }) - -export const HttpErrorC = (type?: A) => - new t.Type( - `Http${type || ''}Error`, - is(type), - (u, c) => (is(type)(u) ? t.success(u) : t.failure(u, c)), - identity, - ) - -const _json = - (request: HttpRequest): HttpRequest => - (url, options) => - request(url, { ...options, json: true, buffer: false }) - -export const json = (http: Http): Http => ({ - delete: _json(http.delete), - get: _json(http.get), - patch: _json(http.patch), - post: _json(http.post), - put: _json(http.put), - head: _json(http.head), - options: _json(http.options), -}) - -const _buffer = - (request: HttpRequest): HttpRequest => - (url, options) => - request(url, { ...options, buffer: true, json: false }) - -export const buffer = (http: Http): Http => ({ - delete: _buffer(http.delete), - get: _buffer(http.get), - patch: _buffer(http.patch), - post: _buffer(http.post), - put: _buffer(http.put), - head: _buffer(http.head), - options: _buffer(http.options), -}) - -export const cache = - (cache: $C.Cache) => - (http: Http): Http => ({ - ...http, - get: (url, options) => - pipe( - [url, options] as const, - J.stringify, - Ei.match( - () => http.get(url, options), - (key) => - pipe( - cache.get(key, HttpResponseC(t.unknown)), - TE.alt(() => - pipe( - http.get(url, options), - TE.chainFirst((response) => - pipe( - response as HttpResponse, - cache.set(key, HttpResponseC(Json)), - TE.altW(() => TE.of(undefined)), - ), - ), - ), - ), - ), - ), - ), - }) - -export const pool = (http: Http): Http => { - const pool = new Map< - Readonly<[string, HttpOptions | undefined]>, - Promise> - >() - - return { - ...http, - get: (url, options) => { - const key = [url, options] as const - - return pipe( - pool.get(key), - O.fromNullable, - O.match( - () => () => { - const promise = http - .get(url, options)() - .finally(() => pool.delete(key)) - pool.set(key, promise) - - return promise - }, - constant, - ), - ) - }, - } -} - -const _log = - ( - method: HttpMethod, - request: HttpRequest, - log: { start: $L.Logger; end: $L.Logger }, - ): HttpRequest => - (url, options) => - $R.salt(TE.MonadIO)(R.randomInt(0, Number.MAX_SAFE_INTEGER), (salt) => { - const message = `[${salt}] \r${$Stri.uppercase(method)} ${url}` - - return pipe( - log.start(message), - TE.fromIO, - TE.chain(() => request(url, options)), - TE.chainFirstIOK(() => log.end(message)), - TE.orElseW((error) => - pipe( - log.end(message), - TE.fromIO, - TE.chain(() => TE.left(error)), - ), - ), - ) - }) - -export const log = - (logStart: $L.Logger, logEnd = $L.void) => - (http: Http): Http => ({ - delete: _log('delete', http.delete, { start: logStart, end: logEnd }), - get: _log('get', http.get, { start: logStart, end: logEnd }), - patch: _log('patch', http.patch, { start: logStart, end: logEnd }), - post: _log('post', http.post, { start: logStart, end: logEnd }), - put: _log('put', http.put, { start: logStart, end: logEnd }), - head: _log('head', http.head, { start: logStart, end: logEnd }), - options: _log('options', http.options, { start: logStart, end: logEnd }), - }) - -export { mock } diff --git a/src/Stream.ts b/src/Stream.ts deleted file mode 100644 index 3e4093b..0000000 --- a/src/Stream.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { identity } from 'fp-ts/function' -import * as t from 'io-ts' -import { Duplex, Readable, Writable } from 'stream' - -const isReadable = (u: unknown): u is NodeJS.ReadableStream => - u instanceof Readable - -export const ReadableStreamC = new t.Type( - 'ReadableStream', - isReadable, - (u, c) => (isReadable(u) ? t.success(u) : t.failure(u, c)), - identity, -) - -const isWritable = (u: unknown): u is NodeJS.WritableStream => - u instanceof Writable - -export const WritableStreamC = new t.Type( - 'WritableStream', - isWritable, - (u, c) => (isWritable(u) ? t.success(u) : t.failure(u, c)), - identity, -) - -const isReadWrite = (u: unknown): u is NodeJS.ReadWriteStream => - u instanceof Duplex - -export const ReadWriteStreamC = new t.Type( - 'ReadWriteStream', - isReadWrite, - (u, c) => (isReadWrite(u) ? t.success(u) : t.failure(u, c)), - identity, -) diff --git a/src/cache/Memcached.test.ts b/src/cache/Memcached.test.ts deleted file mode 100644 index 8c63e99..0000000 --- a/src/cache/Memcached.test.ts +++ /dev/null @@ -1,79 +0,0 @@ -import * as E from 'fp-ts/Either' -import { pipe } from 'fp-ts/function' -import * as T from 'fp-ts/Task' -import * as TE from 'fp-ts/TaskEither' -import * as t from 'io-ts' -// eslint-disable-next-line @typescript-eslint/ban-ts-comment -// @ts-ignore -import Memcached from 'memcached-mock' -import { $memcached } from './Memcached' - -describe('Cache', () => { - describe('memcached', () => { - describe('get', () => { - it('should fail with a missing item', async () => { - const _memcached = $memcached(() => new Memcached()) - - await expect( - pipe(_memcached.get('foo', t.unknown), T.map(E.isLeft))(), - ).resolves.toBe(true) - }) - it('should fail with wrong item encoding', async () => { - const _memcached = $memcached(() => new Memcached()) - - await expect( - pipe( - 'foo', - _memcached.set('foo', t.string), - TE.chain(() => _memcached.get('foo', t.number)), - T.map(E.isLeft), - )(), - ).resolves.toBe(true) - }) - it('should succeed with correct item encoding', async () => { - const _memcached = $memcached(() => new Memcached()) - - await expect( - pipe( - 'foo', - _memcached.set('foo', t.string), - TE.chain(() => _memcached.get('foo', t.string)), - T.map(E.isRight), - )(), - ).resolves.toBe(true) - }) - }) - - describe('delete', () => { - it('should delete an item', async () => { - const _memcached = $memcached(() => new Memcached()) - - await expect( - pipe( - 'foo', - _memcached.set('foo', t.string), - TE.chainFirst(() => _memcached.delete('foo')), - TE.chain(() => _memcached.get('foo', t.string)), - T.map(E.isLeft), - )(), - ).resolves.toBe(true) - }) - }) - - describe('clear', () => { - it('should clear the cache', async () => { - const _memcached = $memcached(() => new Memcached()) - - await expect( - pipe( - 'foo', - _memcached.set('foo', t.string), - TE.chainFirst(() => _memcached.clear), - TE.chain(() => _memcached.get('foo', t.string)), - T.map(E.isLeft), - )(), - ).resolves.toBe(true) - }) - }) - }) -}) diff --git a/src/cache/Memcached.ts b/src/cache/Memcached.ts deleted file mode 100644 index 28272dc..0000000 --- a/src/cache/Memcached.ts +++ /dev/null @@ -1,87 +0,0 @@ -import * as Ei from 'fp-ts/Either' -import { flow, Lazy, pipe } from 'fp-ts/function' -import * as TE from 'fp-ts/TaskEither' -import Memcached from 'memcached' -import * as $C from '../Cache' -import * as $Er from '../Error' -import { memoize } from '../function' -import * as $TE from '../TaskEither' - -export const $memcached = ( - memcached: Lazy, - ttl = Infinity, -): $C.Cache => { - const _memcached = memoize(memcached) - - return { - get: (key, codec) => - pipe( - $TE.tryCatch( - () => - new Promise((resolve, reject) => - _memcached().get(key, (error, data) => { - // eslint-disable-next-line eqeqeq - undefined != error || undefined == data - ? reject(error) - : resolve(data) - }), - ), - $Er.fromUnknown(Error(`Cannot find cache item "${key}"`)), - ), - TE.chainEitherK( - flow( - codec.decode, - Ei.mapLeft( - $Er.fromUnknown( - Error(`Cannot decode cache item "${key}" into "${codec.name}"`), - ), - ), - ), - ), - ), - set: - (key, codec, _ttl = ttl) => - (value) => - pipe( - $TE.tryCatch( - () => - new Promise((resolve, reject) => - _memcached().set( - key, - codec.encode(value), - _ttl / 1000, - (error) => - // eslint-disable-next-line eqeqeq - undefined != error ? reject(error) : resolve(), - ), - ), - $Er.fromUnknown(Error(`Cannot write cache item "${key}"`)), - ), - ), - delete: (key) => - pipe( - $TE.tryCatch( - () => - new Promise((resolve, reject) => - _memcached().del(key, (error) => { - // eslint-disable-next-line eqeqeq - undefined != error ? reject(error) : resolve() - }), - ), - $Er.fromUnknown(Error(`Cannot delete cache item "${key}"`)), - ), - ), - clear: pipe( - $TE.tryCatch( - () => - new Promise((resolve, reject) => - _memcached().flush((error) => - // eslint-disable-next-line eqeqeq - undefined != error ? reject(error) : resolve(), - ), - ), - $Er.fromUnknown(Error('Cannot clear cache')), - ), - ), - } -} diff --git a/src/cache/Memory.ts b/src/cache/Memory.ts deleted file mode 100644 index bd435ce..0000000 --- a/src/cache/Memory.ts +++ /dev/null @@ -1,47 +0,0 @@ -import * as Ei from 'fp-ts/Either' -import { pipe } from 'fp-ts/function' -import * as $C from '../Cache' - -export const memory = (ttl = Infinity): $C.Cache => { - let cache: Record = {} - let timeouts: Record = {} - - return { - get: (key, codec) => async () => - pipe( - key in cache - ? Ei.right(cache[key]) - : Ei.left(Error(`Cannot find cache item "${key}"`)), - Ei.filterOrElse(codec.is, () => - Error(`Cannot decode cache item "${key}" into "${codec.name}"`), - ), - ), - set: - (key, _, _ttl = ttl) => - (value) => - async () => { - clearTimeout(timeouts[key]) - cache[key] = value - timeouts[key] = setTimeout(() => { - delete cache[key] - delete timeouts[key] - }, Math.min(Math.pow(2, 31) - 1, Math.max(0, _ttl))) - - return Ei.of(undefined) - }, - delete: (key) => async () => { - clearTimeout(timeouts[key]) - delete cache[key] - delete timeouts[key] - - return Ei.of(undefined) - }, - clear: async () => { - Object.values(timeouts).forEach(clearTimeout) - cache = {} - timeouts = {} - - return Ei.of(undefined) - }, - } -} diff --git a/src/cache/Redis.test.ts b/src/cache/Redis.test.ts deleted file mode 100644 index c2a0223..0000000 --- a/src/cache/Redis.test.ts +++ /dev/null @@ -1,111 +0,0 @@ -import * as E from 'fp-ts/Either' -import { constVoid, pipe } from 'fp-ts/function' -import * as T from 'fp-ts/Task' -import * as TE from 'fp-ts/TaskEither' -import * as t from 'io-ts' -import redis from 'redis-mock' -import { $redis } from './Redis' - -describe('Cache', () => { - describe('redis', () => { - describe('get', () => { - it('should fail with a missing item', async () => { - const _redis = $redis(redis.createClient) - - await expect( - pipe(_redis.get('foo', t.unknown), T.map(E.isLeft))(), - ).resolves.toBe(true) - }) - it('should fail with wrong item encoding', async () => { - const _redis = $redis(redis.createClient) - - await expect( - pipe( - 'foo', - _redis.set('foo', t.string), - TE.chain(() => _redis.get('foo', t.number)), - T.map(E.isLeft), - )(), - ).resolves.toBe(true) - }) - it('should succeed with correct item encoding', async () => { - const _redis = $redis(redis.createClient) - - await expect( - pipe( - 'foo', - _redis.set('foo', t.string), - TE.chain(() => _redis.get('foo', t.string)), - T.map(E.isRight), - )(), - ).resolves.toBe(true) - }) - }) - - describe('set', () => { - it('should set string item properly', async () => { - const _redis = $redis(redis.createClient) - - const result = await _redis.set('foo', t.string)('foo')() - - expect(result).toStrictEqual(E.of(constVoid())) - await expect(_redis.get('foo', t.string)()).resolves.toStrictEqual( - E.of('foo'), - ) - }) - it('should set number item properly', async () => { - const _redis = $redis(redis.createClient) - - const result = await _redis.set('foo', t.number)(42)() - - expect(result).toStrictEqual(E.of(constVoid())) - await expect(_redis.get('foo', t.number)()).resolves.toStrictEqual( - E.of(42), - ) - }) - it('should set object item properly', async () => { - const _redis = $redis(redis.createClient) - const codec = t.type({ foo: t.string, bar: t.number }) - - const result = await _redis.set('foo', codec)({ foo: 'foo', bar: 42 })() - - expect(result).toStrictEqual(E.of(constVoid())) - await expect(_redis.get('foo', codec)()).resolves.toStrictEqual( - E.of({ foo: 'foo', bar: 42 }), - ) - }) - }) - - describe('delete', () => { - it('should delete an item', async () => { - const _redis = $redis(redis.createClient) - - await expect( - pipe( - 'foo', - _redis.set('foo', t.string), - TE.chainFirst(() => _redis.delete('foo')), - TE.chain(() => _redis.get('foo', t.string)), - T.map(E.isLeft), - )(), - ).resolves.toBe(true) - }) - }) - - describe('clear', () => { - it('should clear the cache', async () => { - const _redis = $redis(redis.createClient) - - await expect( - pipe( - 'foo', - _redis.set('foo', t.string), - TE.chainFirst(() => _redis.clear), - TE.chain(() => _redis.get('foo', t.string)), - T.map(E.isLeft), - )(), - ).resolves.toBe(true) - }) - }) - }) -}) diff --git a/src/cache/Redis.ts b/src/cache/Redis.ts deleted file mode 100644 index d03ff2e..0000000 --- a/src/cache/Redis.ts +++ /dev/null @@ -1,106 +0,0 @@ -import * as Ei from 'fp-ts/Either' -import { flow, Lazy, pipe } from 'fp-ts/function' -import * as TE from 'fp-ts/TaskEither' -import { JsonFromString } from 'io-ts-types' -import { RedisClient } from 'redis' -import * as $C from '../Cache' -import * as $Er from '../Error' -import { memoize } from '../function' -import * as $TE from '../TaskEither' - -export const $redis = (redis: Lazy, ttl = Infinity): $C.Cache => { - const _redis = memoize( - () => - new Promise((resolve, reject) => { - const client = redis() - client.on('error', reject).on('ready', () => resolve(client)) - }), - ) - - return { - get: (key, codec) => - pipe( - $TE.tryCatch( - () => - new Promise((resolve, reject) => - _redis() - .then((client) => - client.get(key, (error, result) => { - null !== error || null === result - ? reject(error) - : resolve(result) - }), - ) - .catch(reject), - ), - $Er.fromUnknown(Error(`Cannot find cache item "${key}"`)), - ), - TE.chainEitherK( - flow( - JsonFromString.decode, - Ei.chain(codec.decode), - Ei.mapLeft( - $Er.fromUnknown( - Error(`Cannot decode cache item "${key}" into "${codec.name}"`), - ), - ), - ), - ), - ), - set: - (key, codec, _ttl = ttl) => - (value) => - pipe( - $TE.tryCatch( - () => - new Promise((resolve, reject) => - _redis() - .then((client) => - client.set( - key, - JsonFromString.pipe(codec).encode(value), - 'EX', - _ttl / 1000, - (error) => (null !== error ? reject(error) : resolve()), - ), - ) - .catch(reject), - ), - $Er.fromUnknown(Error(`Cannot write cache item "${key}"`)), - ), - ), - delete: (key) => - pipe( - $TE.tryCatch( - () => - new Promise((resolve, reject) => - _redis() - .then((client) => - client.del(key, (error, result) => { - null !== error || null === result - ? reject(error) - : resolve() - }), - ) - .catch(reject), - ), - $Er.fromUnknown(Error(`Cannot delete cache item "${key}"`)), - ), - ), - clear: pipe( - $TE.tryCatch( - () => - new Promise((resolve, reject) => - _redis() - .then((client) => - client.flushdb((error) => - null !== error ? reject(error) : resolve(), - ), - ) - .catch(reject), - ), - $Er.fromUnknown(Error('Cannot clear cache')), - ), - ), - } -} diff --git a/src/cache/Storage.test.ts b/src/cache/Storage.test.ts deleted file mode 100644 index 682f05c..0000000 --- a/src/cache/Storage.test.ts +++ /dev/null @@ -1,104 +0,0 @@ -import * as E from 'fp-ts/Either' -import { pipe } from 'fp-ts/function' -import * as T from 'fp-ts/Task' -import * as TE from 'fp-ts/TaskEither' -import * as t from 'io-ts' -import { storage } from './Storage' - -class MemoryStorage implements Storage { - private storage: Record = {} - - getItem(key: string): string | null { - return key in this.storage ? this.storage[key] : null - } - - setItem(key: string, value: string): void { - this.storage[key] = value - } - - removeItem(key: string): void { - delete this.storage[key] - } - - clear(): void { - this.storage = {} - } - - get length(): number { - return Object.keys(this.storage).length - } - - key(_: number): string | null { - return null - } -} - -describe('Cache', () => { - describe('storage', () => { - describe('get', () => { - it('should fail with a missing item', async () => { - const _storage = storage(() => new MemoryStorage()) - - await expect( - pipe(_storage.get('foo', t.unknown), T.map(E.isLeft))(), - ).resolves.toBe(true) - }) - it('should fail with wrong item encoding', async () => { - const _storage = storage(() => new MemoryStorage()) - - await expect( - pipe( - 'foo', - _storage.set('foo', t.string), - TE.chain(() => _storage.get('foo', t.number)), - T.map(E.isLeft), - )(), - ).resolves.toBe(true) - }) - it('should succeed with correct item encoding', async () => { - const _storage = storage(() => new MemoryStorage()) - - await expect( - pipe( - 'foo', - _storage.set('foo', t.string), - TE.chain(() => _storage.get('foo', t.string)), - T.map(E.isRight), - )(), - ).resolves.toBe(true) - }) - }) - - describe('delete', () => { - it('should delete an item', async () => { - const _storage = storage(() => new MemoryStorage()) - - await expect( - pipe( - 'foo', - _storage.set('foo', t.string), - TE.chainFirst(() => _storage.delete('foo')), - TE.chain(() => _storage.get('foo', t.string)), - T.map(E.isLeft), - )(), - ).resolves.toBe(true) - }) - }) - - describe('clear', () => { - it('should clear the cache', async () => { - const _storage = storage(() => new MemoryStorage()) - - await expect( - pipe( - 'foo', - _storage.set('foo', t.string), - TE.chainFirst(() => _storage.clear), - TE.chain(() => _storage.get('foo', t.string)), - T.map(E.isLeft), - )(), - ).resolves.toBe(true) - }) - }) - }) -}) diff --git a/src/cache/Storage.ts b/src/cache/Storage.ts deleted file mode 100644 index 60f0b4e..0000000 --- a/src/cache/Storage.ts +++ /dev/null @@ -1,84 +0,0 @@ -import * as Ei from 'fp-ts/Either' -import { flow, Lazy, pipe } from 'fp-ts/function' -import * as J from 'fp-ts/Json' -import * as t from 'io-ts' -import { Json } from 'io-ts-types' -import * as $C from '../Cache' -import * as $Er from '../Error' -import { memoize } from '../function' -import * as $S from '../struct' - -const CacheItemC = t.type({ - exp: t.number, - value: Json, -}) - -const _storage = ( - storage: Lazy, - name?: string, - ttl = Infinity, -): $C.Cache => { - const _storage = memoize(storage) - - return { - get: (key, codec) => async () => - pipe( - _storage().getItem(`${undefined !== name ? `${name}_` : ''}${key}`), - Ei.fromNullable(Error(`Cannot find cache item "${key}"`)), - Ei.chain( - flow( - J.parse, - Ei.chainW(CacheItemC.decode), - Ei.mapLeft( - $Er.fromUnknown(Error(`Cannot decode cache item "${key}"`)), - ), - ), - ), - Ei.filterOrElse( - ({ exp }) => Date.now() < exp, - () => Error(`Cache item "${key}" is expired`), - ), - Ei.map($S.lookup('value')), - Ei.chain( - flow( - codec.decode, - Ei.mapLeft( - $Er.fromUnknown( - Error(`Cannot decode cache item "${key}" into "${codec.name}"`), - ), - ), - ), - ), - ), - set: - (key, codec, _ttl = ttl) => - (value) => - async () => - pipe( - { - exp: Math.min( - Number.MAX_SAFE_INTEGER, - Date.now() + Math.max(0, _ttl) + 1, - ), - value: codec.encode(value), - }, - J.stringify, - Ei.bimap( - $Er.fromUnknown(Error(`Cannot encode cache item "${key}"`)), - (item) => - _storage().setItem( - `${undefined !== name ? `${name}_` : ''}${key}`, - item, - ), - ), - ), - delete: (key) => async () => - pipe( - _storage().removeItem(`${undefined !== name ? `${name}_` : ''}${key}`), - Ei.of, - ), - clear: async () => pipe(_storage().clear(), Ei.of), - } -} - -export { _storage as storage } diff --git a/src/http/Axios.test.ts b/src/http/Axios.test.ts deleted file mode 100644 index 25c0169..0000000 --- a/src/http/Axios.test.ts +++ /dev/null @@ -1,112 +0,0 @@ -import axios from 'axios' -import * as E from 'fp-ts/Either' -import { pipe } from 'fp-ts/function' -import * as TE from 'fp-ts/TaskEither' -import { mocked } from 'ts-jest/utils' -import { $http } from '../index' -import { $axios } from './Axios' - -jest.mock('axios') - -describe('Http', () => { - describe('axios', () => { - describe('get', () => { - it('should wrap a response', async () => { - mocked(axios, true).request.mockResolvedValue({ - config: { url: 'bar' }, - status: 200, - headers: { - foo: 'bar', - thx: 1138, - mad: ['max'], - }, - data: 42, - }) - - await expect( - $axios(mocked(axios, true)).get('foo')(), - ).resolves.toStrictEqual( - E.right({ - url: 'bar', - status: 200, - headers: { - foo: 'bar', - mad: ['max'], - }, - body: 42, - }), - ) - }) - it('should wrap an error', async () => { - const error = Error('foo') - mocked(axios, true).request.mockRejectedValue(error) - - await expect( - $axios(mocked(axios, true)).get('foo')(), - ).resolves.toStrictEqual(E.left(error)) - }) - it('should wrap an HTTP error', async () => { - mocked(axios, true).request.mockRejectedValue({ - name: 'foo', - message: 'bar', - response: { - config: {}, - status: 500, - headers: { - foo: 'bar', - thx: 1138, - mad: ['max'], - }, - data: 42, - }, - }) - mocked(axios, true).isAxiosError.mockReturnValue(true) - - await expect( - pipe( - $axios(mocked(axios, true)).get('foo'), - TE.mapLeft((error: any) => error.response), - )(), - ).resolves.toStrictEqual( - E.left({ - url: 'foo', - status: 500, - headers: { - foo: 'bar', - mad: ['max'], - }, - body: 42, - }), - ) - }) - }) - describe('buffer', () => { - it('should return initial buffer', async () => { - const base64 = - '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' - const binary = Buffer.from(base64, 'base64').toString('binary') - mocked(axios, true).request.mockResolvedValue({ - config: { url: 'bar' }, - status: 200, - headers: { - 'content-type': 'application/pdf', - }, - data: binary, - }) - - await expect( - pipe($axios(mocked(axios, true)), $http.buffer).get('foo')(), - ).resolves.toStrictEqual( - E.right({ - url: 'bar', - status: 200, - headers: { - 'content-type': 'application/pdf', - }, - body: binary, - }), - ) - }) - }) - }) -}) diff --git a/src/http/Axios.ts b/src/http/Axios.ts deleted file mode 100644 index 4cfb944..0000000 --- a/src/http/Axios.ts +++ /dev/null @@ -1,78 +0,0 @@ -import { AxiosResponse, AxiosStatic } from 'axios' -import * as E from 'fp-ts/Either' -import { pipe } from 'fp-ts/function' -import * as RR from 'fp-ts/ReadonlyRecord' -import * as t from 'io-ts' -import * as $E from '../Error' -import * as $H from '../Http' -import * as $S from '../string' -import * as $TE from '../TaskEither' - -const response = - (url: string) => - (response: AxiosResponse): $H.HttpResponse => ({ - url: response.config.url || url, - status: response.status, - headers: pipe( - response.headers, - t.readonly(t.record(t.string, t.unknown)).decode, - E.map(RR.filter(t.union([t.string, t.readonlyArray(t.string)]).is)), - E.getOrElse(() => ({})), - ), - body: response.data, - }) - -const request = ( - axios: AxiosStatic, - method: $H.HttpMethod, - url: string, - options: $H.HttpOptions = {}, -) => - $TE.tryCatch( - () => - axios - .request({ - data: options.body, - headers: { - ...options.headers, - ...(options.json ? { 'Content-Type': 'application/json' } : null), - }, - method, - params: options.query, - // eslint-disable-next-line no-nested-ternary - ...(options.json - ? { responseType: 'json' } - : options.buffer - ? { responseType: 'arraybuffer' } - : null), - url, - }) - .then(response(url)) - .catch((error) => { - if (!axios.isAxiosError(error) || undefined === error.response) { - throw error - } - - throw $E.wrap( - new $H.HttpError( - response(url)(error.response), - `Cannot make HTTP request "${$S.uppercase(method)} ${url}": ${ - error.message - }`, - ), - )(error) - }), - $E.fromUnknown( - Error(`Cannot make HTTP request "${$S.uppercase(method)} ${url}"`), - ), - ) - -export const $axios = (_axios: AxiosStatic): $H.Http => ({ - delete: (url, options) => request(_axios, 'delete', url, options), - get: (url, options) => request(_axios, 'get', url, options), - patch: (url, options) => request(_axios, 'patch', url, options), - post: (url, options) => request(_axios, 'post', url, options), - put: (url, options) => request(_axios, 'put', url, options), - head: (url, options) => request(_axios, 'head', url, options), - options: (url, options) => request(_axios, 'options', url, options), -}) diff --git a/src/http/Fetch.test.ts b/src/http/Fetch.test.ts deleted file mode 100644 index 93d2050..0000000 --- a/src/http/Fetch.test.ts +++ /dev/null @@ -1,83 +0,0 @@ -import * as E from 'fp-ts/Either' -import { pipe } from 'fp-ts/function' -import * as TE from 'fp-ts/TaskEither' -import fetch from 'node-fetch' -import { mocked } from 'ts-jest/utils' -import { $fetch } from './Fetch' - -jest.mock('node-fetch') - -describe('Http', () => { - describe('fetch', () => { - describe('get', () => { - it('should wrap a response', async () => { - mocked(fetch, true).mockResolvedValue({ - ok: true, - url: 'bar', - status: 200, - headers: { - entries: () => [ - ['foo', 'bar'], - ['mad', 'max'], - ], - }, - text: () => Promise.resolve('foo'), - } as any) - - await expect( - $fetch(mocked(fetch, true) as any).get('foo')(), - ).resolves.toStrictEqual( - E.right({ - url: 'bar', - status: 200, - headers: { - foo: 'bar', - mad: 'max', - }, - body: 'foo', - }), - ) - }) - it('should wrap an error', async () => { - const error = Error('foo') - mocked(fetch, true).mockRejectedValue(error) - - await expect( - $fetch(mocked(fetch, true) as any).get('foo')(), - ).resolves.toStrictEqual(E.left(error)) - }) - it('should wrap an HTTP error', async () => { - mocked(fetch, true).mockResolvedValue({ - ok: false, - url: 'bar', - status: 500, - statusText: 'foo', - headers: { - entries: () => [ - ['foo', 'bar'], - ['mad', 'max'], - ], - }, - text: () => Promise.resolve('foo'), - } as any) - - await expect( - pipe( - $fetch(mocked(fetch, true) as any).get('foo'), - TE.mapLeft((error: any) => error.response), - )(), - ).resolves.toStrictEqual( - E.left({ - url: 'bar', - status: 500, - headers: { - foo: 'bar', - mad: 'max', - }, - body: 'foo', - }), - ) - }) - }) - }) -}) diff --git a/src/http/Fetch.ts b/src/http/Fetch.ts deleted file mode 100644 index 90cf35d..0000000 --- a/src/http/Fetch.ts +++ /dev/null @@ -1,101 +0,0 @@ -import * as Ei from 'fp-ts/Either' -import { constUndefined, pipe } from 'fp-ts/function' -import * as J from 'fp-ts/Json' -import * as O from 'fp-ts/Option' -import * as RA from 'fp-ts/ReadonlyArray' -import * as RR from 'fp-ts/ReadonlyRecord' -import * as Se from 'fp-ts/Semigroup' -import * as t from 'io-ts' -import { NonEmptyString } from 'io-ts-types' -import * as $Er from '../Error' -import * as $H from '../Http' -import * as $St from '../string' -import * as $TE from '../TaskEither' - -const request = ( - _fetch: typeof fetch, - method: $H.HttpMethod, - url: string, - options: $H.HttpOptions = {}, -) => - $TE.tryCatch( - () => - _fetch( - pipe( - options.query, - O.fromNullable, - O.map(RR.map((value) => value.toString())), - O.map((query) => new URLSearchParams(query)), - O.map((params) => params.toString()), - O.filter(NonEmptyString.is), - O.match( - () => url, - (queryString) => `${url}?${queryString}`, - ), - ), - { - // eslint-disable-next-line no-nested-ternary - body: options.json - ? pipe(options.body, J.stringify, Ei.getOrElseW(constUndefined)) - : t.record(t.string, t.unknown).is(options.body) - ? pipe( - options.body, - O.fromNullable, - O.map( - RR.reduceWithIndex(new FormData(), (name, form, value) => { - if (t.union([t.boolean, t.number, t.string]).is(value)) { - form.append(name, value.toString()) - } - - return form - }), - ), - O.getOrElseW(constUndefined), - ) - : undefined, - headers: { - ...options.headers, - ...(options.json ? { 'Content-Type': 'application/json' } : null), - }, - method: $St.uppercase(method), - }, - ).then((response) => - (response.ok && options.json ? response.json() : response.text()).then( - (body) => { - const _response = { - url: response.url, - status: response.status, - headers: pipe( - [...response.headers.entries()], - RR.fromFoldable(Se.last(), RA.Foldable), - ), - body, - } - - if (!response.ok) { - throw new $H.HttpError( - _response, - `Cannot make HTTP request "${$St.uppercase(method)} ${url}": ${ - response.statusText - }`, - ) - } - - return _response - }, - ), - ), - $Er.fromUnknown( - Error(`Cannot make HTTP request "${$St.uppercase(method)} ${url}"`), - ), - ) - -export const $fetch = (_fetch: typeof fetch): $H.Http => ({ - delete: (url, options) => request(_fetch, 'delete', url, options), - get: (url, options) => request(_fetch, 'get', url, options), - patch: (url, options) => request(_fetch, 'patch', url, options), - post: (url, options) => request(_fetch, 'post', url, options), - put: (url, options) => request(_fetch, 'put', url, options), - head: (url, options) => request(_fetch, 'head', url, options), - options: (url, options) => request(_fetch, 'options', url, options), -}) diff --git a/src/http/Got.test.ts b/src/http/Got.test.ts deleted file mode 100644 index f622837..0000000 --- a/src/http/Got.test.ts +++ /dev/null @@ -1,47 +0,0 @@ -import * as E from 'fp-ts/Either' -import got from 'got' -import { mocked } from 'ts-jest/utils' -import { $got } from './Got' - -jest.mock('got') - -describe('Http', () => { - describe('got', () => { - describe('get', () => { - it('should wrap a response', async () => { - mocked(got, true).mockResolvedValue({ - url: 'bar', - statusCode: 200, - headers: { - foo: 'bar', - thx: undefined, - mad: ['max'], - }, - body: 42, - }) - - await expect( - $got(mocked(got, true)).get('foo')(), - ).resolves.toStrictEqual( - E.right({ - url: 'bar', - status: 200, - headers: { - foo: 'bar', - mad: ['max'], - }, - body: 42, - }), - ) - }) - it('should wrap an error', async () => { - const error = Error('foo') - mocked(got, true).mockRejectedValue(error) - - await expect( - $got(mocked(got, true)).get('foo')(), - ).resolves.toStrictEqual(E.left(error)) - }) - }) - }) -}) diff --git a/src/http/Got.ts b/src/http/Got.ts deleted file mode 100644 index f16d9e3..0000000 --- a/src/http/Got.ts +++ /dev/null @@ -1,74 +0,0 @@ -import { pipe } from 'fp-ts/function' -import * as RR from 'fp-ts/ReadonlyRecord' -import { Got, HTTPError } from 'got' -import * as t from 'io-ts' -import * as $E from '../Error' -import * as $H from '../Http' -import * as $S from '../string' -import * as $TE from '../TaskEither' - -const request = ( - _got: Got, - method: $H.HttpMethod, - url: string, - options: $H.HttpOptions = {}, -) => - $TE.tryCatch( - () => - _got(url, { - headers: options.headers, - method, - retry: 0, - searchParams: options.query, - ...(options.json - ? { json: options.body, responseType: 'json' } - : { form: options.body }), - }) - .then((response) => ({ - url: response.url, - status: response.statusCode, - headers: pipe( - response.headers, - RR.filter(t.union([t.string, t.readonlyArray(t.string)]).is), - ), - body: response.body, - })) - .catch((error) => { - if (!(error instanceof HTTPError)) { - throw error - } - - throw $E.wrap( - new $H.HttpError( - { - url: error.response.url, - status: error.response.statusCode, - headers: pipe( - error.response.headers, - RR.filter(t.union([t.string, t.readonlyArray(t.string)]).is), - ), - body: error.response.body, - }, - `Cannot make HTTP request "${$S.uppercase(method)} ${url}": ${ - error.message - }`, - ), - )(error) - }), - $E.fromUnknown( - Error(`Cannot make HTTP request "${$S.uppercase(method)} ${url}"`), - ), - ) - -/** - * @deprecated Use `$axios` instead - */ -export const $got = (_got: Got): $H.Http => ({ - delete: (url, options) => request(_got, 'delete', url, options), - get: (url, options) => request(_got, 'get', url, options), - patch: (url, options) => request(_got, 'patch', url, options), - post: (url, options) => request(_got, 'post', url, options), - put: (url, options) => request(_got, 'put', url, options), - head: (url, options) => request(_got, 'head', url, options), - options: (url, options) => request(_got, 'options', url, options), -}) diff --git a/src/http/Mock.ts b/src/http/Mock.ts deleted file mode 100644 index ac7aa15..0000000 --- a/src/http/Mock.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { pipe } from 'fp-ts/function' -import * as TE from 'fp-ts/TaskEither' -import * as t from 'io-ts' -import { run } from '../function' -import * as $H from '../Http' -import * as $M from '../Mock' - -const response = (url: string, error = false): $M.Mock<$H.HttpResponse> => - $M.struct({ - url: $M.literal(url), - status: error ? $M.integer(300, 599) : $M.integer(200, 299), - headers: $M.readonlyRecord( - $M.string, - $M.union($M.string, $M.readonlyArray($M.string)), - ), - body: $M.unknown(), - }) - -const error = (url: string): $M.Mock => - $M.struct({ - name: $M.string, - message: $M.string, - stack: $M.string, - response: $M.nullable(response(url, true)), - }) - -const request: $H.HttpRequest = (url) => - pipe( - $M.union(error(url), response(url)), - TE.fromIOK(run), - TE.chain((mock) => - $H.HttpResponseC(t.unknown).is(mock) - ? TE.right<$H.HttpError, $H.HttpResponse>(mock) - : TE.left(mock), - ), - ) - -export const mock: $H.Http = { - delete: request, - get: request, - patch: request, - post: request, - put: request, - head: request, - options: request, -} diff --git a/src/index.ts b/src/index.ts index 3d06fbd..5af51bd 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,7 +1,5 @@ import * as $aggregate from './Aggregate' import * as $binary from './Binary' -import * as $buffer from './Buffer' -import * as $cache from './Cache' import * as $console from './Console' import * as $crypto from './Crypto' import * as $date from './Date' @@ -9,7 +7,6 @@ import * as $eq from './Eq' import * as $error from './Error' import * as _$generatorL from './GeneratorL' import * as $has from './Has' -import * as $http from './Http' import * as $log from './Log' import * as $magma from './Magma' import * as $matrix from './Matrix' @@ -25,7 +22,6 @@ import * as $readonlyArray from './ReadonlyArray' import * as $readonlyRecord from './ReadonlyRecord' import * as $readonlyTuple from './ReadonlyTuple' import * as $storage from './Storage' -import * as $stream from './Stream' import * as $string from './string' import * as $struct from './struct' import * as $taskEither from './TaskEither' @@ -62,8 +58,6 @@ const $generatorL = _$generatorL export { $aggregate, $binary, - $buffer, - $cache, $console, $crypto, $date, @@ -71,7 +65,6 @@ export { $error, $generatorL, $has, - $http, $log, $magma, $matrix, @@ -87,7 +80,6 @@ export { $readonlyRecord, $readonlyTuple, $storage, - $stream, $string, $struct, $taskEither, diff --git a/src/storage/Flydrive.test.ts b/src/storage/Flydrive.test.ts deleted file mode 100644 index c24f783..0000000 --- a/src/storage/Flydrive.test.ts +++ /dev/null @@ -1,130 +0,0 @@ -import { Storage, StorageManager } from '@slynova/flydrive' -import * as E from 'fp-ts/Either' -import { pipe } from 'fp-ts/function' -import * as T from 'fp-ts/Task' -import * as TE from 'fp-ts/TaskEither' -import { Readable } from 'stream' -import * as $B from '../Buffer' -import * as $S from '../Stream' -import { $flydrive } from './Flydrive' - -class MemoryStorage extends Storage { - private storage: Record = {} - - getStream(location: string) { - if (!(location in this.storage)) { - throw undefined - } - - return Readable.from($B.BufferFromStringC.encode(this.storage[location])) - } - - getUrl(location: string) { - if (!(location in this.storage)) { - throw undefined - } - - return `data:;base64,${this.storage[location].toString('base64')}` - } - - async getBuffer(location: string) { - if (!(location in this.storage)) { - throw undefined - } - - return { - content: this.storage[location], - raw: undefined, - } - } - - async put(location: string, content: unknown) { - if (!$B.BufferC.is(content) && !$S.ReadableStreamC.is(content)) { - throw undefined - } - - const buffer = $S.ReadableStreamC.is(content) - ? await $B.fromStream(content)() - : E.right(content) - if (E.isLeft(buffer)) { - throw undefined - } - - this.storage[location] = buffer.right - - return { raw: undefined } - } - - async delete(location: string) { - if (!(location in this.storage)) { - return { wasDeleted: false, raw: undefined } - } - - delete this.storage[location] - - return { wasDeleted: true, raw: undefined } - } -} - -const flydrive = () => { - const _flydrive = new StorageManager({ - disks: { test: { driver: 'memory', config: {} } }, - default: 'test', - }) - _flydrive.registerDriver('memory', MemoryStorage) - - return _flydrive -} - -describe('Storage', () => { - describe('flydrive', () => { - describe('read', () => { - it('should fail with a missing file system', async () => { - const _flydrive = $flydrive(flydrive) - - await expect( - pipe(_flydrive.read('foo', { fileSystem: 'foo' }), T.map(E.isLeft))(), - ).resolves.toBe(true) - }) - it('should fail with a missing file', async () => { - const _flydrive = $flydrive(flydrive) - - await expect( - pipe( - _flydrive.read('foo', { fileSystem: 'test' }), - T.map(E.isLeft), - )(), - ).resolves.toBe(true) - await expect( - pipe(_flydrive.read('foo'), T.map(E.isLeft))(), - ).resolves.toBe(true) - }) - it('should succeed with an existent file', async () => { - const _flydrive = $flydrive(flydrive) - - await expect( - pipe( - Buffer.from('foo'), - _flydrive.write('foo'), - TE.chain(() => _flydrive.read('foo')), - )(), - ).resolves.toStrictEqual(E.right(Buffer.from('foo'))) - }) - }) - describe('delete', () => { - it('should delete a file', async () => { - const _flydrive = $flydrive(flydrive) - - await expect( - pipe( - Buffer.from('foo'), - _flydrive.write('foo'), - TE.chainFirst(() => _flydrive.delete('foo')), - TE.chain(() => _flydrive.read('foo')), - T.map(E.isLeft), - )(), - ).resolves.toBe(true) - }) - }) - }) -}) diff --git a/src/storage/Flydrive.ts b/src/storage/Flydrive.ts deleted file mode 100644 index 0df5bb9..0000000 --- a/src/storage/Flydrive.ts +++ /dev/null @@ -1,112 +0,0 @@ -import { StorageManager } from '@slynova/flydrive' -import { constVoid, Lazy, pipe } from 'fp-ts/function' -import * as TE from 'fp-ts/TaskEither' -import * as $E from '../Error' -import { memoize } from '../function' -import * as $Sto from '../Storage' -import * as $Str from '../struct' -import * as $TE from '../TaskEither' - -export const $flydrive = (flydrive: Lazy): $Sto.Storage => { - const _flydrive = memoize(flydrive) - - return { - getStream: (path, { fileSystem } = {}) => - $TE.tryCatch( - async () => _flydrive().disk(fileSystem).getStream(path), - $E.fromUnknown( - Error( - `Cannot get stream for file "${path}"${ - undefined !== fileSystem ? ` on file system "${fileSystem}"` : '' - }`, - ), - ), - ), - getUrl: (path, { fileSystem } = {}) => - pipe( - $TE.tryCatch( - () => - _flydrive() - .disk(fileSystem) - .exists(path) - .then(({ exists }) => - exists ? Promise.resolve() : Promise.reject(), - ), - $E.fromUnknown( - Error( - `Cannot find file "${path}"${ - undefined !== fileSystem - ? ` on file system "${fileSystem}"` - : '' - }`, - ), - ), - ), - TE.apSecond( - $TE.tryCatch( - () => Promise.resolve(_flydrive().disk(fileSystem).getUrl(path)), - $E.fromUnknown( - Error( - `Cannot get URL for file "${path}"${ - undefined !== fileSystem - ? ` on file system "${fileSystem}"` - : '' - }`, - ), - ), - ), - ), - ), - read: (path, { fileSystem } = {}) => - $TE.tryCatch( - () => - _flydrive() - .disk(fileSystem) - .getBuffer(path) - .then($Str.lookup('content')), - $E.fromUnknown( - Error( - `Cannot read file "${path}"${ - undefined !== fileSystem - ? ` from file system "${fileSystem}"` - : '' - }`, - ), - ), - ), - write: - (path, { fileSystem } = {}) => - (data) => - $TE.tryCatch( - () => _flydrive().disk(fileSystem).put(path, data).then(constVoid), - $E.fromUnknown( - Error( - `Cannot write file "${path}"${ - undefined !== fileSystem - ? ` to file system "${fileSystem}"` - : '' - }`, - ), - ), - ), - delete: (path, { fileSystem } = {}) => - $TE.tryCatch( - () => - _flydrive() - .disk(fileSystem) - .delete(path) - .then(({ wasDeleted }) => - false === wasDeleted ? Promise.reject() : Promise.resolve(), - ), - $E.fromUnknown( - Error( - `Cannot delete file "${path}"${ - undefined !== fileSystem - ? ` from file system "${fileSystem}"` - : '' - }`, - ), - ), - ), - } -} diff --git a/src/storage/Fs.ts b/src/storage/Fs.ts deleted file mode 100644 index ae71acc..0000000 --- a/src/storage/Fs.ts +++ /dev/null @@ -1,38 +0,0 @@ -import * as TE from 'fp-ts/TaskEither' -import _fs from 'fs' -import _path from 'path' -import * as $E from '../Error' -import * as $Sto from '../Storage' -import * as $Str from '../Stream' -import * as $TE from '../TaskEither' - -export const $fs = (fs: typeof _fs, root: string): $Sto.Storage => ({ - getStream: (path) => - $TE.tryCatch( - async () => fs.createReadStream(_path.join(root, path)), - $E.fromUnknown(Error(`Cannot get stream for file "${path}"`)), - ), - getUrl: (path) => TE.left(Error(`Cannot get URL for file "${path}"`)), - read: (path) => - $TE.tryCatch( - () => fs.promises.readFile(_path.join(root, path)), - $E.fromUnknown(Error(`Cannot read file "${path}"`)), - ), - write: (path) => (data) => - $TE.tryCatch( - () => - $Str.ReadableStreamC.is(data) - ? new Promise((resolve, reject) => { - data - .pipe(fs.createWriteStream(path).on('error', reject)) - .on('end', resolve) - }) - : fs.promises.writeFile(_path.join(root, path), data), - $E.fromUnknown(Error(`Cannot write file "${path}"`)), - ), - delete: (path) => - $TE.tryCatch( - () => fs.promises.rm(_path.join(root, path)), - $E.fromUnknown(Error(`Cannot delete file "${path}"`)), - ), -}) diff --git a/yarn.lock b/yarn.lock index d984c9b..384a089 100644 --- a/yarn.lock +++ b/yarn.lock @@ -909,13 +909,6 @@ __metadata: languageName: node linkType: hard -"@sindresorhus/is@npm:^4.0.0": - version: 4.6.0 - resolution: "@sindresorhus/is@npm:4.6.0" - checksum: 83839f13da2c29d55c97abc3bc2c55b250d33a0447554997a85c539e058e57b8da092da396e252b11ec24a0279a0bed1f537fa26302209327060643e327f81d2 - languageName: node - linkType: hard - "@sinonjs/commons@npm:^1.7.0": version: 1.8.3 resolution: "@sinonjs/commons@npm:1.8.3" @@ -934,25 +927,6 @@ __metadata: languageName: node linkType: hard -"@slynova/flydrive@npm:^1.0.0": - version: 1.0.3 - resolution: "@slynova/flydrive@npm:1.0.3" - dependencies: - fs-extra: ^9.0.0 - node-exceptions: ^4.0.1 - checksum: 26c7368707a0f9e792bb7bcc13b115aeaa2c27acd9ae9429fc6e7c6c1816901e62be5f50d99d8f90378af6a12277a77f617e56a7f896cbaa4ee04885b2d5c6ff - languageName: node - linkType: hard - -"@szmarczak/http-timer@npm:^4.0.5": - version: 4.0.6 - resolution: "@szmarczak/http-timer@npm:4.0.6" - dependencies: - defer-to-connect: ^2.0.0 - checksum: c29df3bcec6fc3bdec2b17981d89d9c9fc9bd7d0c9bcfe92821dc533f4440bc890ccde79971838b4ceed1921d456973c4180d7175ee1d0023ad0562240a58d95 - languageName: node - linkType: hard - "@tootallnate/once@npm:1": version: 1.1.2 resolution: "@tootallnate/once@npm:1.1.2" @@ -1036,18 +1010,6 @@ __metadata: languageName: node linkType: hard -"@types/cacheable-request@npm:^6.0.1": - version: 6.0.2 - resolution: "@types/cacheable-request@npm:6.0.2" - dependencies: - "@types/http-cache-semantics": "*" - "@types/keyv": "*" - "@types/node": "*" - "@types/responselike": "*" - checksum: 667d25808dbf46fe104d6f029e0281ff56058d50c7c1b9182774b3e38bb9c1124f56e4c367ba54f92dbde2d1cc573f26eb0e9748710b2822bc0fd1e5498859c6 - languageName: node - linkType: hard - "@types/graceful-fs@npm:^4.1.2": version: 4.1.5 resolution: "@types/graceful-fs@npm:4.1.5" @@ -1057,13 +1019,6 @@ __metadata: languageName: node linkType: hard -"@types/http-cache-semantics@npm:*": - version: 4.0.1 - resolution: "@types/http-cache-semantics@npm:4.0.1" - checksum: 1048aacf627829f0d5f00184e16548205cd9f964bf0841c29b36bc504509230c40bc57c39778703a1c965a6f5b416ae2cbf4c1d4589c889d2838dd9dbfccf6e9 - languageName: node - linkType: hard - "@types/istanbul-lib-coverage@npm:*, @types/istanbul-lib-coverage@npm:^2.0.0, @types/istanbul-lib-coverage@npm:^2.0.1": version: 2.0.4 resolution: "@types/istanbul-lib-coverage@npm:2.0.4" @@ -1099,13 +1054,6 @@ __metadata: languageName: node linkType: hard -"@types/json-buffer@npm:~3.0.0": - version: 3.0.0 - resolution: "@types/json-buffer@npm:3.0.0" - checksum: 6b0a371dd603f0eec9d00874574bae195382570e832560dadf2193ee0d1062b8e0694bbae9798bc758632361c227b1e3b19e3bd914043b498640470a2da38b77 - languageName: node - linkType: hard - "@types/json-schema@npm:^7.0.9": version: 7.0.11 resolution: "@types/json-schema@npm:7.0.11" @@ -1120,24 +1068,6 @@ __metadata: languageName: node linkType: hard -"@types/keyv@npm:*": - version: 3.1.4 - resolution: "@types/keyv@npm:3.1.4" - dependencies: - "@types/node": "*" - checksum: e009a2bfb50e90ca9b7c6e8f648f8464067271fd99116f881073fa6fa76dc8d0133181dd65e6614d5fb1220d671d67b0124aef7d97dc02d7e342ab143a47779d - languageName: node - linkType: hard - -"@types/memcached@npm:^2.0.0": - version: 2.2.7 - resolution: "@types/memcached@npm:2.2.7" - dependencies: - "@types/node": "*" - checksum: 8023cce3f302ed55e88b83613b933c7687135149a7a08dff62ed8fe044f67d8545bf7a93e83b6a39c94ade4b670b78f857477a2ed45b172522a9e88f5dae3f0d - languageName: node - linkType: hard - "@types/node-fetch@npm:^2.5.12": version: 2.6.2 resolution: "@types/node-fetch@npm:2.6.2" @@ -1169,33 +1099,6 @@ __metadata: languageName: node linkType: hard -"@types/redis-mock@npm:^0.17.0": - version: 0.17.1 - resolution: "@types/redis-mock@npm:0.17.1" - dependencies: - "@types/redis": ^2.8.0 - checksum: b3c61974f5470914b44edb4dc33cb5d4ee8d1d4f433bef8ad1ea07a78b8d90963be17008ecb451d0f005aa927c2ad1b9c31583dbb52e0db6eaa9b8b0fc96df95 - languageName: node - linkType: hard - -"@types/redis@npm:^2.0.0, @types/redis@npm:^2.8.0": - version: 2.8.32 - resolution: "@types/redis@npm:2.8.32" - dependencies: - "@types/node": "*" - checksum: 2b12103e05977941870c9a248f6ea51f4b7ad7e0f16a7403799c2ed1b3e63b60f693c39f9186be0ea02776934c4595ddcd2a5bde41e530aaad42d26449f6a669 - languageName: node - linkType: hard - -"@types/responselike@npm:*, @types/responselike@npm:^1.0.0": - version: 1.0.0 - resolution: "@types/responselike@npm:1.0.0" - dependencies: - "@types/node": "*" - checksum: e99fc7cc6265407987b30deda54c1c24bb1478803faf6037557a774b2f034c5b097ffd65847daa87e82a61a250d919f35c3588654b0fdaa816906650f596d1b0 - languageName: node - linkType: hard - "@types/stack-utils@npm:^2.0.0": version: 2.0.1 resolution: "@types/stack-utils@npm:2.0.1" @@ -1661,13 +1564,6 @@ __metadata: languageName: node linkType: hard -"at-least-node@npm:^1.0.0": - version: 1.0.0 - resolution: "at-least-node@npm:1.0.0" - checksum: 463e2f8e43384f1afb54bc68485c436d7622acec08b6fad269b421cb1d29cebb5af751426793d0961ed243146fe4dc983402f6d5a51b720b277818dbf6f2e49e - languageName: node - linkType: hard - "atob@npm:^2.1.2": version: 2.1.2 resolution: "atob@npm:2.1.2" @@ -1677,17 +1573,6 @@ __metadata: languageName: node linkType: hard -"axios@npm:^0.28.0": - version: 0.28.1 - resolution: "axios@npm:0.28.1" - dependencies: - follow-redirects: ^1.15.0 - form-data: ^4.0.0 - proxy-from-env: ^1.1.0 - checksum: 5115a38d79064d07437c5a28f15841e3607634040e3120ec06a2c4367a7d07cf213b16496eab53b6f58ebc5fb377a440ba9ed4782529b14449a1e285734bfb54 - languageName: node - linkType: hard - "babel-jest@npm:^26.6.3": version: 26.6.3 resolution: "babel-jest@npm:26.6.3" @@ -1940,28 +1825,6 @@ __metadata: languageName: node linkType: hard -"cacheable-lookup@npm:^5.0.3": - version: 5.0.4 - resolution: "cacheable-lookup@npm:5.0.4" - checksum: 763e02cf9196bc9afccacd8c418d942fc2677f22261969a4c2c2e760fa44a2351a81557bd908291c3921fe9beb10b976ba8fa50c5ca837c5a0dd945f16468f2d - languageName: node - linkType: hard - -"cacheable-request@npm:^7.0.2": - version: 7.0.2 - resolution: "cacheable-request@npm:7.0.2" - dependencies: - clone-response: ^1.0.2 - get-stream: ^5.1.0 - http-cache-semantics: ^4.0.0 - keyv: ^4.0.0 - lowercase-keys: ^2.0.0 - normalize-url: ^6.0.1 - responselike: ^2.0.0 - checksum: 6152813982945a5c9989cb457a6c499f12edcc7ade323d2fbfd759abc860bdbd1306e08096916bb413c3c47e812f8e4c0a0cc1e112c8ce94381a960f115bc77f - languageName: node - linkType: hard - "call-bind@npm:^1.0.0, call-bind@npm:^1.0.2": version: 1.0.2 resolution: "call-bind@npm:1.0.2" @@ -2106,15 +1969,6 @@ __metadata: languageName: node linkType: hard -"clone-response@npm:^1.0.2": - version: 1.0.2 - resolution: "clone-response@npm:1.0.2" - dependencies: - mimic-response: ^1.0.0 - checksum: 2d0e61547fc66276e0903be9654ada422515f5a15741691352000d47e8c00c226061221074ce2c0064d12e975e84a8687cfd35d8b405750cb4e772f87b256eda - languageName: node - linkType: hard - "co@npm:^4.6.0": version: 4.6.0 resolution: "co@npm:4.6.0" @@ -2203,16 +2057,6 @@ __metadata: languageName: node linkType: hard -"compress-brotli@npm:^1.3.8": - version: 1.3.8 - resolution: "compress-brotli@npm:1.3.8" - dependencies: - "@types/json-buffer": ~3.0.0 - json-buffer: ~3.0.1 - checksum: de7589d692d40eb362f6c91070b5e51bc10b05a89eabb4a7c76c1aa21b625756f8c101c6999e4df0c4dc6199c5ca2e1353573bfdcca5615810f27485394162a5 - languageName: node - linkType: hard - "concat-map@npm:0.0.1": version: 0.0.1 resolution: "concat-map@npm:0.0.1" @@ -2220,13 +2064,6 @@ __metadata: languageName: node linkType: hard -"connection-parse@npm:0.0.x": - version: 0.0.7 - resolution: "connection-parse@npm:0.0.7" - checksum: 82c242157205babf80bd6467a65b4f05c21eed91cc46f76ca26398ef10b031a7a0bb63efbda3386e6d24dbfaf74a9d786b0e2fb6425b3a159c762b18052a5070 - languageName: node - linkType: hard - "console-control-strings@npm:^1.1.0": version: 1.1.0 resolution: "console-control-strings@npm:1.1.0" @@ -2373,15 +2210,6 @@ __metadata: languageName: node linkType: hard -"decompress-response@npm:^6.0.0": - version: 6.0.0 - resolution: "decompress-response@npm:6.0.0" - dependencies: - mimic-response: ^3.1.0 - checksum: d377cf47e02d805e283866c3f50d3d21578b779731e8c5072d6ce8c13cc31493db1c2f6784da9d1d5250822120cefa44f1deab112d5981015f2e17444b763812 - languageName: node - linkType: hard - "deep-is@npm:^0.1.3, deep-is@npm:~0.1.3": version: 0.1.4 resolution: "deep-is@npm:0.1.4" @@ -2396,13 +2224,6 @@ __metadata: languageName: node linkType: hard -"defer-to-connect@npm:^2.0.0": - version: 2.0.1 - resolution: "defer-to-connect@npm:2.0.1" - checksum: 8a9b50d2f25446c0bfefb55a48e90afd58f85b21bcf78e9207cd7b804354f6409032a1705c2491686e202e64fc05f147aa5aa45f9aa82627563f045937f5791b - languageName: node - linkType: hard - "define-properties@npm:^1.1.3, define-properties@npm:^1.1.4": version: 1.1.4 resolution: "define-properties@npm:1.1.4" @@ -2455,13 +2276,6 @@ __metadata: languageName: node linkType: hard -"denque@npm:^1.5.0": - version: 1.5.1 - resolution: "denque@npm:1.5.1" - checksum: 4375ad19d5cea99f90effa82a8cecdaa10f4eb261fbcd7e47cd753ff2737f037aac8f7f4e031cc77f3966314c491c86a0d3b20c128aeee57f791b4662c45108e - languageName: node - linkType: hard - "depd@npm:^1.1.2": version: 1.1.2 resolution: "depd@npm:1.1.2" @@ -3288,16 +3102,6 @@ __metadata: languageName: node linkType: hard -"follow-redirects@npm:^1.15.0": - version: 1.15.6 - resolution: "follow-redirects@npm:1.15.6" - peerDependenciesMeta: - debug: - optional: true - checksum: a62c378dfc8c00f60b9c80cab158ba54e99ba0239a5dd7c81245e5a5b39d10f0c35e249c3379eae719ff0285fff88c365dd446fab19dee771f1d76252df1bbf5 - languageName: node - linkType: hard - "for-in@npm:^1.0.2": version: 1.0.2 resolution: "for-in@npm:1.0.2" @@ -3316,73 +3120,30 @@ __metadata: languageName: node linkType: hard -"form-data@npm:^4.0.0": - version: 4.0.0 - resolution: "form-data@npm:4.0.0" - dependencies: - asynckit: ^0.4.0 - combined-stream: ^1.0.8 - mime-types: ^2.1.12 - checksum: 01135bf8675f9d5c61ff18e2e2932f719ca4de964e3be90ef4c36aacfc7b9cb2fceb5eca0b7e0190e3383fe51c5b37f4cb80b62ca06a99aaabfcfd6ac7c9328c - languageName: node - linkType: hard - "fortepiano@workspace:.": version: 0.0.0-use.local resolution: "fortepiano@workspace:." dependencies: "@rushstack/eslint-patch": ^1.1.3 - "@slynova/flydrive": ^1.0.0 "@types/jest": ^26.0.24 - "@types/memcached": ^2.0.0 "@types/node-fetch": ^2.5.12 - "@types/redis": ^2.0.0 - "@types/redis-mock": ^0.17.0 - axios: ^0.28.0 eslint: ^8.16.0 eslint-config-facile: ^0.5.0 fp-ts: ^2.0.0 - got: ^11.0.0 io-ts: ^2.0.0 io-ts-types: ^0.5.0 jest: ^26.6.3 - memcached: ^2.0.0 - memcached-mock: ^0.1.0 monocle-ts: ^2.3.10 newtype-ts: ^0.3.4 node-fetch: ^2.6.7 prettier: ^2.6.2 - redis: ^3.0.0 - redis-mock: ^0.56.3 ts-jest: ^26.5.6 ts-node: ^10.9.2 typescript: ^4.6.4 peerDependencies: - "@slynova/flydrive": ^1.0.0 - "@types/memcached": ^2.0.0 - "@types/redis": ^2.0.0 - axios: ^0.21.2 || ^0.28.0 fp-ts: ^2.0.0 - got: ^11.0.0 io-ts: ^2.0.0 io-ts-types: ^0.5.0 - memcached: ^2.0.0 - redis: ^3.0.0 - peerDependenciesMeta: - "@slynova/flydrive": - optional: true - "@types/memcached": - optional: true - "@types/redis": - optional: true - axios: - optional: true - got: - optional: true - memcached: - optional: true - redis: - optional: true languageName: unknown linkType: soft @@ -3402,18 +3163,6 @@ __metadata: languageName: node linkType: hard -"fs-extra@npm:^9.0.0": - version: 9.1.0 - resolution: "fs-extra@npm:9.1.0" - dependencies: - at-least-node: ^1.0.0 - graceful-fs: ^4.2.0 - jsonfile: ^6.0.1 - universalify: ^2.0.0 - checksum: ba71ba32e0faa74ab931b7a0031d1523c66a73e225de7426e275e238e312d07313d2da2d33e34a52aa406c8763ade5712eb3ec9ba4d9edce652bcacdc29e6b20 - languageName: node - linkType: hard - "fs-minipass@npm:^2.0.0, fs-minipass@npm:^2.1.0": version: 2.1.0 resolution: "fs-minipass@npm:2.1.0" @@ -3539,7 +3288,7 @@ __metadata: languageName: node linkType: hard -"get-stream@npm:^5.0.0, get-stream@npm:^5.1.0": +"get-stream@npm:^5.0.0": version: 5.2.0 resolution: "get-stream@npm:5.2.0" dependencies: @@ -3640,26 +3389,7 @@ __metadata: languageName: node linkType: hard -"got@npm:^11.0.0": - version: 11.8.5 - resolution: "got@npm:11.8.5" - dependencies: - "@sindresorhus/is": ^4.0.0 - "@szmarczak/http-timer": ^4.0.5 - "@types/cacheable-request": ^6.0.1 - "@types/responselike": ^1.0.0 - cacheable-lookup: ^5.0.3 - cacheable-request: ^7.0.2 - decompress-response: ^6.0.0 - http2-wrapper: ^1.0.0-beta.5.2 - lowercase-keys: ^2.0.0 - p-cancelable: ^2.0.0 - responselike: ^2.0.0 - checksum: 2de8a1bbda4e9b6b2b72b2d2100bc055a59adc1740529e631f61feb44a8b9a1f9f8590941ed9da9df0090b6d6d0ed8ffee94cd9ac086ec3409b392b33440f7d2 - languageName: node - linkType: hard - -"graceful-fs@npm:^4.1.6, graceful-fs@npm:^4.2.0, graceful-fs@npm:^4.2.4, graceful-fs@npm:^4.2.6": +"graceful-fs@npm:^4.2.4, graceful-fs@npm:^4.2.6": version: 4.2.10 resolution: "graceful-fs@npm:4.2.10" checksum: 3f109d70ae123951905d85032ebeae3c2a5a7a997430df00ea30df0e3a6c60cf6689b109654d6fdacd28810a053348c4d14642da1d075049e6be1ba5216218da @@ -3774,16 +3504,6 @@ __metadata: languageName: node linkType: hard -"hashring@npm:3.2.x": - version: 3.2.0 - resolution: "hashring@npm:3.2.0" - dependencies: - connection-parse: 0.0.x - simple-lru-cache: 0.0.x - checksum: d46733d341227a48df48c9c4d31f36a174e8c773df2f9013baed42357f93e07cd99e60dcb40c986b813654d505e5938f0a677bf33935e7be8ee20a0a1fbeb1db - languageName: node - linkType: hard - "hosted-git-info@npm:^2.1.4": version: 2.8.9 resolution: "hosted-git-info@npm:2.8.9" @@ -3807,7 +3527,7 @@ __metadata: languageName: node linkType: hard -"http-cache-semantics@npm:^4.0.0, http-cache-semantics@npm:^4.1.0": +"http-cache-semantics@npm:^4.1.0": version: 4.1.1 resolution: "http-cache-semantics@npm:4.1.1" checksum: 83ac0bc60b17a3a36f9953e7be55e5c8f41acc61b22583060e8dedc9dd5e3607c823a88d0926f9150e571f90946835c7fe150732801010845c72cd8bbff1a236 @@ -3836,16 +3556,6 @@ __metadata: languageName: node linkType: hard -"http2-wrapper@npm:^1.0.0-beta.5.2": - version: 1.0.3 - resolution: "http2-wrapper@npm:1.0.3" - dependencies: - quick-lru: ^5.1.1 - resolve-alpn: ^1.0.0 - checksum: 74160b862ec699e3f859739101ff592d52ce1cb207b7950295bf7962e4aa1597ef709b4292c673bece9c9b300efad0559fc86c71b1409c7a1e02b7229456003e - languageName: node - linkType: hard - "https-proxy-agent@npm:^5.0.0": version: 5.0.1 resolution: "https-proxy-agent@npm:5.0.1" @@ -4410,15 +4120,6 @@ __metadata: languageName: node linkType: hard -"jackpot@npm:>=0.0.6": - version: 0.0.6 - resolution: "jackpot@npm:0.0.6" - dependencies: - retry: 0.6.0 - checksum: 57af0f39f8ffbf12825aaabe60295d2bb9c0e56ef6123168a542f73ce56935498ef35350b53171111214f3bcfe1ac4ff75cf2b64662e714adb1218b5e92ad6b9 - languageName: node - linkType: hard - "jest-changed-files@npm:^26.6.2": version: 26.6.2 resolution: "jest-changed-files@npm:26.6.2" @@ -4945,13 +4646,6 @@ __metadata: languageName: node linkType: hard -"json-buffer@npm:3.0.1, json-buffer@npm:~3.0.1": - version: 3.0.1 - resolution: "json-buffer@npm:3.0.1" - checksum: 9026b03edc2847eefa2e37646c579300a1f3a4586cfb62bf857832b60c852042d0d6ae55d1afb8926163fa54c2b01d83ae24705f34990348bdac6273a29d4581 - languageName: node - linkType: hard - "json-parse-even-better-errors@npm:^2.3.0": version: 2.3.1 resolution: "json-parse-even-better-errors@npm:2.3.1" @@ -4993,19 +4687,6 @@ __metadata: languageName: node linkType: hard -"jsonfile@npm:^6.0.1": - version: 6.1.0 - resolution: "jsonfile@npm:6.1.0" - dependencies: - graceful-fs: ^4.1.6 - universalify: ^2.0.0 - dependenciesMeta: - graceful-fs: - optional: true - checksum: 7af3b8e1ac8fe7f1eccc6263c6ca14e1966fcbc74b618d3c78a0a2075579487547b94f72b7a1114e844a1e15bb00d440e5d1720bfc4612d790a6f285d5ea8354 - languageName: node - linkType: hard - "jsx-ast-utils@npm:^2.4.1 || ^3.0.0": version: 3.3.1 resolution: "jsx-ast-utils@npm:3.3.1" @@ -5016,16 +4697,6 @@ __metadata: languageName: node linkType: hard -"keyv@npm:^4.0.0": - version: 4.3.2 - resolution: "keyv@npm:4.3.2" - dependencies: - compress-brotli: ^1.3.8 - json-buffer: 3.0.1 - checksum: 237952f5faa2ed08da36677d7a3faae48b7e3c305264698cbf4480443f293a2f0c6c63c1d05f5cd4a842ee864dbb395745e6636fecd07489565776a22de7b8d6 - languageName: node - linkType: hard - "kind-of@npm:^3.0.2, kind-of@npm:^3.0.3, kind-of@npm:^3.2.0": version: 3.2.2 resolution: "kind-of@npm:3.2.2" @@ -5143,13 +4814,6 @@ __metadata: languageName: node linkType: hard -"lowercase-keys@npm:^2.0.0": - version: 2.0.0 - resolution: "lowercase-keys@npm:2.0.0" - checksum: 24d7ebd56ccdf15ff529ca9e08863f3c54b0b9d1edb97a3ae1af34940ae666c01a1e6d200707bce730a8ef76cb57cc10e65f245ecaaf7e6bc8639f2fb460ac23 - languageName: node - linkType: hard - "lru-cache@npm:^6.0.0": version: 6.0.0 resolution: "lru-cache@npm:6.0.0" @@ -5231,23 +4895,6 @@ __metadata: languageName: node linkType: hard -"memcached-mock@npm:^0.1.0": - version: 0.1.0 - resolution: "memcached-mock@npm:0.1.0" - checksum: 23a5beccd4890bd75705b9373220c7879fb5970a4b43f09e66329e10d4af5616c08876ccb2e2bfe2690bae3f643dbfcd85d740714ce23d0b64ec955bb364b4ba - languageName: node - linkType: hard - -"memcached@npm:^2.0.0": - version: 2.2.2 - resolution: "memcached@npm:2.2.2" - dependencies: - hashring: 3.2.x - jackpot: ">=0.0.6" - checksum: bb87f0c9422e5a4dc1ca2235115b88ac1b4f3cf0d10435bb1296f54e3c14971ad764b1c26a071c0e24baa6e3095eef8e18ccfe82d70ca8272334ccd4340db1a5 - languageName: node - linkType: hard - "merge-stream@npm:^2.0.0": version: 2.0.0 resolution: "merge-stream@npm:2.0.0" @@ -5316,20 +4963,6 @@ __metadata: languageName: node linkType: hard -"mimic-response@npm:^1.0.0": - version: 1.0.1 - resolution: "mimic-response@npm:1.0.1" - checksum: 034c78753b0e622bc03c983663b1cdf66d03861050e0c8606563d149bc2b02d63f62ce4d32be4ab50d0553ae0ffe647fc34d1f5281184c6e1e8cf4d85e8d9823 - languageName: node - linkType: hard - -"mimic-response@npm:^3.1.0": - version: 3.1.0 - resolution: "mimic-response@npm:3.1.0" - checksum: 25739fee32c17f433626bf19f016df9036b75b3d84a3046c7d156e72ec963dd29d7fc8a302f55a3d6c5a4ff24259676b15d915aad6480815a969ff2ec0836867 - languageName: node - linkType: hard - "minimatch@npm:^3.0.4, minimatch@npm:^3.1.1, minimatch@npm:^3.1.2": version: 3.1.2 resolution: "minimatch@npm:3.1.2" @@ -5531,13 +5164,6 @@ __metadata: languageName: node linkType: hard -"node-exceptions@npm:^4.0.1": - version: 4.0.1 - resolution: "node-exceptions@npm:4.0.1" - checksum: 605850eda8e9e095ce2dc09b5443cc312aecc9bc59059ba5de1eef3c9c85a6a4159051ece59d139baf02b1e6925d73f847b3feb4915ad292651088085864d383 - languageName: node - linkType: hard - "node-fetch@npm:^2.6.7": version: 2.6.7 resolution: "node-fetch@npm:2.6.7" @@ -5639,13 +5265,6 @@ __metadata: languageName: node linkType: hard -"normalize-url@npm:^6.0.1": - version: 6.1.0 - resolution: "normalize-url@npm:6.1.0" - checksum: 4a4944631173e7d521d6b80e4c85ccaeceb2870f315584fa30121f505a6dfd86439c5e3fdd8cd9e0e291290c41d0c3599f0cb12ab356722ed242584c30348e50 - languageName: node - linkType: hard - "npm-run-path@npm:^2.0.0": version: 2.0.2 resolution: "npm-run-path@npm:2.0.2" @@ -5834,13 +5453,6 @@ __metadata: languageName: node linkType: hard -"p-cancelable@npm:^2.0.0": - version: 2.1.1 - resolution: "p-cancelable@npm:2.1.1" - checksum: 3dba12b4fb4a1e3e34524535c7858fc82381bbbd0f247cc32dedc4018592a3950ce66b106d0880b4ec4c2d8d6576f98ca885dc1d7d0f274d1370be20e9523ddf - languageName: node - linkType: hard - "p-each-series@npm:^2.1.0": version: 2.2.0 resolution: "p-each-series@npm:2.2.0" @@ -6117,13 +5729,6 @@ __metadata: languageName: node linkType: hard -"proxy-from-env@npm:^1.1.0": - version: 1.1.0 - resolution: "proxy-from-env@npm:1.1.0" - checksum: ed7fcc2ba0a33404958e34d95d18638249a68c430e30fcb6c478497d72739ba64ce9810a24f53a7d921d0c065e5b78e3822759800698167256b04659366ca4d4 - languageName: node - linkType: hard - "psl@npm:^1.1.33": version: 1.8.0 resolution: "psl@npm:1.8.0" @@ -6162,13 +5767,6 @@ __metadata: languageName: node linkType: hard -"quick-lru@npm:^5.1.1": - version: 5.1.1 - resolution: "quick-lru@npm:5.1.1" - checksum: a516faa25574be7947969883e6068dbe4aa19e8ef8e8e0fd96cddd6d36485e9106d85c0041a27153286b0770b381328f4072aa40d3b18a19f5f7d2b78b94b5ed - languageName: node - linkType: hard - "react-is@npm:^16.13.1": version: 16.13.1 resolution: "react-is@npm:16.13.1" @@ -6229,48 +5827,6 @@ __metadata: languageName: node linkType: hard -"redis-commands@npm:^1.7.0": - version: 1.7.0 - resolution: "redis-commands@npm:1.7.0" - checksum: d1ff7fbcb5e54768c77f731f1d49679d2a62c3899522c28addb4e2e5813aea8bcac3f22519d71d330224c3f2937f935dfc3d8dc65e90db0f5fe22dc2c1515aa7 - languageName: node - linkType: hard - -"redis-errors@npm:^1.0.0, redis-errors@npm:^1.2.0": - version: 1.2.0 - resolution: "redis-errors@npm:1.2.0" - checksum: f28ac2692113f6f9c222670735aa58aeae413464fd58ccf3fce3f700cae7262606300840c802c64f2b53f19f65993da24dc918afc277e9e33ac1ff09edb394f4 - languageName: node - linkType: hard - -"redis-mock@npm:^0.56.3": - version: 0.56.3 - resolution: "redis-mock@npm:0.56.3" - checksum: 8c1293a59610c89a13849191de62aec9e68cb0a116e898b8fd5235235100f987caaeb5dacf56a076263474a2f556bd7fc2e7d2c52364a940f392dacb178b9ff4 - languageName: node - linkType: hard - -"redis-parser@npm:^3.0.0": - version: 3.0.0 - resolution: "redis-parser@npm:3.0.0" - dependencies: - redis-errors: ^1.0.0 - checksum: 89290ae530332f2ae37577647fa18208d10308a1a6ba750b9d9a093e7398f5e5253f19855b64c98757f7129cccce958e4af2573fdc33bad41405f87f1943459a - languageName: node - linkType: hard - -"redis@npm:^3.0.0": - version: 3.1.2 - resolution: "redis@npm:3.1.2" - dependencies: - denque: ^1.5.0 - redis-commands: ^1.7.0 - redis-errors: ^1.2.0 - redis-parser: ^3.0.0 - checksum: baec42198626b22d2dfc063b6a6f30394daee994c21f380e58ecf91c3edee333c4e32907c30f082fe66d2177695f7b2567902eef399ecb22da3e199ea6363a30 - languageName: node - linkType: hard - "regex-not@npm:^1.0.0, regex-not@npm:^1.0.2": version: 1.0.2 resolution: "regex-not@npm:1.0.2" @@ -6348,13 +5904,6 @@ __metadata: languageName: node linkType: hard -"resolve-alpn@npm:^1.0.0": - version: 1.2.1 - resolution: "resolve-alpn@npm:1.2.1" - checksum: f558071fcb2c60b04054c99aebd572a2af97ef64128d59bef7ab73bd50d896a222a056de40ffc545b633d99b304c259ea9d0c06830d5c867c34f0bfa60b8eae0 - languageName: node - linkType: hard - "resolve-cwd@npm:^3.0.0": version: 3.0.0 resolution: "resolve-cwd@npm:3.0.0" @@ -6437,15 +5986,6 @@ __metadata: languageName: node linkType: hard -"responselike@npm:^2.0.0": - version: 2.0.0 - resolution: "responselike@npm:2.0.0" - dependencies: - lowercase-keys: ^2.0.0 - checksum: 6a4d32c37d4e88678ae0a9d69fcc90aafa15b1a3eab455bd65c06af3c6c4976afc47d07a0e5a60d277ab041a465f43bf0a581e0d7ab33786e7a7741573f2e487 - languageName: node - linkType: hard - "ret@npm:~0.1.10": version: 0.1.15 resolution: "ret@npm:0.1.15" @@ -6453,13 +5993,6 @@ __metadata: languageName: node linkType: hard -"retry@npm:0.6.0": - version: 0.6.0 - resolution: "retry@npm:0.6.0" - checksum: 44c7b1179ef9627d3ff11b9948e49094226c28f8838c43e39e3cd6a15689daacd59e82db53c5177793717768a6a15e16db6606b5b51cce7622751349c6a1ccfa - languageName: node - linkType: hard - "retry@npm:^0.12.0": version: 0.12.0 resolution: "retry@npm:0.12.0" @@ -6681,13 +6214,6 @@ __metadata: languageName: node linkType: hard -"simple-lru-cache@npm:0.0.x": - version: 0.0.2 - resolution: "simple-lru-cache@npm:0.0.2" - checksum: 75bc9b788be4dad48b96ff2225604fe9c62d2e69327491ecb4d034b482cb88e5cd810e7b84f6ded3c4a87f1ecd407f1f2fafd5da09cf07dec3b9ce100cc13a44 - languageName: node - linkType: hard - "sisteransi@npm:^1.0.5": version: 1.0.5 resolution: "sisteransi@npm:1.0.5" @@ -7425,13 +6951,6 @@ __metadata: languageName: node linkType: hard -"universalify@npm:^2.0.0": - version: 2.0.0 - resolution: "universalify@npm:2.0.0" - checksum: 2406a4edf4a8830aa6813278bab1f953a8e40f2f63a37873ffa9a3bc8f9745d06cc8e88f3572cb899b7e509013f7f6fcc3e37e8a6d914167a5381d8440518c44 - languageName: node - linkType: hard - "unset-value@npm:^1.0.0": version: 1.0.0 resolution: "unset-value@npm:1.0.0"