@midnight-ntwrk/wallet-sdk-utilities 1.0.0-beta.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,16 @@
1
+ import { NonEmptyReadonlyArray } from 'effect/Array';
2
+ export declare const fold: {
3
+ <T>(folder: (acc: T, item: T) => T): (arr: NonEmptyReadonlyArray<T>) => T;
4
+ <T>(arr: NonEmptyReadonlyArray<T>, folder: (acc: T, item: T) => T): T;
5
+ };
6
+ export type Monoid<T> = {
7
+ empty: T;
8
+ combine: (a: T, b: T) => T;
9
+ };
10
+ export declare const generalSum: {
11
+ <T>(monoid: Monoid<T>): (arr: ReadonlyArray<T>) => T;
12
+ <T>(arr: ReadonlyArray<T>, monoid: Monoid<T>): T;
13
+ };
14
+ export declare const sumNumber: (arr: ReadonlyArray<number>) => number;
15
+ export declare const sumBigInt: (arr: ReadonlyArray<bigint>) => bigint;
16
+ export declare const assertNonEmpty: <T>(arr: ReadonlyArray<T>) => NonEmptyReadonlyArray<T>;
@@ -0,0 +1,22 @@
1
+ import { reduce, match } from 'effect/Array';
2
+ import { dual } from 'effect/Function';
3
+ export const fold = dual(2, (arr, folder) => arr.reduce(folder));
4
+ export const generalSum = dual(2, (arr, monoid) => reduce(arr, monoid.empty, monoid.combine));
5
+ const numberAdditionMonoid = {
6
+ empty: 0,
7
+ combine: (a, b) => a + b,
8
+ };
9
+ const bigintAdditionMonoid = {
10
+ empty: 0n,
11
+ combine: (a, b) => a + b,
12
+ };
13
+ export const sumNumber = generalSum(numberAdditionMonoid);
14
+ export const sumBigInt = generalSum(bigintAdditionMonoid);
15
+ export const assertNonEmpty = (arr) => {
16
+ return match(arr, {
17
+ onNonEmpty: (refined) => refined,
18
+ onEmpty: () => {
19
+ throw new Error('Expected non-empty array');
20
+ },
21
+ });
22
+ };
@@ -0,0 +1,3 @@
1
+ export declare const dateToSeconds: (date: Date) => bigint;
2
+ export declare const secondsToDate: (seconds: bigint | number) => Date;
3
+ export declare const addSeconds: (time: Date, seconds: bigint | number) => Date;
@@ -0,0 +1,9 @@
1
+ export const dateToSeconds = (date) => {
2
+ return BigInt(Math.floor(date.getTime() / 1000));
3
+ };
4
+ export const secondsToDate = (seconds) => {
5
+ return new Date(Number(seconds) * 1000);
6
+ };
7
+ export const addSeconds = (time, seconds) => {
8
+ return new Date(+time + Number(seconds) * 1000);
9
+ };
@@ -0,0 +1,19 @@
1
+ import { Effect, Either } from 'effect';
2
+ export declare const toEffect: <L, R>(either: Either.Either<R, L>) => Effect.Effect<R, L>;
3
+ export declare const flatMapLeft: {
4
+ <R, L, L2>(either: Either.Either<R, L>, cb: (l: L) => Either.Either<R, L2>): Either.Either<R, L2>;
5
+ <R, L, L2>(cb: (l: L) => Either.Either<R, L2>): (either: Either.Either<R, L>) => Either.Either<R, L2>;
6
+ };
7
+ declare const LeftError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => import("effect/Cause").YieldableError & {
8
+ readonly _tag: "LeftError";
9
+ } & Readonly<A>;
10
+ export declare class LeftError<L> extends LeftError_base<{
11
+ message: string;
12
+ cause: L;
13
+ }> {
14
+ constructor({ cause }: {
15
+ cause: L;
16
+ });
17
+ }
18
+ export declare const getOrThrowLeft: <L, R>(either: Either.Either<R, L>) => R;
19
+ export {};
@@ -0,0 +1,27 @@
1
+ import { Effect, Either, Data } from 'effect';
2
+ import { dual } from 'effect/Function';
3
+ export const toEffect = (either) => {
4
+ return Either.match(either, {
5
+ onLeft: (l) => Effect.fail(l),
6
+ onRight: (r) => Effect.succeed(r),
7
+ });
8
+ };
9
+ export const flatMapLeft = dual(2, (either, cb) => {
10
+ return Either.match(either, {
11
+ onRight: (r) => Either.right(r),
12
+ onLeft: cb,
13
+ });
14
+ });
15
+ export class LeftError extends Data.TaggedError('LeftError') {
16
+ constructor({ cause }) {
17
+ super({ message: 'Unexpected left value', cause });
18
+ }
19
+ }
20
+ export const getOrThrowLeft = (either) => {
21
+ return Either.match(either, {
22
+ onRight: (r) => r,
23
+ onLeft: (l) => {
24
+ throw new LeftError({ cause: l });
25
+ },
26
+ });
27
+ };
@@ -0,0 +1,6 @@
1
+ export declare namespace Fluent {
2
+ /**
3
+ * Exclude named methods from `T` so that they are no longer callable.
4
+ */
5
+ type ExcludeMethod<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;
6
+ }
package/dist/Fluent.js ADDED
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,13 @@
1
+ import { Either } from 'effect';
2
+ declare const LedgerError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => import("effect/Cause").YieldableError & {
3
+ readonly _tag: "LedgerError";
4
+ } & Readonly<A>;
5
+ export declare class LedgerError extends LedgerError_base<{
6
+ readonly message: string;
7
+ readonly cause?: unknown;
8
+ }> {
9
+ }
10
+ export declare const ledgerTry: <A>(fn: () => A) => Either.Either<A, LedgerError>;
11
+ export declare const generateHex: (len: number) => string;
12
+ export declare const randomNonce: () => string;
13
+ export {};
@@ -0,0 +1,16 @@
1
+ import { Either, Data } from 'effect';
2
+ export class LedgerError extends Data.TaggedError('LedgerError') {
3
+ }
4
+ export const ledgerTry = (fn) => {
5
+ return Either.try({
6
+ try: fn,
7
+ catch: (error) => {
8
+ const message = error instanceof Error ? error.message : `${error?.toString()}`;
9
+ return new LedgerError({ message: `Error from ledger: ${message}`, cause: error });
10
+ },
11
+ });
12
+ };
13
+ export const generateHex = (len) => {
14
+ return Buffer.from(crypto.getRandomValues(new Uint8Array(len / 2))).toString('hex');
15
+ };
16
+ export const randomNonce = () => generateHex(64);
@@ -0,0 +1,16 @@
1
+ import { Stream } from 'effect';
2
+ import { Observable } from 'rxjs';
3
+ /**
4
+ * A utility that creates a Rx.js `Observable` from a given Effect `Stream`.
5
+ *
6
+ * @param stream The Effect `Stream` from which an `Observable` is required.
7
+ * @returns A Rx.js `Observable` that consumes the elements from `stream`.
8
+ */
9
+ export declare const fromStream: <A, E = never>(stream: Stream.Stream<A, E>) => Observable<A>;
10
+ /**
11
+ * A utility that creates an Effect `Stream` from a given Rx.js `Observable`.
12
+ *
13
+ * @param observable The Rx.js `Observable` from which a `Stream` is required.
14
+ * @returns A `Stream` the consumes elements from `observable`.
15
+ */
16
+ export declare const toStream: <A, E = never>(observable: Observable<A>) => Stream.Stream<A, E>;
@@ -0,0 +1,53 @@
1
+ import { Effect, Stream, Fiber, Option, Chunk } from 'effect';
2
+ import { Observable } from 'rxjs';
3
+ /**
4
+ * A utility that creates a Rx.js `Observable` from a given Effect `Stream`.
5
+ *
6
+ * @param stream The Effect `Stream` from which an `Observable` is required.
7
+ * @returns A Rx.js `Observable` that consumes the elements from `stream`.
8
+ */
9
+ export const fromStream = (stream) => new Observable((subscriber) => {
10
+ const fiber = Effect.runFork(Effect.scoped(Effect.gen(function* () {
11
+ const pull = yield* Stream.toPull(stream);
12
+ while (true) {
13
+ const shouldBreak = yield* Effect.match(pull, {
14
+ onSuccess(values) {
15
+ Chunk.forEach(values, (element) => {
16
+ subscriber.next(element);
17
+ });
18
+ return false;
19
+ },
20
+ onFailure(error) {
21
+ return Option.match(error, {
22
+ onNone() {
23
+ subscriber.complete();
24
+ return true; // Stream has completed, signal the break.
25
+ },
26
+ onSome: (err) => {
27
+ subscriber.error(err);
28
+ return true;
29
+ },
30
+ });
31
+ },
32
+ });
33
+ if (shouldBreak)
34
+ break;
35
+ }
36
+ })));
37
+ // Ensure that if the subscription ends we also dispose of the fiber pulling from the stream.
38
+ subscriber.add(() => Effect.runFork(Fiber.interrupt(fiber)));
39
+ });
40
+ /**
41
+ * A utility that creates an Effect `Stream` from a given Rx.js `Observable`.
42
+ *
43
+ * @param observable The Rx.js `Observable` from which a `Stream` is required.
44
+ * @returns A `Stream` the consumes elements from `observable`.
45
+ */
46
+ export const toStream = (observable) => Stream.async((emit) => {
47
+ const subscription = observable.subscribe({
48
+ next: (value) => void emit.single(value),
49
+ error: (err) => void emit.fail(err),
50
+ complete: () => void emit.end(),
51
+ });
52
+ return Effect.sync(() => subscription.unsubscribe());
53
+ });
@@ -0,0 +1,2 @@
1
+ export declare const merge: <K extends string | number | symbol, T>(combine: (a: T, b: T) => T) => (records: Array<Record<K, T>>) => Record<K, T>;
2
+ export declare const mergeWithAccumulator: <K extends string | number | symbol, T, S>(mempty: S, combine: (acc: S, b: T) => S) => (records: Array<Record<K, T>>) => Record<K, S>;
@@ -0,0 +1,28 @@
1
+ export const merge = (combine) => (records) => {
2
+ const result = {};
3
+ for (const record of records) {
4
+ for (const key in record) {
5
+ if (Object.hasOwn(result, key)) {
6
+ result[key] = combine(result[key], record[key]);
7
+ }
8
+ else {
9
+ result[key] = record[key];
10
+ }
11
+ }
12
+ }
13
+ return result;
14
+ };
15
+ export const mergeWithAccumulator = (mempty, combine) => (records) => {
16
+ const result = {};
17
+ for (const record of records) {
18
+ for (const key in record) {
19
+ if (Object.hasOwn(result, key)) {
20
+ result[key] = combine(result[key], record[key]);
21
+ }
22
+ else {
23
+ result[key] = combine(mempty, record[key]);
24
+ }
25
+ }
26
+ }
27
+ return result;
28
+ };
@@ -0,0 +1,26 @@
1
+ import { PolyFunction, WithTag } from './polyFunction.js';
2
+ /**
3
+ * Heterogeneous list - as in - list, where elements have different types
4
+ * Here - more as an additional API over TS's tuple type
5
+ */
6
+ export type Empty = [];
7
+ export type NonEmpty<T> = T extends Array<infer E> ? [E, ...T] : never;
8
+ export type Prepend<List extends unknown[], Element> = [Element, ...List];
9
+ export type Append<List extends unknown[], Element> = [...List, Element];
10
+ export type Reverse<List extends unknown[]> = List extends [...infer Init, infer Last] ? [Last, ...Reverse<Init>] : List extends [] ? [] : never;
11
+ export type HeadOr<List, Default> = List extends [infer TheHead, ...any[]] ? TheHead : List extends [] ? Default : never;
12
+ export type Head<List extends any[]> = HeadOr<List, never>;
13
+ export type Tail<List extends unknown[]> = List extends [unknown, ...infer Tail] ? Tail : [];
14
+ export type Tails<List extends unknown[]> = List extends [unknown, ...infer Tail] ? Tails<Tail> | Tail : [];
15
+ export type Each<List extends unknown[]> = List[number];
16
+ export type Find<List extends any[], Predicate> = List extends [infer TheHead, ...infer Rest] ? TheHead extends Predicate ? TheHead : Find<Rest, Predicate> : never;
17
+ export declare const empty: Empty;
18
+ export declare const prepend: <List extends unknown[], Element>(list: List, element: Element) => Prepend<List, Element>;
19
+ export declare const append: <List extends unknown[], Element>(list: List, element: Element) => Append<List, Element>;
20
+ export declare function headOr<List extends unknown[], Default>(list: List, def: () => Default): HeadOr<List, Default>;
21
+ export declare const head: <List extends unknown[]>(list: List) => Head<List>;
22
+ export declare const tail: <List extends unknown[]>(list: List) => Tail<List>;
23
+ export declare const reverse: <List extends unknown[]>(list: List) => Reverse<List>;
24
+ export declare const find: <List extends unknown[], Predicate>(list: List, predicate: (value: Each<List>) => value is Predicate) => Find<List, Predicate>;
25
+ export declare const foldLeft: <List extends WithTag<string | symbol>[], Acc>(list: List, acc: Acc, folder: (acc: Acc) => PolyFunction<Each<List>, Acc>) => Acc;
26
+ export declare const foldRight: <List extends WithTag<string | symbol>[], Acc>(list: List, acc: Acc, folder: (acc: Acc) => PolyFunction<Each<List>, Acc>) => Acc;
package/dist/hlist.js ADDED
@@ -0,0 +1,37 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ import { dispatch } from './polyFunction.js';
3
+ export const empty = [];
4
+ export const prepend = (list, element) => {
5
+ return [element, ...list];
6
+ };
7
+ export const append = (list, element) => {
8
+ return [...list, element];
9
+ };
10
+ export function headOr(list, def) {
11
+ if (list.length == 0) {
12
+ return def();
13
+ }
14
+ else {
15
+ return list.at(0);
16
+ }
17
+ }
18
+ export const head = (list) => {
19
+ return headOr(list, () => {
20
+ throw new Error('Cannot get head from empty hlist');
21
+ });
22
+ };
23
+ export const tail = (list) => {
24
+ return list.toSpliced(0, 1);
25
+ };
26
+ export const reverse = (list) => {
27
+ return list.toReversed();
28
+ };
29
+ export const find = (list, predicate) => {
30
+ return list.find(predicate);
31
+ };
32
+ export const foldLeft = (list, acc, folder) => {
33
+ return list.reduce((acc, item) => dispatch(item, folder(acc)), acc);
34
+ };
35
+ export const foldRight = (list, acc, folder) => {
36
+ return list.reduceRight((acc, item) => dispatch(item, folder(acc)), acc);
37
+ };
@@ -0,0 +1,9 @@
1
+ export * as ArrayOps from './ArrayOps.js';
2
+ export * as DateOps from './DateOps.js';
3
+ export * as EitherOps from './EitherOps.js';
4
+ export * as Fluent from './Fluent.js';
5
+ export * as HList from './hlist.js';
6
+ export * as LedgerOps from './LedgerOps.js';
7
+ export * as ObservableOps from './ObservableOps.js';
8
+ export * as Poly from './polyFunction.js';
9
+ export * as RecordOps from './RecordOps.js';
package/dist/index.js ADDED
@@ -0,0 +1,9 @@
1
+ export * as ArrayOps from './ArrayOps.js';
2
+ export * as DateOps from './DateOps.js';
3
+ export * as EitherOps from './EitherOps.js';
4
+ export * as Fluent from './Fluent.js';
5
+ export * as HList from './hlist.js';
6
+ export * as LedgerOps from './LedgerOps.js';
7
+ export * as ObservableOps from './ObservableOps.js';
8
+ export * as Poly from './polyFunction.js';
9
+ export * as RecordOps from './RecordOps.js';
@@ -0,0 +1,26 @@
1
+ declare const ClientError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => import("effect/Cause").YieldableError & {
2
+ readonly _tag: "ClientError";
3
+ } & Readonly<A>;
4
+ /**
5
+ * An error representing a connection or client-side error.
6
+ *
7
+ * @remarks
8
+ * This error typically indicates a connection issue with a target server, or when the client has submitted some
9
+ * data that could not be processed.
10
+ */
11
+ export declare class ClientError extends ClientError_base<{
12
+ readonly message: string;
13
+ readonly cause?: unknown;
14
+ }> {
15
+ }
16
+ declare const ServerError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => import("effect/Cause").YieldableError & {
17
+ readonly _tag: "ServerError";
18
+ } & Readonly<A>;
19
+ /**
20
+ * An error representing a server-side error.
21
+ */
22
+ export declare class ServerError extends ServerError_base<{
23
+ readonly message: string;
24
+ }> {
25
+ }
26
+ export {};
@@ -0,0 +1,15 @@
1
+ import { Data } from 'effect';
2
+ /**
3
+ * An error representing a connection or client-side error.
4
+ *
5
+ * @remarks
6
+ * This error typically indicates a connection issue with a target server, or when the client has submitted some
7
+ * data that could not be processed.
8
+ */
9
+ export class ClientError extends Data.TaggedError('ClientError') {
10
+ }
11
+ /**
12
+ * An error representing a server-side error.
13
+ */
14
+ export class ServerError extends Data.TaggedError('ServerError') {
15
+ }
@@ -0,0 +1,19 @@
1
+ import { Either } from 'effect';
2
+ import * as Brand from 'effect/Brand';
3
+ import { InvalidProtocolSchemeError } from './URLError.js';
4
+ /**
5
+ * A 'HTTP' URL.
6
+ */
7
+ export type HttpUrl = Brand.Branded<URL, 'HttpURL'>;
8
+ /**
9
+ * Constructs a 'HTTP' URL from a source URL, ensuring that the protocol is correct.
10
+ */
11
+ export declare const HttpURL: Brand.Brand.Constructor<HttpUrl>;
12
+ /**
13
+ * Constructs a new {@link HttpURL} from a given string.
14
+ *
15
+ * @param url The URL to be made into a HTTP URL.
16
+ * @returns An `Either` that represents the valid HTTP URL constructed from `url`; or an
17
+ * {@link InvalidProtocolSchemeError}.
18
+ */
19
+ export declare const make: (url: URL | string) => Either.Either<HttpUrl, InvalidProtocolSchemeError>;
@@ -0,0 +1,23 @@
1
+ import { Either } from 'effect';
2
+ import * as Brand from 'effect/Brand';
3
+ import { InvalidProtocolSchemeError } from './URLError.js';
4
+ /**
5
+ * Constructs a 'HTTP' URL from a source URL, ensuring that the protocol is correct.
6
+ */
7
+ export const HttpURL = Brand.refined((url) => url.protocol === 'http:' || url.protocol === 'https:', (url) => Brand.error(`Invalid protocol scheme '${url.protocol}'. Expected 'http:' or 'https:'`));
8
+ /**
9
+ * Constructs a new {@link HttpURL} from a given string.
10
+ *
11
+ * @param url The URL to be made into a HTTP URL.
12
+ * @returns An `Either` that represents the valid HTTP URL constructed from `url`; or an
13
+ * {@link InvalidProtocolSchemeError}.
14
+ */
15
+ export const make = (url) => {
16
+ const targetURL = new URL(url);
17
+ try {
18
+ return Either.right(HttpURL(targetURL));
19
+ }
20
+ catch (err) {
21
+ return Either.left(new InvalidProtocolSchemeError({ message: String(err), invalidScheme: targetURL.protocol }));
22
+ }
23
+ };
@@ -0,0 +1,27 @@
1
+ declare const InvalidProtocolSchemeError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => import("effect/Cause").YieldableError & {
2
+ readonly _tag: "InvalidProtocolSchemeError";
3
+ } & Readonly<A>;
4
+ /**
5
+ * A configuration error where the protocol scheme of a given server URL was unexpected (e.g., used
6
+ * `'ftp:'` rather than `'http:'` for a server running over HTTP).
7
+ */
8
+ export declare class InvalidProtocolSchemeError extends InvalidProtocolSchemeError_base<{
9
+ /** A message describing the error. */
10
+ readonly message: string;
11
+ /** The scheme that caused the error. */
12
+ readonly invalidScheme: string;
13
+ }> {
14
+ static readonly tag: "InvalidProtocolSchemeError";
15
+ }
16
+ declare const FailedToDeriveWebSocketUrlError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => import("effect/Cause").YieldableError & {
17
+ readonly _tag: "FailedToDeriveWebSocketUrlError";
18
+ } & Readonly<A>;
19
+ export declare class FailedToDeriveWebSocketUrlError extends FailedToDeriveWebSocketUrlError_base<{
20
+ /** A message describing the error. */
21
+ readonly message: string;
22
+ readonly cause?: unknown;
23
+ }> {
24
+ static readonly tag: "FailedToDeriveWebSocketUrlError";
25
+ }
26
+ export type URLError = InvalidProtocolSchemeError | FailedToDeriveWebSocketUrlError;
27
+ export {};
@@ -0,0 +1,11 @@
1
+ import { Data } from 'effect';
2
+ /**
3
+ * A configuration error where the protocol scheme of a given server URL was unexpected (e.g., used
4
+ * `'ftp:'` rather than `'http:'` for a server running over HTTP).
5
+ */
6
+ export class InvalidProtocolSchemeError extends Data.TaggedError('InvalidProtocolSchemeError') {
7
+ static tag = 'InvalidProtocolSchemeError';
8
+ }
9
+ export class FailedToDeriveWebSocketUrlError extends Data.TaggedError('FailedToDeriveWebSocketUrlError') {
10
+ static tag = 'FailedToDeriveWebSocketUrlError';
11
+ }
@@ -0,0 +1,19 @@
1
+ import { Either } from 'effect';
2
+ import * as Brand from 'effect/Brand';
3
+ import { InvalidProtocolSchemeError } from './URLError.js';
4
+ /**
5
+ * A 'HTTP' URL.
6
+ */
7
+ export type WsURL = Brand.Branded<URL, 'WsURL'>;
8
+ /**
9
+ * Constructs a 'WS' URL from a source URL, ensuring that the protocol is correct.
10
+ */
11
+ export declare const WsURL: Brand.Brand.Constructor<WsURL>;
12
+ /**
13
+ * Constructs a new {@link WsURL} from a given string.
14
+ *
15
+ * @param url The URL to be made into a WebSocket URL.
16
+ * @returns An `Either` that represents the valid WebSocket URL constructed from `url`; or an
17
+ * {@link InvalidProtocolSchemeError}.
18
+ */
19
+ export declare const make: (url: URL | string) => Either.Either<WsURL, InvalidProtocolSchemeError>;
@@ -0,0 +1,23 @@
1
+ import { Either } from 'effect';
2
+ import * as Brand from 'effect/Brand';
3
+ import { InvalidProtocolSchemeError } from './URLError.js';
4
+ /**
5
+ * Constructs a 'WS' URL from a source URL, ensuring that the protocol is correct.
6
+ */
7
+ export const WsURL = Brand.refined((url) => url.protocol === 'ws:' || url.protocol === 'wss:', (url) => Brand.error(`Invalid protocol scheme '${url.protocol}'. Expected 'ws:' or 'wss:'`));
8
+ /**
9
+ * Constructs a new {@link WsURL} from a given string.
10
+ *
11
+ * @param url The URL to be made into a WebSocket URL.
12
+ * @returns An `Either` that represents the valid WebSocket URL constructed from `url`; or an
13
+ * {@link InvalidProtocolSchemeError}.
14
+ */
15
+ export const make = (url) => {
16
+ const targetURL = new URL(url);
17
+ try {
18
+ return Either.right(WsURL(targetURL));
19
+ }
20
+ catch (err) {
21
+ return Either.left(new InvalidProtocolSchemeError({ message: String(err), invalidScheme: targetURL.protocol }));
22
+ }
23
+ };
@@ -0,0 +1,4 @@
1
+ export * as HttpURL from './HttpURL.js';
2
+ export * as WsURL from './WsURL.js';
3
+ export * from './URLError.js';
4
+ export * from './ClientServerErrors.js';
@@ -0,0 +1,4 @@
1
+ export * as HttpURL from './HttpURL.js';
2
+ export * as WsURL from './WsURL.js';
3
+ export * from './URLError.js';
4
+ export * from './ClientServerErrors.js';
@@ -0,0 +1,14 @@
1
+ export type WithTag<T extends string | symbol> = {
2
+ __polyTag__: T;
3
+ };
4
+ export type TagOf<T> = T extends WithTag<infer Tag> ? Tag : never;
5
+ export type WithTagFrom<T> = WithTag<TagOf<T>>;
6
+ /**
7
+ * Polymorphic function - function defined for multiple types at once
8
+ * Leveraging tagging mechanics it can predictably work at runtime and be quite intuitively defined by hand
9
+ */
10
+ export type PolyFunction<Variants extends WithTag<string | symbol>, T> = {
11
+ [V in Variants as TagOf<V>]: (variant: V) => T;
12
+ };
13
+ export declare const getTag: <TTag extends string | symbol>(t: WithTag<TTag>) => TTag;
14
+ export declare const dispatch: <TVariant extends WithTag<string | symbol>, TResult>(subject: TVariant, impl: PolyFunction<TVariant, TResult>) => TResult;
@@ -0,0 +1,12 @@
1
+ export const getTag = (t) => t.__polyTag__;
2
+ export const dispatch = (subject, impl) => {
3
+ if (subject.__polyTag__ in impl) {
4
+ //Sadly, the type casts below are needed because eslint or TS limitations
5
+ const subjectTag = subject.__polyTag__;
6
+ const chosen = impl[subjectTag];
7
+ return chosen(subject);
8
+ }
9
+ else {
10
+ throw new Error(`Not found implementation for ${String(subject.__polyTag__)}`);
11
+ }
12
+ };
@@ -0,0 +1,9 @@
1
+ /**
2
+ * A utility type that ensures that a given type is `true` or otherwise forces a compile time error.
3
+ */
4
+ export type Expect<T extends true> = T;
5
+ /**
6
+ * A utility type that exactly compares two types for equality.
7
+ */
8
+ export type Equal<X, Y> = (<T>() => T extends X ? 1 : 2) extends <T>() => T extends Y ? 1 : 2 ? true : false;
9
+ export type ItemType<T> = T extends ReadonlyArray<infer R> ? R : never;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export * as TestContainers from './test-containers.js';
@@ -0,0 +1 @@
1
+ export * as TestContainers from './test-containers.js';
@@ -0,0 +1,13 @@
1
+ import { Effect, Scope } from 'effect';
2
+ import { GenericContainer, StartedNetwork, type StartedTestContainer } from 'testcontainers';
3
+ export declare const createNetwork: () => Effect.Effect<StartedNetwork, never, Scope.Scope>;
4
+ export declare const runNodeContainer: (adjustment?: (t: GenericContainer) => GenericContainer) => Effect.Effect<StartedTestContainer, Error, Scope.Scope>;
5
+ export declare const runProofServerContainer: (adjustment?: (t: GenericContainer) => GenericContainer) => Effect.Effect<StartedTestContainer, Error, Scope.Scope>;
6
+ export declare const runTxGenerator: (config: {
7
+ nodeUrl: string;
8
+ destPath: string;
9
+ fileName: string;
10
+ txsPerBatch: number;
11
+ batches: number;
12
+ }, adjustment?: (t: GenericContainer) => GenericContainer) => Effect.Effect<StartedTestContainer, Error, Scope.Scope>;
13
+ export declare const findAvailablePort: Effect.Effect<number>;
@@ -0,0 +1,46 @@
1
+ import { Effect, identity } from 'effect';
2
+ import { GenericContainer, Network, Wait } from 'testcontainers';
3
+ import { getPortPromise } from 'portfinder';
4
+ export const createNetwork = () => Effect.acquireRelease(Effect.promise(() => new Network().start()), (net) => Effect.promise(() => net.stop()));
5
+ const startContainer = (container) => {
6
+ return Effect.acquireRelease(Effect.promise(() => container.start()), (container) => Effect.promise(() => container.stop({ timeout: 5_000 })));
7
+ };
8
+ export const runNodeContainer = (adjustment = identity) => {
9
+ const container = new GenericContainer('ghcr.io/midnight-ntwrk/midnight-node:0.17.0-rc.4')
10
+ .withEnvironment({
11
+ CFG_PRESET: 'dev',
12
+ SIDECHAIN_BLOCK_BENEFICIARY: '04bcf7ad3be7a5c790460be82a713af570f22e0f801f6659ab8e84a52be6969e',
13
+ })
14
+ .withExposedPorts(9944)
15
+ .withWaitStrategy(Wait.forListeningPorts());
16
+ return startContainer(adjustment(container));
17
+ };
18
+ export const runProofServerContainer = (adjustment = identity) => {
19
+ const container = new GenericContainer('ghcr.io/midnight-ntwrk/proof-server:6.1.0-alpha.3')
20
+ .withEnvironment({
21
+ RUST_BACKTRACE: 'full',
22
+ })
23
+ .withExposedPorts(6300)
24
+ .withCommand(['midnight-proof-server -v'])
25
+ .withWaitStrategy(Wait.forListeningPorts());
26
+ return startContainer(adjustment(container));
27
+ };
28
+ export const runTxGenerator = (config, adjustment = identity) => {
29
+ const container = new GenericContainer('ghcr.io/midnight-ntwrk/midnight-node-toolkit:0.17.0-rc.4')
30
+ .withBindMounts([{ source: config.destPath, target: '/tmp', mode: 'rw' }])
31
+ .withCommand([
32
+ 'generate-txs',
33
+ '--src-url',
34
+ config.nodeUrl,
35
+ '--dest-file',
36
+ `/tmp/${config.fileName}`,
37
+ 'batches',
38
+ '--num-batches',
39
+ String(config.batches),
40
+ '--num-txs-per-batch',
41
+ String(config.txsPerBatch),
42
+ ])
43
+ .withWaitStrategy(Wait.forLogMessage('✓ generated transactions'));
44
+ return startContainer(adjustment(container));
45
+ };
46
+ export const findAvailablePort = Effect.promise(() => getPortPromise());
@@ -0,0 +1,15 @@
1
+ /**
2
+ * A utility type that checks whether type A can be assigned to type To
3
+ * It appears to be useful when exact inferred type are slightly too complex to express and we want the express
4
+ * a slightly simplified type rule like Expect<CanAssign<{foo: number}, object & {foo: number}>>
5
+ */
6
+ export type CanAssign<A, To> = A extends To ? true : false;
7
+ /**
8
+ * A utility type that ensures that a given type is `true` or otherwise forces a compile time error.
9
+ */
10
+ export type Expect<T extends true> = T;
11
+ export type ItemType<T> = T extends ReadonlyArray<infer R> ? R : never;
12
+ /**
13
+ * A utility type that exactly compares two types for equality.
14
+ */
15
+ export type Equal<X, Y> = (<T>() => T extends X ? 1 : 2) extends <T>() => T extends Y ? 1 : 2 ? true : false;
package/dist/types.js ADDED
@@ -0,0 +1 @@
1
+ export {};
package/package.json ADDED
@@ -0,0 +1,63 @@
1
+ {
2
+ "name": "@midnight-ntwrk/wallet-sdk-utilities",
3
+ "description": "Domain-agnostic utilities for the wallet SDK - common operations and types",
4
+ "version": "1.0.0-beta.6",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "author": "IOHK",
10
+ "license": "Apache-2.0",
11
+ "publishConfig": {
12
+ "registry": "https://npm.pkg.github.com/"
13
+ },
14
+ "files": [
15
+ "dist/"
16
+ ],
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "git+https://github.com/midnight-ntwrk/artifacts.git"
20
+ },
21
+ "exports": {
22
+ ".": {
23
+ "types": "./dist/index.d.ts",
24
+ "import": "./dist/index.js"
25
+ },
26
+ "./networking": {
27
+ "types": "./dist/networking/index.d.ts",
28
+ "import": "./dist/networking/index.js"
29
+ },
30
+ "./types": {
31
+ "types": "./dist/types.d.ts",
32
+ "import": "./dist/types.js"
33
+ },
34
+ "./testing": {
35
+ "types": "./dist/testing/index.d.ts",
36
+ "import": "./dist/testing/index.js"
37
+ }
38
+ },
39
+ "dependencies": {
40
+ "effect": "^3.17.3",
41
+ "portfinder": "^1.0.37",
42
+ "rxjs": "^7.5",
43
+ "testcontainers": "^11.4.0"
44
+ },
45
+ "scripts": {
46
+ "typecheck": "tsc -b ./tsconfig.json --noEmit",
47
+ "test": "vitest run",
48
+ "lint": "eslint --max-warnings 0",
49
+ "format": "prettier --write \"**/*.{ts,js,json,yaml,yml}\"",
50
+ "dist": "tsc -b ./tsconfig.build.json",
51
+ "dist:publish": "tsc -b ./tsconfig.publish.json",
52
+ "clean": "rimraf --glob dist 'tsconfig.*.tsbuildinfo' && date +%s > .clean-timestamp",
53
+ "publint": "publint --strict"
54
+ },
55
+ "devDependencies": {
56
+ "eslint": "^9.37.0",
57
+ "fast-check": "^4.2.0",
58
+ "publint": "~0.3.14",
59
+ "rimraf": "^6.0.1",
60
+ "typescript": "^5.9.3",
61
+ "vitest": "^3.2.4"
62
+ }
63
+ }