@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 +93 -24
- package/dist/chainConnectionManager.d.ts +3 -5
- package/dist/chainConnectionManager.js +49 -29
- package/dist/createContainer.js +52 -16
- package/dist/index.d.ts +1 -1
- package/dist/rateLimiter.d.ts +0 -1
- package/dist/rateLimiter.js +1 -1
- package/dist/types.d.ts +8 -5
- package/package.json +6 -7
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
|
-
|
|
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
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
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(
|
|
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
|
-
###
|
|
275
|
+
### handleGetLegacyAccounts
|
|
204
276
|
|
|
205
277
|
```ts
|
|
206
|
-
container.
|
|
207
|
-
const accounts = await
|
|
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
|
-
###
|
|
297
|
+
### handleCreateTransactionWithLegacyAccount
|
|
226
298
|
|
|
227
299
|
```ts
|
|
228
|
-
container.
|
|
300
|
+
container.handleCreateTransactionWithLegacyAccount(async (payload, { ok, err }) => {
|
|
229
301
|
try {
|
|
230
|
-
const signedTx = await
|
|
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((
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
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 '
|
|
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(
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
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(
|
|
40
|
-
if ('error' in
|
|
41
|
-
pending.reject(
|
|
32
|
+
pendingRequests.delete(String(message.id));
|
|
33
|
+
if ('error' in message) {
|
|
34
|
+
pending.reject(message.error);
|
|
42
35
|
}
|
|
43
36
|
else {
|
|
44
|
-
pending.resolve(
|
|
37
|
+
pending.resolve(message.result);
|
|
45
38
|
}
|
|
46
39
|
return;
|
|
47
40
|
}
|
|
48
41
|
}
|
|
49
|
-
// Subscription notification
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
follow.
|
|
56
|
-
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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();
|
package/dist/createContainer.js
CHANGED
|
@@ -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
|
|
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
|
|
114
|
-
const
|
|
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
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
185
|
-
return handleV1Request(
|
|
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
|
-
|
|
191
|
-
return handleV1Request(
|
|
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
|
-
|
|
200
|
-
return handleV1Request(
|
|
235
|
+
handleSignRawWithLegacyAccount(handler) {
|
|
236
|
+
return handleV1Request(handleSignRawWithLegacyAccountSlot, () => new SigningErr.Unknown({ reason: UNSUPPORTED_MESSAGE_FORMAT_ERROR }), handler);
|
|
201
237
|
},
|
|
202
|
-
|
|
203
|
-
return handleV1Request(
|
|
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('
|
|
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';
|
package/dist/rateLimiter.d.ts
CHANGED
package/dist/rateLimiter.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { GenericError } from '@novasamatech/host-api';
|
|
2
|
-
|
|
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
|
-
|
|
72
|
+
handleGetLegacyAccounts: InferHandler<'v1', HostApiProtocol['host_get_legacy_accounts']>;
|
|
70
73
|
handleCreateTransaction: InferHandler<'v1', HostApiProtocol['host_create_transaction']>;
|
|
71
|
-
|
|
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
|
-
|
|
75
|
-
|
|
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-
|
|
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
|
|
29
|
-
"
|
|
30
|
-
"@
|
|
31
|
-
"
|
|
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.
|
|
34
|
+
"electron": "^41.2.0"
|
|
36
35
|
},
|
|
37
36
|
"publishConfig": {
|
|
38
37
|
"access": "public"
|