@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/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/product-sdk and @novasamatech/host-api,
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 type { StatementProof } from "./types.js";
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 an unknown error. `JSON.stringify`
28
- * on `Error` returns `"{}"` because `message` and `stack` are non-enumerable
29
- * without this helper, wire failures surface as `"... failed: {}"` with
30
- * zero diagnostic context.
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 formatError(err: unknown): string {
33
- if (err instanceof Error) return err.message;
34
- if (typeof err === "string") return err;
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(err);
55
+ return JSON.stringify(inner);
37
56
  } catch {
38
- return String(err);
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)` Navigate to a URL within the host
103
- * - `permission(permissions)` Request permissions from the host
104
- * - `localStorageRead/Write/Clear` Host-backed storage
105
- * - `sign(payload)` Request transaction signing
106
- * - `deriveEntropy(context)` Derive deterministic entropy
107
- * - `themeSubscribe()` Subscribe to host theme changes
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
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
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/product-sdk` which provides
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/product-sdk");
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/product-sdk");
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 interface for bulletin chain operations.
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 interface PreimageManager {
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
- * Look up a preimage by key.
208
- * @param key - The preimage key (hex string).
209
- * @param callback - Called with the data when found, or null if not yet available.
210
- * @returns Subscription handle with unsubscribe method.
211
- */
212
- lookup(
213
- key: string,
214
- callback: (preimage: Uint8Array | null) => void,
215
- ): { unsubscribe: () => void; onInterrupt: (cb: () => void) => () => void };
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/product-sdk");
226
- return sdk.createAccountsProvider() as unknown as AccountsProvider;
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: "BulletInAllowance", value: undefined },
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: ${formatError(err)}`, {
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: ${formatError(err)}`, { cause: err });
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 interface from @novasamatech/product-sdk.
435
- *
436
- * Provides methods for accessing host wallet accounts, product accounts,
437
- * and Ring VRF operations.
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 interface AccountsProvider {
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: "BulletInAllowance", value: undefined }]),
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
- * Persistent string and JSON storage exposed by the host container. Most
3
- * apps reach it indirectly through the Storage package's `KvStore`; reach for
4
- * it directly via {@link getHostLocalStorage} when you need raw host storage
5
- * without the KV abstraction.
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
- export interface HostLocalStorage {
8
- readString(key: string): Promise<string | null>;
9
- writeString(key: string, value: string): Promise<void>;
10
- readJSON<T>(key: string): Promise<T | null>;
11
- writeJSON<T>(key: string, value: T): Promise<void>;
12
- /**
13
- * Clear a specific key from storage.
14
- * @param key - The key to clear
15
- */
16
- clear(key: string): Promise<void>;
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 `Sr25519`, `Ed25519`, `Ecdsa`, and `OnChain` (chain-
37
+ * signature schemes - `Sr25519`, `Ed25519`, `Ecdsa`, and `OnChain` (chain-
23
38
  * attestation-based proofs).
24
39
  *
25
- * Mirrors `@novasamatech/product-sdk@0.7`'s proof shape.
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
- | { tag: "Sr25519"; value: { signature: Uint8Array; signer: Uint8Array } }
29
- | { tag: "Ed25519"; value: { signature: Uint8Array; signer: Uint8Array } }
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. Mirrors `StatementTopicFilter` from
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 = { matchAll: Uint8Array[] } | { matchAny: Uint8Array[] };
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 interface StatementsPage {
52
- statements: unknown[];
53
- isComplete: boolean;
54
- }
74
+ export type StatementsPage = NovasamaStatementsPage;
55
75
 
56
- /** Subscription handle returned by the host. */
57
- export interface HostSubscription {
58
- unsubscribe: () => void;
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
- * Shape matches `@novasamatech/product-sdk@0.7`'s `createStatementStore()`.
90
+ * Type identical to `createStatementStore()` from
91
+ * `@novasamatech/host-api-wrapper`.
68
92
  */
69
- export interface HostStatementStore {
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>;