@effectstream/utils 0.100.0
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.
- package/package.json +28 -0
- package/src/binary-search.test.ts +38 -0
- package/src/binary-search.ts +45 -0
- package/src/captcha.ts +21 -0
- package/src/concurrency/condVar.ts +52 -0
- package/src/concurrency/latch.test.ts +51 -0
- package/src/concurrency/latch.ts +61 -0
- package/src/concurrency/mod.ts +4 -0
- package/src/concurrency/retry.test.ts +59 -0
- package/src/concurrency/retry.ts +67 -0
- package/src/concurrency/utils.ts +33 -0
- package/src/config.ts +484 -0
- package/src/constants.ts +10 -0
- package/src/decorators/bound.ts +22 -0
- package/src/decorators/mod.ts +1 -0
- package/src/mod.ts +8 -0
- package/src/runtime-spawn.ts +188 -0
- package/src/runtime.ts +89 -0
- package/src/types/json-query.ts +36 -0
- package/src/types/misc.ts +173 -0
- package/src/types/mod.ts +6 -0
- package/src/types/nominal.ts +168 -0
- package/src/types/typebox-helpers.ts +446 -0
- package/src/types/utils.ts +60 -0
- package/src/types/validators/algorand.ts +120 -0
- package/src/types/validators/cardano.ts +139 -0
- package/src/types/validators/mina.ts +54 -0
- package/src/types/validators/minicbor.ts +468 -0
- package/src/types/validators/mod.ts +2 -0
- package/src/types/validators/utils.ts +34 -0
- package/src/viem.ts +41 -0
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Process spawn abstraction using node:child_process.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { spawn as nodeSpawn } from "node:child_process";
|
|
6
|
+
import { Readable, Writable } from "node:stream";
|
|
7
|
+
|
|
8
|
+
/** Result of a spawned process. stdout/stderr are Web ReadableStreams so they can be pipeTo()'d. */
|
|
9
|
+
export interface SpawnChild {
|
|
10
|
+
readonly pid: number;
|
|
11
|
+
/** Present when options.stdin === "piped". */
|
|
12
|
+
readonly stdin?: WritableStream<Uint8Array>;
|
|
13
|
+
readonly stdout: ReadableStream<Uint8Array>;
|
|
14
|
+
readonly stderr: ReadableStream<Uint8Array>;
|
|
15
|
+
readonly status: Promise<{
|
|
16
|
+
success: boolean;
|
|
17
|
+
code?: number;
|
|
18
|
+
signal?: string;
|
|
19
|
+
}>;
|
|
20
|
+
kill(signal?: NodeJS.Signals): void;
|
|
21
|
+
ref(): void;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface SpawnOptions {
|
|
25
|
+
args?: string[];
|
|
26
|
+
cwd?: string;
|
|
27
|
+
env?: Record<string, string>;
|
|
28
|
+
signal?: AbortSignal;
|
|
29
|
+
stdin?: "inherit" | "piped" | "null";
|
|
30
|
+
stdout?: "inherit" | "piped" | "null";
|
|
31
|
+
stderr?: "inherit" | "piped" | "null";
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** Output from a completed process (for spawnOutput). */
|
|
35
|
+
export interface SpawnOutputResult {
|
|
36
|
+
stdout: Uint8Array;
|
|
37
|
+
stderr: Uint8Array;
|
|
38
|
+
success: boolean;
|
|
39
|
+
code?: number;
|
|
40
|
+
signal?: string;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** Empty stream used when stdio is "inherit" so callers can always use pipeTo. */
|
|
44
|
+
function emptyReadableStream(): ReadableStream<Uint8Array> {
|
|
45
|
+
return new ReadableStream({
|
|
46
|
+
start(controller) {
|
|
47
|
+
controller.close();
|
|
48
|
+
},
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Spawn a child process. Returns a handle with Web ReadableStreams for stdout/stderr
|
|
54
|
+
* so they can be used with pipeTo() in any runtime.
|
|
55
|
+
*/
|
|
56
|
+
export function spawn(command: string, options: SpawnOptions = {}): SpawnChild {
|
|
57
|
+
const args = options.args ?? [];
|
|
58
|
+
const stdio: ("inherit" | "pipe" | "ignore")[] = [
|
|
59
|
+
options.stdin === "piped"
|
|
60
|
+
? "pipe"
|
|
61
|
+
: options.stdin === "null"
|
|
62
|
+
? "ignore"
|
|
63
|
+
: "inherit",
|
|
64
|
+
options.stdout === "piped"
|
|
65
|
+
? "pipe"
|
|
66
|
+
: options.stdout === "null"
|
|
67
|
+
? "ignore"
|
|
68
|
+
: "inherit",
|
|
69
|
+
options.stderr === "piped"
|
|
70
|
+
? "pipe"
|
|
71
|
+
: options.stderr === "null"
|
|
72
|
+
? "ignore"
|
|
73
|
+
: "inherit",
|
|
74
|
+
];
|
|
75
|
+
|
|
76
|
+
const cp = nodeSpawn(command, args, {
|
|
77
|
+
cwd: options.cwd,
|
|
78
|
+
env: { ...process.env, ...options.env, FORCE_COLOR: "true" },
|
|
79
|
+
stdio,
|
|
80
|
+
signal: options.signal,
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
const stdout: ReadableStream<Uint8Array> =
|
|
84
|
+
options.stdout === "piped" && cp.stdout
|
|
85
|
+
? (Readable.toWeb(cp.stdout) as unknown as ReadableStream<Uint8Array>)
|
|
86
|
+
: emptyReadableStream();
|
|
87
|
+
const stderr: ReadableStream<Uint8Array> =
|
|
88
|
+
options.stderr === "piped" && cp.stderr
|
|
89
|
+
? (Readable.toWeb(cp.stderr) as unknown as ReadableStream<Uint8Array>)
|
|
90
|
+
: emptyReadableStream();
|
|
91
|
+
|
|
92
|
+
const status = new Promise<{
|
|
93
|
+
success: boolean;
|
|
94
|
+
code?: number;
|
|
95
|
+
signal?: string;
|
|
96
|
+
}>((resolve) => {
|
|
97
|
+
cp.on("close", (code: number | null, signal: string | null) => {
|
|
98
|
+
resolve({
|
|
99
|
+
success: code === 0,
|
|
100
|
+
code: code ?? undefined,
|
|
101
|
+
signal: signal ?? undefined,
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
let stdinStream: WritableStream<Uint8Array> | undefined;
|
|
107
|
+
if (options.stdin === "piped" && cp.stdin) {
|
|
108
|
+
stdinStream = Writable.toWeb(cp.stdin) as WritableStream<Uint8Array>;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return {
|
|
112
|
+
get pid() {
|
|
113
|
+
return cp.pid ?? 0;
|
|
114
|
+
},
|
|
115
|
+
stdin: stdinStream,
|
|
116
|
+
stdout,
|
|
117
|
+
stderr,
|
|
118
|
+
status,
|
|
119
|
+
kill(signal?: NodeJS.Signals) {
|
|
120
|
+
cp.kill(signal ?? "SIGTERM");
|
|
121
|
+
},
|
|
122
|
+
ref() {
|
|
123
|
+
if (typeof cp.ref === "function") cp.ref();
|
|
124
|
+
},
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Run a command and wait for it to complete, returning collected stdout/stderr.
|
|
130
|
+
* Use for short-lived commands (e.g. tmux install, kill-server).
|
|
131
|
+
*/
|
|
132
|
+
export async function spawnOutput(
|
|
133
|
+
command: string,
|
|
134
|
+
options: SpawnOptions & { stdinInput?: Uint8Array } = {},
|
|
135
|
+
): Promise<SpawnOutputResult> {
|
|
136
|
+
const { stdinInput, ...spawnOpts } = options;
|
|
137
|
+
const useStdin = stdinInput != null;
|
|
138
|
+
const child = spawn(command, {
|
|
139
|
+
...spawnOpts,
|
|
140
|
+
stdin: useStdin ? "piped" : spawnOpts.stdin,
|
|
141
|
+
stdout: "piped",
|
|
142
|
+
stderr: "piped",
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
if (useStdin && child.stdin) {
|
|
146
|
+
const writer = child.stdin.getWriter();
|
|
147
|
+
await writer.write(stdinInput);
|
|
148
|
+
await writer.close();
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const [stdout, stderr, status] = await Promise.all([
|
|
152
|
+
streamToUint8Array(child.stdout),
|
|
153
|
+
streamToUint8Array(child.stderr),
|
|
154
|
+
child.status,
|
|
155
|
+
]);
|
|
156
|
+
|
|
157
|
+
return {
|
|
158
|
+
stdout,
|
|
159
|
+
stderr,
|
|
160
|
+
success: status.success,
|
|
161
|
+
code: status.code,
|
|
162
|
+
signal: status.signal,
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
async function streamToUint8Array(
|
|
167
|
+
stream: ReadableStream<Uint8Array>,
|
|
168
|
+
): Promise<Uint8Array> {
|
|
169
|
+
const chunks: Uint8Array[] = [];
|
|
170
|
+
const reader = stream.getReader();
|
|
171
|
+
try {
|
|
172
|
+
while (true) {
|
|
173
|
+
const { done, value } = await reader.read();
|
|
174
|
+
if (done) break;
|
|
175
|
+
if (value) chunks.push(value);
|
|
176
|
+
}
|
|
177
|
+
} finally {
|
|
178
|
+
reader.releaseLock();
|
|
179
|
+
}
|
|
180
|
+
const total = chunks.reduce((n, c) => n + c.length, 0);
|
|
181
|
+
const out = new Uint8Array(total);
|
|
182
|
+
let offset = 0;
|
|
183
|
+
for (const c of chunks) {
|
|
184
|
+
out.set(c, offset);
|
|
185
|
+
offset += c.length;
|
|
186
|
+
}
|
|
187
|
+
return out;
|
|
188
|
+
}
|
package/src/runtime.ts
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
type RuntimeEnvironment = 'backend' | 'frontend' | 'unknown';
|
|
2
|
+
type Runtime = 'node' | 'deno' | 'bun' | 'browser' | 'unknown';
|
|
3
|
+
|
|
4
|
+
export function getRuntime(): {runtime: Runtime, environment: RuntimeEnvironment} {
|
|
5
|
+
// Check for Deno
|
|
6
|
+
// @ts-ignore: Deno is added to global scope in Deno environments
|
|
7
|
+
if (typeof Deno !== 'undefined') {
|
|
8
|
+
return { runtime: 'deno', environment: 'backend' };
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
// Check for Bun
|
|
12
|
+
// @ts-ignore: Bun is added to global scope in Bun environments
|
|
13
|
+
if (typeof Bun !== 'undefined') {
|
|
14
|
+
return { runtime: 'bun', environment: 'backend' };
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// Check for Node.js
|
|
18
|
+
// Node environments have a `process` object with versions
|
|
19
|
+
if (
|
|
20
|
+
typeof process !== 'undefined' &&
|
|
21
|
+
(process as any).versions &&
|
|
22
|
+
(process as any).versions.node
|
|
23
|
+
) {
|
|
24
|
+
return { runtime: 'node', environment: 'backend' };
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Check for Browser
|
|
28
|
+
// Browsers typically have `window` and `document`
|
|
29
|
+
if (
|
|
30
|
+
typeof window !== 'undefined' &&
|
|
31
|
+
// @ts-ignore: document is added to global scope in browser environments
|
|
32
|
+
typeof document !== 'undefined'
|
|
33
|
+
) {
|
|
34
|
+
return { runtime: 'browser', environment: 'frontend' };
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return { runtime: 'unknown', environment: 'unknown' };
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Helpers for common process operations.
|
|
42
|
+
*/
|
|
43
|
+
|
|
44
|
+
/** Get environment variable. */
|
|
45
|
+
export function getEnv(key: string): string | undefined {
|
|
46
|
+
return process.env[key];
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** Set environment variable. */
|
|
50
|
+
export function setEnv(key: string, value: string): void {
|
|
51
|
+
process.env[key] = value;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** CLI arguments (argv without script path). */
|
|
55
|
+
export function args(): string[] {
|
|
56
|
+
return process.argv.slice(2);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** Exit process with code. */
|
|
60
|
+
export function exit(code: number): never {
|
|
61
|
+
return process.exit(code);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** Current working directory. */
|
|
65
|
+
export function cwd(): string {
|
|
66
|
+
return process.cwd();
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** Terminal size when available. */
|
|
70
|
+
export function consoleSize(): { columns: number; rows: number } {
|
|
71
|
+
return {
|
|
72
|
+
columns: process.stdout.columns ?? 80,
|
|
73
|
+
rows: (process.stdout as any).rows ?? 24,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** Set process exit code (for graceful shutdown). */
|
|
78
|
+
export function setExitCode(code: number): void {
|
|
79
|
+
process.exitCode = code;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** Check if error is "file/dir not found". */
|
|
83
|
+
export function isNotFoundError(err: unknown): boolean {
|
|
84
|
+
if (err && typeof err === "object") {
|
|
85
|
+
const e = err as { code?: string };
|
|
86
|
+
if (e.code === "ENOENT") return true;
|
|
87
|
+
}
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export type ErrorCode = number;
|
|
2
|
+
export type ErrorMessageMapping = Record<ErrorCode, string>;
|
|
3
|
+
|
|
4
|
+
export type ErrorMessageFxn = (errorCode: ErrorCode) => string;
|
|
5
|
+
|
|
6
|
+
export interface SuccessfulResultMessage {
|
|
7
|
+
success: true;
|
|
8
|
+
message: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface SuccessfulResult<T> {
|
|
12
|
+
success: true;
|
|
13
|
+
result: T;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface FailedResult {
|
|
17
|
+
success: false;
|
|
18
|
+
errorMessage: string;
|
|
19
|
+
errorCode?: number;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export type Result<T> = SuccessfulResult<T> | FailedResult;
|
|
23
|
+
|
|
24
|
+
export type InternalServerErrorResult = FailedResult;
|
|
25
|
+
|
|
26
|
+
/** comes from the `tsoa` package, but we don't want it as a dependency just for this type */
|
|
27
|
+
export interface FieldErrors {
|
|
28
|
+
[name: string]: {
|
|
29
|
+
message: string;
|
|
30
|
+
value?: any;
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
export interface ValidateErrorResult {
|
|
34
|
+
message: "Validation Failed";
|
|
35
|
+
details?: FieldErrors;
|
|
36
|
+
}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import type { TObject } from "@sinclair/typebox";
|
|
2
|
+
import type { EvmAddress } from "./nominal.ts";
|
|
3
|
+
|
|
4
|
+
export type IntersectObject<T, Obj> = T extends TObject<infer O>
|
|
5
|
+
? TObject<ShallowMergeIntersects<O & Obj>>
|
|
6
|
+
: never;
|
|
7
|
+
|
|
8
|
+
// TODO: this probably doesn't belong in this file
|
|
9
|
+
export type TransactionTemplate = {
|
|
10
|
+
data: string;
|
|
11
|
+
to: EvmAddress;
|
|
12
|
+
gasPrice: string;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @description Combines members of an intersection into a readable type.
|
|
17
|
+
*
|
|
18
|
+
* @see {@link https://twitter.com/Riyaadh_Abr/status/1622736576303312899/photo/1}
|
|
19
|
+
* @example
|
|
20
|
+
* MergeIntersects<{ a: string } & { b: string } & { c: number, d: bigint }>
|
|
21
|
+
* => { a: string, b: string, c: number, d: bigint }
|
|
22
|
+
*/
|
|
23
|
+
export type MergeIntersects<T> = T extends
|
|
24
|
+
| Record<string, unknown>
|
|
25
|
+
| readonly Record<string, unknown>[]
|
|
26
|
+
? T extends infer Obj ? { [K in keyof Obj]: MergeIntersects<Obj[K]> }
|
|
27
|
+
: never
|
|
28
|
+
: T;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Same as the above, but shallow (not recursive)
|
|
32
|
+
* This is useful if you don't want Typescript to expand an underlying type
|
|
33
|
+
*
|
|
34
|
+
* ex: avoid { foo: FooType } turning into { foo: { a: string, b: string } }
|
|
35
|
+
*/
|
|
36
|
+
export type ShallowMergeIntersects<T> =
|
|
37
|
+
& {
|
|
38
|
+
[K in keyof T]: T[K];
|
|
39
|
+
}
|
|
40
|
+
& {};
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Flips an object so key are values and values are keys
|
|
44
|
+
*
|
|
45
|
+
* ex: Record<A, B> becomes Partial<Record<B, A>>
|
|
46
|
+
*/
|
|
47
|
+
export type FlipObject<T extends Record<any, any>> = {
|
|
48
|
+
[Value in T[keyof T]]: keyof {
|
|
49
|
+
[Key in keyof T as Value extends T[Key] ? Key : never]: any;
|
|
50
|
+
};
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
export type NoUndefinedField<T> = { [P in keyof T]-?: NonNullable<T[P]> };
|
|
54
|
+
|
|
55
|
+
export type ElementOf<T extends readonly any[]> = T extends (infer Elem)[]
|
|
56
|
+
? Elem
|
|
57
|
+
: never;
|
|
58
|
+
export type ValueOf<T> = T[keyof T];
|
|
59
|
+
|
|
60
|
+
export type Satisfies<Base, T> = T extends Base ? true : false;
|
|
61
|
+
|
|
62
|
+
export type RemoveNeverEntries<T extends Record<any, any>> = {
|
|
63
|
+
[K in keyof T as T[K] extends never ? never : K]: T[K];
|
|
64
|
+
};
|
|
65
|
+
export type IdxOf<T> = { [idx in keyof T]: idx }[any];
|
|
66
|
+
|
|
67
|
+
export type RemoveUnknown<T> = unknown extends T
|
|
68
|
+
? (T extends unknown ? never : T)
|
|
69
|
+
: T;
|
|
70
|
+
|
|
71
|
+
type ImmutablePrimitive =
|
|
72
|
+
| undefined
|
|
73
|
+
| null
|
|
74
|
+
| boolean
|
|
75
|
+
| string
|
|
76
|
+
| number
|
|
77
|
+
| Function;
|
|
78
|
+
export type Mutable<T> = { -readonly [P in keyof T]: T[P] };
|
|
79
|
+
export type DeepMutable<T> = T extends ImmutablePrimitive ? T
|
|
80
|
+
: T extends ReadonlyArray<infer U> ? Array<DeepMutable<U>>
|
|
81
|
+
: T extends ReadonlySet<infer U> ? Set<DeepMutable<U>>
|
|
82
|
+
: T extends ReadonlyMap<infer K, infer V>
|
|
83
|
+
? Map<DeepMutable<K>, DeepMutable<V>>
|
|
84
|
+
: T extends Function ? T
|
|
85
|
+
: T extends object ? { -readonly [K in keyof T]: DeepMutable<T[K]> }
|
|
86
|
+
: T;
|
|
87
|
+
export type DeepReadonly<T> = T extends ImmutablePrimitive ? T
|
|
88
|
+
: T extends Array<infer U> ? ReadonlyArray<DeepReadonly<U>>
|
|
89
|
+
: T extends Map<infer K, infer V>
|
|
90
|
+
? ReadonlyMap<DeepReadonly<K>, DeepReadonly<V>>
|
|
91
|
+
: T extends Set<infer M> ? ReadonlySet<DeepReadonly<M>>
|
|
92
|
+
: {
|
|
93
|
+
readonly [K in keyof T]: DeepReadonly<T[K]>;
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
export type UnionToIntersection<U> =
|
|
97
|
+
(U extends any ? (k: U) => void : never) extends (
|
|
98
|
+
k: infer I extends U,
|
|
99
|
+
) => void ? I
|
|
100
|
+
: never;
|
|
101
|
+
|
|
102
|
+
const __TypeError = Symbol("OpaqueTypeError");
|
|
103
|
+
type TypeError<BaseType extends string> = BaseType & {
|
|
104
|
+
readonly [__TypeError]: BaseType;
|
|
105
|
+
};
|
|
106
|
+
/**
|
|
107
|
+
* Prints custom error message
|
|
108
|
+
* Taken from https://github.com/wevm/abitype/blob/main/packages/abitype/src/types.ts#L11
|
|
109
|
+
*
|
|
110
|
+
* @param messages - Error message
|
|
111
|
+
* @returns Custom error message
|
|
112
|
+
*
|
|
113
|
+
* @example
|
|
114
|
+
* type Result = Error<'Custom error message'>
|
|
115
|
+
* // ^? type Result = ['Error: Custom error message']
|
|
116
|
+
*/
|
|
117
|
+
export type TypeErrorMessage<messages extends string | string[]> =
|
|
118
|
+
messages extends string ? TypeError<messages>
|
|
119
|
+
: {
|
|
120
|
+
[key in keyof messages]: messages[key] extends
|
|
121
|
+
infer message extends string ? TypeError<message>
|
|
122
|
+
: never;
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Types that Typescript allows inside a string template
|
|
127
|
+
*/
|
|
128
|
+
export type Stringifiable =
|
|
129
|
+
| string
|
|
130
|
+
| number
|
|
131
|
+
| bigint
|
|
132
|
+
| boolean
|
|
133
|
+
| null
|
|
134
|
+
| undefined;
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Turns an Object whose keys are numbers into an equivalent tuple
|
|
138
|
+
* WARNING: This ONLY works if the keys are consecutive numbers starting from 0
|
|
139
|
+
*/
|
|
140
|
+
export type ToTupleSimple<
|
|
141
|
+
T extends { [key: number]: any },
|
|
142
|
+
Acc extends any[] = [],
|
|
143
|
+
> = Acc["length"] extends keyof T ? ToTupleSimple<T, [...Acc, T[Acc["length"]]]>
|
|
144
|
+
: Acc;
|
|
145
|
+
|
|
146
|
+
// Helper type to build a tuple up to a given length `N`, inserting `never` for missing entries
|
|
147
|
+
type BuildTuple<
|
|
148
|
+
T extends { [key: number]: any },
|
|
149
|
+
MaxSize extends number,
|
|
150
|
+
Acc extends any[] = [],
|
|
151
|
+
> = Acc["length"] extends MaxSize ? Acc
|
|
152
|
+
: BuildTuple<
|
|
153
|
+
T,
|
|
154
|
+
MaxSize,
|
|
155
|
+
[...Acc, Acc["length"] extends keyof T ? T[Acc["length"]] : never]
|
|
156
|
+
>;
|
|
157
|
+
|
|
158
|
+
// Helper type to filter out `never` values from a tuple
|
|
159
|
+
type FilterNeverArray<T extends any[]> = T extends [infer First, ...infer Rest]
|
|
160
|
+
? [First] extends [never] ? FilterNeverArray<Rest>
|
|
161
|
+
: [First, ...FilterNeverArray<Rest>]
|
|
162
|
+
: [];
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Turns an Object whose keys are numbers into an equivalent tuple
|
|
166
|
+
* WARNING: This supports objects that are missing entries (not consecutive numbers starting from 0)
|
|
167
|
+
* However, you MUST specify the maximum value in the object keys instead
|
|
168
|
+
* This is required since Typescript doesn't easily support artihmetic at the type level
|
|
169
|
+
*/
|
|
170
|
+
export type ToTupleComplex<
|
|
171
|
+
T extends { [key: number]: any },
|
|
172
|
+
MaxSize extends number,
|
|
173
|
+
> = FilterNeverArray<BuildTuple<T, MaxSize>>;
|
package/src/types/mod.ts
ADDED
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import type { FastFlavor } from "@coderspirit/nominal";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* TODO: remove any instance of this in the codebase
|
|
5
|
+
* Note: often this is uncertainty between HexString0x and HexStringNo0x
|
|
6
|
+
*/
|
|
7
|
+
export type UnknownFormat = string;
|
|
8
|
+
|
|
9
|
+
export type URI = FastFlavor<string, "Uri">;
|
|
10
|
+
|
|
11
|
+
export type Caip2 = FastFlavor<string, "Caip2">;
|
|
12
|
+
/**
|
|
13
|
+
* TODO: probably best to make this more granular to different cryptographic schemes
|
|
14
|
+
* esp. since some return 0x and others don't
|
|
15
|
+
*/
|
|
16
|
+
export type EvmSignature = FastFlavor<HexString0x, "EvmSignature">;
|
|
17
|
+
export type GenericSignature = FastFlavor<string, "OtherSignature">;
|
|
18
|
+
export type Signature =
|
|
19
|
+
| EvmSignature
|
|
20
|
+
| GenericSignature
|
|
21
|
+
| MidnightSignature
|
|
22
|
+
;
|
|
23
|
+
|
|
24
|
+
export type VersionString = `${number}.${number}.${number}`;
|
|
25
|
+
|
|
26
|
+
// TODO: should probably differentiate between block numbers of different networks
|
|
27
|
+
// and maybe even Paima block number / emulated block number
|
|
28
|
+
export type EffectstreamBlockNumber = FastFlavor<number, "EffectstreamBlockNumber">;
|
|
29
|
+
export type EvmBlockNumber = FastFlavor<number, "EvmBlockNumber">;
|
|
30
|
+
export type NtpBlockNumber = FastFlavor<number, "NtpBlockNumber">;
|
|
31
|
+
export type MidnightBlockNumber = FastFlavor<number, "MidnightBlockNumber">;
|
|
32
|
+
export type CardanoBlockNumber = FastFlavor<number, "CardanoBlockNumber">;
|
|
33
|
+
export type BitcoinBlockNumber = FastFlavor<number, "BitcoinBlockNumber">;
|
|
34
|
+
|
|
35
|
+
export type BlockNumber =
|
|
36
|
+
| EffectstreamBlockNumber
|
|
37
|
+
| EvmBlockNumber
|
|
38
|
+
| NtpBlockNumber
|
|
39
|
+
| MidnightBlockNumber
|
|
40
|
+
| CardanoBlockNumber
|
|
41
|
+
| BitcoinBlockNumber;
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* recall: slots may be empty, so absolute slot number is not usually equal to block number
|
|
45
|
+
*/
|
|
46
|
+
export type AbsoluteSlotNumber = FastFlavor<number, "AbsoluteSlotNumber">;
|
|
47
|
+
export type RelativeSlotNumber = FastFlavor<number, "RelativeSlotNumber">;
|
|
48
|
+
export type EpochNumber = FastFlavor<number, "EpochNumber">;
|
|
49
|
+
|
|
50
|
+
// don't make it a flavor so it can easily be assigned to/from flavors
|
|
51
|
+
export type HexString0x = `0x${string}`;
|
|
52
|
+
export type HexStringNo0x = FastFlavor<string, "HexStringNo0x">;
|
|
53
|
+
export type Base64String = FastFlavor<string, "Base64String">;
|
|
54
|
+
|
|
55
|
+
// TODO: change these to brands later
|
|
56
|
+
export type IntervalMs = FastFlavor<number, "IntervalMs">;
|
|
57
|
+
export type IntervalSec = FastFlavor<number, "IntervalSec">;
|
|
58
|
+
export type TimestampMs = FastFlavor<number, "TimestampMs">;
|
|
59
|
+
export type TimestampMsStr = FastFlavor<string, "TimestampMsStr">;
|
|
60
|
+
export type TimestampSec = FastFlavor<number, "TimestampSec">;
|
|
61
|
+
export type TimestampIso8601 = FastFlavor<string, "TimestampIso8601">;
|
|
62
|
+
|
|
63
|
+
export type AlgorandBlockHash = FastFlavor<UnknownFormat, "AlgorandBlockHash">;
|
|
64
|
+
export type AlgorandTxHash = FastFlavor<UnknownFormat, "AlgorandTxHash">;
|
|
65
|
+
// TODO: this is close to /^[A-Z2-7]{58}$/
|
|
66
|
+
export type AlgorandAddress = FastFlavor<string, "AlgorandAddress">;
|
|
67
|
+
|
|
68
|
+
export type AvailBlockHash = FastFlavor<UnknownFormat, "AvailBlockHash">;
|
|
69
|
+
export type AvailTxHash = FastFlavor<UnknownFormat, "AvailTxHash">;
|
|
70
|
+
export type AvailAddress = SubstrateAddress;
|
|
71
|
+
|
|
72
|
+
export type CardanoBlockHash = FastFlavor<string, "CardanoBlockHash">;
|
|
73
|
+
export type CardanoTxHash = FastFlavor<string, "CardanoTxHash">;
|
|
74
|
+
// TODO: bech32 string
|
|
75
|
+
export type CardanoAddress = FastFlavor<string, "CardanoAddress">;
|
|
76
|
+
export type CardanoCredential = FastFlavor<string, "CardanoCredential">;
|
|
77
|
+
export type CardanoPolicyId = FastFlavor<string, "CardanoPolicyId">;
|
|
78
|
+
export type CardanoAssetName = FastFlavor<string, "CardanoAssetName">;
|
|
79
|
+
export type CardanoCip14Fingerprint = FastFlavor<
|
|
80
|
+
string,
|
|
81
|
+
"CardanoCip14Fingerprint"
|
|
82
|
+
>;
|
|
83
|
+
export type CardanoPoolId = FastFlavor<string, "CardanoPoolId">;
|
|
84
|
+
export type CardanoAmountLovelace = FastFlavor<string, "CardanoAmountLovelace">;
|
|
85
|
+
|
|
86
|
+
export type NtpBlockHash = FastFlavor<string, "NtpBlockHash">;
|
|
87
|
+
export type NtpTxHash = FastFlavor<string, "NtpTxHash">; // TODO: is this needed?
|
|
88
|
+
export type NtpAddress = FastFlavor<string, "NtpAddress">; // TODO: is this needed?
|
|
89
|
+
|
|
90
|
+
export type EvmBlockHash = FastFlavor<HexString0x, "EvmBlockHash">;
|
|
91
|
+
export type EvmTxHash = FastFlavor<HexString0x, "EvmTxHash">;
|
|
92
|
+
export type EvmAddress = FastFlavor<HexString0x, "EvmAddress">;
|
|
93
|
+
export type EvmSelector = FastFlavor<HexString0x, "EvmSelector">;
|
|
94
|
+
export type Evm4ByteSelector = FastFlavor<HexString0x, "Evm4ByteSelector">;
|
|
95
|
+
|
|
96
|
+
export type MidnightBlockHash = FastFlavor<HexString0x, "MidnightBlockHash">;
|
|
97
|
+
export type MidnightTxHash = FastFlavor<HexString0x, "MidnightTxHash">;
|
|
98
|
+
export type MidnightAddress = FastFlavor<string, "MidnightAddress">;
|
|
99
|
+
export type MidnightSignature = FastFlavor<string, "MidnightSignature">;
|
|
100
|
+
|
|
101
|
+
export type MinaBlockHash = FastFlavor<UnknownFormat, "MinaBlockHash">;
|
|
102
|
+
export type MinaTxHash = FastFlavor<UnknownFormat, "MinaTxHash">;
|
|
103
|
+
export type MinaAddress = FastFlavor<string, "MinaAddress">;
|
|
104
|
+
|
|
105
|
+
export type PolkadotAddress = SubstrateAddress;
|
|
106
|
+
export type PolkadotBlockHash = FastFlavor<UnknownFormat, "PolkadotBlockHash">;
|
|
107
|
+
export type PolkadotTxHash = FastFlavor<UnknownFormat, "PolkadotTxHash">;
|
|
108
|
+
|
|
109
|
+
// TODO: close to the regex /^[1-9A-HJ-NP-Za-km-z]{47,48}$/
|
|
110
|
+
export type SubstrateAddress = FastFlavor<string, "SubstrateAddress">;
|
|
111
|
+
|
|
112
|
+
export type NearAddress = FastFlavor<string, "NearAddress">;
|
|
113
|
+
|
|
114
|
+
export type BitcoinBlockHash = FastFlavor<string, "BitcoinBlockHash">;
|
|
115
|
+
export type BitcoinTxId = FastFlavor<string, "BitcoinTxId">;
|
|
116
|
+
export type BitcoinAddress = FastFlavor<string, "BitcoinAddress">;
|
|
117
|
+
|
|
118
|
+
export type WalletAddress =
|
|
119
|
+
| AlgorandAddress
|
|
120
|
+
| AvailAddress
|
|
121
|
+
| CardanoAddress
|
|
122
|
+
| EvmAddress
|
|
123
|
+
| MidnightAddress
|
|
124
|
+
| MinaAddress
|
|
125
|
+
| SubstrateAddress
|
|
126
|
+
| BitcoinAddress;
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* TODO: probably best to make this more granular to different cryptographic schemes
|
|
130
|
+
*/
|
|
131
|
+
export type EvmPrivateKey = FastFlavor<HexString0x, "EvmPrivateKey">;
|
|
132
|
+
export type GenericPrivateKey = FastFlavor<string, "GenericPrivateKey">;
|
|
133
|
+
export type PrivateKey =
|
|
134
|
+
| EvmPrivateKey
|
|
135
|
+
| GenericPrivateKey;
|
|
136
|
+
|
|
137
|
+
export type EffectstreamTxHash = FastFlavor<HexString0x, "EffectstreamTxHash">;
|
|
138
|
+
export type TxHash =
|
|
139
|
+
| AlgorandTxHash
|
|
140
|
+
| AvailTxHash
|
|
141
|
+
| CardanoTxHash
|
|
142
|
+
| EvmTxHash
|
|
143
|
+
| MidnightTxHash
|
|
144
|
+
| MinaTxHash
|
|
145
|
+
| EffectstreamTxHash
|
|
146
|
+
| NtpTxHash;
|
|
147
|
+
// | SubstrateTxHash;
|
|
148
|
+
|
|
149
|
+
export type EffectstreamBlockHash = FastFlavor<HexString0x, "EffectstreamBlockHash">;
|
|
150
|
+
export type BlockHash =
|
|
151
|
+
| AlgorandBlockHash
|
|
152
|
+
| AvailBlockHash
|
|
153
|
+
| CardanoBlockHash
|
|
154
|
+
| EvmBlockHash
|
|
155
|
+
| MidnightBlockHash
|
|
156
|
+
| MinaBlockHash
|
|
157
|
+
| EffectstreamBlockHash
|
|
158
|
+
| NtpBlockHash
|
|
159
|
+
| BitcoinBlockHash;
|
|
160
|
+
// | SubstrateBlockHash;
|
|
161
|
+
|
|
162
|
+
export type NtpPageJson = FastFlavor<string, "NTPPageJson">;
|
|
163
|
+
export type EvmRpcPageJson = FastFlavor<string, "EvmRpcPageJson">;
|
|
164
|
+
export type CarpCursorJson = FastFlavor<string, "CarpCursorJson">;
|
|
165
|
+
export type MidnightEncodedStateJson = FastFlavor<
|
|
166
|
+
string,
|
|
167
|
+
"MidnightEncodedStateJson"
|
|
168
|
+
>;
|