@parity/product-sdk-signer 0.6.4 → 0.8.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/index.d.ts +71 -6
- package/dist/index.js +72 -2
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
- package/src/errors.ts +12 -1
- package/src/providers/host.ts +307 -16
- package/src/signer-manager.ts +86 -0
package/dist/index.d.ts
CHANGED
|
@@ -199,7 +199,18 @@ type OnConnect = (account: SignerAccount, ctx: ConnectContext) => void | Promise
|
|
|
199
199
|
declare class SignerError extends Error {
|
|
200
200
|
constructor(message: string, options?: ErrorOptions);
|
|
201
201
|
}
|
|
202
|
-
/**
|
|
202
|
+
/**
|
|
203
|
+
* The Host API is not available.
|
|
204
|
+
*
|
|
205
|
+
* Common causes:
|
|
206
|
+
* - The app is loaded outside a Polkadot host container (a regular browser tab
|
|
207
|
+
* under `npm run dev`, no iframe, no WebView). This is the dominant case
|
|
208
|
+
* during local development.
|
|
209
|
+
* - The optional `@novasamatech/host-api(-wrapper)` peer is not installed.
|
|
210
|
+
*
|
|
211
|
+
* Branch with `instanceof HostUnavailableError` to surface a "open this app
|
|
212
|
+
* in a Polkadot host, or pick a dev provider" message to the user.
|
|
213
|
+
*/
|
|
203
214
|
declare class HostUnavailableError extends SignerError {
|
|
204
215
|
constructor(message?: string);
|
|
205
216
|
}
|
|
@@ -277,8 +288,6 @@ interface HostProviderOptions {
|
|
|
277
288
|
* `dotNsIdentifier`, skipping the legacy fetch entirely. For apps
|
|
278
289
|
* that sign exclusively with a per-dapp derived account.
|
|
279
290
|
*
|
|
280
|
-
* `SignerAccount.name` is populated best-effort from
|
|
281
|
-
* `accounts.getUserId().primaryUsername`; failures leave it null.
|
|
282
291
|
* Signing is pinned to `createTransaction` (see PR #96).
|
|
283
292
|
*/
|
|
284
293
|
productAccount?: {
|
|
@@ -286,6 +295,20 @@ interface HostProviderOptions {
|
|
|
286
295
|
dotNsIdentifier: string;
|
|
287
296
|
/** Derivation index within the app scope. Default: 0. */
|
|
288
297
|
derivationIndex?: number;
|
|
298
|
+
/**
|
|
299
|
+
* Populate `SignerAccount.name` best-effort from
|
|
300
|
+
* `accounts.getUserId().primaryUsername`.
|
|
301
|
+
*
|
|
302
|
+
* On by default. Set to `false` to skip the fetch: `getUserId`
|
|
303
|
+
* triggers a host identity-permission prompt, so apps that don't
|
|
304
|
+
* render the user's name (those with their own display chain, e.g.
|
|
305
|
+
* registry username → fallback) can opt out and avoid the prompt.
|
|
306
|
+
* When enabled and the fetch fails (NotConnected, PermissionDenied,
|
|
307
|
+
* codec drift) the name stays null and connect still succeeds. The
|
|
308
|
+
* name can also be fetched later on demand via
|
|
309
|
+
* {@link HostProvider.getUserId}. Default: `true`.
|
|
310
|
+
*/
|
|
311
|
+
requestName?: boolean;
|
|
289
312
|
};
|
|
290
313
|
}
|
|
291
314
|
/**
|
|
@@ -368,13 +391,28 @@ interface ProductSdkModule {
|
|
|
368
391
|
createAccountsProvider: () => AccountsProvider;
|
|
369
392
|
/** Present from product-sdk ≥ 0.6; used to request TransactionSubmit. */
|
|
370
393
|
hostApi?: HostApiPermissionBridge;
|
|
394
|
+
/**
|
|
395
|
+
* `sandboxTransport.isCorrectEnvironment()` returns `false` when the app
|
|
396
|
+
* is loaded outside a Polkadot host container (e.g. a regular browser
|
|
397
|
+
* tab). Calling `getLegacyAccounts()` / `getProductAccount()` in that
|
|
398
|
+
* state surfaces the upstream `Environment is not correct` exception,
|
|
399
|
+
* so we pre-check during `connect()` and raise a specific
|
|
400
|
+
* {@link HostUnavailableError} with actionable guidance instead.
|
|
401
|
+
*/
|
|
402
|
+
sandboxTransport?: {
|
|
403
|
+
isCorrectEnvironment(): boolean;
|
|
404
|
+
};
|
|
371
405
|
}
|
|
372
406
|
/**
|
|
373
407
|
* Provider for the Host API (Polkadot Desktop / Android).
|
|
374
408
|
*
|
|
375
|
-
* Dynamically imports `@novasamatech/host-api-wrapper` at runtime
|
|
376
|
-
*
|
|
377
|
-
*
|
|
409
|
+
* Dynamically imports `@novasamatech/host-api-wrapper` at runtime. Apps running
|
|
410
|
+
* outside a host container — e.g. a plain browser tab during `npm run dev` —
|
|
411
|
+
* resolve to {@link HostUnavailableError} with guidance on what to do (open
|
|
412
|
+
* the app inside a Polkadot host or pick a non-host provider). The check uses
|
|
413
|
+
* the wrapper's `sandboxTransport.isCorrectEnvironment()` predicate and runs
|
|
414
|
+
* before any host RPC call, so the user never sees the upstream
|
|
415
|
+
* `Environment is not correct` exception leaking through.
|
|
378
416
|
*
|
|
379
417
|
* Supports both non-product accounts (user's external wallets) and product
|
|
380
418
|
* accounts (app-scoped derived accounts managed by the host).
|
|
@@ -429,6 +467,22 @@ declare class HostProvider implements SignerProvider {
|
|
|
429
467
|
* Requires a prior successful `connect()` call.
|
|
430
468
|
*/
|
|
431
469
|
getProductAccountAlias(dotNsIdentifier: string, derivationIndex?: number): Promise<Result<ContextualAlias, SignerError>>;
|
|
470
|
+
/**
|
|
471
|
+
* Fetch the connected user's primary username from the host.
|
|
472
|
+
*
|
|
473
|
+
* Use this to retrieve the name lazily — e.g. on a profile screen that
|
|
474
|
+
* actually displays it — when `connect()` ran without
|
|
475
|
+
* `productAccount.requestName` (the default) and so never fetched it.
|
|
476
|
+
* Like the connect-time fetch this triggers a host identity-permission
|
|
477
|
+
* prompt; unlike it, the result is returned as a structured `Result` so
|
|
478
|
+
* callers can react to a `PermissionDenied` / `NotConnected` rejection
|
|
479
|
+
* explicitly instead of silently falling back to a nameless account.
|
|
480
|
+
*
|
|
481
|
+
* Requires a prior successful `connect()` call.
|
|
482
|
+
*/
|
|
483
|
+
getUserId(): Promise<Result<{
|
|
484
|
+
primaryUsername: string;
|
|
485
|
+
}, SignerError>>;
|
|
432
486
|
/**
|
|
433
487
|
* Create a Ring VRF proof for anonymous operations.
|
|
434
488
|
*
|
|
@@ -589,6 +643,17 @@ declare class SignerManager {
|
|
|
589
643
|
* Returns a SIGNING_FAILED error if no account is selected or signing fails.
|
|
590
644
|
*/
|
|
591
645
|
signRaw(data: Uint8Array): Promise<Result<Uint8Array, SignerError>>;
|
|
646
|
+
/**
|
|
647
|
+
* Fetch the connected user's host identity.
|
|
648
|
+
*
|
|
649
|
+
* This uses the Host API identity permission path and is only available
|
|
650
|
+
* when connected through the host provider. The primary username can be
|
|
651
|
+
* used by higher-level helpers that need to bind an action to the user's
|
|
652
|
+
* DotNS / people username.
|
|
653
|
+
*/
|
|
654
|
+
getUserId(): Promise<Result<{
|
|
655
|
+
primaryUsername: string;
|
|
656
|
+
}, SignerError>>;
|
|
592
657
|
/**
|
|
593
658
|
* Get an app-scoped product account from the host.
|
|
594
659
|
*
|
package/dist/index.js
CHANGED
|
@@ -348,6 +348,40 @@ var HostProvider = class {
|
|
|
348
348
|
);
|
|
349
349
|
}
|
|
350
350
|
}
|
|
351
|
+
/**
|
|
352
|
+
* Fetch the connected user's primary username from the host.
|
|
353
|
+
*
|
|
354
|
+
* Use this to retrieve the name lazily — e.g. on a profile screen that
|
|
355
|
+
* actually displays it — when `connect()` ran without
|
|
356
|
+
* `productAccount.requestName` (the default) and so never fetched it.
|
|
357
|
+
* Like the connect-time fetch this triggers a host identity-permission
|
|
358
|
+
* prompt; unlike it, the result is returned as a structured `Result` so
|
|
359
|
+
* callers can react to a `PermissionDenied` / `NotConnected` rejection
|
|
360
|
+
* explicitly instead of silently falling back to a nameless account.
|
|
361
|
+
*
|
|
362
|
+
* Requires a prior successful `connect()` call.
|
|
363
|
+
*/
|
|
364
|
+
async getUserId() {
|
|
365
|
+
if (!this.accountsProvider) {
|
|
366
|
+
return err(new HostUnavailableError("Host provider is not connected"));
|
|
367
|
+
}
|
|
368
|
+
try {
|
|
369
|
+
const result = await this.accountsProvider.getUserId().match(
|
|
370
|
+
(value) => value,
|
|
371
|
+
(error) => {
|
|
372
|
+
throw new Error(`Host rejected user id request: ${formatError(error)}`);
|
|
373
|
+
}
|
|
374
|
+
);
|
|
375
|
+
return ok(result);
|
|
376
|
+
} catch (cause) {
|
|
377
|
+
log2.error("failed to get user id", { cause });
|
|
378
|
+
return err(
|
|
379
|
+
new HostRejectedError(
|
|
380
|
+
cause instanceof Error ? cause.message : "Failed to get user id"
|
|
381
|
+
)
|
|
382
|
+
);
|
|
383
|
+
}
|
|
384
|
+
}
|
|
351
385
|
/**
|
|
352
386
|
* Create a Ring VRF proof for anonymous operations.
|
|
353
387
|
*
|
|
@@ -392,6 +426,14 @@ var HostProvider = class {
|
|
|
392
426
|
)
|
|
393
427
|
);
|
|
394
428
|
}
|
|
429
|
+
if (sdk.sandboxTransport && !sdk.sandboxTransport.isCorrectEnvironment()) {
|
|
430
|
+
log2.warn("not inside a host container \u2014 Host API unavailable");
|
|
431
|
+
return err(
|
|
432
|
+
new HostUnavailableError(
|
|
433
|
+
"Host API is not available: not running inside a Polkadot host container. Open this app inside Polkadot Desktop or the Polkadot Mobile WebView, or pick a non-host signer provider (e.g. dev accounts)."
|
|
434
|
+
)
|
|
435
|
+
);
|
|
436
|
+
}
|
|
395
437
|
const provider = sdk.createAccountsProvider();
|
|
396
438
|
this.accountsProvider = provider;
|
|
397
439
|
let signerAccounts;
|
|
@@ -399,7 +441,8 @@ var HostProvider = class {
|
|
|
399
441
|
const accountResult = await this.fetchProductSignerAccount(
|
|
400
442
|
provider,
|
|
401
443
|
this.productAccount.dotNsIdentifier,
|
|
402
|
-
this.productAccount.derivationIndex ?? 0
|
|
444
|
+
this.productAccount.derivationIndex ?? 0,
|
|
445
|
+
this.productAccount.requestName ?? true
|
|
403
446
|
);
|
|
404
447
|
if (!accountResult.ok) return accountResult;
|
|
405
448
|
signerAccounts = [accountResult.value];
|
|
@@ -413,6 +456,14 @@ var HostProvider = class {
|
|
|
413
456
|
}
|
|
414
457
|
);
|
|
415
458
|
} catch (cause) {
|
|
459
|
+
if (cause instanceof Error && /environment is not correct/i.test(cause.message)) {
|
|
460
|
+
log2.warn("not inside a host container (detected at getLegacyAccounts)");
|
|
461
|
+
return err(
|
|
462
|
+
new HostUnavailableError(
|
|
463
|
+
"Host API is not available: not running inside a Polkadot host container. Open this app inside Polkadot Desktop or the Polkadot Mobile WebView, or pick a non-host signer provider (e.g. dev accounts)."
|
|
464
|
+
)
|
|
465
|
+
);
|
|
466
|
+
}
|
|
416
467
|
log2.error("failed to get accounts from host", { cause });
|
|
417
468
|
return err(
|
|
418
469
|
new HostRejectedError(
|
|
@@ -458,8 +509,9 @@ var HostProvider = class {
|
|
|
458
509
|
this.statusCleanup = typeof sub === "function" ? sub : () => sub.unsubscribe();
|
|
459
510
|
return ok(signerAccounts);
|
|
460
511
|
}
|
|
461
|
-
async fetchProductSignerAccount(provider, dotNsIdentifier, derivationIndex) {
|
|
512
|
+
async fetchProductSignerAccount(provider, dotNsIdentifier, derivationIndex, requestName) {
|
|
462
513
|
const fetchUsername = async () => {
|
|
514
|
+
if (!requestName) return null;
|
|
463
515
|
try {
|
|
464
516
|
return await provider.getUserId().match(
|
|
465
517
|
(result) => result.primaryUsername,
|
|
@@ -723,6 +775,24 @@ var SignerManager = class {
|
|
|
723
775
|
}
|
|
724
776
|
}
|
|
725
777
|
// ── Host-only: Product Account API ─────────────────────────────
|
|
778
|
+
/**
|
|
779
|
+
* Fetch the connected user's host identity.
|
|
780
|
+
*
|
|
781
|
+
* This uses the Host API identity permission path and is only available
|
|
782
|
+
* when connected through the host provider. The primary username can be
|
|
783
|
+
* used by higher-level helpers that need to bind an action to the user's
|
|
784
|
+
* DotNS / people username.
|
|
785
|
+
*/
|
|
786
|
+
async getUserId() {
|
|
787
|
+
if (this.isDestroyed) return err(new DestroyedError());
|
|
788
|
+
const host = this.getHostProvider();
|
|
789
|
+
if (!host) {
|
|
790
|
+
return err(
|
|
791
|
+
new HostUnavailableError("User identity requires a host provider connection")
|
|
792
|
+
);
|
|
793
|
+
}
|
|
794
|
+
return host.getUserId();
|
|
795
|
+
}
|
|
726
796
|
/**
|
|
727
797
|
* Get an app-scoped product account from the host.
|
|
728
798
|
*
|