@parity/product-sdk 0.0.0-dev.312.0 → 0.0.0-dev.329.1
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 +3 -1
- package/dist/{chunk-BRZNHTLQ.js → chunk-7GM3HUZF.js} +2 -2
- package/dist/chunk-7GM3HUZF.js.map +1 -0
- package/dist/chunk-TUXU2VPS.js +14 -0
- package/dist/chunk-TUXU2VPS.js.map +1 -0
- package/dist/{chunk-DHRCWMY5.js → chunk-VWD6HK2C.js} +29 -20
- package/dist/chunk-VWD6HK2C.js.map +1 -0
- package/dist/core/index.d.ts +50 -3
- package/dist/core/index.js +3 -2
- package/dist/{dotns-bswWAmR2.d.ts → dotns-CtmOwVQW.d.ts} +2 -2
- package/dist/identity/index.d.ts +118 -89
- package/dist/identity/index.js +200 -78
- package/dist/identity/index.js.map +1 -1
- package/dist/index.d.ts +3 -53
- package/dist/index.js +3 -2
- 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/react/index.d.ts +5 -5
- package/dist/react/index.js +4 -3
- package/dist/react/index.js.map +1 -1
- package/dist/renderer/index.d.ts +1 -0
- package/dist/renderer/index.js +3 -0
- package/dist/renderer/index.js.map +1 -0
- package/dist/testing/index.d.ts +2 -2
- package/dist/testing/index.js +3 -5
- package/dist/testing/index.js.map +1 -1
- package/dist/{types-B5Zx4RNq.d.ts → types-BpWw-OJl.d.ts} +19 -9
- package/package.json +23 -12
- package/src/core/createApp.test.ts +194 -0
- package/src/core/createApp.ts +35 -22
- package/src/core/local-storage-api.ts +74 -0
- package/src/core/types.ts +18 -7
- package/src/identity/dotns-abis.ts +44 -9
- package/src/identity/dotns-addresses.test.ts +536 -0
- package/src/identity/dotns-addresses.ts +320 -0
- package/src/identity/dotns-errors.ts +2 -0
- package/src/identity/dotns-namehash.ts +2 -2
- package/src/identity/dotns-registry.test.ts +158 -3
- package/src/identity/dotns-registry.ts +71 -73
- package/src/identity/dotns.ts +2 -2
- package/src/identity/index.test.ts +43 -0
- package/src/identity/index.ts +10 -6
- package/src/identity/types.ts +0 -19
- package/src/index.ts +3 -2
- package/src/individuality/contract.test.ts +426 -2
- package/src/nfts/contract.test.ts +58 -0
- package/src/nfts/index.ts +8 -0
- package/src/react/context.ts +1 -1
- package/src/react/index.ts +1 -1
- package/src/react/provider.tsx +3 -3
- package/src/renderer/index.ts +10 -0
- package/src/testing.ts +14 -11
- package/dist/chunk-BRZNHTLQ.js.map +0 -1
- package/dist/chunk-DHRCWMY5.js.map +0 -1
- package/src/identity/product-account.test.ts +0 -130
- package/src/identity/product-account.ts +0 -115
package/src/core/createApp.ts
CHANGED
|
@@ -16,6 +16,7 @@ import type {
|
|
|
16
16
|
CloudStorageApi,
|
|
17
17
|
LocalStorageApi,
|
|
18
18
|
} from "./types.js";
|
|
19
|
+
import { createLocalStorageApi } from "./local-storage-api.js";
|
|
19
20
|
import { configure, createLogger } from "@parity/product-sdk-logger";
|
|
20
21
|
import { createLocalKvStore } from "@parity/product-sdk-local-storage";
|
|
21
22
|
import { SignerManager } from "@parity/product-sdk-signer";
|
|
@@ -33,7 +34,12 @@ import {
|
|
|
33
34
|
destroyAll,
|
|
34
35
|
} from "@parity/product-sdk-chain-client";
|
|
35
36
|
import { accountIdBytes } from "@parity/product-sdk-address";
|
|
36
|
-
import {
|
|
37
|
+
import {
|
|
38
|
+
getAccountsProvider,
|
|
39
|
+
getTruApi,
|
|
40
|
+
HostCallFailedError,
|
|
41
|
+
HostUnavailableError,
|
|
42
|
+
} from "@parity/product-sdk-host";
|
|
37
43
|
import {
|
|
38
44
|
accountIdBytesToHex,
|
|
39
45
|
type PeopleUsernameQueryApi,
|
|
@@ -54,19 +60,16 @@ const log = createLogger("app");
|
|
|
54
60
|
*
|
|
55
61
|
* // Default: cloud storage enabled with paseo environment
|
|
56
62
|
* const app = await createApp({
|
|
57
|
-
* name: 'my-app',
|
|
58
63
|
* logLevel: 'info',
|
|
59
64
|
* });
|
|
60
65
|
*
|
|
61
66
|
* // Custom cloud storage environment
|
|
62
67
|
* const prodApp = await createApp({
|
|
63
|
-
* name: 'my-app',
|
|
64
68
|
* cloudStorage: { environment: 'polkadot' },
|
|
65
69
|
* });
|
|
66
70
|
*
|
|
67
71
|
* // Disable cloud storage entirely
|
|
68
72
|
* const noCloudStorageApp = await createApp({
|
|
69
|
-
* name: 'my-app',
|
|
70
73
|
* cloudStorage: false,
|
|
71
74
|
* });
|
|
72
75
|
*
|
|
@@ -82,20 +85,40 @@ const log = createLogger("app");
|
|
|
82
85
|
* }
|
|
83
86
|
* ```
|
|
84
87
|
*/
|
|
85
|
-
export async function createApp(config: AppConfig): Promise<App> {
|
|
88
|
+
export async function createApp(config: AppConfig = {}): Promise<App> {
|
|
86
89
|
// Set log level if specified
|
|
87
90
|
if (config.logLevel) {
|
|
88
91
|
configure({ level: config.logLevel });
|
|
89
92
|
}
|
|
90
93
|
|
|
91
|
-
|
|
94
|
+
if (config.name !== undefined) {
|
|
95
|
+
log.warn(
|
|
96
|
+
"createApp: name is deprecated and ignored. Remove the name option. The SDK resolves the app name from system.getProductContext(), dropping the product ID's final domain suffix (my-app.dot -> my-app). Local development IDs stay unchanged.",
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const truApi = await getTruApi();
|
|
101
|
+
if (!truApi) {
|
|
102
|
+
throw new HostUnavailableError("createApp requires a host product context");
|
|
103
|
+
}
|
|
104
|
+
const { productId } = await truApi.system.getProductContext().match(
|
|
105
|
+
(context) => context,
|
|
106
|
+
(error) => {
|
|
107
|
+
throw new HostCallFailedError("system.getProductContext", error);
|
|
108
|
+
},
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
const isLocalHost = /^(?:localhost|127\.0\.0\.1|[^:]+\.localhost)(?::\d+)?$/i.test(productId);
|
|
112
|
+
const name = isLocalHost ? productId : productId.replace(/\.[^.]+$/, "");
|
|
113
|
+
|
|
114
|
+
log.info("Creating Product SDK app", { name });
|
|
92
115
|
|
|
93
116
|
// Initialize storage (container-only - will throw if not in container)
|
|
94
|
-
const localKvStore = await createLocalKvStore({ prefix:
|
|
117
|
+
const localKvStore = await createLocalKvStore({ prefix: name });
|
|
95
118
|
|
|
96
119
|
// Initialize signer manager
|
|
97
120
|
const signerManager = new SignerManager({
|
|
98
|
-
dappName:
|
|
121
|
+
dappName: productId,
|
|
99
122
|
});
|
|
100
123
|
|
|
101
124
|
// Initialize cloud storage client (configurable, defaults to paseo).
|
|
@@ -124,18 +147,8 @@ export async function createApp(config: AppConfig): Promise<App> {
|
|
|
124
147
|
log.debug("Cloud Storage client disabled");
|
|
125
148
|
}
|
|
126
149
|
|
|
127
|
-
//
|
|
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
|
-
};
|
|
150
|
+
// Storage API adapter — shared with `createFakeApp` so the two cannot drift.
|
|
151
|
+
const localStorageApi: LocalStorageApi = createLocalStorageApi(localKvStore);
|
|
139
152
|
|
|
140
153
|
// Create wallet API adapter
|
|
141
154
|
const walletApi = createWalletApi(signerManager);
|
|
@@ -206,7 +219,7 @@ export async function createApp(config: AppConfig): Promise<App> {
|
|
|
206
219
|
: null;
|
|
207
220
|
|
|
208
221
|
log.info("Product SDK app created", {
|
|
209
|
-
name
|
|
222
|
+
name,
|
|
210
223
|
cloudStorage: cloudStorageEnabled ? cloudStorageEnvironment : "disabled",
|
|
211
224
|
});
|
|
212
225
|
|
|
@@ -215,7 +228,7 @@ export async function createApp(config: AppConfig): Promise<App> {
|
|
|
215
228
|
localStorage: localStorageApi,
|
|
216
229
|
chain: chainApi,
|
|
217
230
|
cloudStorage: cloudStorageApi,
|
|
218
|
-
getAppInfo: () => ({ ...config }),
|
|
231
|
+
getAppInfo: () => ({ ...config, name }),
|
|
219
232
|
};
|
|
220
233
|
}
|
|
221
234
|
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
// Copyright 2026 Parity Technologies (UK) Ltd.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
/**
|
|
4
|
+
* The one adapter from a {@link LocalKvStore} to the SDK's {@link LocalStorageApi}.
|
|
5
|
+
*
|
|
6
|
+
* Both `createApp` (host-backed store) and `createFakeApp` (in-memory store)
|
|
7
|
+
* build their `localStorage` through here, so the shipped adapter and the test
|
|
8
|
+
* fake cannot drift — which is exactly how `clear()` came to be a no-op in
|
|
9
|
+
* production while the fake emptied (#344). The in-source test below drives one
|
|
10
|
+
* assertion set through this factory over an in-memory store; anything the fake
|
|
11
|
+
* exposes, the real path exposes the same way.
|
|
12
|
+
*/
|
|
13
|
+
import type { LocalKvStore } from "@parity/product-sdk-local-storage";
|
|
14
|
+
import type { LocalStorageApi } from "./types.js";
|
|
15
|
+
|
|
16
|
+
/** Wrap a {@link LocalKvStore} as the SDK's {@link LocalStorageApi}. */
|
|
17
|
+
export function createLocalStorageApi(kv: LocalKvStore): LocalStorageApi {
|
|
18
|
+
return {
|
|
19
|
+
get: (key) => kv.get(key),
|
|
20
|
+
set: (key, value) => kv.set(key, value),
|
|
21
|
+
getJSON: <T>(key: string) => kv.getJSON<T>(key),
|
|
22
|
+
setJSON: <T>(key: string, value: T) => kv.setJSON(key, value),
|
|
23
|
+
remove: (key) => kv.remove(key),
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (import.meta.vitest) {
|
|
28
|
+
const { describe, test, expect } = import.meta.vitest;
|
|
29
|
+
|
|
30
|
+
/** A minimal in-memory {@link LocalKvStore}, string- and JSON-aware. */
|
|
31
|
+
function memoryKvStore(): LocalKvStore {
|
|
32
|
+
const store = new Map<string, string>();
|
|
33
|
+
return {
|
|
34
|
+
async get(key) {
|
|
35
|
+
return store.get(key) ?? null;
|
|
36
|
+
},
|
|
37
|
+
async set(key, value) {
|
|
38
|
+
store.set(key, value);
|
|
39
|
+
},
|
|
40
|
+
async remove(key) {
|
|
41
|
+
store.delete(key);
|
|
42
|
+
},
|
|
43
|
+
async getJSON<T>(key: string) {
|
|
44
|
+
const raw = store.get(key);
|
|
45
|
+
return raw === undefined ? null : (JSON.parse(raw) as T);
|
|
46
|
+
},
|
|
47
|
+
async setJSON(key, value) {
|
|
48
|
+
store.set(key, JSON.stringify(value));
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
describe("createLocalStorageApi", () => {
|
|
54
|
+
test("round-trips strings and JSON, and remove deletes one key", async () => {
|
|
55
|
+
const api = createLocalStorageApi(memoryKvStore());
|
|
56
|
+
|
|
57
|
+
await api.set("k", "v");
|
|
58
|
+
await api.setJSON("o", { n: 1 });
|
|
59
|
+
expect(await api.get("k")).toBe("v");
|
|
60
|
+
expect(await api.getJSON("o")).toEqual({ n: 1 });
|
|
61
|
+
expect(await api.get("missing")).toBeNull();
|
|
62
|
+
|
|
63
|
+
await api.remove("k");
|
|
64
|
+
expect(await api.get("k")).toBeNull();
|
|
65
|
+
// No clear-all: an untouched key stays.
|
|
66
|
+
expect(await api.getJSON("o")).toEqual({ n: 1 });
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
test("exposes exactly the LocalStorageApi surface — no clear()", () => {
|
|
70
|
+
const api = createLocalStorageApi(memoryKvStore());
|
|
71
|
+
expect(Object.keys(api).sort()).toEqual(["get", "getJSON", "remove", "set", "setJSON"]);
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
}
|
package/src/core/types.ts
CHANGED
|
@@ -25,8 +25,8 @@ export interface CloudStorageConfig {
|
|
|
25
25
|
|
|
26
26
|
/** Configuration for createApp */
|
|
27
27
|
export interface AppConfig {
|
|
28
|
-
/**
|
|
29
|
-
name
|
|
28
|
+
/** @deprecated Ignored with a warning. The host product ID supplies the app name. */
|
|
29
|
+
name?: string;
|
|
30
30
|
/** Log level for SDK operations (default: 'info') */
|
|
31
31
|
logLevel?: LogLevel;
|
|
32
32
|
/**
|
|
@@ -37,6 +37,12 @@ export interface AppConfig {
|
|
|
37
37
|
cloudStorage?: CloudStorageConfig | false;
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
+
/** App configuration with the identity resolved from the host. */
|
|
41
|
+
export interface AppInfo extends Omit<AppConfig, "name"> {
|
|
42
|
+
/** App name and storage prefix, omitting the host ID's final domain suffix. Local host IDs stay unchanged. */
|
|
43
|
+
name: string;
|
|
44
|
+
}
|
|
45
|
+
|
|
40
46
|
/** Wallet API exposed by the SDK */
|
|
41
47
|
export interface WalletApi {
|
|
42
48
|
/** Connect to available wallet providers */
|
|
@@ -72,7 +78,14 @@ export interface WalletApi {
|
|
|
72
78
|
createProof(message: Uint8Array): Promise<Uint8Array>;
|
|
73
79
|
}
|
|
74
80
|
|
|
75
|
-
/**
|
|
81
|
+
/**
|
|
82
|
+
* Storage API exposed by the SDK: per-key get / set / remove, string and JSON.
|
|
83
|
+
*
|
|
84
|
+
* There is no `clear()`. Host localStorage exposes no key enumeration (only
|
|
85
|
+
* per-key read / write / remove), so a clear-all cannot be implemented — it was
|
|
86
|
+
* a silent no-op in a host container. Remove keys individually with `remove`,
|
|
87
|
+
* or track the keys your app writes and remove them.
|
|
88
|
+
*/
|
|
76
89
|
export interface LocalStorageApi {
|
|
77
90
|
/** Get a value by key */
|
|
78
91
|
get(key: string): Promise<string | null>;
|
|
@@ -84,8 +97,6 @@ export interface LocalStorageApi {
|
|
|
84
97
|
setJSON<T = unknown>(key: string, value: T): Promise<void>;
|
|
85
98
|
/** Remove a value by key */
|
|
86
99
|
remove(key: string): Promise<void>;
|
|
87
|
-
/** Clear all values */
|
|
88
|
-
clear(): Promise<void>;
|
|
89
100
|
}
|
|
90
101
|
|
|
91
102
|
/** Chain API exposed by the SDK */
|
|
@@ -171,8 +182,8 @@ export interface App {
|
|
|
171
182
|
chain: ChainApi;
|
|
172
183
|
/** Cloud Storage operations (null if disabled via config) */
|
|
173
184
|
cloudStorage: CloudStorageApi | null;
|
|
174
|
-
/** Get app configuration */
|
|
175
|
-
getAppInfo():
|
|
185
|
+
/** Get app configuration with the host-derived name. */
|
|
186
|
+
getAppInfo(): AppInfo;
|
|
176
187
|
}
|
|
177
188
|
|
|
178
189
|
/** Account information */
|
|
@@ -238,6 +238,39 @@ export const DOTNS_PROTOCOL_REGISTRY_ABI: AbiEntry[] = [
|
|
|
238
238
|
outputs: [{ name: "node", type: "bytes32" }],
|
|
239
239
|
stateMutability: "view",
|
|
240
240
|
},
|
|
241
|
+
{
|
|
242
|
+
type: "function",
|
|
243
|
+
name: "get",
|
|
244
|
+
inputs: [{ name: "key", type: "bytes32" }],
|
|
245
|
+
outputs: [{ name: "addr", type: "address" }],
|
|
246
|
+
stateMutability: "view",
|
|
247
|
+
},
|
|
248
|
+
];
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* `RootGatewayDispatcher.TARGET`, the PoP controller it forwards to. `immutable`,
|
|
252
|
+
* so a rotation means a new dispatcher and a new pallet value, which is why
|
|
253
|
+
* discovery starts at the pallet rather than here.
|
|
254
|
+
*/
|
|
255
|
+
export const DOTNS_ROOT_GATEWAY_DISPATCHER_ABI: AbiEntry[] = [
|
|
256
|
+
{
|
|
257
|
+
type: "function",
|
|
258
|
+
name: "TARGET",
|
|
259
|
+
inputs: [],
|
|
260
|
+
outputs: [{ name: "", type: "address" }],
|
|
261
|
+
stateMutability: "view",
|
|
262
|
+
},
|
|
263
|
+
];
|
|
264
|
+
|
|
265
|
+
/** `DotnsPopController.protocolRegistry`, the only hop that names the registry. */
|
|
266
|
+
export const DOTNS_POP_CONTROLLER_ABI: AbiEntry[] = [
|
|
267
|
+
{
|
|
268
|
+
type: "function",
|
|
269
|
+
name: "protocolRegistry",
|
|
270
|
+
inputs: [],
|
|
271
|
+
outputs: [{ name: "", type: "address" }],
|
|
272
|
+
stateMutability: "view",
|
|
273
|
+
},
|
|
241
274
|
];
|
|
242
275
|
|
|
243
276
|
/** `IPopRules.PopStatus`. Ordering is meaningful: a user meets a tier when `userStatus >= status`. */
|
|
@@ -248,21 +281,23 @@ export const POP_STATUS = { NoStatus: 0, PopLite: 1, PopFull: 2, Reserved: 3 } a
|
|
|
248
281
|
*
|
|
249
282
|
* Not a per-network table, despite what the old name (`PASEO_ASSETHUB_DOTNS`)
|
|
250
283
|
* implied: every DotNS network is deployed through the same CREATE3 factory, so
|
|
251
|
-
* the addresses are identical everywhere and **only the TLD differs
|
|
252
|
-
* on
|
|
253
|
-
* returns the same registry on each, and all six
|
|
254
|
-
* both. `paritytech/dotns` `DEPLOYMENTS.md` states the mechanism, and
|
|
284
|
+
* the addresses are identical everywhere and **only the TLD differs**, `.paseo`
|
|
285
|
+
* on Paseo Asset Hub Next V2 and `.test` on Previewnet. Verified on both:
|
|
286
|
+
* `protocolRegistry.get(...)` returns the same registry on each, and all six
|
|
287
|
+
* addresses hold contracts on both. `paritytech/dotns` `DEPLOYMENTS.md` states the mechanism, and
|
|
255
288
|
* `preview-net-v1` confirms it from the deploy side: the TLD is passed only as
|
|
256
289
|
* registry init calldata, so it moves no address.
|
|
257
290
|
*
|
|
258
291
|
* So extending this module to another network means resolving its TLD, which
|
|
259
292
|
* `resolveTld` already does — not adding a second address table.
|
|
260
293
|
*
|
|
261
|
-
*
|
|
262
|
-
* `
|
|
263
|
-
* `
|
|
264
|
-
*
|
|
265
|
-
*
|
|
294
|
+
* Five answer `DotnsProtocolRegistry.get(bytes32)` under the keys in
|
|
295
|
+
* `DOTNS_REGISTRY_KEYS`, two of which differ from the field name used here.
|
|
296
|
+
* `protocolRegistry` has no key and comes from the gateway walk. All six have a
|
|
297
|
+
* `Revive.AccountInfoOf` entry.
|
|
298
|
+
*
|
|
299
|
+
* Pinned, not resolved at runtime: re-verify after a redeploy, or have the
|
|
300
|
+
* client do it with `verifyDotNsAddresses`.
|
|
266
301
|
*/
|
|
267
302
|
export const DOTNS_ADDRESSES = {
|
|
268
303
|
registry: "0xf34054fd76BbF85f216cf9908226D5f0A72E50CA",
|