@parity/product-sdk 0.22.0 → 0.23.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 (40) hide show
  1. package/dist/chunk-BRZNHTLQ.js +89 -0
  2. package/dist/chunk-BRZNHTLQ.js.map +1 -0
  3. package/dist/{chunk-6BI66XUJ.js → chunk-DHRCWMY5.js} +9 -10
  4. package/dist/chunk-DHRCWMY5.js.map +1 -0
  5. package/dist/core/index.d.ts +2 -2
  6. package/dist/core/index.js +2 -2
  7. package/dist/dotns-bswWAmR2.d.ts +136 -0
  8. package/dist/identity/index.d.ts +502 -45
  9. package/dist/identity/index.js +800 -32
  10. package/dist/identity/index.js.map +1 -1
  11. package/dist/index.d.ts +3 -3
  12. package/dist/index.js +2 -2
  13. package/dist/react/index.d.ts +2 -2
  14. package/dist/react/index.js +2 -2
  15. package/dist/testing/index.d.ts +2 -2
  16. package/dist/{types-DTgyMIi0.d.ts → types-B5Zx4RNq.d.ts} +1 -1
  17. package/package.json +10 -10
  18. package/src/core/createApp.ts +10 -8
  19. package/src/identity/dotns-abis.test.ts +43 -0
  20. package/src/identity/dotns-abis.ts +309 -0
  21. package/src/identity/dotns-addresses.test.ts +536 -0
  22. package/src/identity/dotns-addresses.ts +320 -0
  23. package/src/identity/dotns-errors.ts +36 -0
  24. package/src/identity/dotns-namehash.test.ts +155 -0
  25. package/src/identity/dotns-namehash.ts +149 -0
  26. package/src/identity/dotns-owner.test.ts +92 -0
  27. package/src/identity/dotns-registry.test.ts +1309 -0
  28. package/src/identity/dotns-registry.ts +868 -0
  29. package/src/identity/dotns.test.ts +128 -0
  30. package/src/identity/dotns.ts +91 -78
  31. package/src/identity/index.test.ts +43 -0
  32. package/src/identity/index.ts +40 -10
  33. package/src/identity/types.ts +29 -25
  34. package/src/individuality/contract.test.ts +272 -2
  35. package/dist/chunk-6BI66XUJ.js.map +0 -1
  36. package/dist/chunk-BIKT6X54.js +0 -70
  37. package/dist/chunk-BIKT6X54.js.map +0 -1
  38. package/dist/dotns-DIaptENj.d.ts +0 -167
  39. package/src/identity/product-account.test.ts +0 -129
  40. package/src/identity/product-account.ts +0 -115
@@ -10,7 +10,16 @@
10
10
  * it by construction.
11
11
  *
12
12
  * This file closes that gap: if a descriptor regeneration changes a key or a
13
- * value type, `pnpm typecheck` fails here.
13
+ * value type, `pnpm typecheck` fails here. It guards both of that package's
14
+ * chain contracts, `IndividualityChain` for the personhood batch and
15
+ * `ConsumersChain` for the account to username read.
16
+ *
17
+ * **It checks the built `dist`, not the sibling's `src`.** The contracts resolve
18
+ * through `@parity/product-sdk-individuality`'s `types` field, so editing a
19
+ * contract and running this typecheck without rebuilding that package asserts
20
+ * against the previous build. Run `pnpm -r build` first, or the guard silently
21
+ * checks stale types. Verified 2026-08-19 by mutating a contract and watching
22
+ * the typecheck pass until the sibling was rebuilt.
14
23
  *
15
24
  * **It lives in the umbrella package deliberately.** Inside the individuality
16
25
  * package the same assertion is vacuous, passing even against a contract that
@@ -22,7 +31,23 @@
22
31
  * `@ts-expect-error` would report as unused and this file would fail.
23
32
  */
24
33
  import type { getChainAPI } from "@parity/product-sdk-chain-client";
25
- import type { IndividualityChain } from "@parity/product-sdk-individuality";
34
+ import type {
35
+ RingVRFProof as HostRingVRFProof,
36
+ VrfSignature as HostVrfSignature,
37
+ VrfTranscriptItem as HostVrfTranscriptItem,
38
+ } from "@parity/product-sdk-host";
39
+ import type {
40
+ AirdropChain,
41
+ ClaimChain,
42
+ ConsumersChain,
43
+ GameChain,
44
+ IndividualityChain,
45
+ PrizeStatusChain,
46
+ SignUpChain,
47
+ AccountVrfSignature,
48
+ VrfTranscriptItem as IndividualityVrfTranscriptItem,
49
+ RingVRFProof as AsPersonRingVRFProof,
50
+ } from "@parity/product-sdk-individuality";
26
51
  import { expect, test } from "vitest";
27
52
 
28
53
  // The false branch must be `false`, not `never`. `never` is assignable to
@@ -37,6 +62,29 @@ type DevnetClient = Awaited<ReturnType<typeof getChainAPI<"devnet">>>;
37
62
  type PaseoSatisfiesContract = Assert<PaseoClient extends IndividualityChain ? true : false>;
38
63
  type DevnetSatisfiesContract = Assert<DevnetClient extends IndividualityChain ? true : false>;
39
64
 
65
+ // `ConsumersChain` needs this more than the batch contract does: its value shape
66
+ // was derived from the pallet and the codegen rather than read off the emitted
67
+ // descriptor, so these two lines are what make that derivation a checked fact.
68
+ type PaseoSatisfiesConsumers = Assert<PaseoClient extends ConsumersChain ? true : false>;
69
+ type DevnetSatisfiesConsumers = Assert<DevnetClient extends ConsumersChain ? true : false>;
70
+
71
+ // Separate from the personhood contract: reading draws needs neither `Resources`
72
+ // nor `PeopleLite`. Both chains satisfy it, which is weaker than it looks — devnet's
73
+ // event-id base is 28 bytes to paseo's 27, and `SizedHex<N>` erases `N`, so only the
74
+ // length check in `airdrop-ids.ts` catches that.
75
+ type PaseoSatisfiesAirdropContract = Assert<PaseoClient extends AirdropChain ? true : false>;
76
+ type DevnetSatisfiesAirdropContract = Assert<DevnetClient extends AirdropChain ? true : false>;
77
+
78
+ // Same again for the current-game contract, which shares no entry with either of
79
+ // the other two — but paseo only, and that asymmetry is the point.
80
+ type PaseoSatisfiesGameContract = Assert<PaseoClient extends GameChain ? true : false>;
81
+
82
+ // Devnet's metadata predates the multi-airdrop game work — the 28-byte base above is
83
+ // one symptom, `game-types.ts` lists the rest — so the game surface is paseo-only.
84
+ // Asserted negatively on purpose: a devnet re-pin breaks this line, which is the
85
+ // prompt to flip it positive and check the read against it.
86
+ type DevnetPredatesTheGameContract = Assert<DevnetClient extends GameChain ? false : true>;
87
+
40
88
  // Negative control, kept type-only so it emits no runtime code. If
41
89
  // `IndividualityChain` ever stopped constraining, this flips to `false` and the
42
90
  // file fails to typecheck, which is what keeps the assertions above honest.
@@ -48,6 +96,228 @@ type ClientWithoutIndividuality = {
48
96
  type RejectsBogusClient = Assert<
49
97
  ClientWithoutIndividuality extends IndividualityChain ? false : true
50
98
  >;
99
+ type RejectsBogusAirdropClient = Assert<
100
+ ClientWithoutIndividuality extends AirdropChain ? false : true
101
+ >;
102
+ type RejectsBogusGameClient = Assert<ClientWithoutIndividuality extends GameChain ? false : true>;
103
+
104
+ // `Game.Game` being optional is what makes "between games" representable at all,
105
+ // and `GameIndex` / `GameSchedules` being `ValueQuery` is what lets the read treat
106
+ // them as always answering. The structural contract pins the latter two by typing
107
+ // them non-optional; this pins the first, which no assignability check would
108
+ // catch — a suddenly-required `Game` would still satisfy an optional contract.
109
+ type GameStorage = PaseoClient["individuality"]["query"]["Game"];
110
+ type GameValue = Awaited<ReturnType<GameStorage["Game"]["getValue"]>>;
111
+ type GameIsOptional = Assert<undefined extends GameValue ? true : false>;
112
+ // Negative control: `GameIndex` is `ValueQuery`, so it must *not* admit undefined.
113
+ type GameIndexValue = Awaited<ReturnType<GameStorage["GameIndex"]["getValue"]>>;
114
+ type GameIndexIsNotOptional = Assert<undefined extends GameIndexValue ? false : true>;
115
+
116
+ // The event id is derived from a runtime constant rather than a storage entry, so
117
+ // the constant has to exist and still be a plain string. Its *width* cannot be
118
+ // asserted here: PAPI's `SizedHex<N>` is `string & { __hexString?: N | unknown }`,
119
+ // and the `| unknown` collapses every width to the same type, so `SizedHex<32>`
120
+ // and `SizedHex<27>` are mutually assignable and any such assertion would pass
121
+ // vacuously. The 27-byte expectation is enforced at runtime instead, by the
122
+ // length check in `airdrop-ids.ts` and the pinned vectors beside it.
123
+ type GameConstants = PaseoClient["individuality"]["constants"]["Game"];
124
+ type EventIdBaseExists = Assert<"airdrop_event_id_base" extends keyof GameConstants ? true : false>;
125
+ type AirdropEventIdBase = Awaited<ReturnType<GameConstants["airdrop_event_id_base"]>>;
126
+ type EventIdBaseIsAString = Assert<AirdropEventIdBase extends string ? true : false>;
127
+
128
+ // The composed prize-status read spans both pallets, so it is the intersection
129
+ // that has to hold — and on paseo only, since it inherits `GameChain`.
130
+ type PaseoSatisfiesPrizeStatusContract = Assert<
131
+ PaseoClient extends PrizeStatusChain ? true : false
132
+ >;
133
+ type DevnetPredatesThePrizeStatusContract = Assert<
134
+ DevnetClient extends PrizeStatusChain ? false : true
135
+ >;
136
+
137
+ // `Registrations` is keyed by the entropy slot with the entry as its *value*, so
138
+ // `readDrawRegistration` can only work by scanning the event's prefix. Pinning the
139
+ // arity here is what would catch a descriptor regeneration that added a reverse
140
+ // index and made the scan unnecessary.
141
+ type RegistrationsEntries = Awaited<
142
+ ReturnType<PaseoClient["individuality"]["query"]["Airdrop"]["Registrations"]["getEntries"]>
143
+ >;
144
+ type RegistrationsKeyIsEventIdAndSlot = Assert<
145
+ RegistrationsEntries[number]["keyArgs"] extends [unknown, unknown] ? true : false
146
+ >;
147
+
148
+ // `Winners` is a double map keyed by the registration entry, which is what makes
149
+ // "did I win" a point lookup instead of a scan of every winner. If a descriptor
150
+ // regeneration ever collapsed it to a single key, the read layer would silently
151
+ // need rewriting, so the arity is pinned.
152
+ type WinnersKey = Parameters<
153
+ PaseoClient["individuality"]["query"]["Airdrop"]["Winners"]["getValue"]
154
+ >;
155
+ type WinnersTakesTwoKeys = Assert<
156
+ WinnersKey extends [unknown, unknown, ...unknown[]] ? true : false
157
+ >;
158
+
159
+ type RejectsBogusConsumersClient = Assert<
160
+ ClientWithoutIndividuality extends ConsumersChain ? false : true
161
+ >;
162
+
163
+ // The write half declares its own `RingVRFProof` rather than importing the
164
+ // host's, for the same reason `IndividualityChain` is structural: it keeps the
165
+ // individuality package free of a dependency on `@parity/product-sdk-host`. The
166
+ // cost is that a field rename on the host side would go unnoticed there, since
167
+ // nothing in that package resolves the host type. Here both are direct
168
+ // dependencies, so this is where the two can be tied together.
169
+ type HostProofSatisfiesLocal = Assert<HostRingVRFProof extends AsPersonRingVRFProof ? true : false>;
170
+
171
+ // Negative control for the same assertion. If `AsPersonRingVRFProof` ever
172
+ // stopped constraining, this flips to `false` and the file fails to typecheck.
173
+ type ProofWithoutRingIndex = {
174
+ proof: Uint8Array;
175
+ contextualAlias: { context: Uint8Array; alias: Uint8Array };
176
+ ringRevision: number;
177
+ };
178
+ type RejectsProofMissingRingIndex = Assert<
179
+ ProofWithoutRingIndex extends AsPersonRingVRFProof ? false : true
180
+ >;
181
+
182
+ // `AliasWithProof` is only ever accepted for `People.set_alias_account`, so the
183
+ // call has to exist on the real chain with the two arguments the extension's
184
+ // validation reads. A descriptor regeneration that renames either fails here.
185
+ type PeopleTx = PaseoClient["individuality"]["tx"]["People"];
186
+ type SetAliasAccountExists = Assert<"set_alias_account" extends keyof PeopleTx ? true : false>;
187
+ type SetAliasAccountArgs = Parameters<PeopleTx["set_alias_account"]>[0];
188
+ type SetAliasAccountTakesAccountAndValidAt = Assert<
189
+ "account" extends keyof SetAliasAccountArgs
190
+ ? "call_valid_at" extends keyof SetAliasAccountArgs
191
+ ? true
192
+ : false
193
+ : false
194
+ >;
195
+
196
+ // The JSDoc examples in the individuality package submit
197
+ // `Game.sign_up_with_alias` under a person origin. A person origin supplies only
198
+ // the origin, never the call arguments, so those snippets go stale the moment
199
+ // this call's parameters change — and nothing else in the repo compiles them.
200
+ type GameTx = PaseoClient["individuality"]["tx"]["Game"];
201
+ type SignUpWithAliasExists = Assert<"sign_up_with_alias" extends keyof GameTx ? true : false>;
202
+ type SignUpWithAliasArgs = Parameters<GameTx["sign_up_with_alias"]>[0];
203
+ type SignUpWithAliasTakesTheDocumentedArgs = Assert<
204
+ "identifier_key" extends keyof SignUpWithAliasArgs
205
+ ? "statement_account" extends keyof SignUpWithAliasArgs
206
+ ? "sig" extends keyof SignUpWithAliasArgs
207
+ ? true
208
+ : false
209
+ : false
210
+ : false
211
+ >;
212
+
213
+ // Negative control for the assertion above. The `extends keyof` chain would pass
214
+ // vacuously if `SignUpWithAliasArgs` ever resolved to something permissive such
215
+ // as `any`, so this pins a shape that is missing `sig` and requires it to fail.
216
+ type SignUpArgsWithoutSig = Pick<SignUpWithAliasArgs, "identifier_key" | "statement_account">;
217
+ type RejectsSignUpArgsMissingSig = Assert<"sig" extends keyof SignUpArgsWithoutSig ? false : true>;
218
+
219
+ // The claim is the one contract here that touches `tx` as well as storage. Paseo
220
+ // only, like the game surface it composes with.
221
+ type PaseoSatisfiesClaimContract = Assert<PaseoClient extends ClaimChain ? true : false>;
222
+ type RejectsBogusClaimClient = Assert<ClientWithoutIndividuality extends ClaimChain ? false : true>;
223
+
224
+ // `claim_airdrop`'s three arguments, pinned by name. `ClaimChain` types them
225
+ // structurally, and PAPI encodes whatever object it is handed — so a renamed field
226
+ // would encode as `undefined` and fail on chain with nothing local to point at it.
227
+ type ClaimAirdropArgs = Parameters<GameTx["claim_airdrop"]>[0];
228
+ type ClaimAirdropTakesTheDocumentedArgs = Assert<
229
+ "game_index" extends keyof ClaimAirdropArgs
230
+ ? "airdrop_index" extends keyof ClaimAirdropArgs
231
+ ? "beneficiary" extends keyof ClaimAirdropArgs
232
+ ? true
233
+ : false
234
+ : false
235
+ : false
236
+ >;
237
+
238
+ // Game sign-up.
239
+ type PaseoSatisfiesSignUpContract = Assert<PaseoClient extends SignUpChain ? true : false>;
240
+ type RejectsBogusSignUpClient = Assert<
241
+ ClientWithoutIndividuality extends SignUpChain ? false : true
242
+ >;
243
+
244
+ // `SignUpChain` alone does not reject devnet and cannot: a `tx` argument is
245
+ // checked contravariantly and excess-property checking does not apply between
246
+ // named types, so an interface naming `airdrops` is satisfied by devnet's call,
247
+ // which has only `airdrop`. `identifier_key` does not separate them either, since
248
+ // `SizedHex<N>`'s brand is optional. Assert on the intersection the read takes,
249
+ // where `GameChain` is the half that rejects devnet.
250
+ type PaseoSatisfiesSignUpRead = Assert<PaseoClient extends GameChain & SignUpChain ? true : false>;
251
+ type DevnetPredatesTheSignUpRead = Assert<
252
+ DevnetClient extends GameChain & SignUpChain ? false : true
253
+ >;
254
+
255
+ // The divergence itself: devnet's argument is `airdrop`, so `signUpWithAccountTx`
256
+ // emitting `airdrops` would encode as `undefined` and enter no draw at all.
257
+ type DevnetGameTx = DevnetClient["individuality"]["tx"]["Game"];
258
+ type DevnetSignUpArgs = Parameters<DevnetGameTx["sign_up_with_account"]>[0];
259
+ type DevnetHasNoAirdropsArg = Assert<"airdrops" extends keyof DevnetSignUpArgs ? false : true>;
260
+ type DevnetHasTheSingularArg = Assert<"airdrop" extends keyof DevnetSignUpArgs ? true : false>;
261
+
262
+ // Pinned by name for the same reason `claim_airdrop`'s are: PAPI encodes the
263
+ // object it is handed, so a renamed field silently encodes as `undefined`.
264
+ type SignUpWithAccountArgs = Parameters<GameTx["sign_up_with_account"]>[0];
265
+ type SignUpWithAccountTakesTheDocumentedArgs = Assert<
266
+ "identifier_key" extends keyof SignUpWithAccountArgs
267
+ ? "airdrops" extends keyof SignUpWithAccountArgs
268
+ ? true
269
+ : false
270
+ : false
271
+ >;
272
+
273
+ // `None` is how a player enters no draw, and the only form a recognized player
274
+ // can use at all.
275
+ type AirdropsArg = SignUpWithAccountArgs["airdrops"];
276
+ type AirdropsIsOptional = Assert<undefined extends AirdropsArg ? true : false>;
277
+
278
+ // Extracted from the enum rather than restated, so a renamed field fails here
279
+ // instead of on chain.
280
+ type AccountVrfs = Extract<NonNullable<AirdropsArg>, { type: "Account" }>["value"][number];
281
+ type AccountVrfHasPreOutputAndProof = Assert<
282
+ "pre_output" extends keyof AccountVrfs
283
+ ? "proof" extends keyof AccountVrfs
284
+ ? true
285
+ : false
286
+ : false
287
+ >;
288
+
289
+ // The VRF types are local copies of the host's, declared here for the same reason
290
+ // `AsPersonRingVRFProof` is: so the package keeps no host dependency. Those host
291
+ // types are mapped straight off truapi's wire types, so a rename there changes them
292
+ // with no line of this repo touched, and the break would land as a runtime
293
+ // TypeError rather than a failed typecheck.
294
+ type HostVrfSignatureSatisfiesLocal = Assert<
295
+ HostVrfSignature extends AccountVrfSignature ? true : false
296
+ >;
297
+ type HostVrfItemSatisfiesLocal = Assert<
298
+ HostVrfTranscriptItem extends IndividualityVrfTranscriptItem ? true : false
299
+ >;
300
+
301
+ // Negative controls, so the two above cannot pass vacuously.
302
+ type RejectsSignatureMissingProof = Assert<
303
+ { preOutput: Uint8Array } extends AccountVrfSignature ? false : true
304
+ >;
305
+ type RejectsItemMissingValue = Assert<
306
+ { label: Uint8Array } extends IndividualityVrfTranscriptItem ? false : true
307
+ >;
308
+
309
+ // `Game.Players`: the variant spelling the read keys by, and the one field it uses.
310
+ // Sibling reads got exactly these pins.
311
+ type PlayersEntry = PaseoClient["individuality"]["query"]["Game"]["Players"];
312
+ type PlayersKey = Parameters<PlayersEntry["getValue"]>[0];
313
+ type PlayersKeyIsAccountOrPerson = Assert<
314
+ PlayersKey extends { type: "Account" | "Person" } ? true : false
315
+ >;
316
+ type RejectsAliasSpelling = Assert<
317
+ { type: "Alias"; value: string } extends PlayersKey ? false : true
318
+ >;
319
+ type PlayersValue = NonNullable<Awaited<ReturnType<PlayersEntry["getValue"]>>>;
320
+ type PlayersHasRegistered = Assert<"registered" extends keyof PlayersValue ? true : false>;
51
321
 
52
322
  test("the individuality chain contract is asserted at compile time", () => {
53
323
  // The type assertions above are the test. This keeps vitest from reporting
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/core/createApp.ts"],"names":["err"],"mappings":"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","file":"chunk-6BI66XUJ.js","sourcesContent":["// Copyright 2026 Parity Technologies (UK) Ltd.\n// SPDX-License-Identifier: Apache-2.0\n/**\n * createApp - Main entry point for the Product SDK\n *\n * Creates an App instance with wallet, storage, chain, and cloud storage APIs.\n */\n\nimport type { ChainDefinition } from \"polkadot-api\";\nimport type {\n App,\n AppConfig,\n WalletApi,\n ChainApi,\n Account,\n CloudStorageApi,\n LocalStorageApi,\n} from \"./types.js\";\nimport { configure, createLogger } from \"@parity/product-sdk-logger\";\nimport { createLocalKvStore } from \"@parity/product-sdk-local-storage\";\nimport { SignerManager } from \"@parity/product-sdk-signer\";\nimport {\n CloudStorageClient,\n ProductCloudStorageError,\n calculateCid,\n createLazySigner,\n} from \"@parity/product-sdk-cloud-storage\";\nimport { err, ok } from \"@parity/result\";\nimport {\n createChainClient,\n getClient,\n isConnected,\n destroyAll,\n} from \"@parity/product-sdk-chain-client\";\nimport { getAccountsProvider } from \"@parity/product-sdk-host\";\nimport {\n accountIdHexToBytes,\n type PeopleUsernameQueryApi,\n resolvePeopleUsernameOwner,\n} from \"../identity/dotns.js\";\n\nconst log = createLogger(\"app\");\n\n/**\n * Create a new Product SDK app instance\n *\n * @param config - Application configuration\n * @returns App instance with all APIs\n *\n * @example\n * ```ts\n * import { createApp } from '@parity/product-sdk';\n *\n * // Default: cloud storage enabled with paseo environment\n * const app = await createApp({\n * name: 'my-app',\n * logLevel: 'info',\n * });\n *\n * // Custom cloud storage environment\n * const prodApp = await createApp({\n * name: 'my-app',\n * cloudStorage: { environment: 'polkadot' },\n * });\n *\n * // Disable cloud storage entirely\n * const noCloudStorageApp = await createApp({\n * name: 'my-app',\n * cloudStorage: false,\n * });\n *\n * // Connect wallet\n * const { accounts } = await app.wallet.connect();\n *\n * // Use storage\n * await app.localStorage.set('key', 'value');\n *\n * // Use cloud storage (check for null if it might be disabled)\n * if (app.cloudStorage) {\n * const cid = await app.cloudStorage.upload('hello world');\n * }\n * ```\n */\nexport async function createApp(config: AppConfig): Promise<App> {\n // Set log level if specified\n if (config.logLevel) {\n configure({ level: config.logLevel });\n }\n\n log.info(\"Creating Product SDK app\", { name: config.name });\n\n // Initialize storage (container-only - will throw if not in container)\n const localKvStore = await createLocalKvStore({ prefix: config.name });\n\n // Initialize signer manager\n const signerManager = new SignerManager({\n dappName: config.name,\n });\n\n // Initialize cloud storage client (configurable, defaults to paseo).\n //\n // The signer is wrapped lazily so the cloud storage client can be built before\n // an account is selected. Uploads will throw a clear error if no signer\n // is available at submission time. Reads (fetch / fetchJson) don't need\n // a signer, so they work regardless of whether an account is selected --\n // but they are container-only and throw CloudStorageHostUnavailableError\n // outside a host container (no IPFS-gateway fallback).\n const cloudStorageEnabled = config.cloudStorage !== false;\n const cloudStorageEnvironment =\n typeof config.cloudStorage === \"object\" ? config.cloudStorage.environment : \"paseo\";\n const cloudStorageClient = cloudStorageEnabled\n ? await CloudStorageClient.create({\n environment: cloudStorageEnvironment,\n signer: createLazySigner(() => signerManager.getSigner()),\n })\n : null;\n\n if (cloudStorageEnabled) {\n log.debug(\"Cloud Storage client (Bulletin) initialized\", {\n environment: cloudStorageEnvironment,\n });\n } else {\n log.debug(\"Cloud Storage client disabled\");\n }\n\n // Create storage API adapter\n const localStorageApi: LocalStorageApi = {\n get: (key) => localKvStore.get(key),\n set: (key, value) => localKvStore.set(key, value),\n getJSON: <T>(key: string) => localKvStore.getJSON<T>(key),\n setJSON: <T>(key: string, value: T) => localKvStore.setJSON(key, value),\n remove: (key) => localKvStore.remove(key),\n clear: async () => {\n // LocalKvStore doesn't have clear - this is a no-op\n log.debug(\"clear() is not supported in container storage mode\");\n },\n };\n\n // Create wallet API adapter\n const walletApi = createWalletApi(signerManager);\n\n // Create chain API\n const chainApi: ChainApi = {\n getClient(descriptor) {\n log.debug(\"getClient called\", { genesis: descriptor.genesis });\n const client = getClient(descriptor);\n return client.getTypedApi(descriptor);\n },\n\n getRawClient(descriptor) {\n log.debug(\"getRawClient called\", { genesis: descriptor.genesis });\n return getClient(descriptor);\n },\n\n async connect<T extends Record<string, ChainDefinition>>(chains: T) {\n log.debug(\"connect called\", { chains: Object.keys(chains) });\n return createChainClient({ chains });\n },\n\n isConnected(descriptor) {\n return isConnected(descriptor);\n },\n\n destroyAll() {\n log.debug(\"destroyAll called\");\n destroyAll();\n },\n };\n\n // Create Cloud Storage API adapter (null if disabled)\n const cloudStorageApi: CloudStorageApi | null = cloudStorageClient\n ? {\n upload: async (data) => {\n const bytes = typeof data === \"string\" ? new TextEncoder().encode(data) : data;\n try {\n // Explicitly request a DAG-PB manifest so chunked uploads always\n // resolve to a single root CID. Without this, AsyncBulletinClient\n // can return `result.cid: undefined` for chunked-without-manifest\n // uploads — but app consumers expect a CID they can hand to\n // `fetch(cid)`, so treat a missing CID as an error.\n const uploaded = await cloudStorageClient\n .store(bytes)\n .withManifest(true)\n .send();\n if (!uploaded.cid) {\n return err(\n new ProductCloudStorageError(\n \"Cloud storage upload returned no CID despite .withManifest(true). Upstream contract may have shifted — file an issue.\",\n ),\n );\n }\n return ok(uploaded.cid.toString());\n } catch (cause) {\n const message = cause instanceof Error ? cause.message : String(cause);\n return err(new ProductCloudStorageError(message, { cause }));\n }\n },\n fetch: (cid) => cloudStorageClient.fetchBytes(cid),\n computeCid: async (data) => {\n const bytes = typeof data === \"string\" ? new TextEncoder().encode(data) : data;\n const cid = await calculateCid(bytes);\n return cid.toString();\n },\n }\n : null;\n\n log.info(\"Product SDK app created\", {\n name: config.name,\n cloudStorage: cloudStorageEnabled ? cloudStorageEnvironment : \"disabled\",\n });\n\n return {\n wallet: walletApi,\n localStorage: localStorageApi,\n chain: chainApi,\n cloudStorage: cloudStorageApi,\n getAppInfo: () => ({ ...config }),\n };\n}\n\n/**\n * Create wallet API adapter using SignerManager from leaf package\n */\nfunction createWalletApi(signerManager: SignerManager): WalletApi {\n // Track account change subscribers\n const accountChangeSubscribers = new Set<(account: Account | null) => void>();\n\n // Subscribe to signer manager state changes\n signerManager.subscribe((state) => {\n const account = state.selectedAccount\n ? {\n address: state.selectedAccount.address,\n name: state.selectedAccount.name ?? undefined,\n source: state.selectedAccount.source,\n }\n : null;\n for (const callback of accountChangeSubscribers) {\n try {\n callback(account);\n } catch (e) {\n log.warn(\"Account change callback threw\", { error: e });\n }\n }\n });\n\n return {\n async connect(): Promise<{ accounts: Account[] }> {\n const result = await signerManager.connect();\n if (!result.ok) {\n throw new Error(result.error.message);\n }\n return {\n accounts: result.value.map((a) => ({\n address: a.address,\n name: a.name ?? undefined,\n source: a.source,\n })),\n };\n },\n\n async disconnect(): Promise<void> {\n signerManager.disconnect();\n },\n\n getAccounts(): Account[] {\n return signerManager.getState().accounts.map((a) => ({\n address: a.address,\n name: a.name ?? undefined,\n source: a.source,\n }));\n },\n\n getSelectedAccount(): Account | null {\n const selected = signerManager.getState().selectedAccount;\n if (!selected) return null;\n return {\n address: selected.address,\n name: selected.name ?? undefined,\n source: selected.source,\n };\n },\n\n selectAccount(address: string): void {\n signerManager.selectAccount(address);\n },\n\n async signMessage(message: string | Uint8Array): Promise<Uint8Array> {\n const bytes = typeof message === \"string\" ? new TextEncoder().encode(message) : message;\n const result = await signerManager.signRaw(bytes);\n if (!result.ok) {\n throw new Error(result.error.message);\n }\n return result.value;\n },\n\n async signMessageWithDotNsIdentity(args) {\n const message =\n typeof args.message === \"string\"\n ? new TextEncoder().encode(args.message)\n : args.message;\n const accountsProvider = await getHostAccountsProvider();\n const username = args.username ?? (await getPrimaryUsername(accountsProvider));\n\n // Reuse an already-connected People chain when the caller has\n // wired one up via `app.chain.connect({ ..., <name>: peopleChain })`.\n // Fall back to opening a transient connection so first-time users\n // don't have to think about chain lifecycles. The chain-client\n // module caches by genesis fingerprint, so subsequent\n // signMessageWithDotNsIdentity calls share whichever connection\n // got established first.\n const peopleClient = isConnected(args.peopleChain)\n ? getClient(args.peopleChain)\n : await createChainClient({ chains: { people: args.peopleChain } }).then(\n (c) => c.raw.people,\n );\n // PAPI's `TypedApi.query.X.Y.getValue` is variadic\n // (`...args: [...WithCallOptions<Args>]`) so it's not assignable\n // to our deliberately-narrow `(key) => Promise<...>` shape. The\n // resolver only ever passes the storage key; the cast adapts the\n // wider PAPI surface to the minimum we depend on.\n const peopleApi = peopleClient.getTypedApi(\n args.peopleChain,\n ) as unknown as PeopleUsernameQueryApi;\n const accountId = await resolvePeopleUsernameOwner(username, peopleApi);\n if (!accountId) {\n throw new Error(`No account owns DotNS username \"${username}\"`);\n }\n\n const owner = accountIdHexToBytes(accountId);\n const signer = accountsProvider.getLegacyAccountSigner({\n publicKey: owner,\n name: username,\n });\n\n try {\n return {\n username,\n accountId,\n signature: await signer.signBytes(message),\n };\n } catch (cause) {\n throw new Error(\n `Failed to sign with DotNS username \"${username}\": ${\n cause instanceof Error ? cause.message : String(cause)\n }`,\n { cause },\n );\n }\n },\n\n onAccountChange(callback: (account: Account | null) => void): () => void {\n accountChangeSubscribers.add(callback);\n return () => accountChangeSubscribers.delete(callback);\n },\n\n getProductAccount(): Account | null {\n // Product accounts require async call - this sync API can't support it properly\n // Users should use SignerManager.getProductAccount() directly\n log.warn(\n \"getProductAccount() is deprecated - use SignerManager.getProductAccount() directly\",\n );\n return null;\n },\n\n getAnonymousAlias(): string | null {\n // Anonymous aliases require async call - this sync API can't support it properly\n // Users should use SignerManager.getProductAccountAlias() directly\n log.warn(\n \"getAnonymousAlias() is deprecated - use SignerManager.getProductAccountAlias() directly\",\n );\n return null;\n },\n\n async createProof(_message: Uint8Array): Promise<Uint8Array> {\n // Ring VRF proofs require SignerManager.createRingVRFProof() directly\n throw new Error(\n \"createProof() is not implemented in the App API. \" +\n \"Use SignerManager.createRingVRFProof() directly.\",\n );\n },\n };\n}\n\ntype HostAccountsProvider = NonNullable<Awaited<ReturnType<typeof getAccountsProvider>>>;\n\nasync function getHostAccountsProvider(): Promise<HostAccountsProvider> {\n const provider = await getAccountsProvider();\n if (!provider) {\n throw new Error(\"Host accounts provider is not available\");\n }\n return provider;\n}\n\nasync function getPrimaryUsername(accountsProvider: HostAccountsProvider): Promise<string> {\n const result = await accountsProvider.getUserId().match(\n (value) => value,\n (err) => {\n throw err;\n },\n );\n const username = result.primaryUsername.trim();\n if (!username) {\n throw new Error(\"Host identity did not provide a primary DotNS username\");\n }\n return username;\n}\n"]}
@@ -1,70 +0,0 @@
1
- import { accountIdBytes } from '@parity/product-sdk-address';
2
- import { hexToBytes, bytesToHex } from '@parity/product-sdk-crypto';
3
- import { createLogger } from '@parity/product-sdk-logger';
4
-
5
- // src/identity/dotns.ts
6
- var log = createLogger("identity");
7
- function isValidDotNsName(name) {
8
- if (!name.endsWith(".dot")) return false;
9
- const label = name.slice(0, -4);
10
- if (label.length < 3 || label.length > 63) return false;
11
- return /^[a-z0-9]([a-z0-9-]*[a-z0-9])?$/.test(label);
12
- }
13
- function normalizeDotNsName(name) {
14
- let normalized = name.toLowerCase().trim();
15
- if (!normalized.endsWith(".dot")) {
16
- normalized += ".dot";
17
- }
18
- return normalized;
19
- }
20
- async function resolveDotNs(name) {
21
- const normalized = normalizeDotNsName(name);
22
- if (!isValidDotNsName(normalized)) {
23
- log.warn("Invalid DotNS name", { name });
24
- return null;
25
- }
26
- log.debug("Resolving DotNS name", { name: normalized });
27
- throw new Error(
28
- "resolveDotNs() is not yet implemented. This is a skeleton for the Product SDK structure."
29
- );
30
- }
31
- async function reverseDotNs(address) {
32
- log.debug("Reverse resolving address", { address });
33
- throw new Error(
34
- "reverseDotNs() is not yet implemented. This is a skeleton for the Product SDK structure."
35
- );
36
- }
37
- async function isDotNsAvailable(name) {
38
- const record = await resolveDotNs(name).catch(() => null);
39
- return record === null;
40
- }
41
- async function resolvePeopleUsernameOwner(username, peopleApi) {
42
- const owner = await peopleApi.query.Resources.UsernameOwnerOf.getValue(
43
- new TextEncoder().encode(username)
44
- );
45
- if (!owner) return null;
46
- return accountIdBytesToHex(accountIdBytes(owner));
47
- }
48
- function assertHex(value) {
49
- if (!/^0x[0-9a-fA-F]*$/.test(value)) {
50
- throw new Error(`Expected 0x-prefixed hex string, got ${value}`);
51
- }
52
- return value;
53
- }
54
- function accountIdHexToBytes(accountId) {
55
- const bytes = hexToBytes(assertHex(accountId).slice(2));
56
- if (bytes.length !== 32) {
57
- throw new Error(`Expected 32-byte AccountId, got ${bytes.length} bytes`);
58
- }
59
- return bytes;
60
- }
61
- function accountIdBytesToHex(bytes) {
62
- if (bytes.length !== 32) {
63
- throw new Error(`Expected 32-byte AccountId, got ${bytes.length} bytes`);
64
- }
65
- return `0x${bytesToHex(bytes)}`;
66
- }
67
-
68
- export { accountIdHexToBytes, isDotNsAvailable, isValidDotNsName, normalizeDotNsName, resolveDotNs, resolvePeopleUsernameOwner, reverseDotNs };
69
- //# sourceMappingURL=chunk-BIKT6X54.js.map
70
- //# sourceMappingURL=chunk-BIKT6X54.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/identity/dotns.ts"],"names":[],"mappings":"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","file":"chunk-BIKT6X54.js","sourcesContent":["// Copyright 2026 Parity Technologies (UK) Ltd.\n// SPDX-License-Identifier: Apache-2.0\n/**\n * DotNS (Polkadot Name Service) utilities\n *\n * Provides name resolution for .dot domains\n */\n\nimport { accountIdBytes } from \"@parity/product-sdk-address\";\nimport { bytesToHex, hexToBytes } from \"@parity/product-sdk-crypto\";\nimport { createLogger } from \"@parity/product-sdk-logger\";\nimport type {\n ChainDefinition,\n PalletsTypedef,\n PlainDescriptor,\n RuntimeDescriptor,\n SS58String,\n StorageDescriptor,\n TxDescriptor,\n} from \"polkadot-api\";\nimport type { DotNsRecord } from \"./types.js\";\n\nconst log = createLogger(\"identity\");\n\ntype AnyDescriptorEntry<T> = Record<string, Record<string, T>>;\n\ntype PeopleUsernameStorage = {\n Resources: {\n UsernameOwnerOf: StorageDescriptor<[Uint8Array], SS58String, true, never>;\n };\n};\n\ntype PeopleUsernamePallets = PalletsTypedef<\n PeopleUsernameStorage,\n AnyDescriptorEntry<TxDescriptor<any>>,\n AnyDescriptorEntry<PlainDescriptor<any>>,\n AnyDescriptorEntry<PlainDescriptor<any>>,\n AnyDescriptorEntry<PlainDescriptor<any>>,\n AnyDescriptorEntry<RuntimeDescriptor<any, any>>\n>;\n\n/**\n * Descriptor narrowed to \"any chain that exposes `Resources.UsernameOwnerOf`\".\n *\n * Used as the input to `signMessageWithDotNsIdentity` so the SDK doesn't pin\n * a specific People-chain genesis — anything with the right storage shape\n * (paseo-individuality today, future People Lite, etc.) is accepted.\n */\nexport type PeopleUsernameChain = ChainDefinition & {\n descriptors: Promise<unknown> & {\n pallets: PeopleUsernamePallets;\n };\n};\n\n/**\n * Minimal typed-api shape required to resolve a username on a People chain.\n *\n * This is a narrow structural type — anything with the right\n * `query.Resources.UsernameOwnerOf.getValue` shape works, including a real\n * `TypedApi<PeopleUsernameChain>` slice of a `ChainClient` or a hand-rolled\n * test double.\n */\nexport type PeopleUsernameQueryApi = {\n query: {\n Resources: {\n UsernameOwnerOf: {\n getValue: (key: Uint8Array) => Promise<SS58String | undefined>;\n };\n };\n };\n};\n\n/**\n * Check if a string is a valid DotNS name\n *\n * @param name - Name to validate\n * @returns True if valid DotNS name\n */\nexport function isValidDotNsName(name: string): boolean {\n // Basic validation: alphanumeric, hyphens, ends with .dot\n if (!name.endsWith(\".dot\")) return false;\n const label = name.slice(0, -4);\n if (label.length < 3 || label.length > 63) return false;\n return /^[a-z0-9]([a-z0-9-]*[a-z0-9])?$/.test(label);\n}\n\n/**\n * Normalize a DotNS name (lowercase, trim whitespace)\n *\n * @param name - Name to normalize\n * @returns Normalized name\n */\nexport function normalizeDotNsName(name: string): string {\n let normalized = name.toLowerCase().trim();\n if (!normalized.endsWith(\".dot\")) {\n normalized += \".dot\";\n }\n return normalized;\n}\n\n/**\n * Resolve a DotNS name to an address.\n *\n * @deprecated Not implemented — throws at runtime. Use\n * `wallet.signMessageWithDotNsIdentity({ peopleChain, username })` (which\n * internally calls {@link resolvePeopleUsernameOwner}) for the supported\n * People-chain username flow.\n *\n * @param name - DotNS name (e.g., \"alice.dot\")\n * @returns Resolved record or null if not found\n */\nexport async function resolveDotNs(name: string): Promise<DotNsRecord | null> {\n const normalized = normalizeDotNsName(name);\n\n if (!isValidDotNsName(normalized)) {\n log.warn(\"Invalid DotNS name\", { name });\n return null;\n }\n\n log.debug(\"Resolving DotNS name\", { name: normalized });\n\n // TODO: Implement via PAPI query to DotNS pallet\n throw new Error(\n \"resolveDotNs() is not yet implemented. \" +\n \"This is a skeleton for the Product SDK structure.\",\n );\n}\n\n/**\n * Reverse resolve an address to a DotNS name.\n *\n * @deprecated Not implemented — throws at runtime. Reverse lookup will land\n * alongside future identity work; for now resolve forward via\n * `wallet.signMessageWithDotNsIdentity`.\n *\n * @param address - SS58 address\n * @returns Primary name or null if none set\n */\nexport async function reverseDotNs(address: string): Promise<string | null> {\n log.debug(\"Reverse resolving address\", { address });\n\n // TODO: Implement via PAPI query to DotNS pallet\n throw new Error(\n \"reverseDotNs() is not yet implemented. \" +\n \"This is a skeleton for the Product SDK structure.\",\n );\n}\n\n/**\n * Check if a DotNS name is available for registration.\n *\n * @deprecated Not implemented — depends on {@link resolveDotNs} which throws.\n *\n * @param name - Name to check\n * @returns True if available\n */\nexport async function isDotNsAvailable(name: string): Promise<boolean> {\n const record = await resolveDotNs(name).catch(() => null);\n return record === null;\n}\n\n/**\n * Resolve a People / People Lite username to its owning `AccountId32`.\n *\n * Queries `Resources.UsernameOwnerOf` on the caller-supplied typed-api fragment.\n * The returned value is the raw 32-byte account id as a `0x`-prefixed hex\n * string, or `null` when no owner is registered for that username.\n *\n * The `username` is UTF-8 encoded as-is — no normalization is applied. Pass\n * the exact byte string the chain stores (typically with the `.dot` suffix).\n *\n * @internal Exposed for unit testing. Consumers should use\n * `wallet.signMessageWithDotNsIdentity` instead, which orchestrates the\n * chain-connection lifecycle.\n */\nexport async function resolvePeopleUsernameOwner(\n username: string,\n peopleApi: PeopleUsernameQueryApi,\n): Promise<`0x${string}` | null> {\n const owner = await peopleApi.query.Resources.UsernameOwnerOf.getValue(\n new TextEncoder().encode(username),\n );\n if (!owner) return null;\n\n return accountIdBytesToHex(accountIdBytes(owner));\n}\n\nfunction assertHex(value: string): `0x${string}` {\n if (!/^0x[0-9a-fA-F]*$/.test(value)) {\n throw new Error(`Expected 0x-prefixed hex string, got ${value}`);\n }\n return value as `0x${string}`;\n}\n\nexport function accountIdHexToBytes(accountId: `0x${string}`): Uint8Array {\n const bytes = hexToBytes(assertHex(accountId).slice(2));\n if (bytes.length !== 32) {\n throw new Error(`Expected 32-byte AccountId, got ${bytes.length} bytes`);\n }\n return bytes;\n}\n\nfunction accountIdBytesToHex(bytes: Uint8Array): `0x${string}` {\n if (bytes.length !== 32) {\n throw new Error(`Expected 32-byte AccountId, got ${bytes.length} bytes`);\n }\n return `0x${bytesToHex(bytes)}`;\n}\n"]}
@@ -1,167 +0,0 @@
1
- import { ChainDefinition, PalletsTypedef, StorageDescriptor, SS58String, TxDescriptor, PlainDescriptor, RuntimeDescriptor } from 'polkadot-api';
2
-
3
- /**
4
- * Identity module types
5
- *
6
- * Types for DotNS name resolution and context-alias derivation
7
- */
8
- /** DotNS name resolution result */
9
- interface DotNsRecord {
10
- /** Resolved SS58 address */
11
- address: string;
12
- /** Name that was resolved */
13
- name: string;
14
- /** Owner address */
15
- owner: string;
16
- /** Expiration timestamp (if applicable) */
17
- expiresAt?: number;
18
- }
19
- /**
20
- * Context alias info: a deterministic, context-bound alias derived from a parent account
21
- *
22
- * @deprecated Returned by `deriveContextAlias`, whose addresses no key can spend.
23
- * Removal: `@parity/product-sdk` 0.23.0.
24
- */
25
- interface ContextAliasInfo {
26
- /** Alias SS58 address */
27
- address: string;
28
- /** H160 EVM address */
29
- h160Address: `0x${string}`;
30
- /** Parent account address */
31
- parentAddress: string;
32
- /** Context string used for derivation */
33
- context: string;
34
- }
35
- /** Identity verification result */
36
- interface VerificationResult {
37
- /** Whether identity is verified */
38
- verified: boolean;
39
- /** Verification method used */
40
- method: "on-chain" | "judgement" | "social";
41
- /** Verification details */
42
- details?: Record<string, unknown>;
43
- }
44
- /** On-chain identity info */
45
- interface OnChainIdentity {
46
- /** Display name */
47
- display?: string;
48
- /** Legal name */
49
- legal?: string;
50
- /** Web URL */
51
- web?: string;
52
- /** Email */
53
- email?: string;
54
- /** Twitter handle */
55
- twitter?: string;
56
- /** Riot/Matrix handle */
57
- riot?: string;
58
- /** Additional fields */
59
- additional: Array<[string, string]>;
60
- }
61
-
62
- /**
63
- * DotNS (Polkadot Name Service) utilities
64
- *
65
- * Provides name resolution for .dot domains
66
- */
67
-
68
- type AnyDescriptorEntry<T> = Record<string, Record<string, T>>;
69
- type PeopleUsernameStorage = {
70
- Resources: {
71
- UsernameOwnerOf: StorageDescriptor<[Uint8Array], SS58String, true, never>;
72
- };
73
- };
74
- type PeopleUsernamePallets = PalletsTypedef<PeopleUsernameStorage, AnyDescriptorEntry<TxDescriptor<any>>, AnyDescriptorEntry<PlainDescriptor<any>>, AnyDescriptorEntry<PlainDescriptor<any>>, AnyDescriptorEntry<PlainDescriptor<any>>, AnyDescriptorEntry<RuntimeDescriptor<any, any>>>;
75
- /**
76
- * Descriptor narrowed to "any chain that exposes `Resources.UsernameOwnerOf`".
77
- *
78
- * Used as the input to `signMessageWithDotNsIdentity` so the SDK doesn't pin
79
- * a specific People-chain genesis — anything with the right storage shape
80
- * (paseo-individuality today, future People Lite, etc.) is accepted.
81
- */
82
- type PeopleUsernameChain = ChainDefinition & {
83
- descriptors: Promise<unknown> & {
84
- pallets: PeopleUsernamePallets;
85
- };
86
- };
87
- /**
88
- * Minimal typed-api shape required to resolve a username on a People chain.
89
- *
90
- * This is a narrow structural type — anything with the right
91
- * `query.Resources.UsernameOwnerOf.getValue` shape works, including a real
92
- * `TypedApi<PeopleUsernameChain>` slice of a `ChainClient` or a hand-rolled
93
- * test double.
94
- */
95
- type PeopleUsernameQueryApi = {
96
- query: {
97
- Resources: {
98
- UsernameOwnerOf: {
99
- getValue: (key: Uint8Array) => Promise<SS58String | undefined>;
100
- };
101
- };
102
- };
103
- };
104
- /**
105
- * Check if a string is a valid DotNS name
106
- *
107
- * @param name - Name to validate
108
- * @returns True if valid DotNS name
109
- */
110
- declare function isValidDotNsName(name: string): boolean;
111
- /**
112
- * Normalize a DotNS name (lowercase, trim whitespace)
113
- *
114
- * @param name - Name to normalize
115
- * @returns Normalized name
116
- */
117
- declare function normalizeDotNsName(name: string): string;
118
- /**
119
- * Resolve a DotNS name to an address.
120
- *
121
- * @deprecated Not implemented — throws at runtime. Use
122
- * `wallet.signMessageWithDotNsIdentity({ peopleChain, username })` (which
123
- * internally calls {@link resolvePeopleUsernameOwner}) for the supported
124
- * People-chain username flow.
125
- *
126
- * @param name - DotNS name (e.g., "alice.dot")
127
- * @returns Resolved record or null if not found
128
- */
129
- declare function resolveDotNs(name: string): Promise<DotNsRecord | null>;
130
- /**
131
- * Reverse resolve an address to a DotNS name.
132
- *
133
- * @deprecated Not implemented — throws at runtime. Reverse lookup will land
134
- * alongside future identity work; for now resolve forward via
135
- * `wallet.signMessageWithDotNsIdentity`.
136
- *
137
- * @param address - SS58 address
138
- * @returns Primary name or null if none set
139
- */
140
- declare function reverseDotNs(address: string): Promise<string | null>;
141
- /**
142
- * Check if a DotNS name is available for registration.
143
- *
144
- * @deprecated Not implemented — depends on {@link resolveDotNs} which throws.
145
- *
146
- * @param name - Name to check
147
- * @returns True if available
148
- */
149
- declare function isDotNsAvailable(name: string): Promise<boolean>;
150
- /**
151
- * Resolve a People / People Lite username to its owning `AccountId32`.
152
- *
153
- * Queries `Resources.UsernameOwnerOf` on the caller-supplied typed-api fragment.
154
- * The returned value is the raw 32-byte account id as a `0x`-prefixed hex
155
- * string, or `null` when no owner is registered for that username.
156
- *
157
- * The `username` is UTF-8 encoded as-is — no normalization is applied. Pass
158
- * the exact byte string the chain stores (typically with the `.dot` suffix).
159
- *
160
- * @internal Exposed for unit testing. Consumers should use
161
- * `wallet.signMessageWithDotNsIdentity` instead, which orchestrates the
162
- * chain-connection lifecycle.
163
- */
164
- declare function resolvePeopleUsernameOwner(username: string, peopleApi: PeopleUsernameQueryApi): Promise<`0x${string}` | null>;
165
- declare function accountIdHexToBytes(accountId: `0x${string}`): Uint8Array;
166
-
167
- export { type ContextAliasInfo as C, type DotNsRecord as D, type OnChainIdentity as O, type PeopleUsernameChain as P, type VerificationResult as V, type PeopleUsernameQueryApi as a, accountIdHexToBytes as b, isValidDotNsName as c, resolvePeopleUsernameOwner as d, reverseDotNs as e, isDotNsAvailable as i, normalizeDotNsName as n, resolveDotNs as r };