@parity/product-sdk-host 0.4.0 → 0.5.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,82 @@
1
+ /**
2
+ * Higher-level wrapper for the host's theme subscription.
3
+ *
4
+ * `hostApi.themeSubscribe` is reachable via {@link getTruApi}, but consumers
5
+ * have to wire the subscription envelope themselves. `getThemeProvider`
6
+ * returns the `@novasamatech/host-api-wrapper` theme provider object directly,
7
+ * giving callers a `subscribeTheme(cb)` method that resolves to a typed
8
+ * `ThemeMode` ("Light" | "Dark") and yields a `Subscription<void>` handle.
9
+ *
10
+ * @module
11
+ */
12
+
13
+ import { createLogger } from "@parity/product-sdk-logger";
14
+
15
+ import type {
16
+ createThemeProvider,
17
+ ThemeMode as NovasamaThemeMode,
18
+ } from "@novasamatech/host-api-wrapper";
19
+
20
+ const log = createLogger("host:theme");
21
+
22
+ /**
23
+ * Host theme provider handle. Exposes `subscribeTheme(callback)` which
24
+ * receives a typed `ThemeMode` on every change and returns a
25
+ * `Subscription<void>` (`unsubscribe` + `onInterrupt`).
26
+ *
27
+ * Type identical to `createThemeProvider()` from
28
+ * `@novasamatech/host-api-wrapper`.
29
+ */
30
+ export type ThemeProvider = ReturnType<typeof createThemeProvider>;
31
+
32
+ /** Host theme mode value. Re-exported from `@novasamatech/host-api-wrapper`. */
33
+ export type ThemeMode = NovasamaThemeMode;
34
+
35
+ /**
36
+ * Get the host theme provider.
37
+ *
38
+ * Returns the theme-subscription handle exported by
39
+ * `@novasamatech/host-api-wrapper`, or `null` if the package is unavailable
40
+ * (running outside a host container or the optional peer dep isn't
41
+ * installed).
42
+ *
43
+ * Implementation note: upstream `@novasamatech/host-api-wrapper` exports only
44
+ * the `createThemeProvider` factory and no `themeProvider` singleton, so
45
+ * this getter constructs a fresh instance on each call (unlike
46
+ * {@link getPreimageManager} or {@link getHostLocalStorage}, which return
47
+ * upstream singletons). The constructed provider is cheap to allocate; it
48
+ * only opens a subscription when `subscribeTheme` is called.
49
+ *
50
+ * @returns The theme provider, or `null` if unavailable.
51
+ *
52
+ * @example
53
+ * ```ts
54
+ * import { getThemeProvider } from "@parity/product-sdk-host";
55
+ *
56
+ * const provider = await getThemeProvider();
57
+ * if (provider) {
58
+ * const sub = provider.subscribeTheme((mode) => {
59
+ * document.documentElement.dataset.theme = mode.toLowerCase();
60
+ * });
61
+ * // sub.unsubscribe() to stop listening
62
+ * }
63
+ * ```
64
+ */
65
+ export async function getThemeProvider(): Promise<ThemeProvider | null> {
66
+ try {
67
+ const sdk = await import("@novasamatech/host-api-wrapper");
68
+ return sdk.createThemeProvider();
69
+ } catch (err) {
70
+ log.debug("getThemeProvider unavailable", err);
71
+ return null;
72
+ }
73
+ }
74
+
75
+ if (import.meta.vitest) {
76
+ const { test, expect } = import.meta.vitest;
77
+
78
+ test("getThemeProvider returns provider when SDK is available", async () => {
79
+ const provider = await getThemeProvider();
80
+ expect(provider === null || typeof provider === "object").toBe(true);
81
+ });
82
+ }
package/src/truapi.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * TruAPI - the protocol for communicating between apps and the Polkadot host container.
3
3
  *
4
- * This module centralizes access to @novasamatech/product-sdk and @novasamatech/host-api,
4
+ * This module centralizes access to @novasamatech/host-api-wrapper and @novasamatech/host-api,
5
5
  * allowing other @parity/product-sdk-* packages to import from here rather than depending
6
6
  * directly on novasama packages.
7
7
  *
@@ -16,29 +16,56 @@ import type {
16
16
  AllocationOutcome as AllocationOutcomeCodec,
17
17
  CodecType,
18
18
  RemotePermission as RemotePermissionCodec,
19
- Statement as StatementCodec,
20
19
  } from "@novasamatech/host-api";
20
+ import type { createAccountsProvider, preimageManager } from "@novasamatech/host-api-wrapper";
21
21
 
22
- import type { StatementProof } from "./types.js";
22
+ import { isInsideContainer } from "./container.js";
23
+ import type { Statement, StatementProof } from "./types.js";
23
24
 
24
25
  const log = createLogger("host");
25
26
 
26
27
  /**
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.
28
+ * Extract a human-readable message from a host-side error. Hosts wrap
29
+ * errors in versioned envelopes (`{ tag: "v1", value: CodecError }`); this
30
+ * helper unwraps the envelope and renders the inner error's `name`/`message`
31
+ * so callers see the host's actual diagnostic instead of `"[object Object]"`
32
+ * (from `String(err)`) or a JSON-stringified envelope.
33
+ *
34
+ * Exported for the higher-level wrappers (`requestPermission`,
35
+ * `deriveEntropy`, etc.) that build their `throw new Error(...)` messages.
31
36
  */
32
- function formatError(err: unknown): string {
33
- if (err instanceof Error) return err.message;
34
- if (typeof err === "string") return err;
37
+ export function formatHostError(err: unknown): string {
38
+ // Single-level unwrap only; nested envelopes fall through to JSON.stringify.
39
+ const inner = isVersionedEnvelope(err) ? err.value : err;
40
+
41
+ if (inner instanceof Error) return inner.message;
42
+ if (typeof inner === "string") return inner;
43
+ if (
44
+ inner != null &&
45
+ typeof inner === "object" &&
46
+ "message" in inner &&
47
+ typeof (inner as { message: unknown }).message === "string"
48
+ ) {
49
+ const named = inner as { name?: unknown; message: string };
50
+ return typeof named.name === "string" ? `${named.name}: ${named.message}` : named.message;
51
+ }
35
52
  try {
36
- return JSON.stringify(err);
53
+ return JSON.stringify(inner);
37
54
  } catch {
38
- return String(err);
55
+ return String(inner);
39
56
  }
40
57
  }
41
58
 
59
+ function isVersionedEnvelope(value: unknown): value is { tag: string; value: unknown } {
60
+ return (
61
+ value != null &&
62
+ typeof value === "object" &&
63
+ "tag" in value &&
64
+ "value" in value &&
65
+ typeof (value as { tag: unknown }).tag === "string"
66
+ );
67
+ }
68
+
42
69
  // ─────────────────────────────────────────────────────────────────────────────
43
70
  // Helpers from @novasamatech/host-api (re-exported from @novasamatech/scale)
44
71
  // ─────────────────────────────────────────────────────────────────────────────
@@ -99,16 +126,19 @@ export type { HexString } from "@novasamatech/host-api";
99
126
  * The TruApi type - provides low-level methods for communicating with the host.
100
127
  *
101
128
  * 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
129
+ * - `navigateTo(url)` - Navigate to a URL within the host
130
+ * - `permission(permissions)` - Request permissions from the host
131
+ * - `localStorageRead/Write/Clear` - Host-backed storage
132
+ * - `sign(payload)` - Request transaction signing
133
+ * - `deriveEntropy(context)` - Derive deterministic entropy
134
+ * - `themeSubscribe()` - Subscribe to host theme changes
108
135
  * - And many more...
136
+ *
137
+ * Type identical to `hostApi` from `@novasamatech/host-api-wrapper` so that
138
+ * `truApi.X(...)` calls keep their full inference (return types, method
139
+ * names, parameter shapes) instead of decaying to `any`.
109
140
  */
110
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
111
- export type TruApi = any;
141
+ export type TruApi = typeof import("@novasamatech/host-api-wrapper").hostApi;
112
142
 
113
143
  /** Cached TruApi instance */
114
144
  let cachedTruApi: TruApi | null = null;
@@ -116,7 +146,7 @@ let cachedTruApi: TruApi | null = null;
116
146
  /**
117
147
  * Get the TruAPI instance for direct low-level access.
118
148
  *
119
- * Returns the `hostApi` object from `@novasamatech/product-sdk` which provides
149
+ * Returns the `hostApi` object from `@novasamatech/host-api-wrapper` which provides
120
150
  * methods for communicating directly with the host container. Returns `null`
121
151
  * when running outside a container or when the SDK is unavailable.
122
152
  *
@@ -149,7 +179,7 @@ export async function getTruApi(): Promise<TruApi | null> {
149
179
  if (cachedTruApi) return cachedTruApi;
150
180
 
151
181
  try {
152
- const sdk = await import("@novasamatech/product-sdk");
182
+ const sdk = await import("@novasamatech/host-api-wrapper");
153
183
  cachedTruApi = sdk.hostApi;
154
184
  log.debug("TruAPI loaded");
155
185
  return cachedTruApi;
@@ -185,34 +215,44 @@ export async function getTruApi(): Promise<TruApi | null> {
185
215
  */
186
216
  export async function getPreimageManager(): Promise<PreimageManager | null> {
187
217
  try {
188
- const sdk = await import("@novasamatech/product-sdk");
218
+ const sdk = await import("@novasamatech/host-api-wrapper");
189
219
  return sdk.preimageManager;
190
- } catch {
220
+ } catch (err) {
221
+ log.debug("getPreimageManager unavailable", err);
191
222
  return null;
192
223
  }
193
224
  }
194
225
 
195
226
  /**
196
- * Preimage manager interface for bulletin chain operations.
227
+ * Preimage manager handle for bulletin chain operations. `lookup` returns a
228
+ * `Subscription<void>` (`unsubscribe` + `onInterrupt`); `submit` returns a
229
+ * `0x`-prefixed hex preimage key.
230
+ *
231
+ * Type identical to `preimageManager` from `@novasamatech/host-api-wrapper`.
197
232
  */
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>;
233
+ export type PreimageManager = typeof preimageManager;
205
234
 
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 };
235
+ /**
236
+ * Construct a fresh `PreimageManager` instance with an optional custom
237
+ * transport. Use this when you need a non-default transport; otherwise
238
+ * prefer {@link getPreimageManager}, which returns the shared singleton.
239
+ *
240
+ * Mirrors `createPreimageManager` from `@novasamatech/host-api-wrapper`.
241
+ *
242
+ * @param transport - Optional transport; defaults to the sandbox transport.
243
+ * @returns A new `PreimageManager` instance, or `null` if unavailable.
244
+ */
245
+ export async function createHostPreimageManager(
246
+ transport?: import("@novasamatech/host-api").Transport,
247
+ ): Promise<PreimageManager | null> {
248
+ if (!(await isInsideContainer())) return null;
249
+ try {
250
+ const sdk = await import("@novasamatech/host-api-wrapper");
251
+ return sdk.createPreimageManager(transport);
252
+ } catch (err) {
253
+ log.debug("createHostPreimageManager unavailable", err);
254
+ return null;
255
+ }
216
256
  }
217
257
 
218
258
  /**
@@ -222,9 +262,10 @@ export interface PreimageManager {
222
262
  */
223
263
  export async function getAccountsProvider(): Promise<AccountsProvider | null> {
224
264
  try {
225
- const sdk = await import("@novasamatech/product-sdk");
226
- return sdk.createAccountsProvider() as unknown as AccountsProvider;
227
- } catch {
265
+ const sdk = await import("@novasamatech/host-api-wrapper");
266
+ return sdk.createAccountsProvider();
267
+ } catch (err) {
268
+ log.debug("getAccountsProvider unavailable", err);
228
269
  return null;
229
270
  }
230
271
  }
@@ -296,7 +337,7 @@ export async function requestResourceAllocation(
296
337
  return await truApi.requestResourceAllocation(enumValue("v1", resources)).match(
297
338
  (envelope: { tag: "v1"; value: AllocationOutcome[] }) => envelope.value,
298
339
  (err: unknown) => {
299
- throw new Error(`requestResourceAllocation failed: ${formatError(err)}`, {
340
+ throw new Error(`requestResourceAllocation failed: ${formatHostError(err)}`, {
300
341
  cause: err,
301
342
  });
302
343
  },
@@ -307,22 +348,6 @@ export async function requestResourceAllocation(
307
348
  // Authorized Statement Store proof creation (RFC-10 §"Statement Store allowance")
308
349
  // ─────────────────────────────────────────────────────────────────────────────
309
350
 
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
351
  /**
327
352
  * Have the host sign a Statement using an allowance-bearing account it
328
353
  * picks internally — RFC-10 §"Statement Store allowance".
@@ -378,7 +403,9 @@ export async function createProofAuthorized(statement: Statement): Promise<State
378
403
  return await truApi.statementStoreCreateProofAuthorized(enumValue("v1", statement)).match(
379
404
  (envelope: { tag: "v1"; value: StatementProof }) => envelope.value,
380
405
  (err: unknown) => {
381
- throw new Error(`createProofAuthorized failed: ${formatError(err)}`, { cause: err });
406
+ throw new Error(`createProofAuthorized failed: ${formatHostError(err)}`, {
407
+ cause: err,
408
+ });
382
409
  },
383
410
  );
384
411
  }
@@ -431,99 +458,16 @@ export interface ResultAsync<T, E> {
431
458
  }
432
459
 
433
460
  /**
434
- * Accounts provider interface from @novasamatech/product-sdk.
435
- *
436
- * Provides methods for accessing host wallet accounts, product accounts,
437
- * and Ring VRF operations.
461
+ * Accounts provider handle from `@novasamatech/host-api-wrapper`. Surfaces the
462
+ * full upstream API - host wallet accounts, app-scoped product accounts,
463
+ * Ring VRF, user identity (`getUserId`, `requestLogin`), and connection
464
+ * status subscription.
465
+ *
466
+ * Type identical to `createAccountsProvider()` from
467
+ * `@novasamatech/host-api-wrapper`; methods return neverthrow `ResultAsync`
468
+ * values with typed `CodecError` variants in the error channel.
438
469
  */
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
- }
470
+ export type AccountsProvider = ReturnType<typeof createAccountsProvider>;
527
471
 
528
472
  // ─────────────────────────────────────────────────────────────────────────────
529
473
  // Tests
@@ -546,6 +490,22 @@ if (import.meta.vitest) {
546
490
  expect(manager === null || typeof manager === "object").toBe(true);
547
491
  });
548
492
 
493
+ test("createHostPreimageManager returns null outside container", async () => {
494
+ expect(await createHostPreimageManager()).toBeNull();
495
+ });
496
+
497
+ test("formatHostError unwraps versioned envelopes and renders CodecError", () => {
498
+ expect(
499
+ formatHostError({
500
+ tag: "v1",
501
+ value: { name: "GenericError", message: "boom" },
502
+ }),
503
+ ).toBe("GenericError: boom");
504
+ expect(formatHostError(new Error("plain"))).toBe("plain");
505
+ expect(formatHostError("string err")).toBe("string err");
506
+ expect(formatHostError({ tag: "v1", value: { message: "no-name" } })).toBe("no-name");
507
+ });
508
+
549
509
  test("getAccountsProvider returns provider when SDK is available", async () => {
550
510
  // In dev/test mode, product-sdk is installed, so this returns a provider
551
511
  const provider = await getAccountsProvider();
package/src/types.ts CHANGED
@@ -1,62 +1,83 @@
1
1
  /**
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.
2
+ * Public types for the host wrappers.
3
+ *
4
+ * These are re-exported from `@novasamatech/host-api-wrapper` (the runtime
5
+ * objects the host getters cast to) rather than hand-mirrored, so the
6
+ * Parity surface stays in lockstep with the upstream codec types.
6
7
  */
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
- }
8
+
9
+ import type {
10
+ hostLocalStorage,
11
+ createStatementStore,
12
+ ProductAccountId as NovasamaProductAccountId,
13
+ SignedStatement as NovasamaSignedStatement,
14
+ Statement as NovasamaStatement,
15
+ StatementTopicFilter as NovasamaStatementTopicFilter,
16
+ StatementsPage as NovasamaStatementsPage,
17
+ Topic as NovasamaTopic,
18
+ } from "@novasamatech/host-api-wrapper";
19
+ import type { Subscription } from "@novasamatech/host-api";
20
+
21
+ /**
22
+ * Persistent storage exposed by the host container, including string, JSON
23
+ * and raw byte (`readBytes`/`writeBytes`) accessors. Most apps reach it
24
+ * indirectly through the Storage package's `KvStore`; reach for it directly
25
+ * via {@link getHostLocalStorage} when you need raw host storage without the
26
+ * KV abstraction.
27
+ *
28
+ * Type identical to `hostLocalStorage` from `@novasamatech/host-api-wrapper`.
29
+ */
30
+ export type HostLocalStorage = typeof hostLocalStorage;
18
31
 
19
32
  /**
20
33
  * Cryptographic proof attached to a statement before submission, returned by
21
34
  * {@link HostStatementStore.createProof}. Variants cover the supported
22
- * signature schemes `Sr25519`, `Ed25519`, `Ecdsa`, and `OnChain` (chain-
35
+ * signature schemes - `Sr25519`, `Ed25519`, `Ecdsa`, and `OnChain` (chain-
23
36
  * attestation-based proofs).
24
37
  *
25
- * Mirrors `@novasamatech/product-sdk@0.7`'s proof shape.
38
+ * Inferred from `createStatementStore().createProof`'s return type so codec
39
+ * changes surface here as compile errors, not runtime decode failures.
26
40
  */
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
- };
41
+ export type StatementProof = Awaited<
42
+ ReturnType<ReturnType<typeof createStatementStore>["createProof"]>
43
+ >;
35
44
 
36
45
  /**
37
- * Topic-based subscription filter. Mirrors `StatementTopicFilter` from
38
- * `@novasamatech/product-sdk` — the host delivers statements that match
46
+ * Topic-based subscription filter. The host delivers statements that match
39
47
  * either *all* of the listed topics (`matchAll`) or *any* of them
40
- * (`matchAny`).
48
+ * (`matchAny`). Re-exported from `@novasamatech/host-api-wrapper`.
41
49
  */
42
- export type StatementTopicFilter = { matchAll: Uint8Array[] } | { matchAny: Uint8Array[] };
50
+ export type StatementTopicFilter = NovasamaStatementTopicFilter;
51
+
52
+ /** A single topic value used inside a {@link StatementTopicFilter}. Re-exported from `@novasamatech/host-api-wrapper`. */
53
+ export type Topic = NovasamaTopic;
54
+
55
+ /** `[ss58Address, chainPrefix]` tuple identifying a product account at the codec layer. Re-exported from `@novasamatech/host-api-wrapper`. */
56
+ export type ProductAccountId = NovasamaProductAccountId;
57
+
58
+ /** Unsigned statement payload. Re-exported from `@novasamatech/host-api-wrapper`. */
59
+ export type Statement = NovasamaStatement;
60
+
61
+ /** Statement bundled with its {@link StatementProof}. Re-exported from `@novasamatech/host-api-wrapper`. */
62
+ export type SignedStatement = NovasamaSignedStatement;
43
63
 
44
64
  /**
45
65
  * A page of signed statements delivered by {@link HostStatementStore.subscribe}.
46
66
  *
47
67
  * Pages arrive sequentially. `isComplete` is `true` on the final page of a
48
68
  * subscription's initial backfill; subsequent pages contain new statements
49
- * as they appear on chain.
69
+ * as they appear on chain. `statements` is `SignedStatement[]` (typed,
70
+ * not `unknown[]`).
50
71
  */
51
- export interface StatementsPage {
52
- statements: unknown[];
53
- isComplete: boolean;
54
- }
72
+ export type StatementsPage = NovasamaStatementsPage;
55
73
 
56
- /** Subscription handle returned by the host. */
57
- export interface HostSubscription {
58
- unsubscribe: () => void;
59
- }
74
+ /**
75
+ * Subscription handle returned by the host - equivalent to
76
+ * `Subscription<void>` from `@novasamatech/host-api`. Exposes
77
+ * `unsubscribe()` plus an `onInterrupt` hook that fires if the host
78
+ * interrupts the subscription server-side.
79
+ */
80
+ export type HostSubscription = Subscription<void>;
60
81
 
61
82
  /**
62
83
  * Statement Store handle exposed by the host container. Provides
@@ -64,37 +85,7 @@ export interface HostSubscription {
64
85
  * host's native binary protocol; the `statement-store` package layers a
65
86
  * higher-level client on top.
66
87
  *
67
- * Shape matches `@novasamatech/product-sdk@0.7`'s `createStatementStore()`.
88
+ * Type identical to `createStatementStore()` from
89
+ * `@novasamatech/host-api-wrapper`.
68
90
  */
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
- }
91
+ export type HostStatementStore = ReturnType<typeof createStatementStore>;