@parity/product-sdk 0.31.0 → 0.33.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/address/index.d.ts +2 -1
- package/dist/core/index.d.ts +49 -2
- package/dist/index.d.ts +2 -49
- package/dist/nfts/index.d.ts +1 -0
- package/dist/nfts/index.js +3 -0
- package/dist/nfts/index.js.map +1 -0
- package/dist/testing/index.d.ts +1 -0
- package/dist/testing/index.js +1 -0
- package/dist/testing/index.js.map +1 -1
- package/package.json +18 -13
- package/src/individuality/contract.test.ts +73 -1
- package/src/nfts/contract.test.ts +58 -0
- package/src/nfts/index.ts +8 -0
- package/src/testing.ts +1 -0
package/dist/address/index.d.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
export * from '@parity/product-sdk-address';
|
|
2
|
-
import '@parity/product-sdk-cloud-storage';
|
|
3
2
|
import '@parity/product-sdk-chain-client';
|
|
3
|
+
import '@parity/product-sdk-cloud-storage';
|
|
4
4
|
import '@parity/product-sdk-contracts';
|
|
5
5
|
import '@parity/product-sdk-crypto';
|
|
6
6
|
import '@parity/product-sdk-host';
|
|
7
7
|
import '@parity/product-sdk-individuality';
|
|
8
8
|
import '@parity/product-sdk-local-storage';
|
|
9
|
+
import '@parity/product-sdk-nfts';
|
|
9
10
|
import '@parity/product-sdk-renderer';
|
|
10
11
|
import '@parity/product-sdk-signer';
|
package/dist/core/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export { createApp } from '../index.js';
|
|
2
1
|
export { LogEntry, LogHandler, LogLevel, Logger, LoggerConfig, configure, createLogger } from '@parity/product-sdk-logger';
|
|
3
|
-
|
|
2
|
+
import { c as AppConfig, b as App } from '../types-BpWw-OJl.js';
|
|
3
|
+
export { A as Account, d as AppInfo, C as ChainApi, a as CloudStorageApi, e as CloudStorageConfig, D as DotNsIdentitySignature, L as LocalStorageApi, S as SignMessageWithDotNsIdentityArgs, W as WalletApi } from '../types-BpWw-OJl.js';
|
|
4
4
|
export { ChainClient } from '@parity/product-sdk-chain-client';
|
|
5
5
|
export { ChainDefinition, PolkadotClient, TypedApi } from 'polkadot-api';
|
|
6
6
|
import '@parity/result';
|
|
@@ -10,3 +10,50 @@ import '@parity/product-sdk-signer';
|
|
|
10
10
|
import '@parity/product-sdk-local-storage';
|
|
11
11
|
import '@parity/product-sdk-cloud-storage';
|
|
12
12
|
import '../dotns-CtmOwVQW.js';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* createApp - Main entry point for the Product SDK
|
|
16
|
+
*
|
|
17
|
+
* Creates an App instance with wallet, storage, chain, and cloud storage APIs.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Create a new Product SDK app instance
|
|
22
|
+
*
|
|
23
|
+
* @param config - Application configuration
|
|
24
|
+
* @returns App instance with all APIs
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```ts
|
|
28
|
+
* import { createApp } from '@parity/product-sdk';
|
|
29
|
+
*
|
|
30
|
+
* // Default: cloud storage enabled with paseo environment
|
|
31
|
+
* const app = await createApp({
|
|
32
|
+
* logLevel: 'info',
|
|
33
|
+
* });
|
|
34
|
+
*
|
|
35
|
+
* // Custom cloud storage environment
|
|
36
|
+
* const prodApp = await createApp({
|
|
37
|
+
* cloudStorage: { environment: 'polkadot' },
|
|
38
|
+
* });
|
|
39
|
+
*
|
|
40
|
+
* // Disable cloud storage entirely
|
|
41
|
+
* const noCloudStorageApp = await createApp({
|
|
42
|
+
* cloudStorage: false,
|
|
43
|
+
* });
|
|
44
|
+
*
|
|
45
|
+
* // Connect wallet
|
|
46
|
+
* const { accounts } = await app.wallet.connect();
|
|
47
|
+
*
|
|
48
|
+
* // Use storage
|
|
49
|
+
* await app.localStorage.set('key', 'value');
|
|
50
|
+
*
|
|
51
|
+
* // Use cloud storage (check for null if it might be disabled)
|
|
52
|
+
* if (app.cloudStorage) {
|
|
53
|
+
* const cid = await app.cloudStorage.upload('hello world');
|
|
54
|
+
* }
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
declare function createApp(config?: AppConfig): Promise<App>;
|
|
58
|
+
|
|
59
|
+
export { App, AppConfig, createApp };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
export { createApp } from './core/index.js';
|
|
1
2
|
export { LogEntry, LogHandler, LogLevel, Logger, LoggerConfig, configure, createLogger } from '@parity/product-sdk-logger';
|
|
2
|
-
|
|
3
|
-
export { A as Account, d as AppInfo, C as ChainApi, a as CloudStorageApi, D as DotNsIdentitySignature, L as LocalStorageApi, S as SignMessageWithDotNsIdentityArgs, W as WalletApi } from './types-BpWw-OJl.js';
|
|
3
|
+
export { A as Account, b as App, c as AppConfig, d as AppInfo, C as ChainApi, a as CloudStorageApi, D as DotNsIdentitySignature, L as LocalStorageApi, S as SignMessageWithDotNsIdentityArgs, W as WalletApi } from './types-BpWw-OJl.js';
|
|
4
4
|
export { Result, err, isErrorOf, ok } from '@parity/result';
|
|
5
5
|
export { SdkError, isSdkError } from '@parity/product-sdk-errors';
|
|
6
6
|
export { isInsideContainer, isInsideContainerSync } from '@parity/product-sdk-host';
|
|
@@ -10,50 +10,3 @@ export { createLocalKvStore } from '@parity/product-sdk-local-storage';
|
|
|
10
10
|
export { CloudStorageClient, calculateCid } from '@parity/product-sdk-cloud-storage';
|
|
11
11
|
export { ChainDefinition, PolkadotClient, TypedApi } from 'polkadot-api';
|
|
12
12
|
import './dotns-CtmOwVQW.js';
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* createApp - Main entry point for the Product SDK
|
|
16
|
-
*
|
|
17
|
-
* Creates an App instance with wallet, storage, chain, and cloud storage APIs.
|
|
18
|
-
*/
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Create a new Product SDK app instance
|
|
22
|
-
*
|
|
23
|
-
* @param config - Application configuration
|
|
24
|
-
* @returns App instance with all APIs
|
|
25
|
-
*
|
|
26
|
-
* @example
|
|
27
|
-
* ```ts
|
|
28
|
-
* import { createApp } from '@parity/product-sdk';
|
|
29
|
-
*
|
|
30
|
-
* // Default: cloud storage enabled with paseo environment
|
|
31
|
-
* const app = await createApp({
|
|
32
|
-
* logLevel: 'info',
|
|
33
|
-
* });
|
|
34
|
-
*
|
|
35
|
-
* // Custom cloud storage environment
|
|
36
|
-
* const prodApp = await createApp({
|
|
37
|
-
* cloudStorage: { environment: 'polkadot' },
|
|
38
|
-
* });
|
|
39
|
-
*
|
|
40
|
-
* // Disable cloud storage entirely
|
|
41
|
-
* const noCloudStorageApp = await createApp({
|
|
42
|
-
* cloudStorage: false,
|
|
43
|
-
* });
|
|
44
|
-
*
|
|
45
|
-
* // Connect wallet
|
|
46
|
-
* const { accounts } = await app.wallet.connect();
|
|
47
|
-
*
|
|
48
|
-
* // Use storage
|
|
49
|
-
* await app.localStorage.set('key', 'value');
|
|
50
|
-
*
|
|
51
|
-
* // Use cloud storage (check for null if it might be disabled)
|
|
52
|
-
* if (app.cloudStorage) {
|
|
53
|
-
* const cid = await app.cloudStorage.upload('hello world');
|
|
54
|
-
* }
|
|
55
|
-
* ```
|
|
56
|
-
*/
|
|
57
|
-
declare function createApp(config?: AppConfig): Promise<App>;
|
|
58
|
-
|
|
59
|
-
export { App, AppConfig, createApp };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from '@parity/product-sdk-nfts';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"index.js","sourcesContent":[]}
|
package/dist/testing/index.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ export * from '@parity/product-sdk-local-storage/testing';
|
|
|
3
3
|
export * from '@parity/product-sdk-signer/testing';
|
|
4
4
|
export * from '@parity/product-sdk-contracts/testing';
|
|
5
5
|
export * from '@parity/product-sdk-host/testing';
|
|
6
|
+
export * from '@parity/product-sdk-individuality/testing';
|
|
6
7
|
import '@parity/product-sdk-logger';
|
|
7
8
|
import '@parity/product-sdk-cloud-storage';
|
|
8
9
|
import '@parity/result';
|
package/dist/testing/index.js
CHANGED
|
@@ -6,6 +6,7 @@ import { err, ok } from '@parity/result';
|
|
|
6
6
|
export * from '@parity/product-sdk-signer/testing';
|
|
7
7
|
export * from '@parity/product-sdk-contracts/testing';
|
|
8
8
|
export * from '@parity/product-sdk-host/testing';
|
|
9
|
+
export * from '@parity/product-sdk-individuality/testing';
|
|
9
10
|
|
|
10
11
|
var textEncoder = new TextEncoder();
|
|
11
12
|
function makeFakeWallet(options) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/testing.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["// Copyright 2026 Parity Technologies (UK) Ltd.\n// SPDX-License-Identifier: Apache-2.0\n/**\n * Test fakes for `@parity/product-sdk` (umbrella).\n *\n * `createFakeApp` returns a fake {@link App} — use it directly in logic tests or\n * hand it to `ProductSDKContext.Provider` for React component tests, so code that\n * calls `useProductSDK()` / `useWallet()` runs with no host. This entry also\n * re-exports every package's fakes, for a single meta-package import.\n *\n * @packageDocumentation\n */\nimport { ProductCloudStorageError } from \"@parity/product-sdk-cloud-storage\";\nimport type { LocalKvStore } from \"@parity/product-sdk-local-storage\";\nimport { createFakeHostLocalStorage } from \"@parity/product-sdk-local-storage/testing\";\nimport { createLocalStorageApi } from \"./core/local-storage-api.js\";\nimport { err, ok, unwrapErr, unwrapOk } from \"@parity/result\";\n\nimport type {\n Account,\n App,\n ChainApi,\n CloudStorageApi,\n LocalStorageApi,\n WalletApi,\n} from \"./core/types.js\";\n\nconst textEncoder = new TextEncoder();\n\n// Re-export the per-package fakes so `@parity/product-sdk/testing` is a one-stop import.\n// statement-store is deliberately absent: the umbrella doesn't wrap that package, so apps\n// using it depend on it directly — import `@parity/product-sdk-statement-store/testing`\n// there instead. Re-exporting its fake here would add a dependency the umbrella otherwise\n// doesn't have and could skew against the version the app actually installs.\nexport * from \"@parity/product-sdk-local-storage/testing\";\nexport * from \"@parity/product-sdk-signer/testing\";\nexport * from \"@parity/product-sdk-contracts/testing\";\nexport * from \"@parity/product-sdk-host/testing\";\n\n/** Configurable behavior for the fake {@link WalletApi}. */\nexport interface FakeWalletOptions {\n /** Accounts `connect()` / `getAccounts()` expose. Default: none. */\n accounts?: Account[];\n /** Initially selected account. Default: the first account, or `null`. */\n selected?: Account | null;\n /** Bytes returned by `signMessage` / `createProof`. Default: 64 zero bytes. */\n signature?: Uint8Array;\n /** Value returned by `getProductAccount()`. Default: the selected account. */\n productAccount?: Account | null;\n /** Value returned by `getAnonymousAlias()`. Default: `null`. */\n anonymousAlias?: string | null;\n}\n\n/** Options for {@link createFakeApp}. */\nexport interface CreateFakeAppOptions {\n /** App name reported by `getAppInfo()`. Default: `\"fake-app\"`. */\n name?: string;\n /** Configure the fake wallet. */\n wallet?: FakeWalletOptions;\n /** Override the local-storage API. Default: in-memory (backed by `createFakeHostLocalStorage`). */\n localStorage?: LocalStorageApi;\n /** Override the chain API. Default: unconfigured (throws until you provide one). */\n chain?: ChainApi;\n /** Override cloud storage, or pass `null` to disable it. Default: an in-memory fake. */\n cloudStorage?: CloudStorageApi | null;\n}\n\nfunction makeFakeWallet(options?: FakeWalletOptions): WalletApi {\n const accounts = options?.accounts ?? [];\n let selected = options?.selected !== undefined ? options.selected : (accounts[0] ?? null);\n const signature = options?.signature ?? new Uint8Array(64);\n const listeners = new Set<(account: Account | null) => void>();\n const notify = () => {\n for (const l of listeners) l(selected);\n };\n\n return {\n async connect() {\n return { accounts };\n },\n async disconnect() {\n selected = null;\n notify();\n },\n getAccounts() {\n return accounts;\n },\n getSelectedAccount() {\n return selected;\n },\n selectAccount(address) {\n selected = accounts.find((a) => a.address === address) ?? null;\n notify();\n },\n async signMessage() {\n return signature;\n },\n async signMessageWithDotNsIdentity(args) {\n return {\n username: args.username ?? \"alice\",\n accountId: `0x${\"00\".repeat(32)}`,\n signature,\n };\n },\n onAccountChange(callback) {\n listeners.add(callback);\n return () => {\n listeners.delete(callback);\n };\n },\n getProductAccount() {\n return options?.productAccount !== undefined ? options.productAccount : selected;\n },\n getAnonymousAlias() {\n return options?.anonymousAlias ?? null;\n },\n async createProof() {\n return signature;\n },\n };\n}\n\nfunction makeFakeLocalStorage(): LocalStorageApi {\n // Route through the *same* `createLocalStorageApi` factory `createApp` uses,\n // so the fake and the shipped adapter cannot drift (#344). The fake's host\n // is adapted to a `LocalKvStore` here rather than via the async\n // `createLocalKvStore`, so `createFakeApp` stays synchronous; the semantics\n // (get \"\" -> null, getJSON undefined -> null) match `createHostBackend`.\n const host = createFakeHostLocalStorage();\n const kv: LocalKvStore = {\n async get(key) {\n return (await host.readString(key)) || null;\n },\n async set(key, value) {\n await host.writeString(key, value);\n },\n async getJSON<T>(key: string) {\n return ((await host.readJSON(key)) ?? null) as T | null;\n },\n async setJSON(key, value) {\n await host.writeJSON(key, value);\n },\n async remove(key) {\n await host.clear(key);\n },\n };\n return createLocalStorageApi(kv);\n}\n\nfunction makeFakeCloudStorage(): CloudStorageApi {\n const store = new Map<string, Uint8Array>();\n const toBytes = (data: string | Uint8Array) =>\n typeof data === \"string\" ? textEncoder.encode(data) : data;\n // Deterministic content-addressed id so upload / computeCid / fetch line up.\n const cidOf = (bytes: Uint8Array) => {\n let h = 0x811c9dc5;\n for (const b of bytes) {\n h ^= b;\n h = Math.imul(h, 0x01000193);\n }\n return `bafyfake${(h >>> 0).toString(16).padStart(8, \"0\")}`;\n };\n return {\n async upload(data) {\n const bytes = toBytes(data);\n const cid = cidOf(bytes);\n store.set(cid, bytes);\n return ok(cid);\n },\n async fetch(cid) {\n const bytes = store.get(cid);\n if (!bytes) {\n return err(\n new ProductCloudStorageError(\n `fake cloud storage: no object stored for CID ${cid}`,\n ),\n );\n }\n return ok(bytes);\n },\n async computeCid(data) {\n return cidOf(toBytes(data));\n },\n };\n}\n\nfunction makeUnconfiguredChain(): ChainApi {\n const fail = (): never => {\n throw new Error(\n \"createFakeApp: `chain` is not configured. Pass a `chain` override in options. \" +\n \"There is no chain-read fake — the host owns RPC selection; test chain-reading \" +\n \"logic behind your own interface and cover the real wiring in e2e.\",\n );\n };\n // Reads throw (fail fast, no silent undefined); state queries stay quiet.\n return {\n getClient: fail,\n getRawClient: fail,\n connect: fail,\n isConnected: () => false,\n destroyAll: () => {},\n };\n}\n\n/**\n * Create a fake {@link App}. Wallet, local-storage, and cloud-storage are working\n * in-memory fakes; `chain` is unconfigured until you override it. Every sub-API\n * is overridable.\n *\n * @example\n * ```ts\n * import { createFakeApp } from \"@parity/product-sdk/testing\";\n *\n * const app = createFakeApp({ wallet: { accounts: [alice, bob], selected: alice } });\n * await app.wallet.connect();\n * expect(app.wallet.getAccounts()).toHaveLength(2);\n * ```\n *\n * For React, feed the fake to the exported context:\n * ```tsx\n * import { ProductSDKContext } from \"@parity/product-sdk/react\";\n * render(<ProductSDKContext.Provider value={app}><AccountPicker /></ProductSDKContext.Provider>);\n * ```\n */\nexport function createFakeApp(options?: CreateFakeAppOptions): App {\n const name = options?.name ?? \"fake-app\";\n return {\n wallet: makeFakeWallet(options?.wallet),\n localStorage: options?.localStorage ?? makeFakeLocalStorage(),\n chain: options?.chain ?? makeUnconfiguredChain(),\n cloudStorage:\n options?.cloudStorage !== undefined ? options.cloudStorage : makeFakeCloudStorage(),\n getAppInfo: () => ({ name }),\n };\n}\n\nif (import.meta.vitest) {\n const { describe, test, expect } = import.meta.vitest;\n\n const alice: Account = { address: \"5Alice\", name: \"Alice\", source: \"dev\" };\n const bob: Account = { address: \"5Bob\", name: \"Bob\", source: \"dev\" };\n\n describe(\"createFakeApp\", () => {\n test(\"wallet lists, selects, and notifies on account change\", async () => {\n const app = createFakeApp({ wallet: { accounts: [alice, bob], selected: alice } });\n expect(app.wallet.getAccounts()).toHaveLength(2);\n expect(app.wallet.getSelectedAccount()).toEqual(alice);\n\n let changed: Account | null = null;\n app.wallet.onAccountChange((a) => {\n changed = a;\n });\n app.wallet.selectAccount(\"5Bob\");\n expect(app.wallet.getSelectedAccount()).toEqual(bob);\n expect(changed).toEqual(bob);\n\n const { accounts } = await app.wallet.connect();\n expect(accounts).toHaveLength(2);\n });\n\n test(\"localStorage round-trips and remove deletes a key\", async () => {\n const app = createFakeApp();\n await app.localStorage.set(\"k\", \"v\");\n await app.localStorage.setJSON(\"o\", { n: 1 });\n expect(await app.localStorage.get(\"k\")).toBe(\"v\");\n expect(await app.localStorage.getJSON(\"o\")).toEqual({ n: 1 });\n expect(await app.localStorage.get(\"missing\")).toBeNull();\n\n await app.localStorage.remove(\"k\");\n expect(await app.localStorage.get(\"k\")).toBeNull();\n // Untouched keys stay — there is no clear-all.\n expect(await app.localStorage.getJSON(\"o\")).toEqual({ n: 1 });\n });\n\n test(\"cloudStorage round-trips upload -> fetch; computeCid matches upload\", async () => {\n const cs = createFakeApp().cloudStorage;\n if (!cs) throw new Error(\"expected default cloud storage\");\n const cid = unwrapOk(await cs.upload(\"hello\"));\n expect(await cs.computeCid(\"hello\")).toBe(cid);\n expect(new TextDecoder().decode(unwrapOk(await cs.fetch(cid)))).toBe(\"hello\");\n expect(unwrapErr(await cs.fetch(\"bafyfakemissing\"))).toBeInstanceOf(\n ProductCloudStorageError,\n );\n });\n\n test(\"cloudStorage can be disabled with null\", () => {\n expect(createFakeApp({ cloudStorage: null }).cloudStorage).toBeNull();\n });\n\n test(\"chain is unconfigured by default\", () => {\n const app = createFakeApp();\n expect(app.chain.isConnected({} as never)).toBe(false);\n expect(() => app.chain.getClient({} as never)).toThrow(/not configured/);\n });\n\n test(\"getAppInfo reports the name\", () => {\n expect(createFakeApp({ name: \"my-app\" }).getAppInfo().name).toBe(\"my-app\");\n });\n });\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/testing.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["// Copyright 2026 Parity Technologies (UK) Ltd.\n// SPDX-License-Identifier: Apache-2.0\n/**\n * Test fakes for `@parity/product-sdk` (umbrella).\n *\n * `createFakeApp` returns a fake {@link App} — use it directly in logic tests or\n * hand it to `ProductSDKContext.Provider` for React component tests, so code that\n * calls `useProductSDK()` / `useWallet()` runs with no host. This entry also\n * re-exports every package's fakes, for a single meta-package import.\n *\n * @packageDocumentation\n */\nimport { ProductCloudStorageError } from \"@parity/product-sdk-cloud-storage\";\nimport type { LocalKvStore } from \"@parity/product-sdk-local-storage\";\nimport { createFakeHostLocalStorage } from \"@parity/product-sdk-local-storage/testing\";\nimport { createLocalStorageApi } from \"./core/local-storage-api.js\";\nimport { err, ok, unwrapErr, unwrapOk } from \"@parity/result\";\n\nimport type {\n Account,\n App,\n ChainApi,\n CloudStorageApi,\n LocalStorageApi,\n WalletApi,\n} from \"./core/types.js\";\n\nconst textEncoder = new TextEncoder();\n\n// Re-export the per-package fakes so `@parity/product-sdk/testing` is a one-stop import.\n// statement-store is deliberately absent: the umbrella doesn't wrap that package, so apps\n// using it depend on it directly — import `@parity/product-sdk-statement-store/testing`\n// there instead. Re-exporting its fake here would add a dependency the umbrella otherwise\n// doesn't have and could skew against the version the app actually installs.\nexport * from \"@parity/product-sdk-local-storage/testing\";\nexport * from \"@parity/product-sdk-signer/testing\";\nexport * from \"@parity/product-sdk-contracts/testing\";\nexport * from \"@parity/product-sdk-host/testing\";\nexport * from \"@parity/product-sdk-individuality/testing\";\n\n/** Configurable behavior for the fake {@link WalletApi}. */\nexport interface FakeWalletOptions {\n /** Accounts `connect()` / `getAccounts()` expose. Default: none. */\n accounts?: Account[];\n /** Initially selected account. Default: the first account, or `null`. */\n selected?: Account | null;\n /** Bytes returned by `signMessage` / `createProof`. Default: 64 zero bytes. */\n signature?: Uint8Array;\n /** Value returned by `getProductAccount()`. Default: the selected account. */\n productAccount?: Account | null;\n /** Value returned by `getAnonymousAlias()`. Default: `null`. */\n anonymousAlias?: string | null;\n}\n\n/** Options for {@link createFakeApp}. */\nexport interface CreateFakeAppOptions {\n /** App name reported by `getAppInfo()`. Default: `\"fake-app\"`. */\n name?: string;\n /** Configure the fake wallet. */\n wallet?: FakeWalletOptions;\n /** Override the local-storage API. Default: in-memory (backed by `createFakeHostLocalStorage`). */\n localStorage?: LocalStorageApi;\n /** Override the chain API. Default: unconfigured (throws until you provide one). */\n chain?: ChainApi;\n /** Override cloud storage, or pass `null` to disable it. Default: an in-memory fake. */\n cloudStorage?: CloudStorageApi | null;\n}\n\nfunction makeFakeWallet(options?: FakeWalletOptions): WalletApi {\n const accounts = options?.accounts ?? [];\n let selected = options?.selected !== undefined ? options.selected : (accounts[0] ?? null);\n const signature = options?.signature ?? new Uint8Array(64);\n const listeners = new Set<(account: Account | null) => void>();\n const notify = () => {\n for (const l of listeners) l(selected);\n };\n\n return {\n async connect() {\n return { accounts };\n },\n async disconnect() {\n selected = null;\n notify();\n },\n getAccounts() {\n return accounts;\n },\n getSelectedAccount() {\n return selected;\n },\n selectAccount(address) {\n selected = accounts.find((a) => a.address === address) ?? null;\n notify();\n },\n async signMessage() {\n return signature;\n },\n async signMessageWithDotNsIdentity(args) {\n return {\n username: args.username ?? \"alice\",\n accountId: `0x${\"00\".repeat(32)}`,\n signature,\n };\n },\n onAccountChange(callback) {\n listeners.add(callback);\n return () => {\n listeners.delete(callback);\n };\n },\n getProductAccount() {\n return options?.productAccount !== undefined ? options.productAccount : selected;\n },\n getAnonymousAlias() {\n return options?.anonymousAlias ?? null;\n },\n async createProof() {\n return signature;\n },\n };\n}\n\nfunction makeFakeLocalStorage(): LocalStorageApi {\n // Route through the *same* `createLocalStorageApi` factory `createApp` uses,\n // so the fake and the shipped adapter cannot drift (#344). The fake's host\n // is adapted to a `LocalKvStore` here rather than via the async\n // `createLocalKvStore`, so `createFakeApp` stays synchronous; the semantics\n // (get \"\" -> null, getJSON undefined -> null) match `createHostBackend`.\n const host = createFakeHostLocalStorage();\n const kv: LocalKvStore = {\n async get(key) {\n return (await host.readString(key)) || null;\n },\n async set(key, value) {\n await host.writeString(key, value);\n },\n async getJSON<T>(key: string) {\n return ((await host.readJSON(key)) ?? null) as T | null;\n },\n async setJSON(key, value) {\n await host.writeJSON(key, value);\n },\n async remove(key) {\n await host.clear(key);\n },\n };\n return createLocalStorageApi(kv);\n}\n\nfunction makeFakeCloudStorage(): CloudStorageApi {\n const store = new Map<string, Uint8Array>();\n const toBytes = (data: string | Uint8Array) =>\n typeof data === \"string\" ? textEncoder.encode(data) : data;\n // Deterministic content-addressed id so upload / computeCid / fetch line up.\n const cidOf = (bytes: Uint8Array) => {\n let h = 0x811c9dc5;\n for (const b of bytes) {\n h ^= b;\n h = Math.imul(h, 0x01000193);\n }\n return `bafyfake${(h >>> 0).toString(16).padStart(8, \"0\")}`;\n };\n return {\n async upload(data) {\n const bytes = toBytes(data);\n const cid = cidOf(bytes);\n store.set(cid, bytes);\n return ok(cid);\n },\n async fetch(cid) {\n const bytes = store.get(cid);\n if (!bytes) {\n return err(\n new ProductCloudStorageError(\n `fake cloud storage: no object stored for CID ${cid}`,\n ),\n );\n }\n return ok(bytes);\n },\n async computeCid(data) {\n return cidOf(toBytes(data));\n },\n };\n}\n\nfunction makeUnconfiguredChain(): ChainApi {\n const fail = (): never => {\n throw new Error(\n \"createFakeApp: `chain` is not configured. Pass a `chain` override in options. \" +\n \"There is no chain-read fake — the host owns RPC selection; test chain-reading \" +\n \"logic behind your own interface and cover the real wiring in e2e.\",\n );\n };\n // Reads throw (fail fast, no silent undefined); state queries stay quiet.\n return {\n getClient: fail,\n getRawClient: fail,\n connect: fail,\n isConnected: () => false,\n destroyAll: () => {},\n };\n}\n\n/**\n * Create a fake {@link App}. Wallet, local-storage, and cloud-storage are working\n * in-memory fakes; `chain` is unconfigured until you override it. Every sub-API\n * is overridable.\n *\n * @example\n * ```ts\n * import { createFakeApp } from \"@parity/product-sdk/testing\";\n *\n * const app = createFakeApp({ wallet: { accounts: [alice, bob], selected: alice } });\n * await app.wallet.connect();\n * expect(app.wallet.getAccounts()).toHaveLength(2);\n * ```\n *\n * For React, feed the fake to the exported context:\n * ```tsx\n * import { ProductSDKContext } from \"@parity/product-sdk/react\";\n * render(<ProductSDKContext.Provider value={app}><AccountPicker /></ProductSDKContext.Provider>);\n * ```\n */\nexport function createFakeApp(options?: CreateFakeAppOptions): App {\n const name = options?.name ?? \"fake-app\";\n return {\n wallet: makeFakeWallet(options?.wallet),\n localStorage: options?.localStorage ?? makeFakeLocalStorage(),\n chain: options?.chain ?? makeUnconfiguredChain(),\n cloudStorage:\n options?.cloudStorage !== undefined ? options.cloudStorage : makeFakeCloudStorage(),\n getAppInfo: () => ({ name }),\n };\n}\n\nif (import.meta.vitest) {\n const { describe, test, expect } = import.meta.vitest;\n\n const alice: Account = { address: \"5Alice\", name: \"Alice\", source: \"dev\" };\n const bob: Account = { address: \"5Bob\", name: \"Bob\", source: \"dev\" };\n\n describe(\"createFakeApp\", () => {\n test(\"wallet lists, selects, and notifies on account change\", async () => {\n const app = createFakeApp({ wallet: { accounts: [alice, bob], selected: alice } });\n expect(app.wallet.getAccounts()).toHaveLength(2);\n expect(app.wallet.getSelectedAccount()).toEqual(alice);\n\n let changed: Account | null = null;\n app.wallet.onAccountChange((a) => {\n changed = a;\n });\n app.wallet.selectAccount(\"5Bob\");\n expect(app.wallet.getSelectedAccount()).toEqual(bob);\n expect(changed).toEqual(bob);\n\n const { accounts } = await app.wallet.connect();\n expect(accounts).toHaveLength(2);\n });\n\n test(\"localStorage round-trips and remove deletes a key\", async () => {\n const app = createFakeApp();\n await app.localStorage.set(\"k\", \"v\");\n await app.localStorage.setJSON(\"o\", { n: 1 });\n expect(await app.localStorage.get(\"k\")).toBe(\"v\");\n expect(await app.localStorage.getJSON(\"o\")).toEqual({ n: 1 });\n expect(await app.localStorage.get(\"missing\")).toBeNull();\n\n await app.localStorage.remove(\"k\");\n expect(await app.localStorage.get(\"k\")).toBeNull();\n // Untouched keys stay — there is no clear-all.\n expect(await app.localStorage.getJSON(\"o\")).toEqual({ n: 1 });\n });\n\n test(\"cloudStorage round-trips upload -> fetch; computeCid matches upload\", async () => {\n const cs = createFakeApp().cloudStorage;\n if (!cs) throw new Error(\"expected default cloud storage\");\n const cid = unwrapOk(await cs.upload(\"hello\"));\n expect(await cs.computeCid(\"hello\")).toBe(cid);\n expect(new TextDecoder().decode(unwrapOk(await cs.fetch(cid)))).toBe(\"hello\");\n expect(unwrapErr(await cs.fetch(\"bafyfakemissing\"))).toBeInstanceOf(\n ProductCloudStorageError,\n );\n });\n\n test(\"cloudStorage can be disabled with null\", () => {\n expect(createFakeApp({ cloudStorage: null }).cloudStorage).toBeNull();\n });\n\n test(\"chain is unconfigured by default\", () => {\n const app = createFakeApp();\n expect(app.chain.isConnected({} as never)).toBe(false);\n expect(() => app.chain.getClient({} as never)).toThrow(/not configured/);\n });\n\n test(\"getAppInfo reports the name\", () => {\n expect(createFakeApp({ name: \"my-app\" }).getAppInfo().name).toBe(\"my-app\");\n });\n });\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@parity/product-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.33.0",
|
|
4
4
|
"description": "Unified SDK for building products in the Polkadot ecosystem - umbrella package",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -48,6 +48,10 @@
|
|
|
48
48
|
"import": "./dist/individuality/index.js",
|
|
49
49
|
"types": "./dist/individuality/index.d.ts"
|
|
50
50
|
},
|
|
51
|
+
"./nfts": {
|
|
52
|
+
"import": "./dist/nfts/index.js",
|
|
53
|
+
"types": "./dist/nfts/index.d.ts"
|
|
54
|
+
},
|
|
51
55
|
"./react": {
|
|
52
56
|
"import": "./dist/react/index.js",
|
|
53
57
|
"types": "./dist/react/index.d.ts"
|
|
@@ -75,21 +79,22 @@
|
|
|
75
79
|
],
|
|
76
80
|
"dependencies": {
|
|
77
81
|
"polkadot-api": "^2.1.6",
|
|
82
|
+
"@parity/product-sdk-cloud-storage": "0.12.5",
|
|
78
83
|
"@parity/product-sdk-address": "0.2.0",
|
|
79
|
-
"@parity/product-sdk-
|
|
80
|
-
"@parity/product-sdk-
|
|
84
|
+
"@parity/product-sdk-chain-client": "0.12.9",
|
|
85
|
+
"@parity/product-sdk-contracts": "0.10.12",
|
|
86
|
+
"@parity/product-sdk-host": "0.24.0",
|
|
81
87
|
"@parity/product-sdk-crypto": "0.1.1",
|
|
82
|
-
"@parity/product-sdk-
|
|
83
|
-
"@parity/product-sdk-
|
|
84
|
-
"@parity/product-sdk-individuality": "0.6.0",
|
|
85
|
-
"@parity/product-sdk-keys": "0.4.1",
|
|
86
|
-
"@parity/product-sdk-logger": "0.1.1",
|
|
88
|
+
"@parity/product-sdk-individuality": "0.7.0",
|
|
89
|
+
"@parity/product-sdk-keys": "0.4.2",
|
|
87
90
|
"@parity/product-sdk-errors": "0.2.0",
|
|
88
|
-
"@parity/product-sdk-
|
|
89
|
-
"@parity/
|
|
90
|
-
"@parity/product-sdk-
|
|
91
|
-
"@parity/product-sdk-
|
|
92
|
-
"@parity/
|
|
91
|
+
"@parity/product-sdk-logger": "0.1.1",
|
|
92
|
+
"@parity/result": "0.2.0",
|
|
93
|
+
"@parity/product-sdk-nfts": "0.1.0",
|
|
94
|
+
"@parity/product-sdk-signer": "0.16.0",
|
|
95
|
+
"@parity/product-sdk-local-storage": "0.3.14",
|
|
96
|
+
"@parity/product-sdk-renderer": "0.4.0",
|
|
97
|
+
"@parity/product-sdk-tx": "0.4.12"
|
|
93
98
|
},
|
|
94
99
|
"peerDependencies": {
|
|
95
100
|
"react": "^18.0.0 || ^19.0.0"
|
|
@@ -41,6 +41,9 @@ import type {
|
|
|
41
41
|
AirdropChain,
|
|
42
42
|
ClaimChain,
|
|
43
43
|
ConsumersChain,
|
|
44
|
+
CreditCandidatesChain,
|
|
45
|
+
CurrentGameWatchChain,
|
|
46
|
+
FeeEstimable,
|
|
44
47
|
GameChain,
|
|
45
48
|
GamePlayersChain,
|
|
46
49
|
IndividualityChain,
|
|
@@ -49,12 +52,17 @@ import type {
|
|
|
49
52
|
LiteSignUpChain,
|
|
50
53
|
NetworkSuffixChain,
|
|
51
54
|
PapiIndividualityChain,
|
|
55
|
+
ParticipantWatchChain,
|
|
56
|
+
PlayerWatchChain,
|
|
52
57
|
PrizeStatusChain,
|
|
53
58
|
RegisterChain,
|
|
54
59
|
RegistrationEligibilityChain,
|
|
60
|
+
ReportChain,
|
|
55
61
|
RingLocation as SdkRingLocation,
|
|
62
|
+
RosterChain,
|
|
56
63
|
ScoreContextChain,
|
|
57
64
|
SignUpChain,
|
|
65
|
+
SignUpFundsChain,
|
|
58
66
|
AccountVrfSignature,
|
|
59
67
|
VrfTranscriptItem as IndividualityVrfTranscriptItem,
|
|
60
68
|
RingVRFProof as AsPersonRingVRFProof,
|
|
@@ -129,7 +137,9 @@ type FromPapiSatisfiesContracts = Assert<
|
|
|
129
137
|
GamePlayersChain &
|
|
130
138
|
ScoreContextChain &
|
|
131
139
|
SignUpChain &
|
|
132
|
-
LiteSignUpChain
|
|
140
|
+
LiteSignUpChain &
|
|
141
|
+
CreditCandidatesChain &
|
|
142
|
+
WatchChains
|
|
133
143
|
? true
|
|
134
144
|
: false
|
|
135
145
|
>;
|
|
@@ -327,12 +337,74 @@ type ClaimAirdropTakesTheDocumentedArgs = Assert<
|
|
|
327
337
|
: false
|
|
328
338
|
>;
|
|
329
339
|
|
|
340
|
+
// The report and offboard builders touch `tx` only. `full_report` and the two vote
|
|
341
|
+
// variants are pinned by name, since PAPI encodes whatever object it is handed.
|
|
342
|
+
type PaseoSatisfiesReportContract = Assert<PaseoClient extends ReportChain ? true : false>;
|
|
343
|
+
type PreviewnetSatisfiesReportContract = Assert<
|
|
344
|
+
PreviewnetClient extends ReportChain ? true : false
|
|
345
|
+
>;
|
|
346
|
+
type RejectsBogusReportClient = Assert<
|
|
347
|
+
ClientWithoutIndividuality extends ReportChain ? false : true
|
|
348
|
+
>;
|
|
349
|
+
type ReportArgs = Parameters<GameTx["report"]>[0];
|
|
350
|
+
type ReportTakesFullReport = Assert<"full_report" extends keyof ReportArgs ? true : false>;
|
|
351
|
+
type ReportVoteVariant = ReportArgs["full_report"][number][number]["type"];
|
|
352
|
+
type ReportVotesArePersonAndNotPerson = Assert<
|
|
353
|
+
[ReportVoteVariant] extends ["Person" | "NotPerson"]
|
|
354
|
+
? ["Person" | "NotPerson"] extends [ReportVoteVariant]
|
|
355
|
+
? true
|
|
356
|
+
: false
|
|
357
|
+
: false
|
|
358
|
+
>;
|
|
359
|
+
|
|
360
|
+
// The roster reads, and the candidates read that adds `Game.Game` to them.
|
|
361
|
+
// `IndexToPlayer.getValues` takes each `[round, index]` tuple as a single key.
|
|
362
|
+
type PaseoSatisfiesRosterContract = Assert<PaseoClient extends RosterChain ? true : false>;
|
|
363
|
+
type PreviewnetSatisfiesRosterContract = Assert<
|
|
364
|
+
PreviewnetClient extends RosterChain ? true : false
|
|
365
|
+
>;
|
|
366
|
+
type PaseoSatisfiesCreditCandidatesContract = Assert<
|
|
367
|
+
PaseoClient extends CreditCandidatesChain ? true : false
|
|
368
|
+
>;
|
|
369
|
+
type PreviewnetSatisfiesCreditCandidatesContract = Assert<
|
|
370
|
+
PreviewnetClient extends CreditCandidatesChain ? true : false
|
|
371
|
+
>;
|
|
372
|
+
type RejectsBogusRosterClient = Assert<
|
|
373
|
+
ClientWithoutIndividuality extends RosterChain ? false : true
|
|
374
|
+
>;
|
|
375
|
+
|
|
376
|
+
// The watches take `watchValue` rather than `getValue`, which the pinned contracts
|
|
377
|
+
// never name, so a PAPI release that changed its emission shape fails here.
|
|
378
|
+
type WatchChains = CurrentGameWatchChain & PlayerWatchChain & ParticipantWatchChain;
|
|
379
|
+
type PaseoSatisfiesWatchContracts = Assert<PaseoClient extends WatchChains ? true : false>;
|
|
380
|
+
type PreviewnetSatisfiesWatchContracts = Assert<
|
|
381
|
+
PreviewnetClient extends WatchChains ? true : false
|
|
382
|
+
>;
|
|
383
|
+
type RejectsBogusWatchClient = Assert<
|
|
384
|
+
ClientWithoutIndividuality extends CurrentGameWatchChain ? false : true
|
|
385
|
+
>;
|
|
386
|
+
|
|
330
387
|
// Game sign-up.
|
|
331
388
|
type PaseoSatisfiesSignUpContract = Assert<PaseoClient extends SignUpChain ? true : false>;
|
|
332
389
|
type RejectsBogusSignUpClient = Assert<
|
|
333
390
|
ClientWithoutIndividuality extends SignUpChain ? false : true
|
|
334
391
|
>;
|
|
335
392
|
|
|
393
|
+
// The cost read also takes the raw client, for the chain spec that names the token.
|
|
394
|
+
type PaseoSatisfiesSignUpFundsContract = Assert<
|
|
395
|
+
PaseoClient extends SignUpFundsChain ? true : false
|
|
396
|
+
>;
|
|
397
|
+
type PreviewnetSatisfiesSignUpFundsContract = Assert<
|
|
398
|
+
PreviewnetClient extends SignUpFundsChain ? true : false
|
|
399
|
+
>;
|
|
400
|
+
type RejectsBogusSignUpFundsClient = Assert<
|
|
401
|
+
ClientWithoutIndividuality extends SignUpFundsChain ? false : true
|
|
402
|
+
>;
|
|
403
|
+
// The fee comes from the built sign-up itself, so a real PAPI transaction must fit.
|
|
404
|
+
type SignUpTxIsFeeEstimable = Assert<
|
|
405
|
+
ReturnType<GameTx["sign_up_with_account"]> extends FeeEstimable ? true : false
|
|
406
|
+
>;
|
|
407
|
+
|
|
336
408
|
// `SignUpChain` alone does not reject devnet and cannot: a `tx` argument is
|
|
337
409
|
// checked contravariantly and excess-property checking does not apply between
|
|
338
410
|
// named types, so an interface naming `airdrops` is satisfied by devnet's call,
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
// Copyright 2026 Parity Technologies (UK) Ltd.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
/**
|
|
4
|
+
* Compile-time guard for the chain contract in `@parity/product-sdk-nfts`.
|
|
5
|
+
*
|
|
6
|
+
* That package types its chain parameter structurally, listing the storage
|
|
7
|
+
* entries it needs rather than naming a descriptor — same trade as
|
|
8
|
+
* `IndividualityChain`, and the same gap: a hand-written contract can drift from
|
|
9
|
+
* the real chain silently, because the package's own test doubles satisfy it by
|
|
10
|
+
* construction. See `../individuality/contract.test.ts` for why this assertion
|
|
11
|
+
* has to live in `@parity/product-sdk` to mean anything, and why it checks the
|
|
12
|
+
* sibling's built `dist` rather than its `src`.
|
|
13
|
+
*
|
|
14
|
+
* The `ItemDefs` line below is the one that earned this file. PAPI generates its
|
|
15
|
+
* key as `FixedSizeArray<2, number>` rather than the `[number, number]` tuple it
|
|
16
|
+
* gives `CollectionMetadata` and `ItemMetadata`, because the runtime's metadata
|
|
17
|
+
* declares the key type as an array. The raw storage layout is nonetheless two
|
|
18
|
+
* Twox64Concat segments — a genuine two-key map, verified against live state
|
|
19
|
+
* with `rpc.state_getKeys` — so a prefix scan by collection is sound at the
|
|
20
|
+
* protocol level. Whether PAPI's *typing* admits the one-arg `getEntries` that
|
|
21
|
+
* `NftsChain` asks for is a different question, and this is what answers it.
|
|
22
|
+
*
|
|
23
|
+
* **Paseo only, and that asymmetry is the point.** `devnet-asset-hub` carries
|
|
24
|
+
* neither `Scarcity` nor `NftClaims`, so the negative control below is not a
|
|
25
|
+
* hypothetical: it is the live state of the other supported network.
|
|
26
|
+
*/
|
|
27
|
+
import type { getChainAPI } from "@parity/product-sdk-chain-client";
|
|
28
|
+
import type { NftsChain, NftsCreditsChain } from "@parity/product-sdk-nfts";
|
|
29
|
+
import { expect, test } from "vitest";
|
|
30
|
+
|
|
31
|
+
// The false branch must be `false`, not `never`. `never` is assignable to
|
|
32
|
+
// `true`, so a `never` branch would make the assertion unfalsifiable.
|
|
33
|
+
type Assert<T extends true> = T;
|
|
34
|
+
|
|
35
|
+
type PaseoClient = Awaited<ReturnType<typeof getChainAPI<"paseo">>>;
|
|
36
|
+
type DevnetClient = Awaited<ReturnType<typeof getChainAPI<"devnet">>>;
|
|
37
|
+
|
|
38
|
+
// The test: this alias fails to typecheck if the contract drifts from the
|
|
39
|
+
// descriptor, so it needs no export and no runtime reference.
|
|
40
|
+
type PaseoSatisfiesContract = Assert<PaseoClient extends NftsChain ? true : false>;
|
|
41
|
+
|
|
42
|
+
// The credits read spans both chains the preset carries, so the same client
|
|
43
|
+
// has to satisfy the second contract too.
|
|
44
|
+
type PaseoSatisfiesCredits = Assert<PaseoClient extends NftsCreditsChain ? true : false>;
|
|
45
|
+
|
|
46
|
+
// The negative control, and a real fact about the network rather than a
|
|
47
|
+
// hypothetical: devnet Asset Hub has no `Scarcity` and no `NftClaims`. If
|
|
48
|
+
// `NftsChain` ever stopped constraining, this `@ts-expect-error` would report
|
|
49
|
+
// as unused and the file would fail.
|
|
50
|
+
// @ts-expect-error devnet Asset Hub carries neither pallet
|
|
51
|
+
type DevnetLacksPallets = Assert<DevnetClient extends NftsChain ? true : false>;
|
|
52
|
+
|
|
53
|
+
test("nfts chain contract holds against the paseo descriptor", () => {
|
|
54
|
+
// The assertions above are compile-time. This keeps vitest from reporting
|
|
55
|
+
// the file as having no tests, and documents that a green run means tsc
|
|
56
|
+
// accepted them.
|
|
57
|
+
expect(true).toBe(true);
|
|
58
|
+
});
|
package/src/testing.ts
CHANGED
|
@@ -36,6 +36,7 @@ export * from "@parity/product-sdk-local-storage/testing";
|
|
|
36
36
|
export * from "@parity/product-sdk-signer/testing";
|
|
37
37
|
export * from "@parity/product-sdk-contracts/testing";
|
|
38
38
|
export * from "@parity/product-sdk-host/testing";
|
|
39
|
+
export * from "@parity/product-sdk-individuality/testing";
|
|
39
40
|
|
|
40
41
|
/** Configurable behavior for the fake {@link WalletApi}. */
|
|
41
42
|
export interface FakeWalletOptions {
|