@novasamatech/host-chat 0.9.1 → 0.9.2
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 +54 -36
- package/dist/accountService.d.ts +5 -16
- package/dist/accountService.js +6 -32
- package/dist/accountService.spec.d.ts +1 -0
- package/dist/accountService.spec.js +36 -0
- package/dist/codec/identifierKey.d.ts +20 -0
- package/dist/codec/identifierKey.js +18 -0
- package/dist/codec/identifierKey.spec.d.ts +1 -0
- package/dist/codec/identifierKey.spec.js +34 -0
- package/dist/codec/localMessage.d.ts +6 -6
- package/dist/index.d.ts +1 -0
- package/package.json +7 -8
package/README.md
CHANGED
|
@@ -4,15 +4,14 @@ Account lookup and chat-message codecs for host applications integrating with th
|
|
|
4
4
|
|
|
5
5
|
## Overview
|
|
6
6
|
|
|
7
|
-
`@novasamatech/host-chat` exposes the read side of the chat domain: discovering Polkadot
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
statement store.
|
|
7
|
+
`@novasamatech/host-chat` exposes the read side of the chat domain: discovering Polkadot accounts by username and
|
|
8
|
+
resolving their on-chain identity from `Resources.Consumers`. It also publishes the SCALE codecs used by the chat wire
|
|
9
|
+
protocol (messages, attachments, local-message envelopes) so host applications can decode statements they receive over
|
|
10
|
+
the statement store.
|
|
12
11
|
|
|
13
|
-
The package is UI-framework agnostic. The main entry point returns plain async functions
|
|
14
|
-
|
|
15
|
-
|
|
12
|
+
The package is UI-framework agnostic. The main entry point returns plain async functions backed by
|
|
13
|
+
[`neverthrow`](https://github.com/supermacro/neverthrow) `ResultAsync`, and the codec exports are pure SCALE codecs with
|
|
14
|
+
no runtime side effects.
|
|
16
15
|
|
|
17
16
|
## Installation
|
|
18
17
|
|
|
@@ -24,10 +23,18 @@ npm install @novasamatech/host-chat --save -E
|
|
|
24
23
|
|
|
25
24
|
```ts
|
|
26
25
|
import { createAccountService } from '@novasamatech/host-chat';
|
|
26
|
+
import { createIdentityRepository, createIdentityRpcAdapter } from '@novasamatech/host-papp';
|
|
27
|
+
import { createLocalStorageAdapter } from '@novasamatech/storage-adapter';
|
|
27
28
|
import { createLazyClient } from '@novasamatech/statement-store';
|
|
28
29
|
|
|
29
30
|
const lazyClient = createLazyClient(/* chain provider */);
|
|
30
|
-
const accounts = createAccountService(
|
|
31
|
+
const accounts = createAccountService({
|
|
32
|
+
identityEndpoint: 'https://identity-backend.example/',
|
|
33
|
+
identity: createIdentityRepository({
|
|
34
|
+
adapter: createIdentityRpcAdapter(lazyClient),
|
|
35
|
+
storage: createLocalStorageAdapter('my-host-app'),
|
|
36
|
+
}),
|
|
37
|
+
});
|
|
31
38
|
|
|
32
39
|
// Search the off-chain username index for accounts whose username starts with `alice`.
|
|
33
40
|
const search = await accounts.search('alice', 'ASSIGNED');
|
|
@@ -41,43 +48,58 @@ if (search.isOk()) {
|
|
|
41
48
|
const identity = await accounts.getConsumerInfo('5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY');
|
|
42
49
|
if (identity.isOk() && identity.value) {
|
|
43
50
|
console.log(identity.value.fullUsername, identity.value.credibility);
|
|
51
|
+
|
|
52
|
+
// 32-byte X25519 chat encryption key as hex, or null for a keypair type
|
|
53
|
+
// this SDK does not implement.
|
|
54
|
+
console.log(identity.value.identifierKey);
|
|
44
55
|
}
|
|
45
56
|
```
|
|
46
57
|
|
|
47
|
-
|
|
58
|
+
## API
|
|
48
59
|
|
|
49
|
-
`createAccountService
|
|
60
|
+
### `createAccountService({ identityEndpoint, identity })`
|
|
50
61
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
| `paseo-next` | Paseo People (V1) |
|
|
56
|
-
| `paseo-next-v2` | Paseo People (V2 multi-device) |
|
|
62
|
+
- **`identityEndpoint`** — base URL of the off-chain identity backend that `search` queries. A trailing slash is
|
|
63
|
+
optional.
|
|
64
|
+
- **`identity`** — an identity repository, typed `IdentitySource` (`Pick<IdentityRepository, 'getIdentity'>` from
|
|
65
|
+
`@novasamatech/host-papp`).
|
|
57
66
|
|
|
58
|
-
|
|
59
|
-
|
|
67
|
+
The service takes a repository rather than a chain client, so a host that also runs `createPappAdapter` can pass
|
|
68
|
+
`papp.identity` straight in and share one cache and one chain connection:
|
|
60
69
|
|
|
61
|
-
|
|
70
|
+
```ts
|
|
71
|
+
const papp = createPappAdapter({ appId: 'my-host-app' });
|
|
72
|
+
const accounts = createAccountService({ identityEndpoint, identity: papp.identity });
|
|
73
|
+
```
|
|
62
74
|
|
|
63
|
-
|
|
75
|
+
It also makes the service trivial to test — the whole dependency is one function:
|
|
76
|
+
|
|
77
|
+
```ts
|
|
78
|
+
const accounts = createAccountService({
|
|
79
|
+
identityEndpoint,
|
|
80
|
+
identity: { getIdentity: () => okAsync(null) },
|
|
81
|
+
});
|
|
82
|
+
```
|
|
64
83
|
|
|
65
84
|
Returns an object with two methods:
|
|
66
85
|
|
|
67
|
-
- **`search(query, status)`** — query the off-chain username index. `status` is
|
|
68
|
-
|
|
69
|
-
onchainData, createdAt, updatedAt }` rows.
|
|
86
|
+
- **`search(query, status)`** — query the off-chain username index. `status` is `'ASSIGNED' | 'PENDING'`. Resolves to a
|
|
87
|
+
list of `{ candidateAccountId, username, status, onchainData, createdAt, updatedAt }` rows.
|
|
70
88
|
- **`getConsumerInfo(address)`** — resolve a single SS58 address to an `Identity`
|
|
71
|
-
(`{ accountId, fullUsername, liteUsername, credibility }`) by reading
|
|
72
|
-
|
|
73
|
-
|
|
89
|
+
(`{ accountId, fullUsername, liteUsername, credibility, identifierKey }`) by reading `Resources.Consumers` from the
|
|
90
|
+
People chain. Returns `null` if the account has no consumer entry, and an `err` if `address` is not a valid SS58
|
|
91
|
+
address.
|
|
74
92
|
|
|
75
93
|
Both methods return `ResultAsync<…, Error>`; call `.isOk()` / `.isErr()` to discriminate.
|
|
76
94
|
|
|
95
|
+
`Identity` and `Credibility` are re-exported from `@novasamatech/host-papp`, which owns the `Resources.Consumers` reader
|
|
96
|
+
this package delegates to — see its [identity lookups](../host-papp/README.md#identity-lookups) section. Note that
|
|
97
|
+
`credibility.lastUpdate` is `string | null`: it is `null` when the chain record carries no readable timestamp.
|
|
98
|
+
|
|
77
99
|
## Codec subpath exports
|
|
78
100
|
|
|
79
|
-
The chat wire codecs are exposed under explicit subpaths so they can be tree-shaken
|
|
80
|
-
|
|
101
|
+
The chat wire codecs are exposed under explicit subpaths so they can be tree-shaken independently of the main entry
|
|
102
|
+
point:
|
|
81
103
|
|
|
82
104
|
```ts
|
|
83
105
|
import {
|
|
@@ -89,14 +111,10 @@ import {
|
|
|
89
111
|
DeviceRemovedContent,
|
|
90
112
|
} from '@novasamatech/host-chat/codec/message';
|
|
91
113
|
|
|
92
|
-
import {
|
|
93
|
-
FileMeta,
|
|
94
|
-
FileVariant,
|
|
95
|
-
P2PMixnetFile,
|
|
96
|
-
} from '@novasamatech/host-chat/codec/attachment';
|
|
114
|
+
import { FileMeta, FileVariant, P2PMixnetFile } from '@novasamatech/host-chat/codec/attachment';
|
|
97
115
|
|
|
98
116
|
import type { ChatSession } from '@novasamatech/host-chat/session';
|
|
99
117
|
```
|
|
100
118
|
|
|
101
|
-
These are byte-compatible with the Android / iOS Polkadot Mobile clients — modify with
|
|
102
|
-
|
|
119
|
+
These are byte-compatible with the Android / iOS Polkadot Mobile clients — modify with care, the indices are pinned by
|
|
120
|
+
the protocol.
|
package/dist/accountService.d.ts
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
|
+
import type { Identity, IdentityRepository } from '@novasamatech/host-papp';
|
|
1
2
|
import type { HexString } from '@novasamatech/scale';
|
|
2
|
-
import type { LazyClient } from '@novasamatech/statement-store';
|
|
3
3
|
import type { ResultAsync } from 'neverthrow';
|
|
4
|
+
export type { Credibility, Identity } from '@novasamatech/host-papp';
|
|
5
|
+
export type IdentitySource = Pick<IdentityRepository, 'getIdentity'>;
|
|
4
6
|
interface Config {
|
|
5
7
|
identityEndpoint: string;
|
|
6
|
-
|
|
8
|
+
/** Pass `papp.identity`, or build one with `createIdentityRepository({ adapter, storage })`. */
|
|
9
|
+
identity: IdentitySource;
|
|
7
10
|
}
|
|
8
11
|
type AccountStatus = 'ASSIGNED' | 'PENDING';
|
|
9
12
|
type AccountService = {
|
|
@@ -23,18 +26,4 @@ type SearchResponse = {
|
|
|
23
26
|
createdAt: string;
|
|
24
27
|
updatedAt: string;
|
|
25
28
|
}[];
|
|
26
|
-
export type Credibility = {
|
|
27
|
-
type: 'Lite';
|
|
28
|
-
} | {
|
|
29
|
-
type: 'Person';
|
|
30
|
-
alias: `0x${string}`;
|
|
31
|
-
lastUpdate: string;
|
|
32
|
-
};
|
|
33
|
-
export type Identity = {
|
|
34
|
-
accountId: string;
|
|
35
|
-
fullUsername: string | null;
|
|
36
|
-
liteUsername: string;
|
|
37
|
-
credibility: Credibility;
|
|
38
|
-
};
|
|
39
29
|
export declare const createAccountService: (config: Config) => AccountService;
|
|
40
|
-
export {};
|
package/dist/accountService.js
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import { toHex } from '@novasamatech/scale';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { Result, errAsync, fromPromise } from 'neverthrow';
|
|
3
|
+
import { AccountId } from 'polkadot-api';
|
|
4
4
|
import { toError } from './helpers.js';
|
|
5
5
|
export const createAccountService = (config) => {
|
|
6
6
|
const identityEndpoint = config.identityEndpoint.endsWith('/')
|
|
7
7
|
? config.identityEndpoint
|
|
8
8
|
: `${config.identityEndpoint}/`;
|
|
9
|
+
const accountIdCodec = AccountId();
|
|
10
|
+
// `enc` throws on a malformed SS58 address; keep that inside the Result.
|
|
11
|
+
const encodeAccountId = Result.fromThrowable((address) => toHex(accountIdCodec.enc(address)), toError);
|
|
9
12
|
return {
|
|
10
13
|
search(query, status) {
|
|
11
14
|
// Build query string
|
|
@@ -25,36 +28,7 @@ export const createAccountService = (config) => {
|
|
|
25
28
|
});
|
|
26
29
|
},
|
|
27
30
|
getConsumerInfo(address) {
|
|
28
|
-
|
|
29
|
-
const accountId = AccountId();
|
|
30
|
-
const client = config.client.getClient();
|
|
31
|
-
const api = client.getUnsafeApi();
|
|
32
|
-
const consumerInfo = fromPromise(api.query.Resources?.Consumers?.getValue(address), toError);
|
|
33
|
-
return consumerInfo.map(typedRaw => {
|
|
34
|
-
if (!typedRaw)
|
|
35
|
-
return null;
|
|
36
|
-
// Runtime metadata may expose fields in snake_case (V1) or
|
|
37
|
-
// camelCase (V2 multi-device). Read defensively.
|
|
38
|
-
const raw = typedRaw;
|
|
39
|
-
const fullUsername = raw.full_username ?? raw.fullUsername;
|
|
40
|
-
const liteUsername = raw.lite_username ?? raw.liteUsername;
|
|
41
|
-
const credibility = raw.credibility.type === 'Lite'
|
|
42
|
-
? {
|
|
43
|
-
type: 'Lite',
|
|
44
|
-
}
|
|
45
|
-
: {
|
|
46
|
-
type: 'Person',
|
|
47
|
-
alias: raw.credibility.value.alias,
|
|
48
|
-
lastUpdate: (raw.credibility.value.last_update ??
|
|
49
|
-
raw.credibility.value.lastUpdate).toString(),
|
|
50
|
-
};
|
|
51
|
-
return {
|
|
52
|
-
accountId: toHex(accountId.enc(address)),
|
|
53
|
-
fullUsername: fullUsername ? textDecoder.decode(fullUsername) : null,
|
|
54
|
-
liteUsername: liteUsername ? textDecoder.decode(liteUsername) : '',
|
|
55
|
-
credibility: credibility,
|
|
56
|
-
};
|
|
57
|
-
});
|
|
31
|
+
return encodeAccountId(address).asyncAndThen(accountId => config.identity.getIdentity(accountId));
|
|
58
32
|
},
|
|
59
33
|
};
|
|
60
34
|
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { toHex } from '@novasamatech/scale';
|
|
2
|
+
import { okAsync } from 'neverthrow';
|
|
3
|
+
import { AccountId } from 'polkadot-api';
|
|
4
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
5
|
+
import { createAccountService } from './accountService.js';
|
|
6
|
+
const ADDRESS = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY'; // Alice, SS58
|
|
7
|
+
const HEX_ACCOUNT_ID = toHex(AccountId().enc(ADDRESS));
|
|
8
|
+
function identityFor(accountId) {
|
|
9
|
+
return {
|
|
10
|
+
accountId,
|
|
11
|
+
fullUsername: 'alice',
|
|
12
|
+
liteUsername: 'alice.01',
|
|
13
|
+
credibility: { type: 'Lite' },
|
|
14
|
+
identifierKey: `0x${'ab'.repeat(32)}`,
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
const stubIdentity = (resolve) => vi.fn(accountId => okAsync(resolve(accountId)));
|
|
18
|
+
const serviceWith = (getIdentity) => createAccountService({ identityEndpoint: 'https://example.invalid', identity: { getIdentity } });
|
|
19
|
+
describe('accountService.getConsumerInfo', () => {
|
|
20
|
+
it('looks the account up by hex account id and returns its identity', async () => {
|
|
21
|
+
const getIdentity = stubIdentity(identityFor);
|
|
22
|
+
const result = await serviceWith(getIdentity).getConsumerInfo(ADDRESS);
|
|
23
|
+
expect(getIdentity).toHaveBeenCalledWith(HEX_ACCOUNT_ID);
|
|
24
|
+
expect(result._unsafeUnwrap()).toEqual(identityFor(HEX_ACCOUNT_ID));
|
|
25
|
+
});
|
|
26
|
+
it('resolves to null when the account has no consumer record', async () => {
|
|
27
|
+
const service = serviceWith(stubIdentity(() => null));
|
|
28
|
+
expect((await service.getConsumerInfo(ADDRESS))._unsafeUnwrap()).toBeNull();
|
|
29
|
+
});
|
|
30
|
+
it('reports a malformed address as an error rather than throwing', async () => {
|
|
31
|
+
const getIdentity = stubIdentity(identityFor);
|
|
32
|
+
const result = await serviceWith(getIdentity).getConsumerInfo('not-an-address');
|
|
33
|
+
expect(result.isErr()).toBe(true);
|
|
34
|
+
expect(getIdentity).not.toHaveBeenCalled();
|
|
35
|
+
});
|
|
36
|
+
});
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `Resources.Consumers.identifier_key` — a peer's chat encryption key as the chain
|
|
3
|
+
* records it (CHAT-RFC-0004 §4).
|
|
4
|
+
*
|
|
5
|
+
* The 65-byte width predates X25519: it is what an uncompressed P-256 point occupied,
|
|
6
|
+
* and it stayed when the curve changed. Only the keypair type and the key width moved
|
|
7
|
+
* (0x04 + 64 → 0x00 + 32), so the field is still `SizedHex<65>` in runtime metadata.
|
|
8
|
+
*
|
|
9
|
+
* Padding is carried as a field because the RFC requires readers to ignore it rather
|
|
10
|
+
* than validate it. Decoding throws on a keypair type this SDK does not implement —
|
|
11
|
+
* `decodeIdentifierKey` in `accountService.ts` maps that to `null`, since a peer on a
|
|
12
|
+
* curve we can't encrypt to is a normal condition, not a fault.
|
|
13
|
+
*/
|
|
14
|
+
export declare const IdentifierKey: import("scale-ts").Codec<{
|
|
15
|
+
tag: "X25519";
|
|
16
|
+
value: {
|
|
17
|
+
key: Uint8Array<ArrayBufferLike>;
|
|
18
|
+
padding: Uint8Array<ArrayBufferLike>;
|
|
19
|
+
};
|
|
20
|
+
}>;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Bytes, Enum } from '@novasamatech/scale';
|
|
2
|
+
import { Struct } from 'scale-ts';
|
|
3
|
+
/**
|
|
4
|
+
* `Resources.Consumers.identifier_key` — a peer's chat encryption key as the chain
|
|
5
|
+
* records it (CHAT-RFC-0004 §4).
|
|
6
|
+
*
|
|
7
|
+
* The 65-byte width predates X25519: it is what an uncompressed P-256 point occupied,
|
|
8
|
+
* and it stayed when the curve changed. Only the keypair type and the key width moved
|
|
9
|
+
* (0x04 + 64 → 0x00 + 32), so the field is still `SizedHex<65>` in runtime metadata.
|
|
10
|
+
*
|
|
11
|
+
* Padding is carried as a field because the RFC requires readers to ignore it rather
|
|
12
|
+
* than validate it. Decoding throws on a keypair type this SDK does not implement —
|
|
13
|
+
* `decodeIdentifierKey` in `accountService.ts` maps that to `null`, since a peer on a
|
|
14
|
+
* curve we can't encrypt to is a normal condition, not a fault.
|
|
15
|
+
*/
|
|
16
|
+
export const IdentifierKey = Enum({
|
|
17
|
+
X25519: Struct({ key: Bytes(32), padding: Bytes(32) }),
|
|
18
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { IdentifierKey } from './identifierKey.js';
|
|
3
|
+
// CHAT-RFC-0004 §4 container: keypair-type byte ++ key(32) ++ padding(32). Built by
|
|
4
|
+
// hand rather than through the codec — encoding with the thing under test would assert
|
|
5
|
+
// it agrees with itself, not with the RFC. Matches Android `AccountEcdhKeyScaleTest`.
|
|
6
|
+
const container = (keypairType, key, padding = new Uint8Array(32)) => {
|
|
7
|
+
const out = new Uint8Array(65);
|
|
8
|
+
out[0] = keypairType;
|
|
9
|
+
out.set(key, 1);
|
|
10
|
+
out.set(padding, 33);
|
|
11
|
+
return out;
|
|
12
|
+
};
|
|
13
|
+
const KEY = new Uint8Array(32).fill(0xab);
|
|
14
|
+
describe('IdentifierKey', () => {
|
|
15
|
+
it('reads the x25519 key out of the container', () => {
|
|
16
|
+
expect(IdentifierKey.dec(container(0x00, KEY)).value.key).toStrictEqual(KEY);
|
|
17
|
+
});
|
|
18
|
+
it('ignores the padding, as the RFC requires', () => {
|
|
19
|
+
expect(IdentifierKey.dec(container(0x00, KEY, new Uint8Array(32).fill(0x7f))).value.key).toStrictEqual(KEY);
|
|
20
|
+
});
|
|
21
|
+
it('round-trips', () => {
|
|
22
|
+
const value = { tag: 'X25519', value: { key: KEY, padding: new Uint8Array(32) } };
|
|
23
|
+
expect(IdentifierKey.enc(value)).toStrictEqual(container(0x00, KEY));
|
|
24
|
+
expect(IdentifierKey.dec(IdentifierKey.enc(value))).toStrictEqual(value);
|
|
25
|
+
});
|
|
26
|
+
it('rejects a keypair type this SDK does not implement', () => {
|
|
27
|
+
expect(() => IdentifierKey.dec(container(0x04, KEY))).toThrow();
|
|
28
|
+
});
|
|
29
|
+
// The container width is not the key width — reading the field as a bare X25519 key
|
|
30
|
+
// is what broke peer lookup for every account.
|
|
31
|
+
it('rejects a bare 32-byte key', () => {
|
|
32
|
+
expect(() => IdentifierKey.dec(KEY)).toThrow();
|
|
33
|
+
});
|
|
34
|
+
});
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
export declare const OutgoingStatus: import("scale-ts").Codec<"new" | "sent" | "delivered">;
|
|
2
2
|
export declare const IncomingStatus: import("scale-ts").Codec<"new" | "seen">;
|
|
3
3
|
export declare const LocalStatus: import("scale-ts").Codec<{
|
|
4
|
-
tag: "outgoing";
|
|
5
|
-
value: "new" | "sent" | "delivered";
|
|
6
|
-
} | {
|
|
7
4
|
tag: "incoming";
|
|
8
5
|
value: "new" | "seen";
|
|
6
|
+
} | {
|
|
7
|
+
tag: "outgoing";
|
|
8
|
+
value: "new" | "sent" | "delivered";
|
|
9
9
|
}>;
|
|
10
10
|
export declare const LocalMessage: import("scale-ts").Codec<{
|
|
11
11
|
remote: {
|
|
@@ -263,11 +263,11 @@ export declare const LocalMessage: import("scale-ts").Codec<{
|
|
|
263
263
|
};
|
|
264
264
|
peerId: import("@novasamatech/statement-store").AccountId;
|
|
265
265
|
status: {
|
|
266
|
-
tag: "outgoing";
|
|
267
|
-
value: "new" | "sent" | "delivered";
|
|
268
|
-
} | {
|
|
269
266
|
tag: "incoming";
|
|
270
267
|
value: "new" | "seen";
|
|
268
|
+
} | {
|
|
269
|
+
tag: "outgoing";
|
|
270
|
+
value: "new" | "sent" | "delivered";
|
|
271
271
|
};
|
|
272
272
|
order: bigint;
|
|
273
273
|
}>;
|
package/dist/index.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@novasamatech/host-chat",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.9.
|
|
4
|
+
"version": "0.9.2",
|
|
5
5
|
"description": "Host statement store chat integration",
|
|
6
6
|
"license": "Apache-2.0",
|
|
7
7
|
"repository": {
|
|
@@ -11,9 +11,6 @@
|
|
|
11
11
|
"keywords": [
|
|
12
12
|
"polkadot"
|
|
13
13
|
],
|
|
14
|
-
"scripts": {
|
|
15
|
-
"papi:update": "papi update"
|
|
16
|
-
},
|
|
17
14
|
"main": "dist/index.js",
|
|
18
15
|
"exports": {
|
|
19
16
|
"./package.json": "./package.json",
|
|
@@ -40,11 +37,13 @@
|
|
|
40
37
|
"README.md"
|
|
41
38
|
],
|
|
42
39
|
"dependencies": {
|
|
43
|
-
"@novasamatech/
|
|
44
|
-
"@novasamatech/
|
|
45
|
-
"@novasamatech/
|
|
40
|
+
"@novasamatech/host-papp": "0.9.2",
|
|
41
|
+
"@novasamatech/scale": "0.9.2",
|
|
42
|
+
"@novasamatech/statement-store": "0.9.2",
|
|
43
|
+
"@novasamatech/storage-adapter": "0.9.2",
|
|
46
44
|
"nanoid": "6.0.0",
|
|
47
|
-
"neverthrow": "^8.2.0"
|
|
45
|
+
"neverthrow": "^8.2.0",
|
|
46
|
+
"polkadot-api": ">=2"
|
|
48
47
|
},
|
|
49
48
|
"publishConfig": {
|
|
50
49
|
"access": "public"
|