@novasamatech/host-container 0.7.0-0 → 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);
79
- }
80
- if (request.tag === 'TransactionSubmit') {
81
- return ok(true);
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
+ }
82
116
  }
83
- return ok(false);
117
+ return ok(true);
84
118
  });
85
119
  ```
86
120
 
@@ -163,6 +197,44 @@ container.handleThemeSubscribe((_, send, interrupt) => {
163
197
  });
164
198
  ```
165
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
+
166
238
  ### handleAccountGet
167
239
 
168
240
  ```ts
@@ -200,11 +272,11 @@ container.handleAccountCreateProof(async ([[dotnsId, derivationIndex], ringLocat
200
272
  });
201
273
  ```
202
274
 
203
- ### handleGetNonProductAccounts
275
+ ### handleGetLegacyAccounts
204
276
 
205
277
  ```ts
206
- container.handleGetNonProductAccounts(async (_, { ok, err }) => {
207
- const accounts = await getNonProductAccounts();
278
+ container.handleGetLegacyAccounts(async (_, { ok, err }) => {
279
+ const accounts = await getLegacyAccounts();
208
280
  return ok(accounts);
209
281
  });
210
282
  ```
@@ -222,12 +294,12 @@ container.handleCreateTransaction(async ([productAccountId, payload], { ok, err
222
294
  });
223
295
  ```
224
296
 
225
- ### handleCreateTransactionWithNonProductAccount
297
+ ### handleCreateTransactionWithLegacyAccount
226
298
 
227
299
  ```ts
228
- container.handleCreateTransactionWithNonProductAccount(async (payload, { ok, err }) => {
300
+ container.handleCreateTransactionWithLegacyAccount(async (payload, { ok, err }) => {
229
301
  try {
230
- const signedTx = await createTransactionWithNonProductAccount(payload);
302
+ const signedTx = await createTransactionWithLegacyAccount(payload);
231
303
  return ok(signedTx);
232
304
  } catch (e) {
233
305
  return err({ tag: 'Rejected' });
@@ -323,10 +395,11 @@ subscription.unsubscribe();
323
395
  ### handleStatementStoreSubscribe
324
396
 
325
397
  ```ts
326
- container.handleStatementStoreSubscribe((query, send, interrupt) => {
327
- const listener = (statements) => send(statements);
328
- statementStore.subscribe(query, listener);
329
- 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);
330
403
  });
331
404
  ```
332
405
 
@@ -457,10 +530,6 @@ container.handleChainConnection({
457
530
  const endpoint = chains.get(genesisHash);
458
531
  if (!endpoint) return null;
459
532
  return getWsProvider(endpoint);
460
- },
461
- async submitPermission(transaction) {
462
- if (hasPermission(transaction)) return true;
463
- return false;
464
533
  }
465
534
  });
466
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,4 +1,4 @@
1
- import { ChatBotRegistrationErr, ChatMessagePostingErr, ChatRoomRegistrationErr, CreateProofErr, CreateTransactionErr, DeriveEntropyErr, GenericError, NavigateToErr, PaymentRequestErr, PaymentTopUpErr, 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';
@@ -71,6 +71,34 @@ export function createContainer(provider) {
71
71
  });
72
72
  return makeSubscriptionSlot(method, defaultHandler);
73
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
+ }
74
102
  function handleV1Request(slot, makeError, handler) {
75
103
  init();
76
104
  const version = 'v1';
@@ -97,9 +125,11 @@ export function createContainer(provider) {
97
125
  return slot(slotHandler);
98
126
  }
99
127
  // account slots
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 }));
100
130
  const handleAccountGetSlot = makeNotImplementedSlot('host_account_get', () => new RequestCredentialsErr.Unknown({ reason: NOT_IMPLEMENTED }));
101
131
  const handleAccountGetAliasSlot = makeNotImplementedSlot('host_account_get_alias', () => new RequestCredentialsErr.Unknown({ reason: NOT_IMPLEMENTED }));
102
- const handleGetNonProductAccountsSlot = makeNotImplementedSlot('host_get_non_product_accounts', () => new RequestCredentialsErr.Unknown({ reason: NOT_IMPLEMENTED }));
132
+ const handleGetLegacyAccountsSlot = makeNotImplementedSlot('host_get_legacy_accounts', () => new RequestCredentialsErr.Unknown({ reason: NOT_IMPLEMENTED }));
103
133
  const handleAccountCreateProofSlot = makeNotImplementedSlot('host_account_create_proof', () => new CreateProofErr.Unknown({ reason: NOT_IMPLEMENTED }));
104
134
  // entropy derivation slot
105
135
  const handleDeriveEntropySlot = makeNotImplementedSlot('host_derive_entropy', () => new DeriveEntropyErr.Unknown({ reason: NOT_IMPLEMENTED }));
@@ -110,10 +140,10 @@ export function createContainer(provider) {
110
140
  // signing slots
111
141
  const handleSignRawSlot = makeNotImplementedSlot('host_sign_raw', () => new SigningErr.Unknown({ reason: NOT_IMPLEMENTED }));
112
142
  const handleSignPayloadSlot = makeNotImplementedSlot('host_sign_payload', () => new SigningErr.Unknown({ reason: NOT_IMPLEMENTED }));
113
- const handleSignRawWithNonProductAccountSlot = makeNotImplementedSlot('host_sign_raw_with_non_product_account', () => new SigningErr.Unknown({ reason: NOT_IMPLEMENTED }));
114
- const handleSignPayloadWithNonProductAccountSlot = makeNotImplementedSlot('host_sign_payload_with_non_product_account', () => 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 }));
115
145
  const handleCreateTransactionSlot = makeNotImplementedSlot('host_create_transaction', () => new CreateTransactionErr.Unknown({ reason: NOT_IMPLEMENTED }));
116
- const handleCreateTransactionWithNonProductAccountSlot = makeNotImplementedSlot('host_create_transaction_with_non_product_account', () => new CreateTransactionErr.Unknown({ reason: NOT_IMPLEMENTED }));
146
+ const handleCreateTransactionWithLegacyAccountSlot = makeNotImplementedSlot('host_create_transaction_with_legacy_account', () => new CreateTransactionErr.Unknown({ reason: NOT_IMPLEMENTED }));
117
147
  const handleFeatureSupportedSlot = makeNotImplementedSlot('host_feature_supported', () => new GenericError({ reason: NOT_IMPLEMENTED }));
118
148
  const handleDevicePermissionSlot = makeNotImplementedSlot('host_device_permission', () => new GenericError({ reason: NOT_IMPLEMENTED }));
119
149
  const handleRemotePermissionSlot = makeNotImplementedSlot('remote_permission', () => new GenericError({ reason: NOT_IMPLEMENTED }));
@@ -122,9 +152,9 @@ export function createContainer(provider) {
122
152
  const handleChatCreateRoomSlot = makeNotImplementedSlot('host_chat_create_room', () => new ChatRoomRegistrationErr.Unknown({ reason: NOT_IMPLEMENTED }));
123
153
  const handleChatBotRegistrationSlot = makeNotImplementedSlot('host_chat_register_bot', () => new ChatBotRegistrationErr.Unknown({ reason: NOT_IMPLEMENTED }));
124
154
  const handleChatPostMessageSlot = makeNotImplementedSlot('host_chat_post_message', () => new ChatMessagePostingErr.Unknown({ reason: NOT_IMPLEMENTED }));
125
- const handleStatementStoreSubmitSlot = makeNotImplementedSlot('remote_statement_store_submit', () => new GenericError({ reason: NOT_IMPLEMENTED }));
155
+ const handleStatementStoreSubmitSlot = makePermissionGatedRequestSlot('remote_statement_store_submit', 'StatementSubmit', () => new GenericError({ reason: NOT_IMPLEMENTED }));
126
156
  const handleStatementStoreCreateProofSlot = makeNotImplementedSlot('remote_statement_store_create_proof', () => new StatementProofErr.Unknown({ reason: NOT_IMPLEMENTED }));
127
- const handlePreimageSubmitSlot = makeNotImplementedSlot('remote_preimage_submit', () => new PreimageSubmitErr.Unknown({ reason: NOT_IMPLEMENTED }));
157
+ const handlePreimageSubmitSlot = makePermissionGatedRequestSlot('remote_preimage_submit', 'PreimageSubmit', () => new PreimageSubmitErr.Unknown({ reason: NOT_IMPLEMENTED }));
128
158
  // payment request slots
129
159
  const handlePaymentTopUpSlot = makeNotImplementedSlot('host_payment_top_up', () => new PaymentTopUpErr.Unknown({ reason: NOT_IMPLEMENTED }));
130
160
  const handlePaymentRequestSlot = makeNotImplementedSlot('host_payment_request', () => new PaymentRequestErr.Unknown({ reason: NOT_IMPLEMENTED }));
@@ -169,6 +199,12 @@ export function createContainer(provider) {
169
199
  handleThemeSubscribe(handler) {
170
200
  return handleV1Subscription(handleThemeSubscribeSlot, handler);
171
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);
207
+ },
172
208
  handleAccountConnectionStatusSubscribe(handler) {
173
209
  return handleV1Subscription(handleAccountConnectionStatusSubscribeSlot, handler);
174
210
  },
@@ -181,14 +217,14 @@ export function createContainer(provider) {
181
217
  handleAccountCreateProof(handler) {
182
218
  return handleV1Request(handleAccountCreateProofSlot, () => new CreateProofErr.Unknown({ reason: UNSUPPORTED_MESSAGE_FORMAT_ERROR }), handler);
183
219
  },
184
- handleGetNonProductAccounts(handler) {
185
- return handleV1Request(handleGetNonProductAccountsSlot, () => new RequestCredentialsErr.Unknown({ reason: UNSUPPORTED_MESSAGE_FORMAT_ERROR }), handler);
220
+ handleGetLegacyAccounts(handler) {
221
+ return handleV1Request(handleGetLegacyAccountsSlot, () => new RequestCredentialsErr.Unknown({ reason: UNSUPPORTED_MESSAGE_FORMAT_ERROR }), handler);
186
222
  },
187
223
  handleCreateTransaction(handler) {
188
224
  return handleV1Request(handleCreateTransactionSlot, () => new CreateTransactionErr.Unknown({ reason: UNSUPPORTED_MESSAGE_FORMAT_ERROR }), handler);
189
225
  },
190
- handleCreateTransactionWithNonProductAccount(handler) {
191
- return handleV1Request(handleCreateTransactionWithNonProductAccountSlot, () => new CreateTransactionErr.Unknown({ reason: UNSUPPORTED_MESSAGE_FORMAT_ERROR }), handler);
226
+ handleCreateTransactionWithLegacyAccount(handler) {
227
+ return handleV1Request(handleCreateTransactionWithLegacyAccountSlot, () => new CreateTransactionErr.Unknown({ reason: UNSUPPORTED_MESSAGE_FORMAT_ERROR }), handler);
192
228
  },
193
229
  handleSignRaw(handler) {
194
230
  return handleV1Request(handleSignRawSlot, () => new SigningErr.Unknown({ reason: UNSUPPORTED_MESSAGE_FORMAT_ERROR }), handler);
@@ -196,11 +232,11 @@ export function createContainer(provider) {
196
232
  handleSignPayload(handler) {
197
233
  return handleV1Request(handleSignPayloadSlot, () => new SigningErr.Unknown({ reason: UNSUPPORTED_MESSAGE_FORMAT_ERROR }), handler);
198
234
  },
199
- handleSignRawWithNonProductAccount(handler) {
200
- return handleV1Request(handleSignRawWithNonProductAccountSlot, () => new SigningErr.Unknown({ reason: UNSUPPORTED_MESSAGE_FORMAT_ERROR }), handler);
235
+ handleSignRawWithLegacyAccount(handler) {
236
+ return handleV1Request(handleSignRawWithLegacyAccountSlot, () => new SigningErr.Unknown({ reason: UNSUPPORTED_MESSAGE_FORMAT_ERROR }), handler);
201
237
  },
202
- handleSignPayloadWithNonProductAccount(handler) {
203
- return handleV1Request(handleSignPayloadWithNonProductAccountSlot, () => new SigningErr.Unknown({ reason: UNSUPPORTED_MESSAGE_FORMAT_ERROR }), handler);
238
+ handleSignPayloadWithLegacyAccount(handler) {
239
+ return handleV1Request(handleSignPayloadWithLegacyAccountSlot, () => new SigningErr.Unknown({ reason: UNSUPPORTED_MESSAGE_FORMAT_ERROR }), handler);
204
240
  },
205
241
  handleChatCreateRoom(handler) {
206
242
  return handleV1Request(handleChatCreateRoomSlot, () => new ChatRoomRegistrationErr.Unknown({ reason: UNSUPPORTED_MESSAGE_FORMAT_ERROR }), handler);
@@ -489,7 +525,7 @@ export function createContainer(provider) {
489
525
  }
490
526
  const { genesisHash, transaction } = message.value;
491
527
  try {
492
- const permissionResponse = await handleRemotePermissionSlot.call(enumValue('v1', enumValue('TransactionSubmit', undefined)));
528
+ const permissionResponse = await handleRemotePermissionSlot.call(enumValue('v1', [enumValue('ChainSubmit', undefined)]));
493
529
  const permissionGranted = isEnumVariant(permissionResponse, 'v1') &&
494
530
  permissionResponse.value.success === true &&
495
531
  permissionResponse.value.value === true;
package/dist/index.d.ts CHANGED
@@ -1,7 +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
5
  export { deriveProductEntropy } from './deriveEntropy.js';
6
6
  export { createRateLimiter } from './rateLimiter.js';
7
7
  export type { CreateRateLimiterConfig, RateLimiter, RateLimiterConfig, RateLimiterStrategy } 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,
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;
@@ -51,6 +51,7 @@ export type ContainerRequestHandler<V extends string, T extends VersionedProtoco
51
51
  type InferRequestHandler<V extends string, T extends VersionedProtocolRequest> = (callback: ContainerRequestHandler<V, T>) => VoidFunction;
52
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;
53
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];
54
55
  export type Container = {
55
56
  handleFeatureSupported: InferHandler<'v1', HostApiProtocol['host_feature_supported']>;
56
57
  handleDevicePermission: InferHandler<'v1', HostApiProtocol['host_device_permission']>;
@@ -61,18 +62,20 @@ export type Container = {
61
62
  handleLocalStorageRead: InferHandler<'v1', HostApiProtocol['host_local_storage_read']>;
62
63
  handleLocalStorageWrite: InferHandler<'v1', HostApiProtocol['host_local_storage_write']>;
63
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']>;
64
67
  handleAccountConnectionStatusSubscribe: InferHandler<'v1', HostApiProtocol['host_account_connection_status_subscribe']>;
65
68
  handleThemeSubscribe: InferHandler<'v1', HostApiProtocol['host_theme_subscribe']>;
66
69
  handleAccountGet: InferHandler<'v1', HostApiProtocol['host_account_get']>;
67
70
  handleAccountGetAlias: InferHandler<'v1', HostApiProtocol['host_account_get_alias']>;
68
71
  handleAccountCreateProof: InferHandler<'v1', HostApiProtocol['host_account_create_proof']>;
69
- handleGetNonProductAccounts: InferHandler<'v1', HostApiProtocol['host_get_non_product_accounts']>;
72
+ handleGetLegacyAccounts: InferHandler<'v1', HostApiProtocol['host_get_legacy_accounts']>;
70
73
  handleCreateTransaction: InferHandler<'v1', HostApiProtocol['host_create_transaction']>;
71
- handleCreateTransactionWithNonProductAccount: InferHandler<'v1', HostApiProtocol['host_create_transaction_with_non_product_account']>;
74
+ handleCreateTransactionWithLegacyAccount: InferHandler<'v1', HostApiProtocol['host_create_transaction_with_legacy_account']>;
72
75
  handleSignRaw: InferHandler<'v1', HostApiProtocol['host_sign_raw']>;
73
76
  handleSignPayload: InferHandler<'v1', HostApiProtocol['host_sign_payload']>;
74
- handleSignRawWithNonProductAccount: InferHandler<'v1', HostApiProtocol['host_sign_raw_with_non_product_account']>;
75
- handleSignPayloadWithNonProductAccount: InferHandler<'v1', HostApiProtocol['host_sign_payload_with_non_product_account']>;
77
+ handleSignRawWithLegacyAccount: InferHandler<'v1', HostApiProtocol['host_sign_raw_with_legacy_account']>;
78
+ handleSignPayloadWithLegacyAccount: InferHandler<'v1', HostApiProtocol['host_sign_payload_with_legacy_account']>;
76
79
  handleChatCreateRoom: InferHandler<'v1', HostApiProtocol['host_chat_create_room']>;
77
80
  handleChatBotRegistration: InferHandler<'v1', HostApiProtocol['host_chat_register_bot']>;
78
81
  handleChatListSubscribe: InferHandler<'v1', HostApiProtocol['host_chat_list_subscribe']>;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@novasamatech/host-container",
3
3
  "type": "module",
4
- "version": "0.7.0-0",
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,14 +25,13 @@
25
25
  "README.md"
26
26
  ],
27
27
  "dependencies": {
28
- "@noble/hashes": "2.0.1",
29
- "@polkadot-api/utils": "^0.2.0",
30
- "@polkadot-api/json-rpc-provider": "^0.0.4",
31
- "@novasamatech/host-api": "0.7.0-0",
32
- "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"
33
32
  },
34
33
  "devDependencies": {
35
- "electron": "^41.1.0"
34
+ "electron": "^41.2.0"
36
35
  },
37
36
  "publishConfig": {
38
37
  "access": "public"