@parity/product-sdk-host 0.4.0 → 0.6.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/dist/index.d.ts +401 -226
- package/dist/index.js +132 -32
- package/dist/index.js.map +1 -1
- package/package.json +6 -6
- package/src/chains.ts +4 -8
- package/src/chat.ts +126 -0
- package/src/container.ts +47 -9
- package/src/entropy.ts +67 -0
- package/src/index.ts +37 -4
- package/src/payments.ts +100 -0
- package/src/permissions.ts +126 -18
- package/src/theme.ts +106 -0
- package/src/truapi.ts +119 -157
- package/src/types.ts +64 -71
package/src/theme.ts
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
// Copyright 2026 Parity Technologies (UK) Ltd.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
/**
|
|
4
|
+
* Higher-level wrapper for the host's theme subscription.
|
|
5
|
+
*
|
|
6
|
+
* `hostApi.themeSubscribe` is reachable via {@link getTruApi}, but consumers
|
|
7
|
+
* have to wire the subscription envelope themselves. `getThemeProvider`
|
|
8
|
+
* returns the `@novasamatech/host-api-wrapper` theme provider object directly,
|
|
9
|
+
* giving callers a `subscribeTheme(cb)` method that resolves to a typed
|
|
10
|
+
* {@link ThemeMode} — a `{ name, variant }` struct where `variant` is
|
|
11
|
+
* `"Light" | "Dark"` — and yields a `Subscription<void>` handle.
|
|
12
|
+
*
|
|
13
|
+
* @remarks
|
|
14
|
+
* As of `host-api(-wrapper)` v0.8 the theme payload is a struct, not a flat
|
|
15
|
+
* `"light" | "dark"` string: read {@link ThemeMode.variant} for the
|
|
16
|
+
* light/dark value (now capitalized) and {@link ThemeMode.name} for the
|
|
17
|
+
* active theme name (`Default`, or `Custom` carrying a string id).
|
|
18
|
+
*
|
|
19
|
+
* @module
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import { createLogger } from "@parity/product-sdk-logger";
|
|
23
|
+
|
|
24
|
+
import type {
|
|
25
|
+
createThemeProvider,
|
|
26
|
+
ThemeMode as NovasamaThemeMode,
|
|
27
|
+
} from "@novasamatech/host-api-wrapper";
|
|
28
|
+
|
|
29
|
+
const log = createLogger("host:theme");
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Host theme provider handle. Exposes `subscribeTheme(callback)` which
|
|
33
|
+
* receives a typed {@link ThemeMode} struct on every change and returns a
|
|
34
|
+
* `Subscription<void>` (`unsubscribe` + `onInterrupt`).
|
|
35
|
+
*
|
|
36
|
+
* Type identical to `createThemeProvider()` from
|
|
37
|
+
* `@novasamatech/host-api-wrapper`.
|
|
38
|
+
*/
|
|
39
|
+
export type ThemeProvider = ReturnType<typeof createThemeProvider>;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Host theme value. Re-exported from `@novasamatech/host-api-wrapper`.
|
|
43
|
+
*
|
|
44
|
+
* A `{ name, variant }` struct as of v0.8 (previously a flat
|
|
45
|
+
* `"light" | "dark"` string).
|
|
46
|
+
*/
|
|
47
|
+
export type ThemeMode = NovasamaThemeMode;
|
|
48
|
+
|
|
49
|
+
/** Light/dark variant of the active theme: `"Light" | "Dark"`. */
|
|
50
|
+
export type ThemeVariant = ThemeMode["variant"];
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Active theme name: `{ tag: "Default" }`, or `{ tag: "Custom", value }`
|
|
54
|
+
* carrying the custom theme's string id.
|
|
55
|
+
*/
|
|
56
|
+
export type ThemeName = ThemeMode["name"];
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Get the host theme provider.
|
|
60
|
+
*
|
|
61
|
+
* Returns the theme-subscription handle exported by
|
|
62
|
+
* `@novasamatech/host-api-wrapper`, or `null` if the package is unavailable
|
|
63
|
+
* (running outside a host container or the optional peer dep isn't
|
|
64
|
+
* installed).
|
|
65
|
+
*
|
|
66
|
+
* Implementation note: upstream `@novasamatech/host-api-wrapper` exports only
|
|
67
|
+
* the `createThemeProvider` factory and no `themeProvider` singleton, so
|
|
68
|
+
* this getter constructs a fresh instance on each call (unlike
|
|
69
|
+
* {@link getPreimageManager} or {@link getHostLocalStorage}, which return
|
|
70
|
+
* upstream singletons). The constructed provider is cheap to allocate; it
|
|
71
|
+
* only opens a subscription when `subscribeTheme` is called.
|
|
72
|
+
*
|
|
73
|
+
* @returns The theme provider, or `null` if unavailable.
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* ```ts
|
|
77
|
+
* import { getThemeProvider } from "@parity/product-sdk-host";
|
|
78
|
+
*
|
|
79
|
+
* const provider = await getThemeProvider();
|
|
80
|
+
* if (provider) {
|
|
81
|
+
* const sub = provider.subscribeTheme((theme) => {
|
|
82
|
+
* document.documentElement.dataset.theme = theme.variant.toLowerCase();
|
|
83
|
+
* if (theme.name.tag === "Custom") loadCustomTheme(theme.name.value);
|
|
84
|
+
* });
|
|
85
|
+
* // sub.unsubscribe() to stop listening
|
|
86
|
+
* }
|
|
87
|
+
* ```
|
|
88
|
+
*/
|
|
89
|
+
export async function getThemeProvider(): Promise<ThemeProvider | null> {
|
|
90
|
+
try {
|
|
91
|
+
const sdk = await import("@novasamatech/host-api-wrapper");
|
|
92
|
+
return sdk.createThemeProvider();
|
|
93
|
+
} catch (err) {
|
|
94
|
+
log.debug("getThemeProvider unavailable", err);
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (import.meta.vitest) {
|
|
100
|
+
const { test, expect } = import.meta.vitest;
|
|
101
|
+
|
|
102
|
+
test("getThemeProvider returns provider when SDK is available", async () => {
|
|
103
|
+
const provider = await getThemeProvider();
|
|
104
|
+
expect(provider === null || typeof provider === "object").toBe(true);
|
|
105
|
+
});
|
|
106
|
+
}
|
package/src/truapi.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
// Copyright 2026 Parity Technologies (UK) Ltd.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
1
3
|
/**
|
|
2
4
|
* TruAPI - the protocol for communicating between apps and the Polkadot host container.
|
|
3
5
|
*
|
|
4
|
-
* This module centralizes access to @novasamatech/
|
|
6
|
+
* This module centralizes access to @novasamatech/host-api-wrapper and @novasamatech/host-api,
|
|
5
7
|
* allowing other @parity/product-sdk-* packages to import from here rather than depending
|
|
6
8
|
* directly on novasama packages.
|
|
7
9
|
*
|
|
@@ -16,29 +18,56 @@ import type {
|
|
|
16
18
|
AllocationOutcome as AllocationOutcomeCodec,
|
|
17
19
|
CodecType,
|
|
18
20
|
RemotePermission as RemotePermissionCodec,
|
|
19
|
-
Statement as StatementCodec,
|
|
20
21
|
} from "@novasamatech/host-api";
|
|
22
|
+
import type { createAccountsProvider, preimageManager } from "@novasamatech/host-api-wrapper";
|
|
21
23
|
|
|
22
|
-
import
|
|
24
|
+
import { isInsideContainer } from "./container.js";
|
|
25
|
+
import type { Statement, StatementProof } from "./types.js";
|
|
23
26
|
|
|
24
27
|
const log = createLogger("host");
|
|
25
28
|
|
|
26
29
|
/**
|
|
27
|
-
* Extract a human-readable message from
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
30
|
+
* Extract a human-readable message from a host-side error. Hosts wrap
|
|
31
|
+
* errors in versioned envelopes (`{ tag: "v1", value: CodecError }`); this
|
|
32
|
+
* helper unwraps the envelope and renders the inner error's `name`/`message`
|
|
33
|
+
* so callers see the host's actual diagnostic instead of `"[object Object]"`
|
|
34
|
+
* (from `String(err)`) or a JSON-stringified envelope.
|
|
35
|
+
*
|
|
36
|
+
* Exported for the higher-level wrappers (`requestPermission`,
|
|
37
|
+
* `deriveEntropy`, etc.) that build their `throw new Error(...)` messages.
|
|
31
38
|
*/
|
|
32
|
-
function
|
|
33
|
-
|
|
34
|
-
|
|
39
|
+
export function formatHostError(err: unknown): string {
|
|
40
|
+
// Single-level unwrap only; nested envelopes fall through to JSON.stringify.
|
|
41
|
+
const inner = isVersionedEnvelope(err) ? err.value : err;
|
|
42
|
+
|
|
43
|
+
if (inner instanceof Error) return inner.message;
|
|
44
|
+
if (typeof inner === "string") return inner;
|
|
45
|
+
if (
|
|
46
|
+
inner != null &&
|
|
47
|
+
typeof inner === "object" &&
|
|
48
|
+
"message" in inner &&
|
|
49
|
+
typeof (inner as { message: unknown }).message === "string"
|
|
50
|
+
) {
|
|
51
|
+
const named = inner as { name?: unknown; message: string };
|
|
52
|
+
return typeof named.name === "string" ? `${named.name}: ${named.message}` : named.message;
|
|
53
|
+
}
|
|
35
54
|
try {
|
|
36
|
-
return JSON.stringify(
|
|
55
|
+
return JSON.stringify(inner);
|
|
37
56
|
} catch {
|
|
38
|
-
return String(
|
|
57
|
+
return String(inner);
|
|
39
58
|
}
|
|
40
59
|
}
|
|
41
60
|
|
|
61
|
+
function isVersionedEnvelope(value: unknown): value is { tag: string; value: unknown } {
|
|
62
|
+
return (
|
|
63
|
+
value != null &&
|
|
64
|
+
typeof value === "object" &&
|
|
65
|
+
"tag" in value &&
|
|
66
|
+
"value" in value &&
|
|
67
|
+
typeof (value as { tag: unknown }).tag === "string"
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
|
|
42
71
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
43
72
|
// Helpers from @novasamatech/host-api (re-exported from @novasamatech/scale)
|
|
44
73
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
@@ -99,16 +128,19 @@ export type { HexString } from "@novasamatech/host-api";
|
|
|
99
128
|
* The TruApi type - provides low-level methods for communicating with the host.
|
|
100
129
|
*
|
|
101
130
|
* Methods include:
|
|
102
|
-
* - `navigateTo(url)`
|
|
103
|
-
* - `permission(permissions)`
|
|
104
|
-
* - `localStorageRead/Write/Clear`
|
|
105
|
-
* - `sign(payload)`
|
|
106
|
-
* - `deriveEntropy(context)`
|
|
107
|
-
* - `themeSubscribe()`
|
|
131
|
+
* - `navigateTo(url)` - Navigate to a URL within the host
|
|
132
|
+
* - `permission(permissions)` - Request permissions from the host
|
|
133
|
+
* - `localStorageRead/Write/Clear` - Host-backed storage
|
|
134
|
+
* - `sign(payload)` - Request transaction signing
|
|
135
|
+
* - `deriveEntropy(context)` - Derive deterministic entropy
|
|
136
|
+
* - `themeSubscribe()` - Subscribe to host theme changes
|
|
108
137
|
* - And many more...
|
|
138
|
+
*
|
|
139
|
+
* Type identical to `hostApi` from `@novasamatech/host-api-wrapper` so that
|
|
140
|
+
* `truApi.X(...)` calls keep their full inference (return types, method
|
|
141
|
+
* names, parameter shapes) instead of decaying to `any`.
|
|
109
142
|
*/
|
|
110
|
-
|
|
111
|
-
export type TruApi = any;
|
|
143
|
+
export type TruApi = typeof import("@novasamatech/host-api-wrapper").hostApi;
|
|
112
144
|
|
|
113
145
|
/** Cached TruApi instance */
|
|
114
146
|
let cachedTruApi: TruApi | null = null;
|
|
@@ -116,7 +148,7 @@ let cachedTruApi: TruApi | null = null;
|
|
|
116
148
|
/**
|
|
117
149
|
* Get the TruAPI instance for direct low-level access.
|
|
118
150
|
*
|
|
119
|
-
* Returns the `hostApi` object from `@novasamatech/
|
|
151
|
+
* Returns the `hostApi` object from `@novasamatech/host-api-wrapper` which provides
|
|
120
152
|
* methods for communicating directly with the host container. Returns `null`
|
|
121
153
|
* when running outside a container or when the SDK is unavailable.
|
|
122
154
|
*
|
|
@@ -149,7 +181,7 @@ export async function getTruApi(): Promise<TruApi | null> {
|
|
|
149
181
|
if (cachedTruApi) return cachedTruApi;
|
|
150
182
|
|
|
151
183
|
try {
|
|
152
|
-
const sdk = await import("@novasamatech/
|
|
184
|
+
const sdk = await import("@novasamatech/host-api-wrapper");
|
|
153
185
|
cachedTruApi = sdk.hostApi;
|
|
154
186
|
log.debug("TruAPI loaded");
|
|
155
187
|
return cachedTruApi;
|
|
@@ -185,34 +217,44 @@ export async function getTruApi(): Promise<TruApi | null> {
|
|
|
185
217
|
*/
|
|
186
218
|
export async function getPreimageManager(): Promise<PreimageManager | null> {
|
|
187
219
|
try {
|
|
188
|
-
const sdk = await import("@novasamatech/
|
|
220
|
+
const sdk = await import("@novasamatech/host-api-wrapper");
|
|
189
221
|
return sdk.preimageManager;
|
|
190
|
-
} catch {
|
|
222
|
+
} catch (err) {
|
|
223
|
+
log.debug("getPreimageManager unavailable", err);
|
|
191
224
|
return null;
|
|
192
225
|
}
|
|
193
226
|
}
|
|
194
227
|
|
|
195
228
|
/**
|
|
196
|
-
* Preimage manager
|
|
229
|
+
* Preimage manager handle for bulletin chain operations. `lookup` returns a
|
|
230
|
+
* `Subscription<void>` (`unsubscribe` + `onInterrupt`); `submit` returns a
|
|
231
|
+
* `0x`-prefixed hex preimage key.
|
|
232
|
+
*
|
|
233
|
+
* Type identical to `preimageManager` from `@novasamatech/host-api-wrapper`.
|
|
197
234
|
*/
|
|
198
|
-
export
|
|
199
|
-
/**
|
|
200
|
-
* Submit a preimage to the bulletin chain.
|
|
201
|
-
* @param data - The data to submit.
|
|
202
|
-
* @returns The preimage key (hex string).
|
|
203
|
-
*/
|
|
204
|
-
submit(data: Uint8Array): Promise<string>;
|
|
235
|
+
export type PreimageManager = typeof preimageManager;
|
|
205
236
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
237
|
+
/**
|
|
238
|
+
* Construct a fresh `PreimageManager` instance with an optional custom
|
|
239
|
+
* transport. Use this when you need a non-default transport; otherwise
|
|
240
|
+
* prefer {@link getPreimageManager}, which returns the shared singleton.
|
|
241
|
+
*
|
|
242
|
+
* Mirrors `createPreimageManager` from `@novasamatech/host-api-wrapper`.
|
|
243
|
+
*
|
|
244
|
+
* @param transport - Optional transport; defaults to the sandbox transport.
|
|
245
|
+
* @returns A new `PreimageManager` instance, or `null` if unavailable.
|
|
246
|
+
*/
|
|
247
|
+
export async function createHostPreimageManager(
|
|
248
|
+
transport?: import("@novasamatech/host-api").Transport,
|
|
249
|
+
): Promise<PreimageManager | null> {
|
|
250
|
+
if (!(await isInsideContainer())) return null;
|
|
251
|
+
try {
|
|
252
|
+
const sdk = await import("@novasamatech/host-api-wrapper");
|
|
253
|
+
return sdk.createPreimageManager(transport);
|
|
254
|
+
} catch (err) {
|
|
255
|
+
log.debug("createHostPreimageManager unavailable", err);
|
|
256
|
+
return null;
|
|
257
|
+
}
|
|
216
258
|
}
|
|
217
259
|
|
|
218
260
|
/**
|
|
@@ -222,9 +264,10 @@ export interface PreimageManager {
|
|
|
222
264
|
*/
|
|
223
265
|
export async function getAccountsProvider(): Promise<AccountsProvider | null> {
|
|
224
266
|
try {
|
|
225
|
-
const sdk = await import("@novasamatech/
|
|
226
|
-
return sdk.createAccountsProvider()
|
|
227
|
-
} catch {
|
|
267
|
+
const sdk = await import("@novasamatech/host-api-wrapper");
|
|
268
|
+
return sdk.createAccountsProvider();
|
|
269
|
+
} catch (err) {
|
|
270
|
+
log.debug("getAccountsProvider unavailable", err);
|
|
228
271
|
return null;
|
|
229
272
|
}
|
|
230
273
|
}
|
|
@@ -278,7 +321,7 @@ export type RemotePermissionTag = RemotePermission["tag"];
|
|
|
278
321
|
* @example
|
|
279
322
|
* ```ts
|
|
280
323
|
* const outcomes = await requestResourceAllocation([
|
|
281
|
-
* { tag: "
|
|
324
|
+
* { tag: "BulletinAllowance", value: undefined },
|
|
282
325
|
* ]);
|
|
283
326
|
* if (outcomes[0].tag === "Allocated") { ... }
|
|
284
327
|
* ```
|
|
@@ -296,7 +339,7 @@ export async function requestResourceAllocation(
|
|
|
296
339
|
return await truApi.requestResourceAllocation(enumValue("v1", resources)).match(
|
|
297
340
|
(envelope: { tag: "v1"; value: AllocationOutcome[] }) => envelope.value,
|
|
298
341
|
(err: unknown) => {
|
|
299
|
-
throw new Error(`requestResourceAllocation failed: ${
|
|
342
|
+
throw new Error(`requestResourceAllocation failed: ${formatHostError(err)}`, {
|
|
300
343
|
cause: err,
|
|
301
344
|
});
|
|
302
345
|
},
|
|
@@ -307,22 +350,6 @@ export async function requestResourceAllocation(
|
|
|
307
350
|
// Authorized Statement Store proof creation (RFC-10 §"Statement Store allowance")
|
|
308
351
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
309
352
|
|
|
310
|
-
/**
|
|
311
|
-
* A Statement payload destined for the Statement Store. Matches the
|
|
312
|
-
* `pallet-statement` Statement structure.
|
|
313
|
-
*
|
|
314
|
-
* The optional `proof` field is the same {@link StatementProof} shape that
|
|
315
|
-
* {@link createProofAuthorized} returns: pass `undefined` here, call
|
|
316
|
-
* `createProofAuthorized` to obtain the proof, then attach it before
|
|
317
|
-
* submitting via `HostStatementStore.submit`. The `OnChain` variant of
|
|
318
|
-
* `StatementProof` is a chain-attestation reference; the `Sr25519` /
|
|
319
|
-
* `Ed25519` / `Ecdsa` variants are signing proofs.
|
|
320
|
-
*
|
|
321
|
-
* Derived from the upstream codec so structural changes surface as compile
|
|
322
|
-
* errors here, not runtime decode failures.
|
|
323
|
-
*/
|
|
324
|
-
export type Statement = CodecType<typeof StatementCodec>;
|
|
325
|
-
|
|
326
353
|
/**
|
|
327
354
|
* Have the host sign a Statement using an allowance-bearing account it
|
|
328
355
|
* picks internally — RFC-10 §"Statement Store allowance".
|
|
@@ -378,7 +405,9 @@ export async function createProofAuthorized(statement: Statement): Promise<State
|
|
|
378
405
|
return await truApi.statementStoreCreateProofAuthorized(enumValue("v1", statement)).match(
|
|
379
406
|
(envelope: { tag: "v1"; value: StatementProof }) => envelope.value,
|
|
380
407
|
(err: unknown) => {
|
|
381
|
-
throw new Error(`createProofAuthorized failed: ${
|
|
408
|
+
throw new Error(`createProofAuthorized failed: ${formatHostError(err)}`, {
|
|
409
|
+
cause: err,
|
|
410
|
+
});
|
|
382
411
|
},
|
|
383
412
|
);
|
|
384
413
|
}
|
|
@@ -431,99 +460,16 @@ export interface ResultAsync<T, E> {
|
|
|
431
460
|
}
|
|
432
461
|
|
|
433
462
|
/**
|
|
434
|
-
* Accounts provider
|
|
435
|
-
*
|
|
436
|
-
*
|
|
437
|
-
*
|
|
463
|
+
* Accounts provider handle from `@novasamatech/host-api-wrapper`. Surfaces the
|
|
464
|
+
* full upstream API - host wallet accounts, app-scoped product accounts,
|
|
465
|
+
* Ring VRF, user identity (`getUserId`, `requestLogin`), and connection
|
|
466
|
+
* status subscription.
|
|
467
|
+
*
|
|
468
|
+
* Type identical to `createAccountsProvider()` from
|
|
469
|
+
* `@novasamatech/host-api-wrapper`; methods return neverthrow `ResultAsync`
|
|
470
|
+
* values with typed `CodecError` variants in the error channel.
|
|
438
471
|
*/
|
|
439
|
-
export
|
|
440
|
-
/**
|
|
441
|
-
* Get legacy accounts (user's external wallets connected to the host).
|
|
442
|
-
*
|
|
443
|
-
* Renamed from `getNonProductAccounts` in @novasamatech/product-sdk 0.7.
|
|
444
|
-
*
|
|
445
|
-
* @returns ResultAsync resolving to array of accounts.
|
|
446
|
-
*/
|
|
447
|
-
getLegacyAccounts: () => ResultAsync<HostAccount[], unknown>;
|
|
448
|
-
|
|
449
|
-
/**
|
|
450
|
-
* Get a signer for a legacy account.
|
|
451
|
-
*
|
|
452
|
-
* Renamed from `getNonProductAccountSigner` in @novasamatech/product-sdk 0.7.
|
|
453
|
-
*
|
|
454
|
-
* @param account - The product account (used for public key lookup).
|
|
455
|
-
* @returns A PolkadotSigner for signing transactions.
|
|
456
|
-
*/
|
|
457
|
-
getLegacyAccountSigner: (account: ProductAccount) => import("polkadot-api").PolkadotSigner;
|
|
458
|
-
|
|
459
|
-
/**
|
|
460
|
-
* Get an app-scoped product account from the host.
|
|
461
|
-
*
|
|
462
|
-
* Product accounts are derived by the host wallet for each app, identified
|
|
463
|
-
* by `dotNsIdentifier` (e.g., "mark3t.dot"). The user controls these accounts
|
|
464
|
-
* but they are scoped to the requesting app.
|
|
465
|
-
*
|
|
466
|
-
* @param dotNsIdentifier - App identifier (e.g., "mark3t.dot").
|
|
467
|
-
* @param derivationIndex - Derivation index within the app scope. Default: 0
|
|
468
|
-
* @returns ResultAsync resolving to the account.
|
|
469
|
-
*/
|
|
470
|
-
getProductAccount: (
|
|
471
|
-
dotNsIdentifier: string,
|
|
472
|
-
derivationIndex?: number,
|
|
473
|
-
) => ResultAsync<HostAccount, unknown>;
|
|
474
|
-
|
|
475
|
-
/**
|
|
476
|
-
* Get a signer for a product account.
|
|
477
|
-
*
|
|
478
|
-
* @param account - The product account.
|
|
479
|
-
* @returns A PolkadotSigner for signing transactions.
|
|
480
|
-
*/
|
|
481
|
-
getProductAccountSigner: (account: ProductAccount) => import("polkadot-api").PolkadotSigner;
|
|
482
|
-
|
|
483
|
-
/**
|
|
484
|
-
* Get a contextual alias for a product account via Ring VRF.
|
|
485
|
-
*
|
|
486
|
-
* Aliases prove account membership in a ring without revealing which
|
|
487
|
-
* account produced the alias.
|
|
488
|
-
*
|
|
489
|
-
* @param dotNsIdentifier - App identifier.
|
|
490
|
-
* @param derivationIndex - Derivation index. Default: 0
|
|
491
|
-
* @returns ResultAsync resolving to the contextual alias.
|
|
492
|
-
*/
|
|
493
|
-
getProductAccountAlias: (
|
|
494
|
-
dotNsIdentifier: string,
|
|
495
|
-
derivationIndex?: number,
|
|
496
|
-
) => ResultAsync<ContextualAlias, unknown>;
|
|
497
|
-
|
|
498
|
-
/**
|
|
499
|
-
* Create a Ring VRF proof for anonymous operations.
|
|
500
|
-
*
|
|
501
|
-
* Proves that the signer is a member of the ring at the given location
|
|
502
|
-
* without revealing which member.
|
|
503
|
-
*
|
|
504
|
-
* @param dotNsIdentifier - App identifier.
|
|
505
|
-
* @param derivationIndex - Derivation index.
|
|
506
|
-
* @param location - Ring location on-chain.
|
|
507
|
-
* @param message - Message to sign.
|
|
508
|
-
* @returns ResultAsync resolving to the proof bytes.
|
|
509
|
-
*/
|
|
510
|
-
createRingVRFProof: (
|
|
511
|
-
dotNsIdentifier: string,
|
|
512
|
-
derivationIndex: number,
|
|
513
|
-
location: unknown,
|
|
514
|
-
message: Uint8Array,
|
|
515
|
-
) => ResultAsync<Uint8Array, unknown>;
|
|
516
|
-
|
|
517
|
-
/**
|
|
518
|
-
* Subscribe to account connection status changes.
|
|
519
|
-
*
|
|
520
|
-
* @param callback - Called with status string ("connected" | "disconnected").
|
|
521
|
-
* @returns Unsubscribe handle.
|
|
522
|
-
*/
|
|
523
|
-
subscribeAccountConnectionStatus: (
|
|
524
|
-
callback: (status: string) => void,
|
|
525
|
-
) => { unsubscribe: () => void } | (() => void);
|
|
526
|
-
}
|
|
472
|
+
export type AccountsProvider = ReturnType<typeof createAccountsProvider>;
|
|
527
473
|
|
|
528
474
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
529
475
|
// Tests
|
|
@@ -546,6 +492,22 @@ if (import.meta.vitest) {
|
|
|
546
492
|
expect(manager === null || typeof manager === "object").toBe(true);
|
|
547
493
|
});
|
|
548
494
|
|
|
495
|
+
test("createHostPreimageManager returns null outside container", async () => {
|
|
496
|
+
expect(await createHostPreimageManager()).toBeNull();
|
|
497
|
+
});
|
|
498
|
+
|
|
499
|
+
test("formatHostError unwraps versioned envelopes and renders CodecError", () => {
|
|
500
|
+
expect(
|
|
501
|
+
formatHostError({
|
|
502
|
+
tag: "v1",
|
|
503
|
+
value: { name: "GenericError", message: "boom" },
|
|
504
|
+
}),
|
|
505
|
+
).toBe("GenericError: boom");
|
|
506
|
+
expect(formatHostError(new Error("plain"))).toBe("plain");
|
|
507
|
+
expect(formatHostError("string err")).toBe("string err");
|
|
508
|
+
expect(formatHostError({ tag: "v1", value: { message: "no-name" } })).toBe("no-name");
|
|
509
|
+
});
|
|
510
|
+
|
|
549
511
|
test("getAccountsProvider returns provider when SDK is available", async () => {
|
|
550
512
|
// In dev/test mode, product-sdk is installed, so this returns a provider
|
|
551
513
|
const provider = await getAccountsProvider();
|
|
@@ -563,7 +525,7 @@ if (import.meta.vitest) {
|
|
|
563
525
|
const api = await getTruApi();
|
|
564
526
|
if (api === null) {
|
|
565
527
|
await expect(
|
|
566
|
-
requestResourceAllocation([{ tag: "
|
|
528
|
+
requestResourceAllocation([{ tag: "BulletinAllowance", value: undefined }]),
|
|
567
529
|
).rejects.toThrow(/TruAPI unavailable/);
|
|
568
530
|
} else {
|
|
569
531
|
expect(typeof requestResourceAllocation).toBe("function");
|
package/src/types.ts
CHANGED
|
@@ -1,62 +1,85 @@
|
|
|
1
|
+
// Copyright 2026 Parity Technologies (UK) Ltd.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
1
3
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* Public types for the host wrappers.
|
|
5
|
+
*
|
|
6
|
+
* These are re-exported from `@novasamatech/host-api-wrapper` (the runtime
|
|
7
|
+
* objects the host getters cast to) rather than hand-mirrored, so the
|
|
8
|
+
* Parity surface stays in lockstep with the upstream codec types.
|
|
6
9
|
*/
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
}
|
|
10
|
+
|
|
11
|
+
import type {
|
|
12
|
+
hostLocalStorage,
|
|
13
|
+
createStatementStore,
|
|
14
|
+
ProductAccountId as NovasamaProductAccountId,
|
|
15
|
+
SignedStatement as NovasamaSignedStatement,
|
|
16
|
+
Statement as NovasamaStatement,
|
|
17
|
+
StatementTopicFilter as NovasamaStatementTopicFilter,
|
|
18
|
+
StatementsPage as NovasamaStatementsPage,
|
|
19
|
+
Topic as NovasamaTopic,
|
|
20
|
+
} from "@novasamatech/host-api-wrapper";
|
|
21
|
+
import type { Subscription } from "@novasamatech/host-api";
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Persistent storage exposed by the host container, including string, JSON
|
|
25
|
+
* and raw byte (`readBytes`/`writeBytes`) accessors. Most apps reach it
|
|
26
|
+
* indirectly through the Storage package's `KvStore`; reach for it directly
|
|
27
|
+
* via {@link getHostLocalStorage} when you need raw host storage without the
|
|
28
|
+
* KV abstraction.
|
|
29
|
+
*
|
|
30
|
+
* Type identical to `hostLocalStorage` from `@novasamatech/host-api-wrapper`.
|
|
31
|
+
*/
|
|
32
|
+
export type HostLocalStorage = typeof hostLocalStorage;
|
|
18
33
|
|
|
19
34
|
/**
|
|
20
35
|
* Cryptographic proof attached to a statement before submission, returned by
|
|
21
36
|
* {@link HostStatementStore.createProof}. Variants cover the supported
|
|
22
|
-
* signature schemes
|
|
37
|
+
* signature schemes - `Sr25519`, `Ed25519`, `Ecdsa`, and `OnChain` (chain-
|
|
23
38
|
* attestation-based proofs).
|
|
24
39
|
*
|
|
25
|
-
*
|
|
40
|
+
* Inferred from `createStatementStore().createProof`'s return type so codec
|
|
41
|
+
* changes surface here as compile errors, not runtime decode failures.
|
|
26
42
|
*/
|
|
27
|
-
export type StatementProof =
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
| { tag: "Ecdsa"; value: { signature: Uint8Array; signer: Uint8Array } }
|
|
31
|
-
| {
|
|
32
|
-
tag: "OnChain";
|
|
33
|
-
value: { who: Uint8Array; blockHash: Uint8Array; event: bigint };
|
|
34
|
-
};
|
|
43
|
+
export type StatementProof = Awaited<
|
|
44
|
+
ReturnType<ReturnType<typeof createStatementStore>["createProof"]>
|
|
45
|
+
>;
|
|
35
46
|
|
|
36
47
|
/**
|
|
37
|
-
* Topic-based subscription filter.
|
|
38
|
-
* `@novasamatech/product-sdk` — the host delivers statements that match
|
|
48
|
+
* Topic-based subscription filter. The host delivers statements that match
|
|
39
49
|
* either *all* of the listed topics (`matchAll`) or *any* of them
|
|
40
|
-
* (`matchAny`).
|
|
50
|
+
* (`matchAny`). Re-exported from `@novasamatech/host-api-wrapper`.
|
|
41
51
|
*/
|
|
42
|
-
export type StatementTopicFilter =
|
|
52
|
+
export type StatementTopicFilter = NovasamaStatementTopicFilter;
|
|
53
|
+
|
|
54
|
+
/** A single topic value used inside a {@link StatementTopicFilter}. Re-exported from `@novasamatech/host-api-wrapper`. */
|
|
55
|
+
export type Topic = NovasamaTopic;
|
|
56
|
+
|
|
57
|
+
/** `[ss58Address, chainPrefix]` tuple identifying a product account at the codec layer. Re-exported from `@novasamatech/host-api-wrapper`. */
|
|
58
|
+
export type ProductAccountId = NovasamaProductAccountId;
|
|
59
|
+
|
|
60
|
+
/** Unsigned statement payload. Re-exported from `@novasamatech/host-api-wrapper`. */
|
|
61
|
+
export type Statement = NovasamaStatement;
|
|
62
|
+
|
|
63
|
+
/** Statement bundled with its {@link StatementProof}. Re-exported from `@novasamatech/host-api-wrapper`. */
|
|
64
|
+
export type SignedStatement = NovasamaSignedStatement;
|
|
43
65
|
|
|
44
66
|
/**
|
|
45
67
|
* A page of signed statements delivered by {@link HostStatementStore.subscribe}.
|
|
46
68
|
*
|
|
47
69
|
* Pages arrive sequentially. `isComplete` is `true` on the final page of a
|
|
48
70
|
* subscription's initial backfill; subsequent pages contain new statements
|
|
49
|
-
* as they appear on chain.
|
|
71
|
+
* as they appear on chain. `statements` is `SignedStatement[]` (typed,
|
|
72
|
+
* not `unknown[]`).
|
|
50
73
|
*/
|
|
51
|
-
export
|
|
52
|
-
statements: unknown[];
|
|
53
|
-
isComplete: boolean;
|
|
54
|
-
}
|
|
74
|
+
export type StatementsPage = NovasamaStatementsPage;
|
|
55
75
|
|
|
56
|
-
/**
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
76
|
+
/**
|
|
77
|
+
* Subscription handle returned by the host - equivalent to
|
|
78
|
+
* `Subscription<void>` from `@novasamatech/host-api`. Exposes
|
|
79
|
+
* `unsubscribe()` plus an `onInterrupt` hook that fires if the host
|
|
80
|
+
* interrupts the subscription server-side.
|
|
81
|
+
*/
|
|
82
|
+
export type HostSubscription = Subscription<void>;
|
|
60
83
|
|
|
61
84
|
/**
|
|
62
85
|
* Statement Store handle exposed by the host container. Provides
|
|
@@ -64,37 +87,7 @@ export interface HostSubscription {
|
|
|
64
87
|
* host's native binary protocol; the `statement-store` package layers a
|
|
65
88
|
* higher-level client on top.
|
|
66
89
|
*
|
|
67
|
-
*
|
|
90
|
+
* Type identical to `createStatementStore()` from
|
|
91
|
+
* `@novasamatech/host-api-wrapper`.
|
|
68
92
|
*/
|
|
69
|
-
export
|
|
70
|
-
/**
|
|
71
|
-
* Subscribe to statements matching the given topic filter.
|
|
72
|
-
*
|
|
73
|
-
* The callback is invoked once per page of statements. After the initial
|
|
74
|
-
* backfill completes (signaled by `page.isComplete === true`), subsequent
|
|
75
|
-
* pages contain new statements as they're produced.
|
|
76
|
-
*
|
|
77
|
-
* @param filter - Topic match filter (`matchAll` or `matchAny`).
|
|
78
|
-
* @param callback - Called with each `StatementsPage` from the host.
|
|
79
|
-
* @returns Subscription handle with `unsubscribe`.
|
|
80
|
-
*/
|
|
81
|
-
subscribe(
|
|
82
|
-
filter: StatementTopicFilter,
|
|
83
|
-
callback: (page: StatementsPage) => void,
|
|
84
|
-
): HostSubscription;
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* Create a proof for a statement using the given account.
|
|
88
|
-
*
|
|
89
|
-
* @param accountId - The account ID tuple `[ss58Address, chainPrefix]` from product-sdk.
|
|
90
|
-
* @param statement - The unsigned statement.
|
|
91
|
-
* @returns The proof (signature + signer info, or chain-attestation reference).
|
|
92
|
-
*/
|
|
93
|
-
createProof(accountId: [string, number], statement: unknown): Promise<StatementProof>;
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* Submit a signed statement to the bulletin chain.
|
|
97
|
-
* @param signedStatement - Statement with attached proof.
|
|
98
|
-
*/
|
|
99
|
-
submit(signedStatement: unknown): Promise<void>;
|
|
100
|
-
}
|
|
93
|
+
export type HostStatementStore = ReturnType<typeof createStatementStore>;
|