@novasamatech/host-container 0.6.18 → 0.7.0-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 CHANGED
@@ -62,25 +62,59 @@ container.handleFeatureSupported((params, { ok, err }) => {
62
62
 
63
63
  ### handleDevicePermission
64
64
 
65
+ The `request` parameter is one of: `'Notifications'`, `'Camera'`, `'Microphone'`, `'Bluetooth'`, `'NFC'`, `'Location'`, `'Clipboard'`, `'OpenUrl'`, `'Biometrics'`.
66
+
65
67
  ```ts
66
68
  container.handleDevicePermission(async (request, { ok, err }) => {
67
- const granted = await requestDevicePermission(request);
69
+ // request is a string literal: 'Notifications' | 'Camera' | 'Microphone' | ...
70
+ const granted = await promptDevicePermission(request);
68
71
  return ok(granted);
69
72
  });
70
73
  ```
71
74
 
72
75
  ### handlePermission
73
76
 
74
- ```ts
75
- container.handlePermission(async (request, { ok, err }) => {
76
- if (request.tag === 'ExternalRequest') {
77
- const allowed = await checkExternalRequestPermission(request.value);
78
- return ok(allowed);
77
+ The `request` parameter is an **array** of `RemotePermission` items. Return `ok(true)` only when **all** permissions in the batch are granted.
78
+
79
+ Each item has one of these shapes:
80
+ - `{ tag: 'Remote', value: string[] }` — HTTP/WS domain patterns (exact or `*.wildcard`)
81
+ - `{ tag: 'WebRTC', value: undefined }` — WebRTC access (may expose user IP)
82
+ - `{ tag: 'ChainSubmit', value: undefined }` — broadcast transactions via `remote_chain_transaction_broadcast`
83
+ - `{ tag: 'PreimageSubmit', value: undefined }` — submit preimages via `remote_preimage_submit`
84
+ - `{ tag: 'StatementSubmit', value: undefined }` — submit statements via `remote_statement_store_submit`
85
+
86
+ ```ts
87
+ container.handlePermission(async (permissions, { ok, err }) => {
88
+ for (const permission of permissions) {
89
+ switch (permission.tag) {
90
+ case 'Remote': {
91
+ const allowed = await checkDomainPermissions(permission.value);
92
+ if (!allowed) return ok(false);
93
+ break;
94
+ }
95
+ case 'WebRTC': {
96
+ const allowed = await promptWebRTCPermission();
97
+ if (!allowed) return ok(false);
98
+ break;
99
+ }
100
+ case 'ChainSubmit': {
101
+ const allowed = await promptChainSubmitPermission();
102
+ if (!allowed) return ok(false);
103
+ break;
104
+ }
105
+ case 'PreimageSubmit': {
106
+ const allowed = await promptPreimageSubmitPermission();
107
+ if (!allowed) return ok(false);
108
+ break;
109
+ }
110
+ case 'StatementSubmit': {
111
+ const allowed = await promptStatementSubmitPermission();
112
+ if (!allowed) return ok(false);
113
+ break;
114
+ }
115
+ }
79
116
  }
80
- if (request.tag === 'TransactionSubmit') {
81
- return ok(true);
82
- }
83
- return ok(false);
117
+ return ok(true);
84
118
  });
85
119
  ```
86
120
 
@@ -102,6 +136,15 @@ container.handleNavigateTo(async (url, { ok, err }) => {
102
136
  });
103
137
  ```
104
138
 
139
+ ### handleDeriveEntropy
140
+
141
+ ```ts
142
+ container.handleDeriveEntropy(async (key, { ok, err }) => {
143
+ const entropy = await deriveEntropy(key);
144
+ return ok(entropy);
145
+ });
146
+ ```
147
+
105
148
  ### handleLocalStorageRead
106
149
 
107
150
  ```ts
@@ -143,6 +186,55 @@ container.handleAccountConnectionStatusSubscribe((_, send, interrupt) => {
143
186
  });
144
187
  ```
145
188
 
189
+ ### handleThemeSubscribe
190
+
191
+ ```ts
192
+ container.handleThemeSubscribe((_, send, interrupt) => {
193
+ const listener = (theme: 'light' | 'dark') => send(theme);
194
+ themeService.on('change', listener);
195
+ send(themeService.getCurrentTheme());
196
+ return () => themeService.off('change', listener);
197
+ });
198
+ ```
199
+
200
+ ### handleAccountGetRoot
201
+
202
+ Called when a product requests the user's root (primary) account. Show a permission prompt on first call; cache the grant for the session. Return `NotFound` if the user has no DotNS username.
203
+
204
+ ```ts
205
+ import { RequestCredentialsErr } from '@novasamatech/host-api';
206
+
207
+ container.handleAccountGetRoot(async (_, { ok, err }) => {
208
+ const granted = await promptUserForRootAccountAccess();
209
+ if (!granted) {
210
+ return err(new RequestCredentialsErr.Rejected());
211
+ }
212
+ const rootAccount = await getRootAccount();
213
+ if (!rootAccount) {
214
+ return err(new RequestCredentialsErr.NotConnected());
215
+ }
216
+ return ok({ publicKey: rootAccount.publicKey, name: rootAccount.name ?? undefined });
217
+ });
218
+ ```
219
+
220
+ ### handleRequestLogin
221
+
222
+ Called when a product requests the host login UI. Present the sign-in flow and return the outcome. `reason` is an optional human-readable string the product provides to explain why login is needed.
223
+
224
+ ```ts
225
+ import { LoginErr } from '@novasamatech/host-api';
226
+
227
+ container.handleRequestLogin(async (reason, { ok, err }) => {
228
+ const alreadyConnected = await checkIfConnected();
229
+ if (alreadyConnected) return ok('alreadyConnected');
230
+
231
+ const result = await presentLoginUI(reason);
232
+ if (!result.success) return ok('rejected');
233
+
234
+ return ok('success');
235
+ });
236
+ ```
237
+
146
238
  ### handleAccountGet
147
239
 
148
240
  ```ts
@@ -180,11 +272,11 @@ container.handleAccountCreateProof(async ([[dotnsId, derivationIndex], ringLocat
180
272
  });
181
273
  ```
182
274
 
183
- ### handleGetNonProductAccounts
275
+ ### handleGetLegacyAccounts
184
276
 
185
277
  ```ts
186
- container.handleGetNonProductAccounts(async (_, { ok, err }) => {
187
- const accounts = await getNonProductAccounts();
278
+ container.handleGetLegacyAccounts(async (_, { ok, err }) => {
279
+ const accounts = await getLegacyAccounts();
188
280
  return ok(accounts);
189
281
  });
190
282
  ```
@@ -202,12 +294,12 @@ container.handleCreateTransaction(async ([productAccountId, payload], { ok, err
202
294
  });
203
295
  ```
204
296
 
205
- ### handleCreateTransactionWithNonProductAccount
297
+ ### handleCreateTransactionWithLegacyAccount
206
298
 
207
299
  ```ts
208
- container.handleCreateTransactionWithNonProductAccount(async (payload, { ok, err }) => {
300
+ container.handleCreateTransactionWithLegacyAccount(async (payload, { ok, err }) => {
209
301
  try {
210
- const signedTx = await createTransactionWithNonProductAccount(payload);
302
+ const signedTx = await createTransactionWithLegacyAccount(payload);
211
303
  return ok(signedTx);
212
304
  } catch (e) {
213
305
  return err({ tag: 'Rejected' });
@@ -303,10 +395,11 @@ subscription.unsubscribe();
303
395
  ### handleStatementStoreSubscribe
304
396
 
305
397
  ```ts
306
- container.handleStatementStoreSubscribe((query, send, interrupt) => {
307
- const listener = (statements) => send(statements);
308
- statementStore.subscribe(query, listener);
309
- return () => statementStore.unsubscribe(query, listener);
398
+ container.handleStatementStoreSubscribe((filter, send, interrupt) => {
399
+ // filter is { tag: 'MatchAll', value: Uint8Array[] } | { tag: 'MatchAny', value: Uint8Array[] }
400
+ const listener = (page) => send(page);
401
+ statementStore.subscribe(filter, listener);
402
+ return () => statementStore.unsubscribe(filter, listener);
310
403
  });
311
404
  ```
312
405
 
@@ -359,6 +452,69 @@ container.handlePreimageSubmit(async (preimage, { ok, err }) => {
359
452
  });
360
453
  ```
361
454
 
455
+ ### handlePaymentBalanceSubscribe
456
+
457
+ Called when a product subscribes to balance updates. Host should prompt for user consent on the first call; interrupt the subscription to communicate denial.
458
+
459
+ ```ts
460
+ container.handlePaymentBalanceSubscribe((_params, send, interrupt) => {
461
+ const unsubscribe = balanceService.subscribe(balance => {
462
+ send({ available: balance.available, pending: balance.pending });
463
+ });
464
+
465
+ return () => unsubscribe();
466
+ });
467
+ ```
468
+
469
+ ### handlePaymentTopUp
470
+
471
+ Called when a product requests a balance top-up from a product-controlled source. Does not require user consent.
472
+
473
+ ```ts
474
+ container.handlePaymentTopUp(async ({ amount, source }, { ok, err }) => {
475
+ if (source.tag === 'ProductAccount') {
476
+ const [dotNsIdentifier, derivationIndex] = source.value;
477
+ await transferFromProductAccount(dotNsIdentifier, derivationIndex, amount);
478
+ return ok(undefined);
479
+ }
480
+ if (source.tag === 'PrivateKey') {
481
+ await transferFromPrivateKey(source.value, amount);
482
+ return ok(undefined);
483
+ }
484
+ return err(new PaymentTopUpErr.InvalidSource());
485
+ });
486
+ ```
487
+
488
+ ### handlePaymentRequest
489
+
490
+ Called when a product requests a payment from the user's balance. Host MUST show a confirmation UI. Returns a receipt immediately; settlement is asynchronous.
491
+
492
+ ```ts
493
+ container.handlePaymentRequest(async ({ amount, destination }, { ok, err }) => {
494
+ const approved = await showPaymentConfirmation({ amount, destination });
495
+ if (!approved) return err(new PaymentRequestErr.Denied());
496
+
497
+ const paymentId = await paymentService.submit(amount, destination);
498
+ return ok({ id: paymentId });
499
+ });
500
+ ```
501
+
502
+ ### handlePaymentStatusSubscribe
503
+
504
+ Called when a product subscribes to the status of a previously requested payment.
505
+
506
+ ```ts
507
+ container.handlePaymentStatusSubscribe((paymentId, send, interrupt) => {
508
+ const unsubscribe = paymentService.trackStatus(paymentId, status => {
509
+ if (status === 'processing') send({ tag: 'Processing', value: undefined });
510
+ if (status === 'completed') send({ tag: 'Completed', value: undefined });
511
+ if (status === 'failed') send({ tag: 'Failed', value: 'settlement failed' });
512
+ });
513
+
514
+ return () => unsubscribe();
515
+ });
516
+ ```
517
+
362
518
  ### handleChainConnection
363
519
 
364
520
  ```ts
@@ -374,10 +530,6 @@ container.handleChainConnection({
374
530
  const endpoint = chains.get(genesisHash);
375
531
  if (!endpoint) return null;
376
532
  return getWsProvider(endpoint);
377
- },
378
- async submitPermission(transaction) {
379
- if (hasPermission(transaction)) return true;
380
- return false;
381
533
  }
382
534
  });
383
535
  ```
@@ -1,5 +1,6 @@
1
1
  import type { HexString } from '@novasamatech/host-api';
2
- import type { JsonRpcProvider } from '@polkadot-api/json-rpc-provider';
2
+ import type { JsonRpcProvider } from 'polkadot-api';
3
+ type JsonRpcConnection = ReturnType<JsonRpcProvider>;
3
4
  type PendingRequest = {
4
5
  resolve: (result: unknown) => void;
5
6
  reject: (error: unknown) => void;
@@ -10,10 +11,7 @@ type FollowSubscription = {
10
11
  pendingRequestId?: string;
11
12
  };
12
13
  type ChainEntry = {
13
- connection: {
14
- send: (msg: string) => void;
15
- disconnect: () => void;
16
- };
14
+ connection: JsonRpcConnection;
17
15
  pendingRequests: Map<string, PendingRequest>;
18
16
  followSubscriptions: Map<string, FollowSubscription>;
19
17
  refCount: number;
@@ -24,36 +24,31 @@ export function createChainConnectionManager(factory) {
24
24
  followSubscriptions,
25
25
  refCount: 1,
26
26
  };
27
- entry.connection = provider((message) => {
28
- let parsed;
29
- try {
30
- parsed = JSON.parse(message);
31
- }
32
- catch {
33
- return;
34
- }
35
- // Request-response (has 'id' field)
36
- if ('id' in parsed && parsed.id != null) {
37
- const pending = pendingRequests.get(String(parsed.id));
27
+ entry.connection = provider(message => {
28
+ // Response: has 'id' but no 'method'
29
+ if ('id' in message && message.id != null && !('method' in message)) {
30
+ const pending = pendingRequests.get(String(message.id));
38
31
  if (pending) {
39
- pendingRequests.delete(String(parsed.id));
40
- if ('error' in parsed) {
41
- pending.reject(parsed.error);
32
+ pendingRequests.delete(String(message.id));
33
+ if ('error' in message) {
34
+ pending.reject(message.error);
42
35
  }
43
36
  else {
44
- pending.resolve(parsed.result);
37
+ pending.resolve(message.result);
45
38
  }
46
39
  return;
47
40
  }
48
41
  }
49
- // Subscription notification (has params.subscription)
50
- const params = parsed.params;
51
- if (params?.subscription) {
52
- const subId = String(params.subscription);
53
- for (const follow of followSubscriptions.values()) {
54
- if (follow.chainSubId === subId) {
55
- follow.eventListener(params.result);
56
- break;
42
+ // Subscription notification: has 'method' and 'params'
43
+ if ('method' in message && 'params' in message) {
44
+ const params = message.params;
45
+ if (params?.subscription) {
46
+ const subId = String(params.subscription);
47
+ for (const follow of followSubscriptions.values()) {
48
+ if (follow.chainSubId === subId) {
49
+ follow.eventListener(params.result);
50
+ break;
51
+ }
57
52
  }
58
53
  }
59
54
  }
@@ -68,7 +63,7 @@ export function createChainConnectionManager(factory) {
68
63
  const id = getNextId();
69
64
  return new Promise((resolve, reject) => {
70
65
  entry.pendingRequests.set(id, { resolve, reject });
71
- entry.connection.send(JSON.stringify({ jsonrpc: '2.0', id, method, params }));
66
+ entry.connection.send({ jsonrpc: '2.0', id, method, params });
72
67
  });
73
68
  }
74
69
  function startFollow(genesisHash, withRuntime, onEvent) {
@@ -96,7 +91,12 @@ export function createChainConnectionManager(factory) {
96
91
  entry.followSubscriptions.delete(followId);
97
92
  },
98
93
  });
99
- entry.connection.send(JSON.stringify({ jsonrpc: '2.0', id: requestId, method: 'chainHead_v1_follow', params: [withRuntime] }));
94
+ entry.connection.send({
95
+ jsonrpc: '2.0',
96
+ id: requestId,
97
+ method: 'chainHead_v1_follow',
98
+ params: [withRuntime],
99
+ });
100
100
  return { followId };
101
101
  }
102
102
  function stopFollow(genesisHash, followId) {
@@ -109,7 +109,12 @@ export function createChainConnectionManager(factory) {
109
109
  entry.followSubscriptions.delete(followId);
110
110
  if (follow.chainSubId) {
111
111
  const id = getNextId();
112
- entry.connection.send(JSON.stringify({ jsonrpc: '2.0', id, method: 'chainHead_v1_unfollow', params: [follow.chainSubId] }));
112
+ entry.connection.send({
113
+ jsonrpc: '2.0',
114
+ id,
115
+ method: 'chainHead_v1_unfollow',
116
+ params: [follow.chainSubId],
117
+ });
113
118
  }
114
119
  else if (follow.pendingRequestId) {
115
120
  // Follow response hasn't arrived yet — replace the pending resolve to send unfollow when it does
@@ -118,7 +123,12 @@ export function createChainConnectionManager(factory) {
118
123
  const chainSubId = result;
119
124
  if (chainSubId) {
120
125
  const unfollowId = getNextId();
121
- entry.connection.send(JSON.stringify({ jsonrpc: '2.0', id: unfollowId, method: 'chainHead_v1_unfollow', params: [chainSubId] }));
126
+ entry.connection.send({
127
+ jsonrpc: '2.0',
128
+ id: unfollowId,
129
+ method: 'chainHead_v1_unfollow',
130
+ params: [chainSubId],
131
+ });
122
132
  }
123
133
  },
124
134
  reject: () => {
@@ -147,7 +157,12 @@ export function createChainConnectionManager(factory) {
147
157
  for (const follow of entry.followSubscriptions.values()) {
148
158
  if (follow.chainSubId) {
149
159
  const id = getNextId();
150
- entry.connection.send(JSON.stringify({ jsonrpc: '2.0', id, method: 'chainHead_v1_unfollow', params: [follow.chainSubId] }));
160
+ entry.connection.send({
161
+ jsonrpc: '2.0',
162
+ id,
163
+ method: 'chainHead_v1_unfollow',
164
+ params: [follow.chainSubId],
165
+ });
151
166
  }
152
167
  }
153
168
  entry.followSubscriptions.clear();
@@ -160,7 +175,12 @@ export function createChainConnectionManager(factory) {
160
175
  for (const follow of entry.followSubscriptions.values()) {
161
176
  if (follow.chainSubId) {
162
177
  const id = getNextId();
163
- entry.connection.send(JSON.stringify({ jsonrpc: '2.0', id, method: 'chainHead_v1_unfollow', params: [follow.chainSubId] }));
178
+ entry.connection.send({
179
+ jsonrpc: '2.0',
180
+ id,
181
+ method: 'chainHead_v1_unfollow',
182
+ params: [follow.chainSubId],
183
+ });
164
184
  }
165
185
  }
166
186
  entry.followSubscriptions.clear();
@@ -1,9 +1,12 @@
1
- import { ChatBotRegistrationErr, ChatMessagePostingErr, ChatRoomRegistrationErr, CreateProofErr, CreateTransactionErr, GenericError, NavigateToErr, PreimageSubmitErr, RequestCredentialsErr, SigningErr, StatementProofErr, StorageErr, createTransport, enumValue, isEnumVariant, resultErr, resultOk, } from '@novasamatech/host-api';
1
+ import { ChatBotRegistrationErr, ChatMessagePostingErr, ChatRoomRegistrationErr, CreateProofErr, CreateTransactionErr, DeriveEntropyErr, GenericError, LoginErr, NavigateToErr, PaymentRequestErr, PaymentTopUpErr, PreimageSubmitErr, RemotePermission, RequestCredentialsErr, SigningErr, StatementProofErr, StorageErr, createTransport, enumValue, isEnumVariant, resultErr, resultOk, } from '@novasamatech/host-api';
2
2
  import { err, errAsync, ok, okAsync } from 'neverthrow';
3
3
  import { createChainConnectionManager } from './chainConnectionManager.js';
4
4
  const UNSUPPORTED_MESSAGE_FORMAT_ERROR = 'Unsupported message format';
5
5
  const NOT_IMPLEMENTED = 'Not implemented';
6
6
  function guardVersion(value, tag, error) {
7
+ if (!value) {
8
+ return err(error);
9
+ }
7
10
  if (isEnumVariant(value, tag)) {
8
11
  return ok(value.value);
9
12
  }
@@ -51,393 +54,204 @@ export function createContainer(provider) {
51
54
  };
52
55
  };
53
56
  }
57
+ function makeNotImplementedSlot(method, makeError) {
58
+ // Cast needed: async () returns a fixed v1 error shape that TypeScript can't verify
59
+ // matches the generic Method's response type without evaluating template literal types.
60
+ const handler = async () => enumValue('v1', resultErr(makeError()));
61
+ return makeRequestSlot(method, handler);
62
+ }
63
+ function makeInterruptSlot(method) {
64
+ // Cast needed: the default handler ignores typed params/send which TypeScript can't verify
65
+ // matches the generic Method's subscription type without evaluating template literal types.
66
+ const defaultHandler = ((_params, _send, interrupt) => {
67
+ queueMicrotask(interrupt);
68
+ return () => {
69
+ /* nothing to clean up */
70
+ };
71
+ });
72
+ return makeSubscriptionSlot(method, defaultHandler);
73
+ }
74
+ function makePermissionGatedRequestSlot(method, permissionVariant, makeError) {
75
+ const defaultHandler = async () => enumValue('v1', resultErr(makeError()));
76
+ let current = defaultHandler;
77
+ let version = 0;
78
+ transport.handleRequest(method, async (params) => {
79
+ const permissionResponse = await handleRemotePermissionSlot.call(enumValue('v1', [enumValue(permissionVariant, undefined)]));
80
+ const permissionGranted = isEnumVariant(permissionResponse, 'v1') &&
81
+ permissionResponse.value.success === true &&
82
+ permissionResponse.value.value === true;
83
+ if (!permissionGranted) {
84
+ return enumValue('v1', resultErr(makeError()));
85
+ }
86
+ return current(params);
87
+ });
88
+ return {
89
+ update: handler => {
90
+ current = handler;
91
+ const myVersion = ++version;
92
+ return () => {
93
+ if (myVersion !== version)
94
+ return;
95
+ version++;
96
+ current = defaultHandler;
97
+ };
98
+ },
99
+ call: (...args) => current(...args),
100
+ };
101
+ }
102
+ function handleV1Request(slot, makeError, handler) {
103
+ init();
104
+ const version = 'v1';
105
+ return slot.update(async (params) => {
106
+ const error = makeError();
107
+ return guardVersion(params, version, error)
108
+ .asyncMap(async (p) => await handler(p, { ok: (okAsync), err: (errAsync) }))
109
+ .andThen(r => r.map(v => enumValue(version, resultOk(v))))
110
+ .orElse(r => ok(enumValue(version, resultErr(r))))
111
+ .unwrapOr(enumValue(version, resultErr(error)));
112
+ });
113
+ }
114
+ function handleV1Subscription(slot, handler) {
115
+ init();
116
+ const version = 'v1';
117
+ const slotHandler = ((params, send, interrupt) => {
118
+ return guardVersion(params, version, null)
119
+ .map(p => handler(p, ((payload) => send(enumValue(version, payload))), interrupt))
120
+ .orTee(interrupt)
121
+ .unwrapOr(() => {
122
+ /* empty */
123
+ });
124
+ });
125
+ return slot(slotHandler);
126
+ }
54
127
  // account slots
55
- const handleAccountGetSlot = makeRequestSlot('host_account_get', async () => {
56
- const error = new RequestCredentialsErr.Unknown({ reason: NOT_IMPLEMENTED });
57
- return enumValue('v1', resultErr(error));
58
- });
59
- const handleAccountGetAliasSlot = makeRequestSlot('host_account_get_alias', async () => {
60
- const error = new RequestCredentialsErr.Unknown({ reason: NOT_IMPLEMENTED });
61
- return enumValue('v1', resultErr(error));
62
- });
63
- const handleGetNonProductAccountsSlot = makeRequestSlot('host_get_non_product_accounts', async () => {
64
- const error = new RequestCredentialsErr.Unknown({ reason: NOT_IMPLEMENTED });
65
- return enumValue('v1', resultErr(error));
66
- });
67
- const handleAccountCreateProofSlot = makeRequestSlot('host_account_create_proof', async () => {
68
- const error = new CreateProofErr.Unknown({ reason: NOT_IMPLEMENTED });
69
- return enumValue('v1', resultErr(error));
70
- });
128
+ const handleAccountGetRootSlot = makeNotImplementedSlot('host_account_get_root', () => new RequestCredentialsErr.Unknown({ reason: NOT_IMPLEMENTED }));
129
+ const handleRequestLoginSlot = makeNotImplementedSlot('host_request_login', () => new LoginErr.Unknown({ reason: NOT_IMPLEMENTED }));
130
+ const handleAccountGetSlot = makeNotImplementedSlot('host_account_get', () => new RequestCredentialsErr.Unknown({ reason: NOT_IMPLEMENTED }));
131
+ const handleAccountGetAliasSlot = makeNotImplementedSlot('host_account_get_alias', () => new RequestCredentialsErr.Unknown({ reason: NOT_IMPLEMENTED }));
132
+ const handleGetLegacyAccountsSlot = makeNotImplementedSlot('host_get_legacy_accounts', () => new RequestCredentialsErr.Unknown({ reason: NOT_IMPLEMENTED }));
133
+ const handleAccountCreateProofSlot = makeNotImplementedSlot('host_account_create_proof', () => new CreateProofErr.Unknown({ reason: NOT_IMPLEMENTED }));
134
+ // entropy derivation slot
135
+ const handleDeriveEntropySlot = makeNotImplementedSlot('host_derive_entropy', () => new DeriveEntropyErr.Unknown({ reason: NOT_IMPLEMENTED }));
71
136
  // storage slots
72
- const handleLocalStorageReadSlot = makeRequestSlot('host_local_storage_read', async () => {
73
- const error = new StorageErr.Unknown({ reason: NOT_IMPLEMENTED });
74
- return enumValue('v1', resultErr(error));
75
- });
76
- const handleLocalStorageWriteSlot = makeRequestSlot('host_local_storage_write', async () => {
77
- const error = new StorageErr.Unknown({ reason: NOT_IMPLEMENTED });
78
- return enumValue('v1', resultErr(error));
79
- });
80
- const handleLocalStorageClearSlot = makeRequestSlot('host_local_storage_clear', async () => {
81
- const error = new StorageErr.Unknown({ reason: NOT_IMPLEMENTED });
82
- return enumValue('v1', resultErr(error));
83
- });
137
+ const handleLocalStorageReadSlot = makeNotImplementedSlot('host_local_storage_read', () => new StorageErr.Unknown({ reason: NOT_IMPLEMENTED }));
138
+ const handleLocalStorageWriteSlot = makeNotImplementedSlot('host_local_storage_write', () => new StorageErr.Unknown({ reason: NOT_IMPLEMENTED }));
139
+ const handleLocalStorageClearSlot = makeNotImplementedSlot('host_local_storage_clear', () => new StorageErr.Unknown({ reason: NOT_IMPLEMENTED }));
84
140
  // signing slots
85
- const handleSignRawSlot = makeRequestSlot('host_sign_raw', async () => {
86
- const error = new SigningErr.Unknown({ reason: NOT_IMPLEMENTED });
87
- return enumValue('v1', resultErr(error));
88
- });
89
- const handleSignPayloadSlot = makeRequestSlot('host_sign_payload', async () => {
90
- const error = new SigningErr.Unknown({ reason: NOT_IMPLEMENTED });
91
- return enumValue('v1', resultErr(error));
92
- });
93
- const handleCreateTransactionSlot = makeRequestSlot('host_create_transaction', async () => {
94
- const error = new CreateTransactionErr.Unknown({ reason: NOT_IMPLEMENTED });
95
- return enumValue('v1', resultErr(error));
96
- });
97
- const handleCreateTransactionWithNonProductAccountSlot = makeRequestSlot('host_create_transaction_with_non_product_account', async () => {
98
- const error = new CreateTransactionErr.Unknown({ reason: NOT_IMPLEMENTED });
99
- return enumValue('v1', resultErr(error));
100
- });
101
- const handleFeatureSupportedSlot = makeRequestSlot('host_feature_supported', async () => {
102
- const error = new GenericError({ reason: NOT_IMPLEMENTED });
103
- return enumValue('v1', resultErr(error));
104
- });
105
- const handleDevicePermissionSlot = makeRequestSlot('host_device_permission', async () => {
106
- const error = new GenericError({ reason: NOT_IMPLEMENTED });
107
- return enumValue('v1', resultErr(error));
108
- });
109
- const handleRemotePermissionSlot = makeRequestSlot('remote_permission', async () => {
110
- const error = new GenericError({ reason: NOT_IMPLEMENTED });
111
- return enumValue('v1', resultErr(error));
112
- });
113
- const handlePushNotificationSlot = makeRequestSlot('host_push_notification', async () => {
114
- const error = new GenericError({ reason: NOT_IMPLEMENTED });
115
- return enumValue('v1', resultErr(error));
116
- });
117
- const handleNavigateToSlot = makeRequestSlot('host_navigate_to', async () => {
118
- const error = new NavigateToErr.Unknown({ reason: NOT_IMPLEMENTED });
119
- return enumValue('v1', resultErr(error));
120
- });
121
- const handleChatCreateRoomSlot = makeRequestSlot('host_chat_create_room', async () => {
122
- const error = new ChatRoomRegistrationErr.Unknown({ reason: NOT_IMPLEMENTED });
123
- return enumValue('v1', resultErr(error));
124
- });
125
- const handleChatBotRegistrationSlot = makeRequestSlot('host_chat_register_bot', async () => {
126
- const error = new ChatBotRegistrationErr.Unknown({ reason: NOT_IMPLEMENTED });
127
- return enumValue('v1', resultErr(error));
128
- });
129
- const handleChatPostMessageSlot = makeRequestSlot('host_chat_post_message', async () => {
130
- const error = new ChatMessagePostingErr.Unknown({ reason: NOT_IMPLEMENTED });
131
- return enumValue('v1', resultErr(error));
132
- });
133
- const handleStatementStoreSubmitSlot = makeRequestSlot('remote_statement_store_submit', async () => {
134
- const error = new GenericError({ reason: NOT_IMPLEMENTED });
135
- return enumValue('v1', resultErr(error));
136
- });
137
- const handleStatementStoreCreateProofSlot = makeRequestSlot('remote_statement_store_create_proof', async () => {
138
- const error = new StatementProofErr.Unknown({ reason: NOT_IMPLEMENTED });
139
- return enumValue('v1', resultErr(error));
140
- });
141
- const handlePreimageSubmitSlot = makeRequestSlot('remote_preimage_submit', async () => {
142
- const error = new PreimageSubmitErr.Unknown({ reason: NOT_IMPLEMENTED });
143
- return enumValue('v1', resultErr(error));
144
- });
141
+ const handleSignRawSlot = makeNotImplementedSlot('host_sign_raw', () => new SigningErr.Unknown({ reason: NOT_IMPLEMENTED }));
142
+ const handleSignPayloadSlot = makeNotImplementedSlot('host_sign_payload', () => new SigningErr.Unknown({ reason: NOT_IMPLEMENTED }));
143
+ const handleSignRawWithLegacyAccountSlot = makeNotImplementedSlot('host_sign_raw_with_legacy_account', () => new SigningErr.Unknown({ reason: NOT_IMPLEMENTED }));
144
+ const handleSignPayloadWithLegacyAccountSlot = makeNotImplementedSlot('host_sign_payload_with_legacy_account', () => new SigningErr.Unknown({ reason: NOT_IMPLEMENTED }));
145
+ const handleCreateTransactionSlot = makeNotImplementedSlot('host_create_transaction', () => new CreateTransactionErr.Unknown({ reason: NOT_IMPLEMENTED }));
146
+ const handleCreateTransactionWithLegacyAccountSlot = makeNotImplementedSlot('host_create_transaction_with_legacy_account', () => new CreateTransactionErr.Unknown({ reason: NOT_IMPLEMENTED }));
147
+ const handleFeatureSupportedSlot = makeNotImplementedSlot('host_feature_supported', () => new GenericError({ reason: NOT_IMPLEMENTED }));
148
+ const handleDevicePermissionSlot = makeNotImplementedSlot('host_device_permission', () => new GenericError({ reason: NOT_IMPLEMENTED }));
149
+ const handleRemotePermissionSlot = makeNotImplementedSlot('remote_permission', () => new GenericError({ reason: NOT_IMPLEMENTED }));
150
+ const handlePushNotificationSlot = makeNotImplementedSlot('host_push_notification', () => new GenericError({ reason: NOT_IMPLEMENTED }));
151
+ const handleNavigateToSlot = makeNotImplementedSlot('host_navigate_to', () => new NavigateToErr.Unknown({ reason: NOT_IMPLEMENTED }));
152
+ const handleChatCreateRoomSlot = makeNotImplementedSlot('host_chat_create_room', () => new ChatRoomRegistrationErr.Unknown({ reason: NOT_IMPLEMENTED }));
153
+ const handleChatBotRegistrationSlot = makeNotImplementedSlot('host_chat_register_bot', () => new ChatBotRegistrationErr.Unknown({ reason: NOT_IMPLEMENTED }));
154
+ const handleChatPostMessageSlot = makeNotImplementedSlot('host_chat_post_message', () => new ChatMessagePostingErr.Unknown({ reason: NOT_IMPLEMENTED }));
155
+ const handleStatementStoreSubmitSlot = makePermissionGatedRequestSlot('remote_statement_store_submit', 'StatementSubmit', () => new GenericError({ reason: NOT_IMPLEMENTED }));
156
+ const handleStatementStoreCreateProofSlot = makeNotImplementedSlot('remote_statement_store_create_proof', () => new StatementProofErr.Unknown({ reason: NOT_IMPLEMENTED }));
157
+ const handlePreimageSubmitSlot = makePermissionGatedRequestSlot('remote_preimage_submit', 'PreimageSubmit', () => new PreimageSubmitErr.Unknown({ reason: NOT_IMPLEMENTED }));
158
+ // payment request slots
159
+ const handlePaymentTopUpSlot = makeNotImplementedSlot('host_payment_top_up', () => new PaymentTopUpErr.Unknown({ reason: NOT_IMPLEMENTED }));
160
+ const handlePaymentRequestSlot = makeNotImplementedSlot('host_payment_request', () => new PaymentRequestErr.Unknown({ reason: NOT_IMPLEMENTED }));
145
161
  // subscription slots — default interrupts on next microtask so that
146
162
  // the caller has a chance to register an onInterrupt listener first
147
- const handleAccountConnectionStatusSubscribeSlot = makeSubscriptionSlot('host_account_connection_status_subscribe', (_params, _send, interrupt) => {
148
- queueMicrotask(interrupt);
149
- return () => {
150
- /* nothing to clean up */
151
- };
152
- });
153
- const handleChatListSubscribeSlot = makeSubscriptionSlot('host_chat_list_subscribe', (_params, _send, interrupt) => {
154
- queueMicrotask(interrupt);
155
- return () => {
156
- /* nothing to clean up */
157
- };
158
- });
159
- const handleChatActionSubscribeSlot = makeSubscriptionSlot('host_chat_action_subscribe', (_params, _send, interrupt) => {
160
- queueMicrotask(interrupt);
161
- return () => {
162
- /* nothing to clean up */
163
- };
164
- });
165
- const handleStatementStoreSubscribeSlot = makeSubscriptionSlot('remote_statement_store_subscribe', (_params, _send, interrupt) => {
166
- queueMicrotask(interrupt);
167
- return () => {
168
- /* nothing to clean up */
169
- };
170
- });
171
- const handlePreimageLookupSubscribeSlot = makeSubscriptionSlot('remote_preimage_lookup_subscribe', (_params, _send, interrupt) => {
172
- queueMicrotask(interrupt);
173
- return () => {
174
- /* nothing to clean up */
175
- };
176
- });
163
+ const handleThemeSubscribeSlot = makeInterruptSlot('host_theme_subscribe');
164
+ const handleAccountConnectionStatusSubscribeSlot = makeInterruptSlot('host_account_connection_status_subscribe');
165
+ const handleChatListSubscribeSlot = makeInterruptSlot('host_chat_list_subscribe');
166
+ const handleChatActionSubscribeSlot = makeInterruptSlot('host_chat_action_subscribe');
167
+ const handleStatementStoreSubscribeSlot = makeInterruptSlot('remote_statement_store_subscribe');
168
+ const handlePreimageLookupSubscribeSlot = makeInterruptSlot('remote_preimage_lookup_subscribe');
169
+ const handlePaymentBalanceSubscribeSlot = makeInterruptSlot('host_payment_balance_subscribe');
170
+ const handlePaymentStatusSubscribeSlot = makeInterruptSlot('host_payment_status_subscribe');
177
171
  return {
178
172
  handleFeatureSupported(handler) {
179
- init();
180
- return handleFeatureSupportedSlot.update(async (message) => {
181
- const version = 'v1';
182
- const error = new GenericError({ reason: UNSUPPORTED_MESSAGE_FORMAT_ERROR });
183
- return guardVersion(message, version, error)
184
- .asyncMap(async (params) => handler(params, { ok: (okAsync), err: (errAsync) }))
185
- .andThen(r => r.map(r => enumValue(version, resultOk(r))))
186
- .orElse(r => ok(enumValue(version, resultErr(r))))
187
- .unwrapOr(enumValue(version, resultErr(error)));
188
- });
173
+ return handleV1Request(handleFeatureSupportedSlot, () => new GenericError({ reason: UNSUPPORTED_MESSAGE_FORMAT_ERROR }), handler);
189
174
  },
190
175
  handleDevicePermission(handler) {
191
- init();
192
- return handleDevicePermissionSlot.update(async (message) => {
193
- const version = 'v1';
194
- const error = new GenericError({ reason: UNSUPPORTED_MESSAGE_FORMAT_ERROR });
195
- return guardVersion(message, version, error)
196
- .asyncMap(async (params) => handler(params, { ok: (okAsync), err: (errAsync) }))
197
- .andThen(r => r.map(r => enumValue(version, resultOk(r))))
198
- .orElse(r => ok(enumValue(version, resultErr(r))))
199
- .unwrapOr(enumValue(version, resultErr(error)));
200
- });
176
+ return handleV1Request(handleDevicePermissionSlot, () => new GenericError({ reason: UNSUPPORTED_MESSAGE_FORMAT_ERROR }), handler);
201
177
  },
202
178
  handlePermission(handler) {
203
- init();
204
- return handleRemotePermissionSlot.update(async (message) => {
205
- const version = 'v1';
206
- const error = new GenericError({ reason: UNSUPPORTED_MESSAGE_FORMAT_ERROR });
207
- return guardVersion(message, version, error)
208
- .asyncMap(async (params) => handler(params, { ok: (okAsync), err: (errAsync) }))
209
- .andThen(r => r.map(r => enumValue(version, resultOk(r))))
210
- .orElse(r => ok(enumValue(version, resultErr(r))))
211
- .unwrapOr(enumValue(version, resultErr(error)));
212
- });
179
+ return handleV1Request(handleRemotePermissionSlot, () => new GenericError({ reason: UNSUPPORTED_MESSAGE_FORMAT_ERROR }), handler);
213
180
  },
214
181
  handlePushNotification(handler) {
215
- init();
216
- return handlePushNotificationSlot.update(async (message) => {
217
- const version = 'v1';
218
- const error = new GenericError({ reason: UNSUPPORTED_MESSAGE_FORMAT_ERROR });
219
- return guardVersion(message, version, error)
220
- .asyncMap(async (params) => handler(params, { ok: (okAsync), err: (errAsync) }))
221
- .andThen(r => r.map(r => enumValue(version, resultOk(r))))
222
- .orElse(r => ok(enumValue(version, resultErr(r))))
223
- .unwrapOr(enumValue(version, resultErr(error)));
224
- });
182
+ return handleV1Request(handlePushNotificationSlot, () => new GenericError({ reason: UNSUPPORTED_MESSAGE_FORMAT_ERROR }), handler);
225
183
  },
226
184
  handleNavigateTo(handler) {
227
- init();
228
- return handleNavigateToSlot.update(async (message) => {
229
- const version = 'v1';
230
- const error = new NavigateToErr.Unknown({ reason: UNSUPPORTED_MESSAGE_FORMAT_ERROR });
231
- return guardVersion(message, version, error)
232
- .asyncMap(async (params) => handler(params, { ok: (okAsync), err: (errAsync) }))
233
- .andThen(r => r.map(r => enumValue(version, resultOk(r))))
234
- .orElse(r => ok(enumValue(version, resultErr(r))))
235
- .unwrapOr(enumValue(version, resultErr(error)));
236
- });
185
+ return handleV1Request(handleNavigateToSlot, () => new NavigateToErr.Unknown({ reason: UNSUPPORTED_MESSAGE_FORMAT_ERROR }), handler);
186
+ },
187
+ handleDeriveEntropy(handler) {
188
+ return handleV1Request(handleDeriveEntropySlot, () => new DeriveEntropyErr.Unknown({ reason: UNSUPPORTED_MESSAGE_FORMAT_ERROR }), handler);
237
189
  },
238
190
  handleLocalStorageRead(handler) {
239
- init();
240
- return handleLocalStorageReadSlot.update(async (message) => {
241
- const version = 'v1';
242
- const error = new StorageErr.Unknown({ reason: UNSUPPORTED_MESSAGE_FORMAT_ERROR });
243
- return guardVersion(message, version, error)
244
- .asyncMap(async (params) => handler(params, { ok: (okAsync), err: (errAsync) }))
245
- .andThen(r => r.map(r => enumValue(version, resultOk(r))))
246
- .orElse(r => ok(enumValue(version, resultErr(r))))
247
- .unwrapOr(enumValue(version, resultErr(error)));
248
- });
191
+ return handleV1Request(handleLocalStorageReadSlot, () => new StorageErr.Unknown({ reason: UNSUPPORTED_MESSAGE_FORMAT_ERROR }), handler);
249
192
  },
250
193
  handleLocalStorageWrite(handler) {
251
- init();
252
- return handleLocalStorageWriteSlot.update(async (message) => {
253
- const version = 'v1';
254
- const error = new StorageErr.Unknown({ reason: UNSUPPORTED_MESSAGE_FORMAT_ERROR });
255
- return guardVersion(message, version, error)
256
- .asyncMap(async (params) => handler(params, { ok: (okAsync), err: (errAsync) }))
257
- .andThen(r => r.map(r => enumValue(version, resultOk(r))))
258
- .orElse(r => ok(enumValue(version, resultErr(r))))
259
- .unwrapOr(enumValue(version, resultErr(error)));
260
- });
194
+ return handleV1Request(handleLocalStorageWriteSlot, () => new StorageErr.Unknown({ reason: UNSUPPORTED_MESSAGE_FORMAT_ERROR }), handler);
261
195
  },
262
196
  handleLocalStorageClear(handler) {
263
- init();
264
- return handleLocalStorageClearSlot.update(async (message) => {
265
- const version = 'v1';
266
- const error = new StorageErr.Unknown({ reason: UNSUPPORTED_MESSAGE_FORMAT_ERROR });
267
- return guardVersion(message, version, error)
268
- .asyncMap(async (params) => handler(params, { ok: (okAsync), err: (errAsync) }))
269
- .andThen(r => r.map(r => enumValue(version, resultOk(r))))
270
- .orElse(r => ok(enumValue(version, resultErr(r))))
271
- .unwrapOr(enumValue(version, resultErr(error)));
272
- });
197
+ return handleV1Request(handleLocalStorageClearSlot, () => new StorageErr.Unknown({ reason: UNSUPPORTED_MESSAGE_FORMAT_ERROR }), handler);
198
+ },
199
+ handleThemeSubscribe(handler) {
200
+ return handleV1Subscription(handleThemeSubscribeSlot, handler);
201
+ },
202
+ handleAccountGetRoot(handler) {
203
+ return handleV1Request(handleAccountGetRootSlot, () => new RequestCredentialsErr.Unknown({ reason: UNSUPPORTED_MESSAGE_FORMAT_ERROR }), handler);
204
+ },
205
+ handleRequestLogin(handler) {
206
+ return handleV1Request(handleRequestLoginSlot, () => new LoginErr.Unknown({ reason: UNSUPPORTED_MESSAGE_FORMAT_ERROR }), handler);
273
207
  },
274
208
  handleAccountConnectionStatusSubscribe(handler) {
275
- init();
276
- return handleAccountConnectionStatusSubscribeSlot((params, send, interrupt) => {
277
- const version = 'v1';
278
- return guardVersion(params, version, null)
279
- .map(params => handler(params, payload => send(enumValue(version, payload)), interrupt))
280
- .orTee(interrupt)
281
- .unwrapOr(() => {
282
- /* empty */
283
- });
284
- });
209
+ return handleV1Subscription(handleAccountConnectionStatusSubscribeSlot, handler);
285
210
  },
286
211
  handleAccountGet(handler) {
287
- init();
288
- return handleAccountGetSlot.update(async (params) => {
289
- const version = 'v1';
290
- const error = new RequestCredentialsErr.Unknown({ reason: UNSUPPORTED_MESSAGE_FORMAT_ERROR });
291
- return guardVersion(params, version, error)
292
- .asyncMap(async (params) => handler(params, { ok: (okAsync), err: (errAsync) }))
293
- .andThen(r => r.map(r => enumValue(version, resultOk(r))))
294
- .orElse(r => ok(enumValue(version, resultErr(r))))
295
- .unwrapOr(enumValue(version, resultErr(error)));
296
- });
212
+ return handleV1Request(handleAccountGetSlot, () => new RequestCredentialsErr.Unknown({ reason: UNSUPPORTED_MESSAGE_FORMAT_ERROR }), handler);
297
213
  },
298
214
  handleAccountGetAlias(handler) {
299
- init();
300
- return handleAccountGetAliasSlot.update(async (params) => {
301
- const version = 'v1';
302
- const error = new RequestCredentialsErr.Unknown({ reason: UNSUPPORTED_MESSAGE_FORMAT_ERROR });
303
- return guardVersion(params, version, error)
304
- .asyncMap(async (params) => handler(params, { ok: (okAsync), err: (errAsync) }))
305
- .andThen(r => r.map(r => enumValue(version, resultOk(r))))
306
- .orElse(r => ok(enumValue(version, resultErr(r))))
307
- .unwrapOr(enumValue(version, resultErr(error)));
308
- });
215
+ return handleV1Request(handleAccountGetAliasSlot, () => new RequestCredentialsErr.Unknown({ reason: UNSUPPORTED_MESSAGE_FORMAT_ERROR }), handler);
309
216
  },
310
217
  handleAccountCreateProof(handler) {
311
- init();
312
- return handleAccountCreateProofSlot.update(async (params) => {
313
- const version = 'v1';
314
- const error = new CreateProofErr.Unknown({ reason: UNSUPPORTED_MESSAGE_FORMAT_ERROR });
315
- return guardVersion(params, version, error)
316
- .asyncMap(async (params) => handler(params, { ok: (okAsync), err: (errAsync) }))
317
- .andThen(r => r.map(r => enumValue(version, resultOk(r))))
318
- .orElse(r => ok(enumValue(version, resultErr(r))))
319
- .unwrapOr(enumValue(version, resultErr(error)));
320
- });
218
+ return handleV1Request(handleAccountCreateProofSlot, () => new CreateProofErr.Unknown({ reason: UNSUPPORTED_MESSAGE_FORMAT_ERROR }), handler);
321
219
  },
322
- handleGetNonProductAccounts(handler) {
323
- init();
324
- return handleGetNonProductAccountsSlot.update(async (params) => {
325
- const version = 'v1';
326
- const error = new RequestCredentialsErr.Unknown({ reason: UNSUPPORTED_MESSAGE_FORMAT_ERROR });
327
- return guardVersion(params, version, error)
328
- .asyncMap(async (params) => handler(params, { ok: (okAsync), err: (errAsync) }))
329
- .andThen(r => r.map(r => enumValue(version, resultOk(r))))
330
- .orElse(r => ok(enumValue(version, resultErr(r))))
331
- .unwrapOr(enumValue(version, resultErr(error)));
332
- });
220
+ handleGetLegacyAccounts(handler) {
221
+ return handleV1Request(handleGetLegacyAccountsSlot, () => new RequestCredentialsErr.Unknown({ reason: UNSUPPORTED_MESSAGE_FORMAT_ERROR }), handler);
333
222
  },
334
223
  handleCreateTransaction(handler) {
335
- init();
336
- return handleCreateTransactionSlot.update(async (params) => {
337
- const version = 'v1';
338
- const error = new CreateTransactionErr.Unknown({ reason: UNSUPPORTED_MESSAGE_FORMAT_ERROR });
339
- return guardVersion(params, version, error)
340
- .asyncMap(async (params) => handler(params, { ok: (okAsync), err: (errAsync) }))
341
- .andThen(r => r.map(r => enumValue(version, resultOk(r))))
342
- .orElse(r => ok(enumValue(version, resultErr(r))))
343
- .unwrapOr(enumValue(version, resultErr(error)));
344
- });
224
+ return handleV1Request(handleCreateTransactionSlot, () => new CreateTransactionErr.Unknown({ reason: UNSUPPORTED_MESSAGE_FORMAT_ERROR }), handler);
345
225
  },
346
- handleCreateTransactionWithNonProductAccount(handler) {
347
- init();
348
- return handleCreateTransactionWithNonProductAccountSlot.update(async (params) => {
349
- const version = 'v1';
350
- const error = new CreateTransactionErr.Unknown({ reason: UNSUPPORTED_MESSAGE_FORMAT_ERROR });
351
- return guardVersion(params, version, error)
352
- .asyncMap(async (params) => handler(params, { ok: (okAsync), err: (errAsync) }))
353
- .andThen(r => r.map(r => enumValue(version, resultOk(r))))
354
- .orElse(r => ok(enumValue(version, resultErr(r))))
355
- .unwrapOr(enumValue(version, resultErr(error)));
356
- });
226
+ handleCreateTransactionWithLegacyAccount(handler) {
227
+ return handleV1Request(handleCreateTransactionWithLegacyAccountSlot, () => new CreateTransactionErr.Unknown({ reason: UNSUPPORTED_MESSAGE_FORMAT_ERROR }), handler);
357
228
  },
358
229
  handleSignRaw(handler) {
359
- init();
360
- return handleSignRawSlot.update(async (params) => {
361
- const version = 'v1';
362
- const error = new SigningErr.Unknown({ reason: UNSUPPORTED_MESSAGE_FORMAT_ERROR });
363
- return guardVersion(params, version, error)
364
- .asyncMap(async (params) => handler(params, { ok: (okAsync), err: (errAsync) }))
365
- .andThen(r => r.map(r => enumValue(version, resultOk(r))))
366
- .orElse(r => ok(enumValue(version, resultErr(r))))
367
- .unwrapOr(enumValue(version, resultErr(error)));
368
- });
230
+ return handleV1Request(handleSignRawSlot, () => new SigningErr.Unknown({ reason: UNSUPPORTED_MESSAGE_FORMAT_ERROR }), handler);
369
231
  },
370
232
  handleSignPayload(handler) {
371
- init();
372
- return handleSignPayloadSlot.update(async (params) => {
373
- const version = 'v1';
374
- const error = new SigningErr.Unknown({ reason: UNSUPPORTED_MESSAGE_FORMAT_ERROR });
375
- return guardVersion(params, version, error)
376
- .asyncMap(async (params) => handler(params, { ok: (okAsync), err: (errAsync) }))
377
- .andThen(r => r.map(r => enumValue(version, resultOk(r))))
378
- .orElse(r => ok(enumValue(version, resultErr(r))))
379
- .unwrapOr(enumValue(version, resultErr(error)));
380
- });
233
+ return handleV1Request(handleSignPayloadSlot, () => new SigningErr.Unknown({ reason: UNSUPPORTED_MESSAGE_FORMAT_ERROR }), handler);
234
+ },
235
+ handleSignRawWithLegacyAccount(handler) {
236
+ return handleV1Request(handleSignRawWithLegacyAccountSlot, () => new SigningErr.Unknown({ reason: UNSUPPORTED_MESSAGE_FORMAT_ERROR }), handler);
237
+ },
238
+ handleSignPayloadWithLegacyAccount(handler) {
239
+ return handleV1Request(handleSignPayloadWithLegacyAccountSlot, () => new SigningErr.Unknown({ reason: UNSUPPORTED_MESSAGE_FORMAT_ERROR }), handler);
381
240
  },
382
241
  handleChatCreateRoom(handler) {
383
- init();
384
- return handleChatCreateRoomSlot.update(async (params) => {
385
- const version = 'v1';
386
- const error = new ChatRoomRegistrationErr.Unknown({ reason: UNSUPPORTED_MESSAGE_FORMAT_ERROR });
387
- return guardVersion(params, version, error)
388
- .asyncMap(async (params) => handler(params, { ok: (okAsync), err: (errAsync) }))
389
- .andThen(r => r.map(r => enumValue(version, resultOk(r))))
390
- .orElse(r => ok(enumValue(version, resultErr(r))))
391
- .unwrapOr(enumValue(version, resultErr(error)));
392
- });
242
+ return handleV1Request(handleChatCreateRoomSlot, () => new ChatRoomRegistrationErr.Unknown({ reason: UNSUPPORTED_MESSAGE_FORMAT_ERROR }), handler);
393
243
  },
394
244
  handleChatBotRegistration(handler) {
395
- init();
396
- return handleChatBotRegistrationSlot.update(async (params) => {
397
- const version = 'v1';
398
- const error = new ChatBotRegistrationErr.Unknown({ reason: UNSUPPORTED_MESSAGE_FORMAT_ERROR });
399
- return guardVersion(params, version, error)
400
- .asyncMap(async (params) => handler(params, { ok: (okAsync), err: (errAsync) }))
401
- .andThen(r => r.map(r => enumValue(version, resultOk(r))))
402
- .orElse(r => ok(enumValue(version, resultErr(r))))
403
- .unwrapOr(enumValue(version, resultErr(error)));
404
- });
245
+ return handleV1Request(handleChatBotRegistrationSlot, () => new ChatBotRegistrationErr.Unknown({ reason: UNSUPPORTED_MESSAGE_FORMAT_ERROR }), handler);
405
246
  },
406
247
  handleChatListSubscribe(handler) {
407
- init();
408
- return handleChatListSubscribeSlot((params, send, interrupt) => {
409
- const version = 'v1';
410
- return guardVersion(params, version, null)
411
- .map(params => handler(params, payload => send(enumValue(version, payload)), interrupt))
412
- .orTee(interrupt)
413
- .unwrapOr(() => {
414
- /* empty */
415
- });
416
- });
248
+ return handleV1Subscription(handleChatListSubscribeSlot, handler);
417
249
  },
418
250
  handleChatPostMessage(handler) {
419
- init();
420
- return handleChatPostMessageSlot.update(async (params) => {
421
- const version = 'v1';
422
- const error = new ChatMessagePostingErr.Unknown({ reason: UNSUPPORTED_MESSAGE_FORMAT_ERROR });
423
- return guardVersion(params, version, error)
424
- .asyncMap(async (params) => handler(params, { ok: (okAsync), err: (errAsync) }))
425
- .andThen(r => r.map(r => enumValue(version, resultOk(r))))
426
- .orElse(r => ok(enumValue(version, resultErr(r))))
427
- .unwrapOr(enumValue(version, resultErr(error)));
428
- });
251
+ return handleV1Request(handleChatPostMessageSlot, () => new ChatMessagePostingErr.Unknown({ reason: UNSUPPORTED_MESSAGE_FORMAT_ERROR }), handler);
429
252
  },
430
253
  handleChatActionSubscribe(handler) {
431
- init();
432
- return handleChatActionSubscribeSlot((params, send, interrupt) => {
433
- const version = 'v1';
434
- return guardVersion(params, version, null)
435
- .map(params => handler(params, payload => send(enumValue(version, payload)), interrupt))
436
- .orTee(interrupt)
437
- .unwrapOr(() => {
438
- /* empty */
439
- });
440
- });
254
+ return handleV1Subscription(handleChatActionSubscribeSlot, handler);
441
255
  },
442
256
  renderChatCustomMessage({ messageId, messageType, payload }, callback) {
443
257
  init();
@@ -448,64 +262,31 @@ export function createContainer(provider) {
448
262
  });
449
263
  },
450
264
  handleStatementStoreSubscribe(handler) {
451
- init();
452
- return handleStatementStoreSubscribeSlot((params, send, interrupt) => {
453
- const version = 'v1';
454
- return guardVersion(params, version, null)
455
- .map(params => handler(params, payload => send(enumValue(version, payload)), interrupt))
456
- .orTee(interrupt)
457
- .unwrapOr(() => {
458
- /* empty */
459
- });
460
- });
265
+ return handleV1Subscription(handleStatementStoreSubscribeSlot, handler);
461
266
  },
462
267
  handleStatementStoreCreateProof(handler) {
463
- init();
464
- return handleStatementStoreCreateProofSlot.update(async (params) => {
465
- const version = 'v1';
466
- const error = new StatementProofErr.Unknown({ reason: UNSUPPORTED_MESSAGE_FORMAT_ERROR });
467
- return guardVersion(params, version, error)
468
- .asyncMap(async (params) => handler(params, { ok: (okAsync), err: (errAsync) }))
469
- .andThen(r => r.map(r => enumValue(version, resultOk(r))))
470
- .orElse(r => ok(enumValue(version, resultErr(r))))
471
- .unwrapOr(enumValue(version, resultErr(error)));
472
- });
268
+ return handleV1Request(handleStatementStoreCreateProofSlot, () => new StatementProofErr.Unknown({ reason: UNSUPPORTED_MESSAGE_FORMAT_ERROR }), handler);
473
269
  },
474
270
  handleStatementStoreSubmit(handler) {
475
- init();
476
- return handleStatementStoreSubmitSlot.update(async (params) => {
477
- const version = 'v1';
478
- const error = new GenericError({ reason: UNSUPPORTED_MESSAGE_FORMAT_ERROR });
479
- return guardVersion(params, version, error)
480
- .asyncMap(async (params) => handler(params, { ok: (okAsync), err: (errAsync) }))
481
- .andThen(r => r.map(r => enumValue(version, resultOk(r))))
482
- .orElse(r => ok(enumValue(version, resultErr(r))))
483
- .unwrapOr(enumValue(version, resultErr(error)));
484
- });
271
+ return handleV1Request(handleStatementStoreSubmitSlot, () => new GenericError({ reason: UNSUPPORTED_MESSAGE_FORMAT_ERROR }), handler);
485
272
  },
486
273
  handlePreimageLookupSubscribe(handler) {
487
- init();
488
- return handlePreimageLookupSubscribeSlot((params, send, interrupt) => {
489
- const version = 'v1';
490
- return guardVersion(params, version, null)
491
- .map(params => handler(params, payload => send(enumValue(version, payload)), interrupt))
492
- .orTee(interrupt)
493
- .unwrapOr(() => {
494
- /* empty */
495
- });
496
- });
274
+ return handleV1Subscription(handlePreimageLookupSubscribeSlot, handler);
497
275
  },
498
276
  handlePreimageSubmit(handler) {
499
- init();
500
- return handlePreimageSubmitSlot.update(async (params) => {
501
- const version = 'v1';
502
- const error = new PreimageSubmitErr.Unknown({ reason: UNSUPPORTED_MESSAGE_FORMAT_ERROR });
503
- return guardVersion(params, version, error)
504
- .asyncMap(async (params) => handler(params, { ok: (okAsync), err: (errAsync) }))
505
- .andThen(r => r.map(r => enumValue(version, resultOk(r))))
506
- .orElse(r => ok(enumValue(version, resultErr(r))))
507
- .unwrapOr(enumValue(version, resultErr(error)));
508
- });
277
+ return handleV1Request(handlePreimageSubmitSlot, () => new PreimageSubmitErr.Unknown({ reason: UNSUPPORTED_MESSAGE_FORMAT_ERROR }), handler);
278
+ },
279
+ handlePaymentBalanceSubscribe(handler) {
280
+ return handleV1Subscription(handlePaymentBalanceSubscribeSlot, handler);
281
+ },
282
+ handlePaymentTopUp(handler) {
283
+ return handleV1Request(handlePaymentTopUpSlot, () => new PaymentTopUpErr.Unknown({ reason: UNSUPPORTED_MESSAGE_FORMAT_ERROR }), handler);
284
+ },
285
+ handlePaymentRequest(handler) {
286
+ return handleV1Request(handlePaymentRequestSlot, () => new PaymentRequestErr.Unknown({ reason: UNSUPPORTED_MESSAGE_FORMAT_ERROR }), handler);
287
+ },
288
+ handlePaymentStatusSubscribe(handler) {
289
+ return handleV1Subscription(handlePaymentStatusSubscribeSlot, handler);
509
290
  },
510
291
  // chain interaction
511
292
  handleChainConnection(factory) {
@@ -744,7 +525,7 @@ export function createContainer(provider) {
744
525
  }
745
526
  const { genesisHash, transaction } = message.value;
746
527
  try {
747
- const permissionResponse = await handleRemotePermissionSlot.call(enumValue('v1', enumValue('TransactionSubmit', undefined)));
528
+ const permissionResponse = await handleRemotePermissionSlot.call(enumValue('v1', [enumValue('ChainSubmit', undefined)]));
748
529
  const permissionGranted = isEnumVariant(permissionResponse, 'v1') &&
749
530
  permissionResponse.value.success === true &&
750
531
  permissionResponse.value.value === true;
package/dist/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  export { createWebviewProvider } from './createWebviewProvider.js';
2
2
  export { createIframeProvider } from './createIframeProvider.js';
3
3
  export { createContainer } from './createContainer.js';
4
- export type { Container } from './types.js';
4
+ export type { Container, ContainerHandlerOf } from './types.js';
5
+ export { deriveProductEntropy } from './deriveEntropy.js';
5
6
  export { createRateLimiter } from './rateLimiter.js';
6
7
  export type { CreateRateLimiterConfig, RateLimiter, RateLimiterConfig, RateLimiterStrategy } from './rateLimiter.js';
package/dist/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  export { createWebviewProvider } from './createWebviewProvider.js';
2
2
  export { createIframeProvider } from './createIframeProvider.js';
3
3
  export { createContainer } from './createContainer.js';
4
+ export { deriveProductEntropy } from './deriveEntropy.js';
4
5
  export { createRateLimiter } from './rateLimiter.js';
@@ -1,4 +1,3 @@
1
- export declare const RATE_LIMITED_MESSAGE = "Request rate limited";
2
1
  export type RateLimiterConfig = {
3
2
  maxRequestsPerInterval: number;
4
3
  intervalMs: number;
@@ -1,5 +1,5 @@
1
1
  import { GenericError } from '@novasamatech/host-api';
2
- export const RATE_LIMITED_MESSAGE = 'Request rate limited';
2
+ const RATE_LIMITED_MESSAGE = 'Request rate limited';
3
3
  function createQueueStrategy(config) {
4
4
  const state = {
5
5
  remainingTokens: config.maxRequestsPerInterval,
@@ -25,7 +25,7 @@ function createQueueStrategy(config) {
25
25
  state.remainingTokens -= 1;
26
26
  try {
27
27
  const result = task.execute();
28
- if (result != null && typeof result.then === 'function') {
28
+ if (result instanceof Promise) {
29
29
  result.then(task.resolve).catch(task.reject);
30
30
  }
31
31
  else {
@@ -51,7 +51,7 @@ function createQueueStrategy(config) {
51
51
  state.remainingTokens -= 1;
52
52
  try {
53
53
  const result = execute();
54
- if (result != null && typeof result.then === 'function') {
54
+ if (result instanceof Promise) {
55
55
  return result;
56
56
  }
57
57
  return Promise.resolve(result);
@@ -103,7 +103,7 @@ function createDropStrategy(config) {
103
103
  state.remainingTokens -= 1;
104
104
  try {
105
105
  const result = execute();
106
- if (result != null && typeof result.then === 'function') {
106
+ if (result instanceof Promise) {
107
107
  return result;
108
108
  }
109
109
  return Promise.resolve(result);
package/dist/types.d.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  import type { Codec, CodecType, ConnectionStatus, HexString, HostApiProtocol, Subscription, VersionedProtocolRequest, VersionedProtocolSubscription } from '@novasamatech/host-api';
2
2
  import { CustomRendererNode } from '@novasamatech/host-api';
3
- import type { JsonRpcProvider } from '@polkadot-api/json-rpc-provider';
4
3
  import type { ResultAsync, errAsync } from 'neverthrow';
5
4
  import { okAsync } from 'neverthrow';
5
+ import type { JsonRpcProvider } from 'polkadot-api';
6
6
  type SuccessResponse<T> = T extends {
7
7
  success: true;
8
8
  value: infer U;
@@ -11,23 +11,23 @@ type ErrorResponse<T> = T extends {
11
11
  success: false;
12
12
  value: infer U;
13
13
  } ? U : never;
14
- type Value<T extends Codec<any> | Codec<never>> = T extends Codec<any> ? CodecType<T> : unknown;
14
+ export type CodecValue<T extends Codec<any> | Codec<never>> = T extends Codec<any> ? CodecType<T> : unknown;
15
15
  type OrPromise<T> = T | Promise<T>;
16
16
  type ExtractEnumValue<T> = T extends {
17
17
  tag: string;
18
18
  value: infer V;
19
19
  } ? V : never;
20
- type WithVersion<V extends string, T> = ExtractEnumValue<Extract<T, {
20
+ export type WithVersion<V extends string, T> = ExtractEnumValue<Extract<T, {
21
21
  tag: V;
22
22
  }>>;
23
- type UnwrapSuccessResponse<V extends string, T> = T extends {
23
+ export type UnwrapSuccessResponse<V extends string, T> = T extends {
24
24
  tag: infer Tag;
25
25
  value: infer Value;
26
26
  } ? WithVersion<V, {
27
27
  tag: Tag;
28
28
  value: SuccessResponse<Value>;
29
29
  }> : never;
30
- type UnwrapErrorResponse<V extends string, T> = T extends {
30
+ export type UnwrapErrorResponse<V extends string, T> = T extends {
31
31
  tag: infer Tag;
32
32
  value: infer Value;
33
33
  } ? WithVersion<V, {
@@ -44,30 +44,38 @@ type UnwrapVersionedResult<V extends string, T> = T extends {
44
44
  tag: Tag;
45
45
  value: ErrorResponse<Value>;
46
46
  }>> : never;
47
- type InferRequestHandler<V extends string, T extends VersionedProtocolRequest> = (callback: (params: WithVersion<V, Value<T['request']>>, helpers: {
48
- ok: typeof okAsync<UnwrapSuccessResponse<V, Value<T['response']>>>;
49
- err: typeof errAsync<never, UnwrapErrorResponse<V, Value<T['response']>>>;
50
- }) => OrPromise<UnwrapVersionedResult<V, Value<T['response']>>>) => VoidFunction;
51
- type InferSubscribeHandler<V extends string, T extends VersionedProtocolSubscription> = (callback: (params: WithVersion<V, Value<T['start']>>, send: (payload: WithVersion<V, Value<T['receive']>>) => void, interrupt: VoidFunction) => VoidFunction) => VoidFunction;
47
+ export type ContainerRequestHandler<V extends string, T extends VersionedProtocolRequest> = (params: WithVersion<V, CodecValue<T['request']>>, helpers: {
48
+ ok: typeof okAsync<UnwrapSuccessResponse<V, CodecValue<T['response']>>>;
49
+ err: typeof errAsync<never, UnwrapErrorResponse<V, CodecValue<T['response']>>>;
50
+ }) => OrPromise<UnwrapVersionedResult<V, CodecValue<T['response']>>>;
51
+ type InferRequestHandler<V extends string, T extends VersionedProtocolRequest> = (callback: ContainerRequestHandler<V, T>) => VoidFunction;
52
+ type InferSubscribeHandler<V extends string, T extends VersionedProtocolSubscription> = (callback: (params: WithVersion<V, CodecValue<T['start']>>, send: (payload: WithVersion<V, CodecValue<T['receive']>>) => void, interrupt: VoidFunction) => VoidFunction) => VoidFunction;
52
53
  type InferHandler<V extends string, T extends VersionedProtocolRequest | VersionedProtocolSubscription> = T extends VersionedProtocolRequest ? InferRequestHandler<V, T> : T extends VersionedProtocolSubscription ? InferSubscribeHandler<V, T> : never;
54
+ export type ContainerHandlerOf<T extends (...args: any[]) => any> = Parameters<T>[0];
53
55
  export type Container = {
54
56
  handleFeatureSupported: InferHandler<'v1', HostApiProtocol['host_feature_supported']>;
55
57
  handleDevicePermission: InferHandler<'v1', HostApiProtocol['host_device_permission']>;
56
58
  handlePermission: InferHandler<'v1', HostApiProtocol['remote_permission']>;
57
59
  handlePushNotification: InferHandler<'v1', HostApiProtocol['host_push_notification']>;
58
60
  handleNavigateTo: InferHandler<'v1', HostApiProtocol['host_navigate_to']>;
61
+ handleDeriveEntropy: InferHandler<'v1', HostApiProtocol['host_derive_entropy']>;
59
62
  handleLocalStorageRead: InferHandler<'v1', HostApiProtocol['host_local_storage_read']>;
60
63
  handleLocalStorageWrite: InferHandler<'v1', HostApiProtocol['host_local_storage_write']>;
61
64
  handleLocalStorageClear: InferHandler<'v1', HostApiProtocol['host_local_storage_clear']>;
65
+ handleAccountGetRoot: InferHandler<'v1', HostApiProtocol['host_account_get_root']>;
66
+ handleRequestLogin: InferHandler<'v1', HostApiProtocol['host_request_login']>;
62
67
  handleAccountConnectionStatusSubscribe: InferHandler<'v1', HostApiProtocol['host_account_connection_status_subscribe']>;
68
+ handleThemeSubscribe: InferHandler<'v1', HostApiProtocol['host_theme_subscribe']>;
63
69
  handleAccountGet: InferHandler<'v1', HostApiProtocol['host_account_get']>;
64
70
  handleAccountGetAlias: InferHandler<'v1', HostApiProtocol['host_account_get_alias']>;
65
71
  handleAccountCreateProof: InferHandler<'v1', HostApiProtocol['host_account_create_proof']>;
66
- handleGetNonProductAccounts: InferHandler<'v1', HostApiProtocol['host_get_non_product_accounts']>;
72
+ handleGetLegacyAccounts: InferHandler<'v1', HostApiProtocol['host_get_legacy_accounts']>;
67
73
  handleCreateTransaction: InferHandler<'v1', HostApiProtocol['host_create_transaction']>;
68
- handleCreateTransactionWithNonProductAccount: InferHandler<'v1', HostApiProtocol['host_create_transaction_with_non_product_account']>;
74
+ handleCreateTransactionWithLegacyAccount: InferHandler<'v1', HostApiProtocol['host_create_transaction_with_legacy_account']>;
69
75
  handleSignRaw: InferHandler<'v1', HostApiProtocol['host_sign_raw']>;
70
76
  handleSignPayload: InferHandler<'v1', HostApiProtocol['host_sign_payload']>;
77
+ handleSignRawWithLegacyAccount: InferHandler<'v1', HostApiProtocol['host_sign_raw_with_legacy_account']>;
78
+ handleSignPayloadWithLegacyAccount: InferHandler<'v1', HostApiProtocol['host_sign_payload_with_legacy_account']>;
71
79
  handleChatCreateRoom: InferHandler<'v1', HostApiProtocol['host_chat_create_room']>;
72
80
  handleChatBotRegistration: InferHandler<'v1', HostApiProtocol['host_chat_register_bot']>;
73
81
  handleChatListSubscribe: InferHandler<'v1', HostApiProtocol['host_chat_list_subscribe']>;
@@ -83,6 +91,10 @@ export type Container = {
83
91
  handleStatementStoreSubmit: InferHandler<'v1', HostApiProtocol['remote_statement_store_submit']>;
84
92
  handlePreimageLookupSubscribe: InferHandler<'v1', HostApiProtocol['remote_preimage_lookup_subscribe']>;
85
93
  handlePreimageSubmit: InferHandler<'v1', HostApiProtocol['remote_preimage_submit']>;
94
+ handlePaymentBalanceSubscribe: InferHandler<'v1', HostApiProtocol['host_payment_balance_subscribe']>;
95
+ handlePaymentTopUp: InferHandler<'v1', HostApiProtocol['host_payment_top_up']>;
96
+ handlePaymentRequest: InferHandler<'v1', HostApiProtocol['host_payment_request']>;
97
+ handlePaymentStatusSubscribe: InferHandler<'v1', HostApiProtocol['host_payment_status_subscribe']>;
86
98
  handleChainConnection: (factory: (genesisHash: HexString) => JsonRpcProvider | null) => VoidFunction;
87
99
  isReady(): Promise<boolean>;
88
100
  dispose(): void;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@novasamatech/host-container",
3
3
  "type": "module",
4
- "version": "0.6.18",
4
+ "version": "0.7.0-1",
5
5
  "description": "Host container for hosting and managing products within the Polkadot ecosystem.",
6
6
  "license": "Apache-2.0",
7
7
  "repository": {
@@ -25,13 +25,13 @@
25
25
  "README.md"
26
26
  ],
27
27
  "dependencies": {
28
- "@polkadot-api/utils": "^0.2.0",
29
- "@polkadot-api/json-rpc-provider": "^0.0.4",
30
- "@novasamatech/host-api": "0.6.18",
31
- "nanoid": "5.1.7"
28
+ "@noble/hashes": "2.2.0",
29
+ "polkadot-api": ">=2",
30
+ "@novasamatech/host-api": "0.7.0-1",
31
+ "nanoid": "5.1.9"
32
32
  },
33
33
  "devDependencies": {
34
- "electron": "^41.1.0"
34
+ "electron": "^41.2.0"
35
35
  },
36
36
  "publishConfig": {
37
37
  "access": "public"