@novasamatech/host-api-wrapper 0.9.4 → 0.10.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/README.md +45 -0
- package/dist/accounts.d.ts +15 -11
- package/dist/accounts.js +74 -49
- package/dist/coinPayment.d.ts +35 -0
- package/dist/coinPayment.js +67 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +4 -0
- package/dist/localStorage.d.ts +7 -0
- package/dist/localStorage.js +22 -0
- package/dist/locale.d.ts +6 -0
- package/dist/locale.js +18 -0
- package/dist/papiProvider.js +3 -1
- package/dist/system.d.ts +13 -0
- package/dist/system.js +18 -0
- package/dist/worker.d.ts +9 -0
- package/dist/worker.js +22 -0
- package/package.json +5 -4
package/README.md
CHANGED
|
@@ -402,6 +402,17 @@ const config = await storage.readJSON('config');
|
|
|
402
402
|
|
|
403
403
|
// Clear a key
|
|
404
404
|
await storage.clear('key');
|
|
405
|
+
|
|
406
|
+
// Subscribe to a key. The callback fires with the current value right away,
|
|
407
|
+
// then on every later write or clear. `undefined` means the key is absent.
|
|
408
|
+
const sub = storage.subscribeBytes('key', (bytes) => {
|
|
409
|
+
console.log('key changed:', bytes);
|
|
410
|
+
});
|
|
411
|
+
storage.subscribeString('greeting', (text) => console.log(text));
|
|
412
|
+
storage.subscribeJSON('config', (value) => console.log(value));
|
|
413
|
+
|
|
414
|
+
// Stop receiving updates
|
|
415
|
+
sub.unsubscribe();
|
|
405
416
|
```
|
|
406
417
|
|
|
407
418
|
### Derive Entropy
|
|
@@ -509,3 +520,37 @@ const statusSub = payments.subscribePaymentStatus(receipt.id, status => {
|
|
|
509
520
|
if (status.type === 'failed') console.log('Payment failed:', status.reason);
|
|
510
521
|
});
|
|
511
522
|
```
|
|
523
|
+
|
|
524
|
+
### Coin payment (RFC 0017)
|
|
525
|
+
|
|
526
|
+
Firewalled purses, cheques, and receivables. The long-running operations
|
|
527
|
+
(rebalance, delete, deposit, refund, listen) stream clearing status through a
|
|
528
|
+
callback and return a `Subscription`; `onInterrupt` fires with a
|
|
529
|
+
`CoinPaymentErr` if the host tears the stream down.
|
|
530
|
+
|
|
531
|
+
```ts
|
|
532
|
+
import { createCoinPayment } from '@novasamatech/host-api-wrapper';
|
|
533
|
+
|
|
534
|
+
const coinPayment = createCoinPayment();
|
|
535
|
+
|
|
536
|
+
// Create a purse and read it back
|
|
537
|
+
const purse = await coinPayment.createPurse('Terminal purse');
|
|
538
|
+
const info = await coinPayment.queryPurse(purse);
|
|
539
|
+
console.log('balance:', info.balance);
|
|
540
|
+
|
|
541
|
+
// Pay a receivable with a cheque
|
|
542
|
+
const receivable = await coinPayment.createReceivable(purse);
|
|
543
|
+
const cheque = await coinPayment.createCheque(purse, receivable, 1000);
|
|
544
|
+
|
|
545
|
+
// Claim the cheque, watching the coins clear
|
|
546
|
+
const sub = coinPayment.deposit(cheque, status => {
|
|
547
|
+
if (status.tag === 'Done') console.log('cleared:', status.value.cleared);
|
|
548
|
+
if (status.tag === 'Failed') console.log('failed:', status.value.error);
|
|
549
|
+
});
|
|
550
|
+
sub.onInterrupt(err => console.log('deposit interrupted:', err));
|
|
551
|
+
|
|
552
|
+
// Wait for a cheque delivered over a standard channel
|
|
553
|
+
coinPayment.listenForPayment(receivable, item => {
|
|
554
|
+
if (item.tag === 'Cheque') console.log('received cheque:', item.value.amount);
|
|
555
|
+
});
|
|
556
|
+
```
|
package/dist/accounts.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { AccountConnectionStatus as AccountConnectionStatusCodec, AccountSelector, CodecType, LegacyAccount as LegacyAccountCodec, ProductAccountId as ProductAccountIdCodec, RegisteredRingVrfKey as RegisteredRingVrfKeyCodec, RingVrfKeyDisclosure as RingVrfKeyDisclosureCodec, RingVrfKeyHandle as RingVrfKeyHandleCodec, Subscription, Transport, VrfTranscriptItem as VrfTranscriptItemCodec } from '@novasamatech/host-api';
|
|
2
2
|
import { RingLocation } from '@novasamatech/host-api';
|
|
3
|
-
import type {
|
|
3
|
+
import type { SignerTxCreator } from 'polkadot-api/tx-creator';
|
|
4
4
|
export type { AccountSelector } from '@novasamatech/host-api';
|
|
5
5
|
export type ProductAccountId = CodecType<typeof ProductAccountIdCodec>;
|
|
6
6
|
export type ProductAccount = {
|
|
@@ -182,14 +182,16 @@ export declare const createAccountsProvider: (transport?: Transport) => {
|
|
|
182
182
|
reason: string;
|
|
183
183
|
}, "SignVrfErr::Unknown">>;
|
|
184
184
|
/**
|
|
185
|
-
* Builds a `
|
|
185
|
+
* Builds a `TxCreator` (polkadot-api v3) that delegates to the host via
|
|
186
|
+
* `host_create_transaction`. The host keeps ownership of extension inference
|
|
187
|
+
* and signing; the creator maps the v3 `TxPayloadV1` onto the host codec.
|
|
186
188
|
*
|
|
187
|
-
*
|
|
188
|
-
* `
|
|
189
|
+
* `publicKey` is exposed synchronously on the returned object and is taken
|
|
190
|
+
* from `account`, so no up-front `host_account_get` is needed.
|
|
189
191
|
*/
|
|
190
|
-
getProductAccountSigner(account: ProductAccount, signerType?: "signPayload" | "createTransaction"):
|
|
192
|
+
getProductAccountSigner(account: ProductAccount, signerType?: "signPayload" | "createTransaction"): SignerTxCreator;
|
|
191
193
|
subscribeAccountConnectionStatus(callback: (status: AccountConnectionStatus) => void): Subscription<void>;
|
|
192
|
-
getLegacyAccountSigner(account: LegacyAccount):
|
|
194
|
+
getLegacyAccountSigner(account: LegacyAccount): SignerTxCreator;
|
|
193
195
|
};
|
|
194
196
|
export declare const accounts: {
|
|
195
197
|
getUserId(): import("neverthrow").ResultAsync<{
|
|
@@ -328,12 +330,14 @@ export declare const accounts: {
|
|
|
328
330
|
reason: string;
|
|
329
331
|
}, "SignVrfErr::Unknown">>;
|
|
330
332
|
/**
|
|
331
|
-
* Builds a `
|
|
333
|
+
* Builds a `TxCreator` (polkadot-api v3) that delegates to the host via
|
|
334
|
+
* `host_create_transaction`. The host keeps ownership of extension inference
|
|
335
|
+
* and signing; the creator maps the v3 `TxPayloadV1` onto the host codec.
|
|
332
336
|
*
|
|
333
|
-
*
|
|
334
|
-
* `
|
|
337
|
+
* `publicKey` is exposed synchronously on the returned object and is taken
|
|
338
|
+
* from `account`, so no up-front `host_account_get` is needed.
|
|
335
339
|
*/
|
|
336
|
-
getProductAccountSigner(account: ProductAccount, signerType?: "signPayload" | "createTransaction"):
|
|
340
|
+
getProductAccountSigner(account: ProductAccount, signerType?: "signPayload" | "createTransaction"): SignerTxCreator;
|
|
337
341
|
subscribeAccountConnectionStatus(callback: (status: AccountConnectionStatus) => void): Subscription<void>;
|
|
338
|
-
getLegacyAccountSigner(account: LegacyAccount):
|
|
342
|
+
getLegacyAccountSigner(account: LegacyAccount): SignerTxCreator;
|
|
339
343
|
};
|
package/dist/accounts.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { CreateProofErr, GetAliasErr, GetUserIdErr, ListRingVrfKeysErr, LoginErr, ProductProofContext, RegisterRingVrfKeyErr, RequestCredentialsErr, RingLocation, RingVrfSignErr, SignVrfErr, SigningPayload, SigningPayloadWithoutAccount, SigningRawPayload, SigningRawPayloadWithoutAccount, assertEnumVariant, createHostApi, derivationIndexOf, enumValue, fromHex, isEnumVariant, toHex, } from '@novasamatech/host-api';
|
|
2
|
+
import { createV4Tx } from '@polkadot-api/signers-common';
|
|
2
3
|
import { decAnyMetadata, unifyMetadata } from '@polkadot-api/substrate-bindings';
|
|
3
4
|
import { err, ok } from 'neverthrow';
|
|
4
5
|
import { AccountId } from 'polkadot-api';
|
|
5
|
-
import {
|
|
6
|
+
import { getTxCreatorFromPjs } from 'polkadot-api/pjs-signer';
|
|
6
7
|
import { sandboxTransport } from './sandboxTransport.js';
|
|
7
8
|
/**
|
|
8
9
|
* Builds a {@link RingVrfKeyHandle} for a key inside `owner`'s ring VRF domain.
|
|
@@ -206,10 +207,12 @@ export const createAccountsProvider = (transport = sandboxTransport) => {
|
|
|
206
207
|
});
|
|
207
208
|
},
|
|
208
209
|
/**
|
|
209
|
-
* Builds a `
|
|
210
|
+
* Builds a `TxCreator` (polkadot-api v3) that delegates to the host via
|
|
211
|
+
* `host_create_transaction`. The host keeps ownership of extension inference
|
|
212
|
+
* and signing; the creator maps the v3 `TxPayloadV1` onto the host codec.
|
|
210
213
|
*
|
|
211
|
-
*
|
|
212
|
-
* `
|
|
214
|
+
* `publicKey` is exposed synchronously on the returned object and is taken
|
|
215
|
+
* from `account`, so no up-front `host_account_get` is needed.
|
|
213
216
|
*/
|
|
214
217
|
getProductAccountSigner(account, signerType = 'createTransaction') {
|
|
215
218
|
const hostApi = createHostApi(transport);
|
|
@@ -218,7 +221,7 @@ export const createAccountsProvider = (transport = sandboxTransport) => {
|
|
|
218
221
|
* @deprecated added for backward compatibility
|
|
219
222
|
*/
|
|
220
223
|
if (signerType === 'signPayload') {
|
|
221
|
-
return
|
|
224
|
+
return getTxCreatorFromPjs(toHex(account.publicKey), async (payload) => {
|
|
222
225
|
const codecPayload = {
|
|
223
226
|
account: productAccountId,
|
|
224
227
|
payload: buildSigningPayloadFields(payload),
|
|
@@ -262,51 +265,66 @@ export const createAccountsProvider = (transport = sandboxTransport) => {
|
|
|
262
265
|
});
|
|
263
266
|
});
|
|
264
267
|
}
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
268
|
+
// v3 `TxCreator`: a callable that turns a `TxPayloadV1` into a
|
|
269
|
+
// SCALE-encoded extrinsic (hex). A real signature is produced by the host
|
|
270
|
+
// via `host_create_transaction`; a mocked signature (fee estimation) is
|
|
271
|
+
// built locally with a zero-filled signature and no host round-trip,
|
|
272
|
+
// mirroring polkadot-api's own `getTxCreator`.
|
|
273
|
+
const createTx = async (payload, _opts, _bindings, mockedSignature) => {
|
|
274
|
+
// Fee estimation on a v4 extrinsic: build a zero-signed extrinsic
|
|
275
|
+
// locally, with no host round-trip and no real signature. polkadot-api
|
|
276
|
+
// has no local builder for other versions (e.g. v5), so those fall
|
|
277
|
+
// through to the host path below, which returns a well-formed extrinsic
|
|
278
|
+
// of the right size for estimation.
|
|
279
|
+
if (mockedSignature && (payload.txExtVersion ?? 0) === 0) {
|
|
280
|
+
const decMeta = unifyMetadata(decAnyMetadata(payload.context.metadata));
|
|
281
|
+
const v4Extensions = decMeta.extrinsic.extensionsByVersion[0];
|
|
282
|
+
if (v4Extensions) {
|
|
283
|
+
const extra = v4Extensions.map(({ identifier }) => {
|
|
284
|
+
const extension = payload.extensions.find(({ id }) => id === identifier);
|
|
285
|
+
if (!extension) {
|
|
286
|
+
throw new Error(`Missing ${identifier} signed extension`);
|
|
287
|
+
}
|
|
288
|
+
return fromHex(extension.extra);
|
|
289
|
+
});
|
|
290
|
+
const mockSr25519Signature = new Uint8Array(64);
|
|
291
|
+
return toHex(createV4Tx(decMeta, account.publicKey, mockSr25519Signature, extra, fromHex(payload.callData), 'Sr25519'));
|
|
275
292
|
}
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
}
|
|
296
|
-
async signBytes(data) {
|
|
297
|
-
const response = await hostApi.signRaw(enumValue('v1', {
|
|
298
|
-
account: productAccountId,
|
|
299
|
-
payload: { tag: 'Bytes', value: data },
|
|
300
|
-
}));
|
|
301
|
-
return response.match(response => {
|
|
302
|
-
assertEnumVariant(response, 'v1', UNSUPPORTED_VERSION_ERROR);
|
|
303
|
-
return fromHex(response.value.signature);
|
|
304
|
-
}, err => {
|
|
305
|
-
assertEnumVariant(err, 'v1', UNSUPPORTED_VERSION_ERROR);
|
|
306
|
-
throw err.value;
|
|
307
|
-
});
|
|
308
|
-
},
|
|
293
|
+
}
|
|
294
|
+
const txPayload = {
|
|
295
|
+
signer: productAccountId,
|
|
296
|
+
genesisHash: payload.context.genesisHash,
|
|
297
|
+
callData: fromHex(payload.callData),
|
|
298
|
+
extensions: payload.extensions.map(({ id, extra, additionalSigned }) => ({
|
|
299
|
+
id,
|
|
300
|
+
extra: fromHex(extra),
|
|
301
|
+
additionalSigned: fromHex(additionalSigned),
|
|
302
|
+
})),
|
|
303
|
+
txExtVersion: payload.txExtVersion ?? deriveDefaultTxExtVersion(payload.context.metadata),
|
|
304
|
+
};
|
|
305
|
+
const response = await hostApi.createTransaction(enumValue('v1', txPayload));
|
|
306
|
+
return response.match(response => {
|
|
307
|
+
assertEnumVariant(response, 'v1', UNSUPPORTED_VERSION_ERROR);
|
|
308
|
+
return toHex(response.value);
|
|
309
|
+
}, err => {
|
|
310
|
+
assertEnumVariant(err, 'v1', UNSUPPORTED_VERSION_ERROR);
|
|
311
|
+
throw err.value;
|
|
312
|
+
});
|
|
309
313
|
};
|
|
314
|
+
const signBytes = async (data) => {
|
|
315
|
+
const response = await hostApi.signRaw(enumValue('v1', {
|
|
316
|
+
account: productAccountId,
|
|
317
|
+
payload: { tag: 'Bytes', value: data },
|
|
318
|
+
}));
|
|
319
|
+
return response.match(response => {
|
|
320
|
+
assertEnumVariant(response, 'v1', UNSUPPORTED_VERSION_ERROR);
|
|
321
|
+
return fromHex(response.value.signature);
|
|
322
|
+
}, err => {
|
|
323
|
+
assertEnumVariant(err, 'v1', UNSUPPORTED_VERSION_ERROR);
|
|
324
|
+
throw err.value;
|
|
325
|
+
});
|
|
326
|
+
};
|
|
327
|
+
return Object.assign(createTx, { publicKey: account.publicKey, signBytes });
|
|
310
328
|
},
|
|
311
329
|
subscribeAccountConnectionStatus(callback) {
|
|
312
330
|
const subscriber = hostApi.accountConnectionStatusSubscribe(enumValue('v1', undefined), status => {
|
|
@@ -325,7 +343,7 @@ export const createAccountsProvider = (transport = sandboxTransport) => {
|
|
|
325
343
|
// must be an SS58 address the wallet can match — not a raw hex public
|
|
326
344
|
// key. Mirrors the injected-extension path, which uses accountId.dec.
|
|
327
345
|
const accountId = AccountId();
|
|
328
|
-
return
|
|
346
|
+
return getTxCreatorFromPjs(accountId.dec(account.publicKey), async (payload) => {
|
|
329
347
|
const codecPayload = {
|
|
330
348
|
signer: payload.address,
|
|
331
349
|
payload: buildSigningPayloadFields(payload),
|
|
@@ -372,6 +390,13 @@ function asHex(v) {
|
|
|
372
390
|
return v;
|
|
373
391
|
return `0x${v}`;
|
|
374
392
|
}
|
|
393
|
+
// Default transaction-extension version to request when the caller leaves it
|
|
394
|
+
// unset: 0 for extrinsic v4, the version itself otherwise (e.g. v5).
|
|
395
|
+
function deriveDefaultTxExtVersion(metadata) {
|
|
396
|
+
const { version: versions } = unifyMetadata(decAnyMetadata(metadata)).extrinsic;
|
|
397
|
+
const latestVersion = versions.reduce((acc, v) => Math.max(acc, v), 0);
|
|
398
|
+
return latestVersion === 4 ? 0 : latestVersion;
|
|
399
|
+
}
|
|
375
400
|
function buildSigningPayloadFields(payload) {
|
|
376
401
|
return {
|
|
377
402
|
blockHash: asHex(payload.blockHash),
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { CodecType, CoinPaymentCheque, CoinPaymentErr, CoinPaymentListenForItem, CoinPaymentPurseInfo, CoinPaymentStatus, HexString, Subscription, Transport } from '@novasamatech/host-api';
|
|
2
|
+
/** Purse identifier (RFC 0017). `0xffffffff` is the well-known main purse. */
|
|
3
|
+
export type PurseId = number;
|
|
4
|
+
/** Receivable public key, as a 0x-prefixed 32-byte hex string. */
|
|
5
|
+
export type Receivable = HexString;
|
|
6
|
+
export type PurseInfo = CodecType<typeof CoinPaymentPurseInfo>;
|
|
7
|
+
export type Cheque = CodecType<typeof CoinPaymentCheque>;
|
|
8
|
+
/** Clearing status streamed by rebalance, delete, deposit, and refund. */
|
|
9
|
+
export type ClearingStatus = CodecType<typeof CoinPaymentStatus>;
|
|
10
|
+
/** Item streamed by `listenForPayment`: a delivery channel, then the cheque. */
|
|
11
|
+
export type PaymentDelivery = CodecType<typeof CoinPaymentListenForItem>;
|
|
12
|
+
type CoinPaymentInterrupt = CodecType<typeof CoinPaymentErr>;
|
|
13
|
+
export declare const createCoinPayment: (transport?: Transport) => {
|
|
14
|
+
createPurse(name: string): Promise<PurseId>;
|
|
15
|
+
queryPurse(purse: PurseId): Promise<PurseInfo>;
|
|
16
|
+
createReceivable(into: PurseId): Promise<Receivable>;
|
|
17
|
+
createCheque(from: PurseId, to: Receivable, amount: number): Promise<Cheque>;
|
|
18
|
+
rebalancePurse(from: PurseId, to: PurseId, amount: number, onStatus: (status: ClearingStatus) => void): Subscription<CoinPaymentInterrupt>;
|
|
19
|
+
deletePurse(target: PurseId, drainInto: PurseId, onStatus: (status: ClearingStatus) => void): Subscription<CoinPaymentInterrupt>;
|
|
20
|
+
deposit(cheque: Cheque, onStatus: (status: ClearingStatus) => void): Subscription<CoinPaymentInterrupt>;
|
|
21
|
+
refund(receivable: Receivable, onStatus: (status: ClearingStatus) => void): Subscription<CoinPaymentInterrupt>;
|
|
22
|
+
listenForPayment(receivable: Receivable, onDelivery: (item: PaymentDelivery) => void): Subscription<CoinPaymentInterrupt>;
|
|
23
|
+
};
|
|
24
|
+
export declare const hostCoinPayment: {
|
|
25
|
+
createPurse(name: string): Promise<PurseId>;
|
|
26
|
+
queryPurse(purse: PurseId): Promise<PurseInfo>;
|
|
27
|
+
createReceivable(into: PurseId): Promise<Receivable>;
|
|
28
|
+
createCheque(from: PurseId, to: Receivable, amount: number): Promise<Cheque>;
|
|
29
|
+
rebalancePurse(from: PurseId, to: PurseId, amount: number, onStatus: (status: ClearingStatus) => void): Subscription<CoinPaymentInterrupt>;
|
|
30
|
+
deletePurse(target: PurseId, drainInto: PurseId, onStatus: (status: ClearingStatus) => void): Subscription<CoinPaymentInterrupt>;
|
|
31
|
+
deposit(cheque: Cheque, onStatus: (status: ClearingStatus) => void): Subscription<CoinPaymentInterrupt>;
|
|
32
|
+
refund(receivable: Receivable, onStatus: (status: ClearingStatus) => void): Subscription<CoinPaymentInterrupt>;
|
|
33
|
+
listenForPayment(receivable: Receivable, onDelivery: (item: PaymentDelivery) => void): Subscription<CoinPaymentInterrupt>;
|
|
34
|
+
};
|
|
35
|
+
export {};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { createHostApi, enumValue } from '@novasamatech/host-api';
|
|
2
|
+
import { resultToPromise, unwrapVersionedResult } from './helpers.js';
|
|
3
|
+
import { sandboxTransport } from './sandboxTransport.js';
|
|
4
|
+
export const createCoinPayment = (transport = sandboxTransport) => {
|
|
5
|
+
const hostApi = createHostApi(transport);
|
|
6
|
+
const version = 'v1';
|
|
7
|
+
function stream(subscriber) {
|
|
8
|
+
return {
|
|
9
|
+
unsubscribe: subscriber.unsubscribe,
|
|
10
|
+
onInterrupt: cb => subscriber.onInterrupt(v => cb(v.value)),
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
return {
|
|
14
|
+
// Create a new firewalled purse and resolve with its assigned id.
|
|
15
|
+
createPurse(name) {
|
|
16
|
+
return resultToPromise(unwrapVersionedResult(version, hostApi.coinPaymentCreatePurse(enumValue(version, { name })))).then(({ purse }) => purse);
|
|
17
|
+
},
|
|
18
|
+
// Query product-visible metadata and balance for a purse.
|
|
19
|
+
queryPurse(purse) {
|
|
20
|
+
return resultToPromise(unwrapVersionedResult(version, hostApi.coinPaymentQueryPurse(enumValue(version, { purse })))).then(({ info }) => info);
|
|
21
|
+
},
|
|
22
|
+
// Create a fresh receivable public key for depositing into a purse.
|
|
23
|
+
createReceivable(into) {
|
|
24
|
+
return resultToPromise(unwrapVersionedResult(version, hostApi.coinPaymentCreateReceivable(enumValue(version, { into })))).then(({ receivable }) => receivable);
|
|
25
|
+
},
|
|
26
|
+
// Create a cheque paying from a local purse to a receivable.
|
|
27
|
+
createCheque(from, to, amount) {
|
|
28
|
+
return resultToPromise(unwrapVersionedResult(version, hostApi.coinPaymentCreateCheque(enumValue(version, { from, to, amount })))).then(({ cheque }) => cheque);
|
|
29
|
+
},
|
|
30
|
+
// Transfer balance between local purses, streaming clearing status.
|
|
31
|
+
rebalancePurse(from, to, amount, onStatus) {
|
|
32
|
+
return stream(hostApi.coinPaymentRebalancePurse(enumValue(version, { from, to, amount }), payload => {
|
|
33
|
+
if (payload.tag === version)
|
|
34
|
+
onStatus(payload.value);
|
|
35
|
+
}));
|
|
36
|
+
},
|
|
37
|
+
// Delete a purse after draining its balance into another local purse.
|
|
38
|
+
deletePurse(target, drainInto, onStatus) {
|
|
39
|
+
return stream(hostApi.coinPaymentDeletePurse(enumValue(version, { target, drainInto }), payload => {
|
|
40
|
+
if (payload.tag === version)
|
|
41
|
+
onStatus(payload.value);
|
|
42
|
+
}));
|
|
43
|
+
},
|
|
44
|
+
// Claim coins from a cheque into the receivable's purse.
|
|
45
|
+
deposit(cheque, onStatus) {
|
|
46
|
+
return stream(hostApi.coinPaymentDeposit(enumValue(version, { cheque }), payload => {
|
|
47
|
+
if (payload.tag === version)
|
|
48
|
+
onStatus(payload.value);
|
|
49
|
+
}));
|
|
50
|
+
},
|
|
51
|
+
// Attempt to return coins associated with a receivable.
|
|
52
|
+
refund(receivable, onStatus) {
|
|
53
|
+
return stream(hostApi.coinPaymentRefund(enumValue(version, { receivable }), payload => {
|
|
54
|
+
if (payload.tag === version)
|
|
55
|
+
onStatus(payload.value);
|
|
56
|
+
}));
|
|
57
|
+
},
|
|
58
|
+
// Listen for a cheque delivered through a standard transmission channel.
|
|
59
|
+
listenForPayment(receivable, onDelivery) {
|
|
60
|
+
return stream(hostApi.coinPaymentListenForPayment(enumValue(version, { receivable }), payload => {
|
|
61
|
+
if (payload.tag === version)
|
|
62
|
+
onDelivery(payload.value);
|
|
63
|
+
}));
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
};
|
|
67
|
+
export const hostCoinPayment = createCoinPayment();
|
package/dist/index.d.ts
CHANGED
|
@@ -10,9 +10,16 @@ export type { ProductAccountId, ProductAccountRef, SignedStatement, Statement, S
|
|
|
10
10
|
export { createStatementStore } from './statementStore.js';
|
|
11
11
|
export type { AccountConnectionStatus, AccountSelector, LegacyAccount, ProductAccount, ProofContext, RegisteredRingVrfKey, RingVrfKeyDisclosure, RingVrfKeyHandle, VrfTranscriptItem, } from './accounts.js';
|
|
12
12
|
export { accounts, createAccountsProvider, ringVrfKeyHandle } from './accounts.js';
|
|
13
|
+
export type { Locale } from './locale.js';
|
|
14
|
+
export { createLocaleProvider } from './locale.js';
|
|
13
15
|
export type { ThemeMode } from './theme.js';
|
|
14
16
|
export { createThemeProvider } from './theme.js';
|
|
15
17
|
export { createLocalStorage, hostLocalStorage } from './localStorage.js';
|
|
18
|
+
export { createWorker, hostWorker } from './worker.js';
|
|
19
|
+
export type { HostInfo, HostPlatform, ProductContext } from './system.js';
|
|
20
|
+
export { createSystem, hostSystem } from './system.js';
|
|
21
|
+
export type { Cheque, ClearingStatus, PaymentDelivery, PurseInfo, Receivable } from './coinPayment.js';
|
|
22
|
+
export { createCoinPayment, hostCoinPayment } from './coinPayment.js';
|
|
16
23
|
export type { NotificationId, PushNotificationInput } from './notification.js';
|
|
17
24
|
export { createNotificationManager, notificationManager } from './notification.js';
|
|
18
25
|
export { createPreimageManager, preimageManager } from './preimage.js';
|
package/dist/index.js
CHANGED
|
@@ -7,8 +7,12 @@ export { createPapiProvider } from './papiProvider.js';
|
|
|
7
7
|
export { createProductChatManager, matchChatCustomRenderers } from './chat.js';
|
|
8
8
|
export { createStatementStore } from './statementStore.js';
|
|
9
9
|
export { accounts, createAccountsProvider, ringVrfKeyHandle } from './accounts.js';
|
|
10
|
+
export { createLocaleProvider } from './locale.js';
|
|
10
11
|
export { createThemeProvider } from './theme.js';
|
|
11
12
|
export { createLocalStorage, hostLocalStorage } from './localStorage.js';
|
|
13
|
+
export { createWorker, hostWorker } from './worker.js';
|
|
14
|
+
export { createSystem, hostSystem } from './system.js';
|
|
15
|
+
export { createCoinPayment, hostCoinPayment } from './coinPayment.js';
|
|
12
16
|
export { createNotificationManager, notificationManager } from './notification.js';
|
|
13
17
|
export { createPreimageManager, preimageManager } from './preimage.js';
|
|
14
18
|
export { createPaymentManager, paymentManager } from './payments.js';
|
package/dist/localStorage.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { Subscription } from '@novasamatech/host-api';
|
|
1
2
|
export declare const createLocalStorage: (transport?: import("@novasamatech/host-api").Transport) => {
|
|
2
3
|
clear(key: string): Promise<undefined>;
|
|
3
4
|
readBytes(key: string): Promise<Uint8Array<ArrayBufferLike> | undefined>;
|
|
@@ -6,6 +7,9 @@ export declare const createLocalStorage: (transport?: import("@novasamatech/host
|
|
|
6
7
|
writeString(key: string, value: string): Promise<undefined>;
|
|
7
8
|
readJSON(key: string): Promise<any>;
|
|
8
9
|
writeJSON(key: string, value: unknown): Promise<undefined>;
|
|
10
|
+
subscribeBytes(key: string, callback: (value: Uint8Array | undefined) => void): Subscription<void>;
|
|
11
|
+
subscribeString(key: string, callback: (value: string | undefined) => void): Subscription<void>;
|
|
12
|
+
subscribeJSON(key: string, callback: (value: unknown) => void): Subscription<void>;
|
|
9
13
|
};
|
|
10
14
|
export declare const hostLocalStorage: {
|
|
11
15
|
clear(key: string): Promise<undefined>;
|
|
@@ -15,4 +19,7 @@ export declare const hostLocalStorage: {
|
|
|
15
19
|
writeString(key: string, value: string): Promise<undefined>;
|
|
16
20
|
readJSON(key: string): Promise<any>;
|
|
17
21
|
writeJSON(key: string, value: unknown): Promise<undefined>;
|
|
22
|
+
subscribeBytes(key: string, callback: (value: Uint8Array | undefined) => void): Subscription<void>;
|
|
23
|
+
subscribeString(key: string, callback: (value: string | undefined) => void): Subscription<void>;
|
|
24
|
+
subscribeJSON(key: string, callback: (value: unknown) => void): Subscription<void>;
|
|
18
25
|
};
|
package/dist/localStorage.js
CHANGED
|
@@ -15,6 +15,17 @@ export const createLocalStorage = (transport = sandboxTransport) => {
|
|
|
15
15
|
function clearKey(key) {
|
|
16
16
|
return resultToPromise(unwrapVersionedResult(supportedVersion, hostApi.localStorageClear(enumValue(supportedVersion, key))));
|
|
17
17
|
}
|
|
18
|
+
function subscribeBytes(key, callback) {
|
|
19
|
+
const subscriber = hostApi.localStorageSubscribe(enumValue(supportedVersion, { key }), item => {
|
|
20
|
+
if (item.tag === supportedVersion) {
|
|
21
|
+
callback(item.value.value);
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
return {
|
|
25
|
+
unsubscribe: subscriber.unsubscribe,
|
|
26
|
+
onInterrupt: cb => subscriber.onInterrupt(v => cb(v.value)),
|
|
27
|
+
};
|
|
28
|
+
}
|
|
18
29
|
return {
|
|
19
30
|
async clear(key) {
|
|
20
31
|
return clearKey(key);
|
|
@@ -40,6 +51,17 @@ export const createLocalStorage = (transport = sandboxTransport) => {
|
|
|
40
51
|
async writeJSON(key, value) {
|
|
41
52
|
return writeBytes(key, textEncoder.encode(JSON.stringify(value)));
|
|
42
53
|
},
|
|
54
|
+
// Emits the current value immediately, then on every later write or clear
|
|
55
|
+
// of the key. `undefined` means the key was cleared or is absent.
|
|
56
|
+
subscribeBytes(key, callback) {
|
|
57
|
+
return subscribeBytes(key, callback);
|
|
58
|
+
},
|
|
59
|
+
subscribeString(key, callback) {
|
|
60
|
+
return subscribeBytes(key, bytes => callback(bytes === undefined ? undefined : textDecoder.decode(bytes)));
|
|
61
|
+
},
|
|
62
|
+
subscribeJSON(key, callback) {
|
|
63
|
+
return subscribeBytes(key, bytes => callback(bytes === undefined || bytes.length === 0 ? undefined : JSON.parse(textDecoder.decode(bytes))));
|
|
64
|
+
},
|
|
43
65
|
};
|
|
44
66
|
};
|
|
45
67
|
export const hostLocalStorage = createLocalStorage();
|
package/dist/locale.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { CodecType, Subscription, Transport } from '@novasamatech/host-api';
|
|
2
|
+
import { HostLocale } from '@novasamatech/host-api';
|
|
3
|
+
export type Locale = CodecType<typeof HostLocale>;
|
|
4
|
+
export declare function createLocaleProvider(transport?: Transport): {
|
|
5
|
+
subscribeLocale(callback: (locale: Locale) => void): Subscription<void>;
|
|
6
|
+
};
|
package/dist/locale.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { HostLocale, createHostApi, enumValue } from '@novasamatech/host-api';
|
|
2
|
+
import { sandboxTransport } from './sandboxTransport.js';
|
|
3
|
+
export function createLocaleProvider(transport = sandboxTransport) {
|
|
4
|
+
const hostApi = createHostApi(transport);
|
|
5
|
+
return {
|
|
6
|
+
subscribeLocale(callback) {
|
|
7
|
+
const subscriber = hostApi.localeSubscribe(enumValue('v1', undefined), value => {
|
|
8
|
+
if (value.tag === 'v1') {
|
|
9
|
+
callback(value.value);
|
|
10
|
+
}
|
|
11
|
+
});
|
|
12
|
+
return {
|
|
13
|
+
unsubscribe: subscriber.unsubscribe,
|
|
14
|
+
onInterrupt: cb => subscriber.onInterrupt(v => cb(v.value)),
|
|
15
|
+
};
|
|
16
|
+
},
|
|
17
|
+
};
|
|
18
|
+
}
|
package/dist/papiProvider.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createHostApi, enumValue, unwrapResultOrThrow } from '@novasamatech/host-api';
|
|
1
|
+
import { createHostApi, enumValue, isCallErrorFailure, unwrapResultOrThrow } from '@novasamatech/host-api';
|
|
2
2
|
import { getSyncProvider } from '@polkadot-api/json-rpc-provider-proxy';
|
|
3
3
|
import { sandboxTransport } from './sandboxTransport.js';
|
|
4
4
|
export function createPapiProvider(genesisHash,
|
|
@@ -311,6 +311,8 @@ __fallback, internal) {
|
|
|
311
311
|
.then(payload => {
|
|
312
312
|
switch (payload.tag) {
|
|
313
313
|
case 'v1': {
|
|
314
|
+
if (isCallErrorFailure(payload.value))
|
|
315
|
+
return false;
|
|
314
316
|
return unwrapResultOrThrow(payload.value, e => new Error(e.payload.reason));
|
|
315
317
|
}
|
|
316
318
|
default:
|
package/dist/system.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { CodecType, Transport } from '@novasamatech/host-api';
|
|
2
|
+
import { HostInfo, HostPlatform, ProductContext } from '@novasamatech/host-api';
|
|
3
|
+
export type HostPlatform = CodecType<typeof HostPlatform>;
|
|
4
|
+
export type HostInfo = CodecType<typeof HostInfo>;
|
|
5
|
+
export type ProductContext = CodecType<typeof ProductContext>;
|
|
6
|
+
export declare const createSystem: (transport?: Transport) => {
|
|
7
|
+
info(): Promise<HostInfo>;
|
|
8
|
+
getProductContext(): Promise<ProductContext>;
|
|
9
|
+
};
|
|
10
|
+
export declare const hostSystem: {
|
|
11
|
+
info(): Promise<HostInfo>;
|
|
12
|
+
getProductContext(): Promise<ProductContext>;
|
|
13
|
+
};
|
package/dist/system.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { HostInfo, HostPlatform, ProductContext, createHostApi, enumValue } from '@novasamatech/host-api';
|
|
2
|
+
import { resultToPromise, unwrapVersionedResult } from './helpers.js';
|
|
3
|
+
import { sandboxTransport } from './sandboxTransport.js';
|
|
4
|
+
export const createSystem = (transport = sandboxTransport) => {
|
|
5
|
+
const supportedVersion = 'v1';
|
|
6
|
+
const hostApi = createHostApi(transport);
|
|
7
|
+
return {
|
|
8
|
+
// Identity and version of the host currently running the product.
|
|
9
|
+
async info() {
|
|
10
|
+
return resultToPromise(unwrapVersionedResult(supportedVersion, hostApi.info(enumValue(supportedVersion, undefined))));
|
|
11
|
+
},
|
|
12
|
+
// Product context bound to the current host runtime.
|
|
13
|
+
async getProductContext() {
|
|
14
|
+
return resultToPromise(unwrapVersionedResult(supportedVersion, hostApi.getProductContext(enumValue(supportedVersion, undefined))));
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
export const hostSystem = createSystem();
|
package/dist/worker.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Transport } from '@novasamatech/host-api';
|
|
2
|
+
export declare const createWorker: (transport?: Transport) => {
|
|
3
|
+
beginOperation(label?: string): Promise<number>;
|
|
4
|
+
endOperation(id: number): Promise<void>;
|
|
5
|
+
};
|
|
6
|
+
export declare const hostWorker: {
|
|
7
|
+
beginOperation(label?: string): Promise<number>;
|
|
8
|
+
endOperation(id: number): Promise<void>;
|
|
9
|
+
};
|
package/dist/worker.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { createHostApi, enumValue } from '@novasamatech/host-api';
|
|
2
|
+
import { resultToPromise, unwrapVersionedResult } from './helpers.js';
|
|
3
|
+
import { sandboxTransport } from './sandboxTransport.js';
|
|
4
|
+
export const createWorker = (transport = sandboxTransport) => {
|
|
5
|
+
const supportedVersion = 'v1';
|
|
6
|
+
const hostApi = createHostApi(transport);
|
|
7
|
+
return {
|
|
8
|
+
// Begin a pending operation. The host keeps this worker alive while it has
|
|
9
|
+
// at least one open operation, so a background task runs to completion even
|
|
10
|
+
// after the product's surface goes away. Returns the operation id.
|
|
11
|
+
async beginOperation(label) {
|
|
12
|
+
const { id } = await resultToPromise(unwrapVersionedResult(supportedVersion, hostApi.workerBeginOperation(enumValue(supportedVersion, { label }))));
|
|
13
|
+
return id;
|
|
14
|
+
},
|
|
15
|
+
// End a pending operation. Idempotent: an unknown or already-ended id
|
|
16
|
+
// still resolves.
|
|
17
|
+
async endOperation(id) {
|
|
18
|
+
return resultToPromise(unwrapVersionedResult(supportedVersion, hostApi.workerEndOperation(enumValue(supportedVersion, { id }))));
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
export const hostWorker = createWorker();
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@novasamatech/host-api-wrapper",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.10.1",
|
|
5
5
|
"description": "Host API wrapper: integrate and run your product inside Polkadot browser.",
|
|
6
6
|
"license": "Apache-2.0",
|
|
7
7
|
"repository": {
|
|
@@ -27,9 +27,10 @@
|
|
|
27
27
|
"dependencies": {
|
|
28
28
|
"@polkadot/extension-inject": "^0.63.1",
|
|
29
29
|
"@polkadot-api/json-rpc-provider-proxy": "^0.4.0",
|
|
30
|
-
"@polkadot-api/
|
|
31
|
-
"@
|
|
32
|
-
"
|
|
30
|
+
"@polkadot-api/signers-common": "^0.3.0",
|
|
31
|
+
"@polkadot-api/substrate-bindings": "^0.21.0",
|
|
32
|
+
"@novasamatech/host-api": "0.10.1",
|
|
33
|
+
"polkadot-api": ">=3",
|
|
33
34
|
"neverthrow": "^8.2.0"
|
|
34
35
|
},
|
|
35
36
|
"publishConfig": {
|