@parity/product-sdk 0.0.0-dev.312.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.
Files changed (88) hide show
  1. package/LICENSE +201 -0
  2. package/dist/address/index.d.ts +9 -0
  3. package/dist/address/index.js +3 -0
  4. package/dist/address/index.js.map +1 -0
  5. package/dist/chain/index.d.ts +1 -0
  6. package/dist/chain/index.js +3 -0
  7. package/dist/chain/index.js.map +1 -0
  8. package/dist/chunk-BRZNHTLQ.js +89 -0
  9. package/dist/chunk-BRZNHTLQ.js.map +1 -0
  10. package/dist/chunk-DHRCWMY5.js +240 -0
  11. package/dist/chunk-DHRCWMY5.js.map +1 -0
  12. package/dist/chunk-JVJ552RU.js +3 -0
  13. package/dist/chunk-JVJ552RU.js.map +1 -0
  14. package/dist/cloud-storage/index.d.ts +1 -0
  15. package/dist/cloud-storage/index.js +3 -0
  16. package/dist/cloud-storage/index.js.map +1 -0
  17. package/dist/contracts/index.d.ts +1 -0
  18. package/dist/contracts/index.js +3 -0
  19. package/dist/contracts/index.js.map +1 -0
  20. package/dist/core/index.d.ts +12 -0
  21. package/dist/core/index.js +5 -0
  22. package/dist/core/index.js.map +1 -0
  23. package/dist/crypto/index.d.ts +1 -0
  24. package/dist/crypto/index.js +3 -0
  25. package/dist/crypto/index.js.map +1 -0
  26. package/dist/dotns-bswWAmR2.d.ts +136 -0
  27. package/dist/host/index.d.ts +1 -0
  28. package/dist/host/index.js +3 -0
  29. package/dist/host/index.js.map +1 -0
  30. package/dist/identity/index.d.ts +491 -0
  31. package/dist/identity/index.js +691 -0
  32. package/dist/identity/index.js.map +1 -0
  33. package/dist/index.d.ts +62 -0
  34. package/dist/index.js +12 -0
  35. package/dist/index.js.map +1 -0
  36. package/dist/individuality/index.d.ts +1 -0
  37. package/dist/individuality/index.js +3 -0
  38. package/dist/individuality/index.js.map +1 -0
  39. package/dist/local-storage/index.d.ts +1 -0
  40. package/dist/local-storage/index.js +3 -0
  41. package/dist/local-storage/index.js.map +1 -0
  42. package/dist/react/index.d.ts +181 -0
  43. package/dist/react/index.js +198 -0
  44. package/dist/react/index.js.map +1 -0
  45. package/dist/testing/index.d.ts +61 -0
  46. package/dist/testing/index.js +149 -0
  47. package/dist/testing/index.js.map +1 -0
  48. package/dist/types-B5Zx4RNq.d.ts +211 -0
  49. package/dist/wallet/index.d.ts +1 -0
  50. package/dist/wallet/index.js +3 -0
  51. package/dist/wallet/index.js.map +1 -0
  52. package/package.json +118 -0
  53. package/src/address/index.ts +8 -0
  54. package/src/chain/index.ts +8 -0
  55. package/src/cloud-storage/index.ts +8 -0
  56. package/src/contracts/index.ts +8 -0
  57. package/src/core/createApp.ts +408 -0
  58. package/src/core/index.ts +12 -0
  59. package/src/core/logger.ts +15 -0
  60. package/src/core/types.ts +233 -0
  61. package/src/crypto/index.ts +8 -0
  62. package/src/host/index.ts +8 -0
  63. package/src/identity/dotns-abis.test.ts +43 -0
  64. package/src/identity/dotns-abis.ts +274 -0
  65. package/src/identity/dotns-errors.ts +34 -0
  66. package/src/identity/dotns-namehash.test.ts +155 -0
  67. package/src/identity/dotns-namehash.ts +149 -0
  68. package/src/identity/dotns-owner.test.ts +92 -0
  69. package/src/identity/dotns-registry.test.ts +1154 -0
  70. package/src/identity/dotns-registry.ts +870 -0
  71. package/src/identity/dotns.test.ts +128 -0
  72. package/src/identity/dotns.ts +221 -0
  73. package/src/identity/index.ts +61 -0
  74. package/src/identity/product-account.test.ts +130 -0
  75. package/src/identity/product-account.ts +115 -0
  76. package/src/identity/types.ts +87 -0
  77. package/src/index.ts +61 -0
  78. package/src/individuality/contract.test.ts +135 -0
  79. package/src/individuality/index.ts +8 -0
  80. package/src/local-storage/index.ts +8 -0
  81. package/src/react/context.ts +35 -0
  82. package/src/react/index.ts +43 -0
  83. package/src/react/provider.tsx +78 -0
  84. package/src/react/useChain.ts +35 -0
  85. package/src/react/useLocalStorage.ts +127 -0
  86. package/src/react/useWallet.ts +156 -0
  87. package/src/testing.ts +297 -0
  88. package/src/wallet/index.ts +11 -0
@@ -0,0 +1,408 @@
1
+ // Copyright 2026 Parity Technologies (UK) Ltd.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ /**
4
+ * createApp - Main entry point for the Product SDK
5
+ *
6
+ * Creates an App instance with wallet, storage, chain, and cloud storage APIs.
7
+ */
8
+
9
+ import type { ChainDefinition } from "polkadot-api";
10
+ import type {
11
+ App,
12
+ AppConfig,
13
+ WalletApi,
14
+ ChainApi,
15
+ Account,
16
+ CloudStorageApi,
17
+ LocalStorageApi,
18
+ } from "./types.js";
19
+ import { configure, createLogger } from "@parity/product-sdk-logger";
20
+ import { createLocalKvStore } from "@parity/product-sdk-local-storage";
21
+ import { SignerManager } from "@parity/product-sdk-signer";
22
+ import {
23
+ CloudStorageClient,
24
+ ProductCloudStorageError,
25
+ calculateCid,
26
+ createLazySigner,
27
+ } from "@parity/product-sdk-cloud-storage";
28
+ import { err, ok } from "@parity/result";
29
+ import {
30
+ createChainClient,
31
+ getClient,
32
+ isConnected,
33
+ destroyAll,
34
+ } from "@parity/product-sdk-chain-client";
35
+ import { accountIdBytes } from "@parity/product-sdk-address";
36
+ import { getAccountsProvider } from "@parity/product-sdk-host";
37
+ import {
38
+ accountIdBytesToHex,
39
+ type PeopleUsernameQueryApi,
40
+ resolvePeopleUsernameOwner,
41
+ } from "../identity/dotns.js";
42
+
43
+ const log = createLogger("app");
44
+
45
+ /**
46
+ * Create a new Product SDK app instance
47
+ *
48
+ * @param config - Application configuration
49
+ * @returns App instance with all APIs
50
+ *
51
+ * @example
52
+ * ```ts
53
+ * import { createApp } from '@parity/product-sdk';
54
+ *
55
+ * // Default: cloud storage enabled with paseo environment
56
+ * const app = await createApp({
57
+ * name: 'my-app',
58
+ * logLevel: 'info',
59
+ * });
60
+ *
61
+ * // Custom cloud storage environment
62
+ * const prodApp = await createApp({
63
+ * name: 'my-app',
64
+ * cloudStorage: { environment: 'polkadot' },
65
+ * });
66
+ *
67
+ * // Disable cloud storage entirely
68
+ * const noCloudStorageApp = await createApp({
69
+ * name: 'my-app',
70
+ * cloudStorage: false,
71
+ * });
72
+ *
73
+ * // Connect wallet
74
+ * const { accounts } = await app.wallet.connect();
75
+ *
76
+ * // Use storage
77
+ * await app.localStorage.set('key', 'value');
78
+ *
79
+ * // Use cloud storage (check for null if it might be disabled)
80
+ * if (app.cloudStorage) {
81
+ * const cid = await app.cloudStorage.upload('hello world');
82
+ * }
83
+ * ```
84
+ */
85
+ export async function createApp(config: AppConfig): Promise<App> {
86
+ // Set log level if specified
87
+ if (config.logLevel) {
88
+ configure({ level: config.logLevel });
89
+ }
90
+
91
+ log.info("Creating Product SDK app", { name: config.name });
92
+
93
+ // Initialize storage (container-only - will throw if not in container)
94
+ const localKvStore = await createLocalKvStore({ prefix: config.name });
95
+
96
+ // Initialize signer manager
97
+ const signerManager = new SignerManager({
98
+ dappName: config.name,
99
+ });
100
+
101
+ // Initialize cloud storage client (configurable, defaults to paseo).
102
+ //
103
+ // The signer is wrapped lazily so the cloud storage client can be built before
104
+ // an account is selected. Uploads will throw a clear error if no signer
105
+ // is available at submission time. Reads (fetch / fetchJson) don't need
106
+ // a signer, so they work regardless of whether an account is selected --
107
+ // but they are container-only and throw CloudStorageHostUnavailableError
108
+ // outside a host container (no IPFS-gateway fallback).
109
+ const cloudStorageEnabled = config.cloudStorage !== false;
110
+ const cloudStorageEnvironment =
111
+ typeof config.cloudStorage === "object" ? config.cloudStorage.environment : "paseo";
112
+ const cloudStorageClient = cloudStorageEnabled
113
+ ? await CloudStorageClient.create({
114
+ environment: cloudStorageEnvironment,
115
+ signer: createLazySigner(() => signerManager.getSigner()),
116
+ })
117
+ : null;
118
+
119
+ if (cloudStorageEnabled) {
120
+ log.debug("Cloud Storage client (Bulletin) initialized", {
121
+ environment: cloudStorageEnvironment,
122
+ });
123
+ } else {
124
+ log.debug("Cloud Storage client disabled");
125
+ }
126
+
127
+ // Create storage API adapter
128
+ const localStorageApi: LocalStorageApi = {
129
+ get: (key) => localKvStore.get(key),
130
+ set: (key, value) => localKvStore.set(key, value),
131
+ getJSON: <T>(key: string) => localKvStore.getJSON<T>(key),
132
+ setJSON: <T>(key: string, value: T) => localKvStore.setJSON(key, value),
133
+ remove: (key) => localKvStore.remove(key),
134
+ clear: async () => {
135
+ // LocalKvStore doesn't have clear - this is a no-op
136
+ log.debug("clear() is not supported in container storage mode");
137
+ },
138
+ };
139
+
140
+ // Create wallet API adapter
141
+ const walletApi = createWalletApi(signerManager);
142
+
143
+ // Create chain API
144
+ const chainApi: ChainApi = {
145
+ getClient(descriptor) {
146
+ log.debug("getClient called", { genesis: descriptor.genesis });
147
+ const client = getClient(descriptor);
148
+ return client.getTypedApi(descriptor);
149
+ },
150
+
151
+ getRawClient(descriptor) {
152
+ log.debug("getRawClient called", { genesis: descriptor.genesis });
153
+ return getClient(descriptor);
154
+ },
155
+
156
+ async connect<T extends Record<string, ChainDefinition>>(chains: T) {
157
+ log.debug("connect called", { chains: Object.keys(chains) });
158
+ return createChainClient({ chains });
159
+ },
160
+
161
+ isConnected(descriptor) {
162
+ return isConnected(descriptor);
163
+ },
164
+
165
+ destroyAll() {
166
+ log.debug("destroyAll called");
167
+ destroyAll();
168
+ },
169
+ };
170
+
171
+ // Create Cloud Storage API adapter (null if disabled)
172
+ const cloudStorageApi: CloudStorageApi | null = cloudStorageClient
173
+ ? {
174
+ upload: async (data) => {
175
+ const bytes = typeof data === "string" ? new TextEncoder().encode(data) : data;
176
+ try {
177
+ // Explicitly request a DAG-PB manifest so chunked uploads always
178
+ // resolve to a single root CID. Without this, AsyncBulletinClient
179
+ // can return `result.cid: undefined` for chunked-without-manifest
180
+ // uploads — but app consumers expect a CID they can hand to
181
+ // `fetch(cid)`, so treat a missing CID as an error.
182
+ const uploaded = await cloudStorageClient
183
+ .store(bytes)
184
+ .withManifest(true)
185
+ .send();
186
+ if (!uploaded.cid) {
187
+ return err(
188
+ new ProductCloudStorageError(
189
+ "Cloud storage upload returned no CID despite .withManifest(true). Upstream contract may have shifted — file an issue.",
190
+ ),
191
+ );
192
+ }
193
+ return ok(uploaded.cid.toString());
194
+ } catch (cause) {
195
+ const message = cause instanceof Error ? cause.message : String(cause);
196
+ return err(new ProductCloudStorageError(message, { cause }));
197
+ }
198
+ },
199
+ fetch: (cid) => cloudStorageClient.fetchBytes(cid),
200
+ computeCid: async (data) => {
201
+ const bytes = typeof data === "string" ? new TextEncoder().encode(data) : data;
202
+ const cid = await calculateCid(bytes);
203
+ return cid.toString();
204
+ },
205
+ }
206
+ : null;
207
+
208
+ log.info("Product SDK app created", {
209
+ name: config.name,
210
+ cloudStorage: cloudStorageEnabled ? cloudStorageEnvironment : "disabled",
211
+ });
212
+
213
+ return {
214
+ wallet: walletApi,
215
+ localStorage: localStorageApi,
216
+ chain: chainApi,
217
+ cloudStorage: cloudStorageApi,
218
+ getAppInfo: () => ({ ...config }),
219
+ };
220
+ }
221
+
222
+ /**
223
+ * Create wallet API adapter using SignerManager from leaf package
224
+ */
225
+ function createWalletApi(signerManager: SignerManager): WalletApi {
226
+ // Track account change subscribers
227
+ const accountChangeSubscribers = new Set<(account: Account | null) => void>();
228
+
229
+ // Subscribe to signer manager state changes
230
+ signerManager.subscribe((state) => {
231
+ const account = state.selectedAccount
232
+ ? {
233
+ address: state.selectedAccount.address,
234
+ name: state.selectedAccount.name ?? undefined,
235
+ source: state.selectedAccount.source,
236
+ }
237
+ : null;
238
+ for (const callback of accountChangeSubscribers) {
239
+ try {
240
+ callback(account);
241
+ } catch (e) {
242
+ log.warn("Account change callback threw", { error: e });
243
+ }
244
+ }
245
+ });
246
+
247
+ return {
248
+ async connect(): Promise<{ accounts: Account[] }> {
249
+ const result = await signerManager.connect();
250
+ if (!result.ok) {
251
+ throw new Error(result.error.message);
252
+ }
253
+ return {
254
+ accounts: result.value.map((a) => ({
255
+ address: a.address,
256
+ name: a.name ?? undefined,
257
+ source: a.source,
258
+ })),
259
+ };
260
+ },
261
+
262
+ async disconnect(): Promise<void> {
263
+ signerManager.disconnect();
264
+ },
265
+
266
+ getAccounts(): Account[] {
267
+ return signerManager.getState().accounts.map((a) => ({
268
+ address: a.address,
269
+ name: a.name ?? undefined,
270
+ source: a.source,
271
+ }));
272
+ },
273
+
274
+ getSelectedAccount(): Account | null {
275
+ const selected = signerManager.getState().selectedAccount;
276
+ if (!selected) return null;
277
+ return {
278
+ address: selected.address,
279
+ name: selected.name ?? undefined,
280
+ source: selected.source,
281
+ };
282
+ },
283
+
284
+ selectAccount(address: string): void {
285
+ signerManager.selectAccount(address);
286
+ },
287
+
288
+ async signMessage(message: string | Uint8Array): Promise<Uint8Array> {
289
+ const bytes = typeof message === "string" ? new TextEncoder().encode(message) : message;
290
+ const result = await signerManager.signRaw(bytes);
291
+ if (!result.ok) {
292
+ throw new Error(result.error.message);
293
+ }
294
+ return result.value;
295
+ },
296
+
297
+ async signMessageWithDotNsIdentity(args) {
298
+ const message =
299
+ typeof args.message === "string"
300
+ ? new TextEncoder().encode(args.message)
301
+ : args.message;
302
+ const accountsProvider = await getHostAccountsProvider();
303
+ const username = args.username ?? (await getPrimaryUsername(accountsProvider));
304
+
305
+ // Reuse an already-connected People chain when the caller has
306
+ // wired one up via `app.chain.connect({ ..., <name>: peopleChain })`.
307
+ // Fall back to opening a transient connection so first-time users
308
+ // don't have to think about chain lifecycles. The chain-client
309
+ // module caches by genesis fingerprint, so subsequent
310
+ // signMessageWithDotNsIdentity calls share whichever connection
311
+ // got established first.
312
+ const peopleClient = isConnected(args.peopleChain)
313
+ ? getClient(args.peopleChain)
314
+ : await createChainClient({ chains: { people: args.peopleChain } }).then(
315
+ (c) => c.raw.people,
316
+ );
317
+ // PAPI's `TypedApi.query.X.Y.getValue` is variadic
318
+ // (`...args: [...WithCallOptions<Args>]`) so it's not assignable
319
+ // to our deliberately-narrow `(key) => Promise<...>` shape. The
320
+ // resolver only ever passes the storage key; the cast adapts the
321
+ // wider PAPI surface to the minimum we depend on.
322
+ const peopleApi = peopleClient.getTypedApi(
323
+ args.peopleChain,
324
+ ) as unknown as PeopleUsernameQueryApi;
325
+ const owner = await resolvePeopleUsernameOwner(username, peopleApi);
326
+ if (!owner) {
327
+ throw new Error(`No account owns DotNS username "${username}"`);
328
+ }
329
+
330
+ const publicKey = accountIdBytes(owner);
331
+ // This field is hex, not the SS58 the resolver now returns. Converted
332
+ // here and not in the try, so an address failure is not reported as a
333
+ // signing failure.
334
+ const accountId = accountIdBytesToHex(publicKey);
335
+ const signer = accountsProvider.getLegacyAccountSigner({ publicKey, name: username });
336
+
337
+ try {
338
+ return {
339
+ username,
340
+ accountId,
341
+ signature: await signer.signBytes(message),
342
+ };
343
+ } catch (cause) {
344
+ throw new Error(
345
+ `Failed to sign with DotNS username "${username}": ${
346
+ cause instanceof Error ? cause.message : String(cause)
347
+ }`,
348
+ { cause },
349
+ );
350
+ }
351
+ },
352
+
353
+ onAccountChange(callback: (account: Account | null) => void): () => void {
354
+ accountChangeSubscribers.add(callback);
355
+ return () => accountChangeSubscribers.delete(callback);
356
+ },
357
+
358
+ getProductAccount(): Account | null {
359
+ // Product accounts require async call - this sync API can't support it properly
360
+ // Users should use SignerManager.getProductAccount() directly
361
+ log.warn(
362
+ "getProductAccount() is deprecated - use SignerManager.getProductAccount() directly",
363
+ );
364
+ return null;
365
+ },
366
+
367
+ getAnonymousAlias(): string | null {
368
+ // Anonymous aliases require async call - this sync API can't support it properly
369
+ // Users should use SignerManager.getProductAccountAlias() directly
370
+ log.warn(
371
+ "getAnonymousAlias() is deprecated - use SignerManager.getProductAccountAlias() directly",
372
+ );
373
+ return null;
374
+ },
375
+
376
+ async createProof(_message: Uint8Array): Promise<Uint8Array> {
377
+ // Ring VRF proofs require SignerManager.createRingVRFProof() directly
378
+ throw new Error(
379
+ "createProof() is not implemented in the App API. " +
380
+ "Use SignerManager.createRingVRFProof() directly.",
381
+ );
382
+ },
383
+ };
384
+ }
385
+
386
+ type HostAccountsProvider = NonNullable<Awaited<ReturnType<typeof getAccountsProvider>>>;
387
+
388
+ async function getHostAccountsProvider(): Promise<HostAccountsProvider> {
389
+ const provider = await getAccountsProvider();
390
+ if (!provider) {
391
+ throw new Error("Host accounts provider is not available");
392
+ }
393
+ return provider;
394
+ }
395
+
396
+ async function getPrimaryUsername(accountsProvider: HostAccountsProvider): Promise<string> {
397
+ const result = await accountsProvider.getUserId().match(
398
+ (value) => value,
399
+ (err) => {
400
+ throw err;
401
+ },
402
+ );
403
+ const username = result.primaryUsername.trim();
404
+ if (!username) {
405
+ throw new Error("Host identity did not provide a primary DotNS username");
406
+ }
407
+ return username;
408
+ }
@@ -0,0 +1,12 @@
1
+ // Copyright 2026 Parity Technologies (UK) Ltd.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ /**
4
+ * @parity/product-sdk core module
5
+ *
6
+ * Core functionality including createApp, logger, and type definitions.
7
+ */
8
+
9
+ export { createApp } from "./createApp.js";
10
+ export { configure, createLogger } from "./logger.js";
11
+ export type { LogEntry, LogHandler, LoggerConfig, Logger } from "./logger.js";
12
+ export * from "./types.js";
@@ -0,0 +1,15 @@
1
+ // Copyright 2026 Parity Technologies (UK) Ltd.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ /**
4
+ * Logger module for @parity/product-sdk
5
+ *
6
+ * Re-exports from @parity/product-sdk-logger.
7
+ */
8
+ export { configure, createLogger } from "@parity/product-sdk-logger";
9
+ export type {
10
+ LogLevel,
11
+ LogEntry,
12
+ LogHandler,
13
+ LoggerConfig,
14
+ Logger,
15
+ } from "@parity/product-sdk-logger";
@@ -0,0 +1,233 @@
1
+ // Copyright 2026 Parity Technologies (UK) Ltd.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ /**
4
+ * Core types for @parity/product-sdk
5
+ */
6
+
7
+ import type { LogLevel } from "@parity/product-sdk-logger";
8
+ import type {
9
+ CloudStorageEnvironment,
10
+ ProductCloudStorageError,
11
+ } from "@parity/product-sdk-cloud-storage";
12
+ import type { Result } from "@parity/result";
13
+ import type { ChainClient } from "@parity/product-sdk-chain-client";
14
+ import type { PeopleUsernameChain } from "../identity/dotns.js";
15
+ import type { ChainDefinition, TypedApi, PolkadotClient } from "polkadot-api";
16
+
17
+ export type { LogLevel };
18
+ export type { ChainClient };
19
+
20
+ /** Cloud Storage configuration options */
21
+ export interface CloudStorageConfig {
22
+ /** Cloud Storage environment to connect to */
23
+ environment: CloudStorageEnvironment;
24
+ }
25
+
26
+ /** Configuration for createApp */
27
+ export interface AppConfig {
28
+ /** Application name - used to derive product accounts and namespace storage */
29
+ name: string;
30
+ /** Log level for SDK operations (default: 'info') */
31
+ logLevel?: LogLevel;
32
+ /**
33
+ * Cloud Storage configuration.
34
+ * - Omit or pass config object to enable (default: { environment: "paseo" })
35
+ * - Pass `false` to disable cloud storage initialization
36
+ */
37
+ cloudStorage?: CloudStorageConfig | false;
38
+ }
39
+
40
+ /** Wallet API exposed by the SDK */
41
+ export interface WalletApi {
42
+ /** Connect to available wallet providers */
43
+ connect(): Promise<{ accounts: Account[] }>;
44
+ /** Disconnect from wallet */
45
+ disconnect(): Promise<void>;
46
+ /** Get all available accounts */
47
+ getAccounts(): Account[];
48
+ /** Get currently selected account */
49
+ getSelectedAccount(): Account | null;
50
+ /** Select an account by address */
51
+ selectAccount(address: string): void;
52
+ /** Sign an arbitrary message */
53
+ signMessage(message: string | Uint8Array): Promise<Uint8Array>;
54
+ /**
55
+ * Sign a message with the account that owns a People / People Lite DotNS identity.
56
+ *
57
+ * Pass the People / Individuality chain descriptor used for username lookup.
58
+ * Pass `username` to choose a specific identity. When omitted, the SDK first
59
+ * asks the host for the user's primary DotNS name and signs with the account
60
+ * that owns that username.
61
+ */
62
+ signMessageWithDotNsIdentity(
63
+ args: SignMessageWithDotNsIdentityArgs,
64
+ ): Promise<DotNsIdentitySignature>;
65
+ /** Subscribe to account changes */
66
+ onAccountChange(callback: (account: Account | null) => void): () => void;
67
+ /** Get product-scoped account (container mode only) */
68
+ getProductAccount(): Account | null;
69
+ /** Get anonymous alias via Ring VRF (container mode only) */
70
+ getAnonymousAlias(): string | null;
71
+ /** Create Ring VRF proof (container mode only) */
72
+ createProof(message: Uint8Array): Promise<Uint8Array>;
73
+ }
74
+
75
+ /** Storage API exposed by the SDK */
76
+ export interface LocalStorageApi {
77
+ /** Get a value by key */
78
+ get(key: string): Promise<string | null>;
79
+ /** Set a value by key */
80
+ set(key: string, value: string): Promise<void>;
81
+ /** Get a JSON value by key */
82
+ getJSON<T = unknown>(key: string): Promise<T | null>;
83
+ /** Set a JSON value by key */
84
+ setJSON<T = unknown>(key: string, value: T): Promise<void>;
85
+ /** Remove a value by key */
86
+ remove(key: string): Promise<void>;
87
+ /** Clear all values */
88
+ clear(): Promise<void>;
89
+ }
90
+
91
+ /** Chain API exposed by the SDK */
92
+ export interface ChainApi {
93
+ /**
94
+ * Get a typed PAPI client for a chain.
95
+ *
96
+ * Connections are routed through the host provider. The chain must be
97
+ * connected first via {@link connect}.
98
+ *
99
+ * @param descriptor - PAPI chain descriptor (from @parity/product-sdk-descriptors or custom)
100
+ * @returns Typed API for the chain
101
+ * @throws If the chain is not connected
102
+ */
103
+ getClient<T extends ChainDefinition>(descriptor: T): TypedApi<T>;
104
+
105
+ /**
106
+ * Get the raw PolkadotClient for a chain.
107
+ *
108
+ * Use this for advanced APIs like `createContractRuntime` from `@parity/product-sdk-contracts`.
109
+ *
110
+ * @param descriptor - PAPI chain descriptor
111
+ * @returns Raw PolkadotClient instance
112
+ * @throws If the chain is not connected
113
+ */
114
+ getRawClient(descriptor: ChainDefinition): PolkadotClient;
115
+
116
+ /**
117
+ * Connect to one or more chains.
118
+ *
119
+ * Connections are routed through the host provider (container-only).
120
+ * Results are cached - calling with the same descriptors returns existing connections.
121
+ *
122
+ * @param chains - Record of named chain descriptors
123
+ * @returns Connected chain client with typed APIs
124
+ */
125
+ connect<T extends Record<string, ChainDefinition>>(chains: T): Promise<ChainClient<T>>;
126
+
127
+ /**
128
+ * Check if a chain is currently connected.
129
+ */
130
+ isConnected(descriptor: ChainDefinition): boolean;
131
+
132
+ /**
133
+ * Destroy all chain connections.
134
+ */
135
+ destroyAll(): void;
136
+ }
137
+
138
+ /** Cloud Storage API exposed by the SDK */
139
+ export interface CloudStorageApi {
140
+ /**
141
+ * Upload data to the Cloud.
142
+ *
143
+ * Requires a wallet to be connected and an account selected.
144
+ *
145
+ * @returns A {@link Result}: `ok(cid)` on success, or `err(ProductCloudStorageError)`
146
+ * if the upload fails (no signer, network rejection, or no CID returned).
147
+ */
148
+ upload(data: string | Uint8Array): Promise<Result<string, ProductCloudStorageError>>;
149
+ /**
150
+ * Fetch data by CID.
151
+ *
152
+ * @returns A {@link Result}: `ok(bytes)` on success, or `err(ProductCloudStorageError)`.
153
+ */
154
+ fetch(cid: string): Promise<Result<Uint8Array, ProductCloudStorageError>>;
155
+ /**
156
+ * Compute the CID for data without uploading.
157
+ *
158
+ * Async because the underlying hash is computed via Web Crypto. Does not
159
+ * perform I/O, so it throws on invalid input rather than returning a Result.
160
+ */
161
+ computeCid(data: string | Uint8Array): Promise<string>;
162
+ }
163
+
164
+ /** The main App instance returned by createApp */
165
+ export interface App {
166
+ /** Wallet/signing operations */
167
+ wallet: WalletApi;
168
+ /** Local Key-value storage operations */
169
+ localStorage: LocalStorageApi;
170
+ /** Chain interaction operations */
171
+ chain: ChainApi;
172
+ /** Cloud Storage operations (null if disabled via config) */
173
+ cloudStorage: CloudStorageApi | null;
174
+ /** Get app configuration */
175
+ getAppInfo(): AppConfig;
176
+ }
177
+
178
+ /** Account information */
179
+ export interface Account {
180
+ /** Account address (SS58 format) */
181
+ address: string;
182
+ /** Account name/label (if available) */
183
+ name?: string;
184
+ /** Source of the account (host, dev signer, etc.) */
185
+ source: string;
186
+ }
187
+
188
+ /** Arguments for signing with a DotNS / People username identity. */
189
+ export interface SignMessageWithDotNsIdentityArgs {
190
+ /**
191
+ * PAPI descriptor for the People / Individuality chain that exposes
192
+ * `Resources.UsernameOwnerOf`.
193
+ *
194
+ * The SDK reuses an already-connected client when one matches this
195
+ * descriptor's genesis. For long-running apps, call
196
+ * `app.chain.connect({ ..., <name>: peopleChain })` once at startup so
197
+ * every subsequent `signMessageWithDotNsIdentity` call reuses the same
198
+ * chainHead subscription. When the chain isn't already connected, the
199
+ * SDK opens a transient connection for the lookup; that connection then
200
+ * lives in the chain-client cache for the rest of the process.
201
+ */
202
+ peopleChain: PeopleUsernameChain;
203
+ /**
204
+ * People / People Lite username to resolve before signing.
205
+ *
206
+ * If omitted, the SDK fetches the primary DotNS name associated with the
207
+ * connected user from the host identity API. Note: that fetch triggers a
208
+ * host identity-permission prompt, so callers who want to avoid the
209
+ * dialog on a likely-miss should resolve the username themselves first.
210
+ *
211
+ * The string is UTF-8 encoded and used as the storage key on
212
+ * `Resources.UsernameOwnerOf` exactly as supplied — no `.dot` suffix
213
+ * handling is applied. On paseo-individuality today usernames are
214
+ * stored as bare strings (e.g. `alice`, not `alice.dot`); pass the
215
+ * exact value the chain has registered.
216
+ */
217
+ username?: string;
218
+ /** Message to sign. Strings are UTF-8 encoded before signing. */
219
+ message: string | Uint8Array;
220
+ }
221
+
222
+ /** Signature produced for a DotNS / People username identity. */
223
+ export interface DotNsIdentitySignature {
224
+ /** Username used for the lookup. */
225
+ username: string;
226
+ /** Raw `AccountId32` owner resolved from `Resources.UsernameOwnerOf`. */
227
+ accountId: `0x${string}`;
228
+ /** Signature bytes returned by the host wallet. */
229
+ signature: Uint8Array;
230
+ }
231
+
232
+ // Re-export ChainDefinition from polkadot-api for convenience
233
+ export type { ChainDefinition, TypedApi, PolkadotClient } from "polkadot-api";
@@ -0,0 +1,8 @@
1
+ // Copyright 2026 Parity Technologies (UK) Ltd.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ /**
4
+ * @parity/product-sdk/crypto
5
+ *
6
+ * Re-exports from @parity/product-sdk-crypto.
7
+ */
8
+ export * from "@parity/product-sdk-crypto";
@@ -0,0 +1,8 @@
1
+ // Copyright 2026 Parity Technologies (UK) Ltd.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ /**
4
+ * @parity/product-sdk/host
5
+ *
6
+ * Re-exports from @parity/product-sdk-host.
7
+ */
8
+ export * from "@parity/product-sdk-host";