@parity/product-sdk-signer 0.1.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/src/types.ts ADDED
@@ -0,0 +1,177 @@
1
+ import type { PolkadotSigner } from "polkadot-api";
2
+
3
+ import type { SS58String } from "@parity/product-sdk-address";
4
+
5
+ import type { SignerError } from "./errors.js";
6
+
7
+ /** Connection status for a signer provider. */
8
+ export type ConnectionStatus = "disconnected" | "connecting" | "connected";
9
+
10
+ /**
11
+ * Identifies the source of an account.
12
+ *
13
+ * - `"host"`: Host API provider (Polkadot Desktop / Mobile) — the primary provider
14
+ * - `"dev"`: Development accounts (Alice, Bob, etc.) — for testing only
15
+ */
16
+ export type ProviderType = "host" | "dev";
17
+
18
+ /** A signing-capable account from any provider. */
19
+ export interface SignerAccount {
20
+ /** SS58 address (generic prefix 42 by default). */
21
+ address: SS58String;
22
+ /**
23
+ * H160 EVM address derived from the public key.
24
+ *
25
+ * For native Substrate accounts: keccak256(publicKey), last 20 bytes.
26
+ * For EVM-derived accounts: strips the 0xEE padding.
27
+ * Used for pallet-revive / Asset Hub EVM contract interactions.
28
+ */
29
+ h160Address: `0x${string}`;
30
+ /** Raw public key (32 bytes). May be sr25519, ed25519, or ecdsa depending on the provider. */
31
+ publicKey: Uint8Array;
32
+ /** Human-readable name if available from the provider. */
33
+ name: string | null;
34
+ /** Which provider supplied this account. */
35
+ source: ProviderType;
36
+ /** Get the PolkadotSigner for this account. */
37
+ getSigner(): PolkadotSigner;
38
+ }
39
+
40
+ /** Full state snapshot emitted to subscribers. */
41
+ export interface SignerState {
42
+ /** Current connection status. */
43
+ status: ConnectionStatus;
44
+ /** All available accounts across all connected providers. */
45
+ accounts: readonly SignerAccount[];
46
+ /** Currently selected account (null if none selected). */
47
+ selectedAccount: SignerAccount | null;
48
+ /** Which provider is active (null if disconnected). */
49
+ activeProvider: ProviderType | null;
50
+ /** Last error (null if no error). */
51
+ error: SignerError | null;
52
+ }
53
+
54
+ /** Lightweight Result type for operations that can fail expectedly. */
55
+ export type Result<T, E> = { ok: true; value: T } | { ok: false; error: E };
56
+
57
+ /** Create a successful Result. */
58
+ export function ok<T>(value: T): Result<T, never> {
59
+ return { ok: true, value };
60
+ }
61
+
62
+ /** Create a failed Result. */
63
+ export function err<E>(error: E): Result<never, E> {
64
+ return { ok: false, error };
65
+ }
66
+
67
+ /** Factory function that creates a SignerProvider for a given type. */
68
+ export type ProviderFactory = (type: ProviderType) => import("./providers/types.js").SignerProvider;
69
+
70
+ /**
71
+ * Adapter for persisting the selected account address across sessions.
72
+ *
73
+ * `globalThis.localStorage` satisfies this interface. Pass a custom
74
+ * implementation for container environments (e.g., hostLocalStorage)
75
+ * or for testing.
76
+ */
77
+ export interface AccountPersistence {
78
+ getItem(key: string): string | null | Promise<string | null>;
79
+ setItem(key: string, value: string): void | Promise<void>;
80
+ removeItem(key: string): void | Promise<void>;
81
+ }
82
+
83
+ /** Options for SignerManager construction. */
84
+ export interface SignerManagerOptions {
85
+ /** SS58 prefix for address encoding. Default: 42 */
86
+ ss58Prefix?: number;
87
+ /**
88
+ * Maximum time in ms to wait for the Host API.
89
+ * Applied as an AbortSignal timeout on the host provider connection.
90
+ * Default: 10_000
91
+ */
92
+ hostTimeout?: number;
93
+ /** Maximum retry attempts for provider connection. Default: 3 */
94
+ maxRetries?: number;
95
+ /** Custom provider factory. Override to inject test doubles or custom providers. */
96
+ createProvider?: ProviderFactory;
97
+ /**
98
+ * App name used for storage key namespacing. Default: "product-sdk"
99
+ * The selected account is persisted under `product-sdk:signer:{dappName}:selectedAccount`.
100
+ */
101
+ dappName?: string;
102
+ /**
103
+ * Storage adapter for persisting selected account.
104
+ * Uses host localStorage when inside a container.
105
+ * Set to `null` to disable persistence entirely.
106
+ */
107
+ persistence?: AccountPersistence | null;
108
+ }
109
+
110
+ if (import.meta.vitest) {
111
+ const { test, expect, describe } = import.meta.vitest;
112
+
113
+ describe("ok", () => {
114
+ test("produces ok result with value", () => {
115
+ const result = ok(42);
116
+ expect(result.ok).toBe(true);
117
+ expect(result).toEqual({ ok: true, value: 42 });
118
+ });
119
+
120
+ test("works with complex values", () => {
121
+ const result = ok({ name: "Alice", age: 30 });
122
+ expect(result.ok).toBe(true);
123
+ if (result.ok) {
124
+ expect(result.value.name).toBe("Alice");
125
+ }
126
+ });
127
+
128
+ test("works with null value", () => {
129
+ const result = ok(null);
130
+ expect(result).toEqual({ ok: true, value: null });
131
+ });
132
+
133
+ test("works with undefined value", () => {
134
+ const result = ok(undefined);
135
+ expect(result).toEqual({ ok: true, value: undefined });
136
+ });
137
+ });
138
+
139
+ describe("err", () => {
140
+ test("produces error result", () => {
141
+ const result = err("something went wrong");
142
+ expect(result.ok).toBe(false);
143
+ expect(result).toEqual({ ok: false, error: "something went wrong" });
144
+ });
145
+
146
+ test("works with typed error objects", () => {
147
+ const error = { type: "HOST_UNAVAILABLE" as const, message: "no host" };
148
+ const result = err(error);
149
+ expect(result.ok).toBe(false);
150
+ if (!result.ok) {
151
+ expect(result.error.type).toBe("HOST_UNAVAILABLE");
152
+ }
153
+ });
154
+ });
155
+
156
+ describe("Result type narrowing", () => {
157
+ test("ok narrows to value access", () => {
158
+ const result: Result<number, string> = ok(42);
159
+ if (result.ok) {
160
+ const value: number = result.value;
161
+ expect(value).toBe(42);
162
+ } else {
163
+ expect.unreachable("should be ok");
164
+ }
165
+ });
166
+
167
+ test("err narrows to error access", () => {
168
+ const result: Result<number, string> = err("fail");
169
+ if (!result.ok) {
170
+ const error: string = result.error;
171
+ expect(error).toBe("fail");
172
+ } else {
173
+ expect.unreachable("should be err");
174
+ }
175
+ });
176
+ });
177
+ }