@drakkar.software/octobot-client 0.4.0
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 +140 -0
- package/dist/client/adapters/accounts.d.ts +66 -0
- package/dist/client/adapters/accounts.d.ts.map +1 -0
- package/dist/client/adapters/accounts.js +214 -0
- package/dist/client/adapters/accounts.js.map +1 -0
- package/dist/client/adapters/actionHandle.d.ts +29 -0
- package/dist/client/adapters/actionHandle.d.ts.map +1 -0
- package/dist/client/adapters/actionHandle.js +34 -0
- package/dist/client/adapters/actionHandle.js.map +1 -0
- package/dist/client/adapters/automations.d.ts +31 -0
- package/dist/client/adapters/automations.d.ts.map +1 -0
- package/dist/client/adapters/automations.js +79 -0
- package/dist/client/adapters/automations.js.map +1 -0
- package/dist/client/adapters/documents.d.ts +55 -0
- package/dist/client/adapters/documents.d.ts.map +1 -0
- package/dist/client/adapters/documents.js +66 -0
- package/dist/client/adapters/documents.js.map +1 -0
- package/dist/client/adapters/nodeApi.d.ts +25 -0
- package/dist/client/adapters/nodeApi.d.ts.map +1 -0
- package/dist/client/adapters/nodeApi.js +81 -0
- package/dist/client/adapters/nodeApi.js.map +1 -0
- package/dist/client/adapters/settings.d.ts +16 -0
- package/dist/client/adapters/settings.d.ts.map +1 -0
- package/dist/client/adapters/settings.js +43 -0
- package/dist/client/adapters/settings.js.map +1 -0
- package/dist/client/adapters/strategies.d.ts +17 -0
- package/dist/client/adapters/strategies.d.ts.map +1 -0
- package/dist/client/adapters/strategies.js +75 -0
- package/dist/client/adapters/strategies.js.map +1 -0
- package/dist/client/connect/connect.d.ts +40 -0
- package/dist/client/connect/connect.d.ts.map +1 -0
- package/dist/client/connect/connect.js +133 -0
- package/dist/client/connect/connect.js.map +1 -0
- package/dist/client/connect/readOnly.d.ts +97 -0
- package/dist/client/connect/readOnly.d.ts.map +1 -0
- package/dist/client/connect/readOnly.js +167 -0
- package/dist/client/connect/readOnly.js.map +1 -0
- package/dist/client/core/errors.d.ts +80 -0
- package/dist/client/core/errors.d.ts.map +1 -0
- package/dist/client/core/errors.js +154 -0
- package/dist/client/core/errors.js.map +1 -0
- package/dist/client/core/options.d.ts +44 -0
- package/dist/client/core/options.d.ts.map +1 -0
- package/dist/client/core/options.js +2 -0
- package/dist/client/core/options.js.map +1 -0
- package/dist/client/core/session.d.ts +90 -0
- package/dist/client/core/session.d.ts.map +1 -0
- package/dist/client/core/session.js +72 -0
- package/dist/client/core/session.js.map +1 -0
- package/dist/client/core/views.d.ts +40 -0
- package/dist/client/core/views.d.ts.map +1 -0
- package/dist/client/core/views.js +32 -0
- package/dist/client/core/views.js.map +1 -0
- package/dist/client/index.d.ts +16 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +9 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client/mirror/collections.d.ts +125 -0
- package/dist/client/mirror/collections.d.ts.map +1 -0
- package/dist/client/mirror/collections.js +118 -0
- package/dist/client/mirror/collections.js.map +1 -0
- package/dist/client/mirror/index.d.ts +4 -0
- package/dist/client/mirror/index.d.ts.map +1 -0
- package/dist/client/mirror/index.js +4 -0
- package/dist/client/mirror/index.js.map +1 -0
- package/dist/client/mirror/writer.d.ts +39 -0
- package/dist/client/mirror/writer.d.ts.map +1 -0
- package/dist/client/mirror/writer.js +50 -0
- package/dist/client/mirror/writer.js.map +1 -0
- package/dist/client/pairing/mirrorGrant.d.ts +91 -0
- package/dist/client/pairing/mirrorGrant.d.ts.map +1 -0
- package/dist/client/pairing/mirrorGrant.js +99 -0
- package/dist/client/pairing/mirrorGrant.js.map +1 -0
- package/dist/client/pairing/mirrorReader.d.ts +99 -0
- package/dist/client/pairing/mirrorReader.d.ts.map +1 -0
- package/dist/client/pairing/mirrorReader.js +117 -0
- package/dist/client/pairing/mirrorReader.js.map +1 -0
- package/dist/client/pairing/pairingGrantExchange.d.ts +135 -0
- package/dist/client/pairing/pairingGrantExchange.d.ts.map +1 -0
- package/dist/client/pairing/pairingGrantExchange.js +186 -0
- package/dist/client/pairing/pairingGrantExchange.js.map +1 -0
- package/dist/client/pairing/pairingRequest.d.ts +82 -0
- package/dist/client/pairing/pairingRequest.d.ts.map +1 -0
- package/dist/client/pairing/pairingRequest.js +120 -0
- package/dist/client/pairing/pairingRequest.js.map +1 -0
- package/dist/client/strategy.d.ts +36 -0
- package/dist/client/strategy.d.ts.map +1 -0
- package/dist/client/strategy.js +26 -0
- package/dist/client/strategy.js.map +1 -0
- package/dist/collections/index.d.ts +3 -0
- package/dist/collections/index.d.ts.map +1 -0
- package/dist/collections/index.js +3 -0
- package/dist/collections/index.js.map +1 -0
- package/dist/collections/nodeCollections.d.ts +57 -0
- package/dist/collections/nodeCollections.d.ts.map +1 -0
- package/dist/collections/nodeCollections.js +40 -0
- package/dist/collections/nodeCollections.js.map +1 -0
- package/dist/collections/paths.d.ts +7 -0
- package/dist/collections/paths.d.ts.map +1 -0
- package/dist/collections/paths.js +13 -0
- package/dist/collections/paths.js.map +1 -0
- package/dist/crypto/collectionKeys.d.ts +28 -0
- package/dist/crypto/collectionKeys.d.ts.map +1 -0
- package/dist/crypto/collectionKeys.js +53 -0
- package/dist/crypto/collectionKeys.js.map +1 -0
- package/dist/crypto/hkdf.d.ts +14 -0
- package/dist/crypto/hkdf.d.ts.map +1 -0
- package/dist/crypto/hkdf.js +19 -0
- package/dist/crypto/hkdf.js.map +1 -0
- package/dist/crypto/index.d.ts +5 -0
- package/dist/crypto/index.d.ts.map +1 -0
- package/dist/crypto/index.js +5 -0
- package/dist/crypto/index.js.map +1 -0
- package/dist/crypto/secretEncryptor.d.ts +20 -0
- package/dist/crypto/secretEncryptor.d.ts.map +1 -0
- package/dist/crypto/secretEncryptor.js +82 -0
- package/dist/crypto/secretEncryptor.js.map +1 -0
- package/dist/crypto/wireConstants.d.ts +14 -0
- package/dist/crypto/wireConstants.d.ts.map +1 -0
- package/dist/crypto/wireConstants.js +17 -0
- package/dist/crypto/wireConstants.js.map +1 -0
- package/dist/identity/address.d.ts +3 -0
- package/dist/identity/address.d.ts.map +1 -0
- package/dist/identity/address.js +17 -0
- package/dist/identity/address.js.map +1 -0
- package/dist/identity/bip39-wordlist.d.ts +2 -0
- package/dist/identity/bip39-wordlist.d.ts.map +1 -0
- package/dist/identity/bip39-wordlist.js +2051 -0
- package/dist/identity/bip39-wordlist.js.map +1 -0
- package/dist/identity/capProvider.d.ts +45 -0
- package/dist/identity/capProvider.d.ts.map +1 -0
- package/dist/identity/capProvider.js +80 -0
- package/dist/identity/capProvider.js.map +1 -0
- package/dist/identity/derivationSchemes.d.ts +25 -0
- package/dist/identity/derivationSchemes.d.ts.map +1 -0
- package/dist/identity/derivationSchemes.js +34 -0
- package/dist/identity/derivationSchemes.js.map +1 -0
- package/dist/identity/evm.d.ts +8 -0
- package/dist/identity/evm.d.ts.map +1 -0
- package/dist/identity/evm.js +78 -0
- package/dist/identity/evm.js.map +1 -0
- package/dist/identity/index.d.ts +10 -0
- package/dist/identity/index.d.ts.map +1 -0
- package/dist/identity/index.js +10 -0
- package/dist/identity/index.js.map +1 -0
- package/dist/identity/keys.d.ts +17 -0
- package/dist/identity/keys.d.ts.map +1 -0
- package/dist/identity/keys.js +36 -0
- package/dist/identity/keys.js.map +1 -0
- package/dist/identity/mnemonic.d.ts +4 -0
- package/dist/identity/mnemonic.d.ts.map +1 -0
- package/dist/identity/mnemonic.js +93 -0
- package/dist/identity/mnemonic.js.map +1 -0
- package/dist/identity/pairing.d.ts +45 -0
- package/dist/identity/pairing.d.ts.map +1 -0
- package/dist/identity/pairing.js +91 -0
- package/dist/identity/pairing.js.map +1 -0
- package/dist/identity/pairingRequest.d.ts +99 -0
- package/dist/identity/pairingRequest.d.ts.map +1 -0
- package/dist/identity/pairingRequest.js +217 -0
- package/dist/identity/pairingRequest.js.map +1 -0
- package/dist/identity/secret.d.ts +32 -0
- package/dist/identity/secret.d.ts.map +1 -0
- package/dist/identity/secret.js +54 -0
- package/dist/identity/secret.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -0
- package/dist/internal/bytes.d.ts +11 -0
- package/dist/internal/bytes.d.ts.map +1 -0
- package/dist/internal/bytes.js +38 -0
- package/dist/internal/bytes.js.map +1 -0
- package/dist/node-api/dexPair.d.ts +24 -0
- package/dist/node-api/dexPair.d.ts.map +1 -0
- package/dist/node-api/dexPair.js +39 -0
- package/dist/node-api/dexPair.js.map +1 -0
- package/dist/node-api/dsl.d.ts +10 -0
- package/dist/node-api/dsl.d.ts.map +1 -0
- package/dist/node-api/dsl.js +7 -0
- package/dist/node-api/dsl.js.map +1 -0
- package/dist/node-api/exchanges.d.ts +49 -0
- package/dist/node-api/exchanges.d.ts.map +1 -0
- package/dist/node-api/exchanges.js +32 -0
- package/dist/node-api/exchanges.js.map +1 -0
- package/dist/node-api/index.d.ts +12 -0
- package/dist/node-api/index.d.ts.map +1 -0
- package/dist/node-api/index.js +12 -0
- package/dist/node-api/index.js.map +1 -0
- package/dist/node-api/marketMaking.d.ts +39 -0
- package/dist/node-api/marketMaking.d.ts.map +1 -0
- package/dist/node-api/marketMaking.js +44 -0
- package/dist/node-api/marketMaking.js.map +1 -0
- package/dist/node-api/octobots.d.ts +14 -0
- package/dist/node-api/octobots.d.ts.map +1 -0
- package/dist/node-api/octobots.js +16 -0
- package/dist/node-api/octobots.js.map +1 -0
- package/dist/node-api/orderBookPreview.d.ts +11 -0
- package/dist/node-api/orderBookPreview.d.ts.map +1 -0
- package/dist/node-api/orderBookPreview.js +7 -0
- package/dist/node-api/orderBookPreview.js.map +1 -0
- package/dist/node-api/pairing.d.ts +39 -0
- package/dist/node-api/pairing.d.ts.map +1 -0
- package/dist/node-api/pairing.js +61 -0
- package/dist/node-api/pairing.js.map +1 -0
- package/dist/node-api/pairs.d.ts +32 -0
- package/dist/node-api/pairs.d.ts.map +1 -0
- package/dist/node-api/pairs.js +72 -0
- package/dist/node-api/pairs.js.map +1 -0
- package/dist/node-api/requiredFunds.d.ts +11 -0
- package/dist/node-api/requiredFunds.d.ts.map +1 -0
- package/dist/node-api/requiredFunds.js +7 -0
- package/dist/node-api/requiredFunds.js.map +1 -0
- package/dist/node-api/setup.d.ts +25 -0
- package/dist/node-api/setup.d.ts.map +1 -0
- package/dist/node-api/setup.js +13 -0
- package/dist/node-api/setup.js.map +1 -0
- package/dist/node-api/wallet.d.ts +55 -0
- package/dist/node-api/wallet.d.ts.map +1 -0
- package/dist/node-api/wallet.js +87 -0
- package/dist/node-api/wallet.js.map +1 -0
- package/dist/protocol/actions.d.ts +40 -0
- package/dist/protocol/actions.d.ts.map +1 -0
- package/dist/protocol/actions.js +118 -0
- package/dist/protocol/actions.js.map +1 -0
- package/dist/protocol/documents.d.ts +25 -0
- package/dist/protocol/documents.d.ts.map +1 -0
- package/dist/protocol/documents.js +2 -0
- package/dist/protocol/documents.js.map +1 -0
- package/dist/protocol/index.d.ts +10 -0
- package/dist/protocol/index.d.ts.map +1 -0
- package/dist/protocol/index.js +12 -0
- package/dist/protocol/index.js.map +1 -0
- package/dist/protocol/orchestration/createAutomation.d.ts +61 -0
- package/dist/protocol/orchestration/createAutomation.d.ts.map +1 -0
- package/dist/protocol/orchestration/createAutomation.js +71 -0
- package/dist/protocol/orchestration/createAutomation.js.map +1 -0
- package/dist/protocol/poll.d.ts +4 -0
- package/dist/protocol/poll.d.ts.map +1 -0
- package/dist/protocol/poll.js +4 -0
- package/dist/protocol/poll.js.map +1 -0
- package/dist/protocol/proposal.d.ts +36 -0
- package/dist/protocol/proposal.d.ts.map +1 -0
- package/dist/protocol/proposal.js +39 -0
- package/dist/protocol/proposal.js.map +1 -0
- package/dist/protocol/state.d.ts +87 -0
- package/dist/protocol/state.d.ts.map +1 -0
- package/dist/protocol/state.js +303 -0
- package/dist/protocol/state.js.map +1 -0
- package/dist/protocol/strategy/build.d.ts +44 -0
- package/dist/protocol/strategy/build.d.ts.map +1 -0
- package/dist/protocol/strategy/build.js +50 -0
- package/dist/protocol/strategy/build.js.map +1 -0
- package/dist/protocol/strategy/builders.d.ts +252 -0
- package/dist/protocol/strategy/builders.d.ts.map +1 -0
- package/dist/protocol/strategy/builders.js +382 -0
- package/dist/protocol/strategy/builders.js.map +1 -0
- package/dist/protocol/strategy/index.d.ts +5 -0
- package/dist/protocol/strategy/index.d.ts.map +1 -0
- package/dist/protocol/strategy/index.js +4 -0
- package/dist/protocol/strategy/index.js.map +1 -0
- package/dist/protocol/strategy/kinds.d.ts +2 -0
- package/dist/protocol/strategy/kinds.d.ts.map +1 -0
- package/dist/protocol/strategy/kinds.js +2 -0
- package/dist/protocol/strategy/kinds.js.map +1 -0
- package/dist/protocol/strategy/patch.d.ts +59 -0
- package/dist/protocol/strategy/patch.d.ts.map +1 -0
- package/dist/protocol/strategy/patch.js +253 -0
- package/dist/protocol/strategy/patch.js.map +1 -0
- package/dist/protocol/symbols.d.ts +8 -0
- package/dist/protocol/symbols.d.ts.map +1 -0
- package/dist/protocol/symbols.js +11 -0
- package/dist/protocol/symbols.js.map +1 -0
- package/dist/transport/constants.d.ts +8 -0
- package/dist/transport/constants.d.ts.map +1 -0
- package/dist/transport/constants.js +8 -0
- package/dist/transport/constants.js.map +1 -0
- package/dist/transport/documents.d.ts +27 -0
- package/dist/transport/documents.d.ts.map +1 -0
- package/dist/transport/documents.js +34 -0
- package/dist/transport/documents.js.map +1 -0
- package/dist/transport/index.d.ts +8 -0
- package/dist/transport/index.d.ts.map +1 -0
- package/dist/transport/index.js +8 -0
- package/dist/transport/index.js.map +1 -0
- package/dist/transport/probe.d.ts +44 -0
- package/dist/transport/probe.d.ts.map +1 -0
- package/dist/transport/probe.js +121 -0
- package/dist/transport/probe.js.map +1 -0
- package/dist/transport/rendezvous.d.ts +116 -0
- package/dist/transport/rendezvous.d.ts.map +1 -0
- package/dist/transport/rendezvous.js +139 -0
- package/dist/transport/rendezvous.js.map +1 -0
- package/dist/transport/rest.d.ts +35 -0
- package/dist/transport/rest.d.ts.map +1 -0
- package/dist/transport/rest.js +58 -0
- package/dist/transport/rest.js.map +1 -0
- package/dist/transport/syncClient.d.ts +14 -0
- package/dist/transport/syncClient.d.ts.map +1 -0
- package/dist/transport/syncClient.js +30 -0
- package/dist/transport/syncClient.js.map +1 -0
- package/dist/transport/urls.d.ts +35 -0
- package/dist/transport/urls.d.ts.map +1 -0
- package/dist/transport/urls.js +126 -0
- package/dist/transport/urls.js.map +1 -0
- package/package.json +55 -0
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import type { StarfishCapProvider, StarfishClient } from '@drakkar.software/starfish-client';
|
|
2
|
+
import type { Encryptor } from '@drakkar.software/starfish-protocol';
|
|
3
|
+
import { type KeyDerivation } from '../../identity/capProvider.js';
|
|
4
|
+
import type { NodeEndpoint } from '../../transport/urls.js';
|
|
5
|
+
import type { NodeCredentials } from '../../transport/rest.js';
|
|
6
|
+
import { type NodeCollectionKey } from '../../collections/nodeCollections.js';
|
|
7
|
+
/** What `ClientSession.capProvider` needs beyond the bare `StarfishCapProvider`
|
|
8
|
+
* the sync client itself requires — `connect.ts`'s `finalize()` also reads
|
|
9
|
+
* `getUserId()` off it. `WalletCapProvider` satisfies this; so does the
|
|
10
|
+
* installed-credential adapter `connectReadOnlyDevice()` builds — a
|
|
11
|
+
* read-only session never derives a root key at all, so it can't be a real
|
|
12
|
+
* `WalletCapProvider`. */
|
|
13
|
+
export interface SessionCapProvider extends StarfishCapProvider {
|
|
14
|
+
getUserId(): Promise<string>;
|
|
15
|
+
}
|
|
16
|
+
/** Everything a `client/*.ts` API module (`accounts.ts`, `automations.ts`,
|
|
17
|
+
* `strategies.ts`, `settings.ts`, `actionHandle.ts`, `documents.ts`) closes
|
|
18
|
+
* over. Both a full-wallet session (`createSession`) and a read-only
|
|
19
|
+
* pairing session (`createReadOnlySession`) satisfy this — the two differ
|
|
20
|
+
* only in what `collectionEncryptor` can do, which is exactly the point:
|
|
21
|
+
* it is the single place collection-scope enforcement lives.
|
|
22
|
+
*
|
|
23
|
+
* `seed`/`derivation`/`address` are deliberately NOT here — they belong to
|
|
24
|
+
* `WalletClientSession` below, read only by `connect.ts`. If a shared API
|
|
25
|
+
* module ever needs one of those fields, that is a sign it leaked a
|
|
26
|
+
* wallet-only assumption into code the read-only path also runs. */
|
|
27
|
+
export type ClientSession = {
|
|
28
|
+
readonly origin: string;
|
|
29
|
+
readonly node: NodeEndpoint;
|
|
30
|
+
readonly userId: string;
|
|
31
|
+
readonly fetch: typeof fetch;
|
|
32
|
+
readonly defaultTimeoutMs: number;
|
|
33
|
+
readonly basicAuth?: NodeCredentials;
|
|
34
|
+
readonly capProvider: SessionCapProvider;
|
|
35
|
+
readonly syncClient: StarfishClient;
|
|
36
|
+
/** Resolve the `Encryptor` for one node collection. A full-wallet session
|
|
37
|
+
* can derive this for any collection on demand; a read-only session can
|
|
38
|
+
* only do so for the collections its pairing grant actually covers, and
|
|
39
|
+
* throws `OctoBotScopeError` for anything else. See `OctoBotScopeError`'s
|
|
40
|
+
* doc comment for why this client-side check currently matters more than
|
|
41
|
+
* it should. */
|
|
42
|
+
collectionEncryptor(collection: NodeCollectionKey): Promise<Encryptor>;
|
|
43
|
+
/** Drops whatever derived-key state this session holds. Does not touch
|
|
44
|
+
* in-flight requests. */
|
|
45
|
+
close(): void;
|
|
46
|
+
};
|
|
47
|
+
/** The full-wallet session `connect.ts` builds, on top of `ClientSession`.
|
|
48
|
+
* `address`/`derivation`/`seed`/`walletAddress()` are read only inside
|
|
49
|
+
* `connect.ts` itself (to re-derive the wallet address after the cap
|
|
50
|
+
* provider resolves `userId`, and to surface `OctoBotClient.address`) —
|
|
51
|
+
* nothing in the shared `client/*.ts` API modules touches them. */
|
|
52
|
+
export type WalletClientSession = ClientSession & {
|
|
53
|
+
readonly address: string;
|
|
54
|
+
readonly derivation: KeyDerivation;
|
|
55
|
+
readonly seed: string;
|
|
56
|
+
/** The EVM address `seed` derives to under `derivation`. Backed by the
|
|
57
|
+
* same derived-key cache `collectionEncryptor` uses internally — kept off
|
|
58
|
+
* the shared `ClientSession` surface so a read-only session (which has no
|
|
59
|
+
* such cache) never needs to fake it. */
|
|
60
|
+
walletAddress(): Promise<string>;
|
|
61
|
+
};
|
|
62
|
+
export declare function createSession(opts: {
|
|
63
|
+
origin: string;
|
|
64
|
+
node: NodeEndpoint;
|
|
65
|
+
address: string;
|
|
66
|
+
userId: string;
|
|
67
|
+
derivation: KeyDerivation;
|
|
68
|
+
seed: string;
|
|
69
|
+
fetch: typeof fetch;
|
|
70
|
+
defaultTimeoutMs: number;
|
|
71
|
+
basicAuth?: NodeCredentials;
|
|
72
|
+
}): WalletClientSession;
|
|
73
|
+
/** Builds a `ClientSession` for an installed read-only pairing credential —
|
|
74
|
+
* no seed, no root key, no `WalletCapProvider`. `capProvider` is a thin
|
|
75
|
+
* inline adapter over the already-signed cap-cert the pairing payload
|
|
76
|
+
* carries. `collectionKeys` is the payload's per-collection subkey map
|
|
77
|
+
* (see `identity/pairing.ts`'s `ReadOnlyPairingPayload.collectionKeys` and
|
|
78
|
+
* `crypto/collectionKeys.ts`) — each key decrypts exactly one collection,
|
|
79
|
+
* derived one-way from the wallet secret, so this session can never
|
|
80
|
+
* reconstruct that secret or decrypt a collection outside the grant. */
|
|
81
|
+
export declare function createReadOnlySession(opts: {
|
|
82
|
+
origin: string;
|
|
83
|
+
node: NodeEndpoint;
|
|
84
|
+
userId: string;
|
|
85
|
+
fetch: typeof fetch;
|
|
86
|
+
defaultTimeoutMs: number;
|
|
87
|
+
capProvider: SessionCapProvider;
|
|
88
|
+
collectionKeys: Partial<Record<NodeCollectionKey, string>>;
|
|
89
|
+
}): ClientSession;
|
|
90
|
+
//# sourceMappingURL=session.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../../src/client/core/session.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAA;AAC5F,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qCAAqC,CAAA;AACpE,OAAO,EAAqB,KAAK,aAAa,EAAE,MAAM,+BAA+B,CAAA;AAGrF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAA;AAC3D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAA;AAK9D,OAAO,EAAoB,KAAK,iBAAiB,EAAE,MAAM,sCAAsC,CAAA;AAG/F;;;;;2BAK2B;AAC3B,MAAM,WAAW,kBAAmB,SAAQ,mBAAmB;IAC7D,SAAS,IAAI,OAAO,CAAC,MAAM,CAAC,CAAA;CAC7B;AAED;;;;;;;;;;qEAUqE;AACrE,MAAM,MAAM,aAAa,GAAG;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAA;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,KAAK,EAAE,OAAO,KAAK,CAAA;IAC5B,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAA;IACjC,QAAQ,CAAC,SAAS,CAAC,EAAE,eAAe,CAAA;IACpC,QAAQ,CAAC,WAAW,EAAE,kBAAkB,CAAA;IACxC,QAAQ,CAAC,UAAU,EAAE,cAAc,CAAA;IACnC;;;;;qBAKiB;IACjB,mBAAmB,CAAC,UAAU,EAAE,iBAAiB,GAAG,OAAO,CAAC,SAAS,CAAC,CAAA;IACtE;8BAC0B;IAC1B,KAAK,IAAI,IAAI,CAAA;CACd,CAAA;AAED;;;;oEAIoE;AACpE,MAAM,MAAM,mBAAmB,GAAG,aAAa,GAAG;IAChD,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,UAAU,EAAE,aAAa,CAAA;IAClC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB;;;8CAG0C;IAC1C,aAAa,IAAI,OAAO,CAAC,MAAM,CAAC,CAAA;CACjC,CAAA;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE;IAClC,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,YAAY,CAAA;IAClB,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,MAAM,CAAA;IACd,UAAU,EAAE,aAAa,CAAA;IACzB,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,OAAO,KAAK,CAAA;IACnB,gBAAgB,EAAE,MAAM,CAAA;IACxB,SAAS,CAAC,EAAE,eAAe,CAAA;CAC5B,GAAG,mBAAmB,CA6BtB;AAED;;;;;;;yEAOyE;AACzE,wBAAgB,qBAAqB,CAAC,IAAI,EAAE;IAC1C,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,YAAY,CAAA;IAClB,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,OAAO,KAAK,CAAA;IACnB,gBAAgB,EAAE,MAAM,CAAA;IACxB,WAAW,EAAE,kBAAkB,CAAA;IAC/B,cAAc,EAAE,OAAO,CAAC,MAAM,CAAC,iBAAiB,EAAE,MAAM,CAAC,CAAC,CAAA;CAC3D,GAAG,aAAa,CAwBhB"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { WalletCapProvider } from '../../identity/capProvider.js';
|
|
2
|
+
import { createKeyCache } from '../../identity/keys.js';
|
|
3
|
+
import { createSyncClient } from '../../transport/syncClient.js';
|
|
4
|
+
import { SYNC_FETCH_TIMEOUT_MS } from '../../crypto/wireConstants.js';
|
|
5
|
+
import { STARFISH_ENCRYPTION_SALT } from '../../crypto/wireConstants.js';
|
|
6
|
+
import { createSecretEncryptor, createRawKeyEncryptor } from '../../crypto/secretEncryptor.js';
|
|
7
|
+
import { decodeCollectionKey } from '../../crypto/collectionKeys.js';
|
|
8
|
+
import { NODE_COLLECTIONS } from '../../collections/nodeCollections.js';
|
|
9
|
+
import { OctoBotScopeError } from './errors.js';
|
|
10
|
+
export function createSession(opts) {
|
|
11
|
+
const capProvider = new WalletCapProvider(opts.seed, opts.derivation);
|
|
12
|
+
const keyCache = createKeyCache();
|
|
13
|
+
const syncClient = createSyncClient({
|
|
14
|
+
origin: opts.origin,
|
|
15
|
+
capProvider,
|
|
16
|
+
fetch: opts.fetch,
|
|
17
|
+
timeoutMs: opts.defaultTimeoutMs || SYNC_FETCH_TIMEOUT_MS,
|
|
18
|
+
});
|
|
19
|
+
return {
|
|
20
|
+
origin: opts.origin,
|
|
21
|
+
node: opts.node,
|
|
22
|
+
address: opts.address,
|
|
23
|
+
userId: opts.userId,
|
|
24
|
+
derivation: opts.derivation,
|
|
25
|
+
seed: opts.seed,
|
|
26
|
+
fetch: opts.fetch,
|
|
27
|
+
defaultTimeoutMs: opts.defaultTimeoutMs,
|
|
28
|
+
basicAuth: opts.basicAuth,
|
|
29
|
+
capProvider,
|
|
30
|
+
syncClient,
|
|
31
|
+
async collectionEncryptor(collection) {
|
|
32
|
+
const secret = await keyCache.getEncryptionKey(opts.seed, opts.derivation);
|
|
33
|
+
return createSecretEncryptor(secret, STARFISH_ENCRYPTION_SALT, NODE_COLLECTIONS[collection].encryptionInfo);
|
|
34
|
+
},
|
|
35
|
+
walletAddress: () => keyCache.getWalletAddress(opts.seed, opts.derivation),
|
|
36
|
+
close: () => keyCache.clear(),
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
/** Builds a `ClientSession` for an installed read-only pairing credential —
|
|
40
|
+
* no seed, no root key, no `WalletCapProvider`. `capProvider` is a thin
|
|
41
|
+
* inline adapter over the already-signed cap-cert the pairing payload
|
|
42
|
+
* carries. `collectionKeys` is the payload's per-collection subkey map
|
|
43
|
+
* (see `identity/pairing.ts`'s `ReadOnlyPairingPayload.collectionKeys` and
|
|
44
|
+
* `crypto/collectionKeys.ts`) — each key decrypts exactly one collection,
|
|
45
|
+
* derived one-way from the wallet secret, so this session can never
|
|
46
|
+
* reconstruct that secret or decrypt a collection outside the grant. */
|
|
47
|
+
export function createReadOnlySession(opts) {
|
|
48
|
+
const syncClient = createSyncClient({
|
|
49
|
+
origin: opts.origin,
|
|
50
|
+
capProvider: opts.capProvider,
|
|
51
|
+
fetch: opts.fetch,
|
|
52
|
+
timeoutMs: opts.defaultTimeoutMs || SYNC_FETCH_TIMEOUT_MS,
|
|
53
|
+
});
|
|
54
|
+
return {
|
|
55
|
+
origin: opts.origin,
|
|
56
|
+
node: opts.node,
|
|
57
|
+
userId: opts.userId,
|
|
58
|
+
fetch: opts.fetch,
|
|
59
|
+
defaultTimeoutMs: opts.defaultTimeoutMs,
|
|
60
|
+
capProvider: opts.capProvider,
|
|
61
|
+
syncClient,
|
|
62
|
+
async collectionEncryptor(collection) {
|
|
63
|
+
const key = opts.collectionKeys[collection];
|
|
64
|
+
if (key === undefined)
|
|
65
|
+
throw new OctoBotScopeError(collection);
|
|
66
|
+
return createRawKeyEncryptor(decodeCollectionKey(key));
|
|
67
|
+
},
|
|
68
|
+
// No derived-key cache on this path — nothing to drop.
|
|
69
|
+
close: () => { },
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=session.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.js","sourceRoot":"","sources":["../../../src/client/core/session.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { Account as ProtocolAccount, ExchangeConfig, AutomationState, UserAction } from '@drakkar.software/octobot-protocol';
|
|
2
|
+
import { type AutomationRunStatus, type Holding } from '../../protocol/state.js';
|
|
3
|
+
export type { Holding };
|
|
4
|
+
export type AccountKind = 'exchange' | 'wallet' | 'generic';
|
|
5
|
+
/** A friendlier read of a node-reported account. `raw` is the untouched
|
|
6
|
+
* protocol record — nothing here is hidden or lossy, this just saves every
|
|
7
|
+
* caller from re-deriving the same handful of fields. */
|
|
8
|
+
export type AccountView = {
|
|
9
|
+
id: string;
|
|
10
|
+
name: string;
|
|
11
|
+
type: AccountKind;
|
|
12
|
+
/** Resolved through `exchange_configs` — undefined for non-exchange kinds. */
|
|
13
|
+
exchange?: string;
|
|
14
|
+
simulated: boolean;
|
|
15
|
+
/** `false` when the node's own validation marked this account invalid
|
|
16
|
+
* (bad credentials, unreachable venue, …). */
|
|
17
|
+
connected: boolean;
|
|
18
|
+
holdings: Holding[];
|
|
19
|
+
raw: ProtocolAccount;
|
|
20
|
+
};
|
|
21
|
+
export declare function accountViewOf(na: ProtocolAccount, exchangeConfigs: ExchangeConfig[]): AccountView;
|
|
22
|
+
/** A friendlier read of a node-reported automation. `raw` is the untouched
|
|
23
|
+
* protocol record. `strategy` is recovered from the action history — the
|
|
24
|
+
* node's own `AutomationState` carries no strategy reference. */
|
|
25
|
+
export type AutomationView = {
|
|
26
|
+
id: string;
|
|
27
|
+
name: string;
|
|
28
|
+
status: AutomationRunStatus;
|
|
29
|
+
/** Every exchange account this automation trades through. */
|
|
30
|
+
accountIds: string[];
|
|
31
|
+
strategy: {
|
|
32
|
+
id: string;
|
|
33
|
+
version?: string;
|
|
34
|
+
} | null;
|
|
35
|
+
error: string | null;
|
|
36
|
+
assets: Holding[];
|
|
37
|
+
raw: AutomationState;
|
|
38
|
+
};
|
|
39
|
+
export declare function automationViewOf(state: AutomationState, actions: UserAction[]): AutomationView;
|
|
40
|
+
//# sourceMappingURL=views.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"views.d.ts","sourceRoot":"","sources":["../../../src/client/core/views.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,OAAO,IAAI,eAAe,EAC1B,cAAc,EACd,eAAe,EACf,UAAU,EACX,MAAM,oCAAoC,CAAA;AAC3C,OAAO,EAML,KAAK,mBAAmB,EACxB,KAAK,OAAO,EACb,MAAM,yBAAyB,CAAA;AAEhC,YAAY,EAAE,OAAO,EAAE,CAAA;AAEvB,MAAM,MAAM,WAAW,GAAG,UAAU,GAAG,QAAQ,GAAG,SAAS,CAAA;AAE3D;;0DAE0D;AAC1D,MAAM,MAAM,WAAW,GAAG;IACxB,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,WAAW,CAAA;IACjB,8EAA8E;IAC9E,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,OAAO,CAAA;IAClB;mDAC+C;IAC/C,SAAS,EAAE,OAAO,CAAA;IAClB,QAAQ,EAAE,OAAO,EAAE,CAAA;IACnB,GAAG,EAAE,eAAe,CAAA;CACrB,CAAA;AAED,wBAAgB,aAAa,CAAC,EAAE,EAAE,eAAe,EAAE,eAAe,EAAE,cAAc,EAAE,GAAG,WAAW,CAkBjG;AAED;;kEAEkE;AAClE,MAAM,MAAM,cAAc,GAAG;IAC3B,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,mBAAmB,CAAA;IAC3B,6DAA6D;IAC7D,UAAU,EAAE,MAAM,EAAE,CAAA;IACpB,QAAQ,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAA;IACjD,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,MAAM,EAAE,OAAO,EAAE,CAAA;IACjB,GAAG,EAAE,eAAe,CAAA;CACrB,CAAA;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,eAAe,EAAE,OAAO,EAAE,UAAU,EAAE,GAAG,cAAc,CAW9F"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { accountHoldingsFromNodeState, workflowStatusToAutomationStatus, automationErrorOf, automationHoldings, automationStrategyRefOf, } from '../../protocol/state.js';
|
|
2
|
+
export function accountViewOf(na, exchangeConfigs) {
|
|
3
|
+
const specifics = na.specifics;
|
|
4
|
+
const type = specifics?.account_type === 'exchange' ? 'exchange' :
|
|
5
|
+
specifics?.account_type === 'blockchain' ? 'wallet' :
|
|
6
|
+
'generic';
|
|
7
|
+
const cfgId = specifics?.exchange_config_ids?.[0];
|
|
8
|
+
const exchange = cfgId ? exchangeConfigs.find((c) => c.id === cfgId)?.exchange : undefined;
|
|
9
|
+
return {
|
|
10
|
+
id: na.id,
|
|
11
|
+
name: na.name || na.id,
|
|
12
|
+
type,
|
|
13
|
+
exchange,
|
|
14
|
+
simulated: na.is_simulated ?? false,
|
|
15
|
+
connected: na.state?.status !== 'invalid',
|
|
16
|
+
holdings: accountHoldingsFromNodeState(na),
|
|
17
|
+
raw: na,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
export function automationViewOf(state, actions) {
|
|
21
|
+
return {
|
|
22
|
+
id: state.id,
|
|
23
|
+
name: state.metadata?.name || state.id,
|
|
24
|
+
status: workflowStatusToAutomationStatus(state.status),
|
|
25
|
+
accountIds: state.exchange_account_ids ?? [],
|
|
26
|
+
strategy: automationStrategyRefOf(actions, state.id),
|
|
27
|
+
error: automationErrorOf(state),
|
|
28
|
+
assets: automationHoldings(state).map((a) => ({ symbol: a.symbol, total: a.total, free: a.available, used: Math.max(0, a.total - a.available) })),
|
|
29
|
+
raw: state,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=views.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"views.js","sourceRoot":"","sources":["../../../src/client/core/views.ts"],"names":[],"mappings":"AAMA,OAAO,EACL,4BAA4B,EAC5B,gCAAgC,EAChC,iBAAiB,EACjB,kBAAkB,EAClB,uBAAuB,GAGxB,MAAM,yBAAyB,CAAA;AAuBhC,MAAM,UAAU,aAAa,CAAC,EAAmB,EAAE,eAAiC;IAClF,MAAM,SAAS,GAAG,EAAE,CAAC,SAAkF,CAAA;IACvG,MAAM,IAAI,GACR,SAAS,EAAE,YAAY,KAAK,UAAU,CAAG,CAAC,CAAC,UAAU,CAAC,CAAC;QACvD,SAAS,EAAE,YAAY,KAAK,YAAY,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;YACrD,SAAS,CAAA;IACX,MAAM,KAAK,GAAG,SAAS,EAAE,mBAAmB,EAAE,CAAC,CAAC,CAAC,CAAA;IACjD,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,KAAK,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAA;IAC1F,OAAO;QACL,EAAE,EAAE,EAAE,CAAC,EAAE;QACT,IAAI,EAAE,EAAE,CAAC,IAAI,IAAI,EAAE,CAAC,EAAE;QACtB,IAAI;QACJ,QAAQ;QACR,SAAS,EAAE,EAAE,CAAC,YAAY,IAAI,KAAK;QACnC,SAAS,EAAE,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,SAAS;QACzC,QAAQ,EAAE,4BAA4B,CAAC,EAAE,CAAC;QAC1C,GAAG,EAAE,EAAE;KACR,CAAA;AACH,CAAC;AAiBD,MAAM,UAAU,gBAAgB,CAAC,KAAsB,EAAE,OAAqB;IAC5E,OAAO;QACL,EAAE,EAAE,KAAK,CAAC,EAAE;QACZ,IAAI,EAAE,KAAK,CAAC,QAAQ,EAAE,IAAI,IAAI,KAAK,CAAC,EAAE;QACtC,MAAM,EAAE,gCAAgC,CAAC,KAAK,CAAC,MAAM,CAAC;QACtD,UAAU,EAAE,KAAK,CAAC,oBAAoB,IAAI,EAAE;QAC5C,QAAQ,EAAE,uBAAuB,CAAC,OAAO,EAAE,KAAK,CAAC,EAAE,CAAC;QACpD,KAAK,EAAE,iBAAiB,CAAC,KAAK,CAAC;QAC/B,MAAM,EAAE,kBAAkB,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;QACjJ,GAAG,EAAE,KAAK;KACX,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export { connectOctoBot, type OctoBotClient, type ConnectOptions, type SeedDerivation, type CallOptions, } from './connect/connect.js';
|
|
2
|
+
export { connectReadOnlyDevice, type ConnectReadOnlyOptions, type ReadOnlyOctoBotClient, type ReadOnlyAccountsApi, type ReadOnlyAutomationsApi, type ReadOnlyStrategiesApi, type ProposedAction, } from './connect/readOnly.js';
|
|
3
|
+
export { type AccountsApi, type AccountInput } from './adapters/accounts.js';
|
|
4
|
+
export { type AutomationsApi, type CreateAutomationInput, type CreateAutomationProgress } from './adapters/automations.js';
|
|
5
|
+
export { type StrategiesApi } from './adapters/strategies.js';
|
|
6
|
+
export { type SettingsApi } from './adapters/settings.js';
|
|
7
|
+
export { type NodeApi } from './adapters/nodeApi.js';
|
|
8
|
+
export { type DocumentsApi, type ReadOnlyDocumentsApi } from './adapters/documents.js';
|
|
9
|
+
export { type ActionHandle } from './adapters/actionHandle.js';
|
|
10
|
+
export { type AccountView, type AccountKind, type AutomationView, type Holding, accountViewOf, automationViewOf } from './core/views.js';
|
|
11
|
+
export { startPairingRequest, fetchPairingRequestByCode, type StartPairingRequestOptions, type PairingRequestSession, type PairingRequestLookup, } from './pairing/pairingRequest.js';
|
|
12
|
+
export { buildJoinRequestJson, mintPairingGrant, revokePairingGrant, NothingToShareError, type MintedPairingGrant, } from './pairing/mirrorGrant.js';
|
|
13
|
+
export { parseMirrorGrantBundle, readMirrorCollections, attemptDirectMirrorWrite, type MirrorGrantBundle, type MirrorGrantNodeRef, type ReadMirrorCollectionsOptions, type AttemptDirectMirrorWriteOptions, } from './pairing/mirrorReader.js';
|
|
14
|
+
export { publishPairingGrant, clearPairingGrant, fetchPairingGrant, awaitPairingGrant, type UnsealedPairingGrant, } from './pairing/pairingGrantExchange.js';
|
|
15
|
+
export { OctoBotError, OctoBotConfigError, OctoBotConnectionError, OctoBotAuthError, OctoBotHttpError, OctoBotConflictError, OctoBotActionError, OctoBotTimeoutError, OctoBotScopeError, isOctoBotError, type OctoBotErrorCode, } from './core/errors.js';
|
|
16
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,EACd,KAAK,aAAa,EAClB,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,KAAK,WAAW,GACjB,MAAM,sBAAsB,CAAA;AAC7B,OAAO,EACL,qBAAqB,EACrB,KAAK,sBAAsB,EAC3B,KAAK,qBAAqB,EAC1B,KAAK,mBAAmB,EACxB,KAAK,sBAAsB,EAC3B,KAAK,qBAAqB,EAC1B,KAAK,cAAc,GACpB,MAAM,uBAAuB,CAAA;AAC9B,OAAO,EAAE,KAAK,WAAW,EAAE,KAAK,YAAY,EAAE,MAAM,wBAAwB,CAAA;AAC5E,OAAO,EAAE,KAAK,cAAc,EAAE,KAAK,qBAAqB,EAAE,KAAK,wBAAwB,EAAE,MAAM,2BAA2B,CAAA;AAC1H,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,0BAA0B,CAAA;AAC7D,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,wBAAwB,CAAA;AACzD,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,uBAAuB,CAAA;AACpD,OAAO,EAAE,KAAK,YAAY,EAAE,KAAK,oBAAoB,EAAE,MAAM,yBAAyB,CAAA;AACtF,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,4BAA4B,CAAA;AAC9D,OAAO,EAAE,KAAK,WAAW,EAAE,KAAK,WAAW,EAAE,KAAK,cAAc,EAAE,KAAK,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AACxI,OAAO,EACL,mBAAmB,EACnB,yBAAyB,EACzB,KAAK,0BAA0B,EAC/B,KAAK,qBAAqB,EAC1B,KAAK,oBAAoB,GAC1B,MAAM,6BAA6B,CAAA;AACpC,OAAO,EACL,oBAAoB,EACpB,gBAAgB,EAChB,kBAAkB,EAClB,mBAAmB,EACnB,KAAK,kBAAkB,GACxB,MAAM,0BAA0B,CAAA;AACjC,OAAO,EACL,sBAAsB,EACtB,qBAAqB,EACrB,wBAAwB,EACxB,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACvB,KAAK,4BAA4B,EACjC,KAAK,+BAA+B,GACrC,MAAM,2BAA2B,CAAA;AAClC,OAAO,EACL,mBAAmB,EACnB,iBAAiB,EACjB,iBAAiB,EACjB,iBAAiB,EACjB,KAAK,oBAAoB,GAC1B,MAAM,mCAAmC,CAAA;AAC1C,OAAO,EACL,YAAY,EACZ,kBAAkB,EAClB,sBAAsB,EACtB,gBAAgB,EAChB,gBAAgB,EAChB,oBAAoB,EACpB,kBAAkB,EAClB,mBAAmB,EACnB,iBAAiB,EACjB,cAAc,EACd,KAAK,gBAAgB,GACtB,MAAM,kBAAkB,CAAA"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { connectOctoBot, } from './connect/connect.js';
|
|
2
|
+
export { connectReadOnlyDevice, } from './connect/readOnly.js';
|
|
3
|
+
export { accountViewOf, automationViewOf } from './core/views.js';
|
|
4
|
+
export { startPairingRequest, fetchPairingRequestByCode, } from './pairing/pairingRequest.js';
|
|
5
|
+
export { buildJoinRequestJson, mintPairingGrant, revokePairingGrant, NothingToShareError, } from './pairing/mirrorGrant.js';
|
|
6
|
+
export { parseMirrorGrantBundle, readMirrorCollections, attemptDirectMirrorWrite, } from './pairing/mirrorReader.js';
|
|
7
|
+
export { publishPairingGrant, clearPairingGrant, fetchPairingGrant, awaitPairingGrant, } from './pairing/pairingGrantExchange.js';
|
|
8
|
+
export { OctoBotError, OctoBotConfigError, OctoBotConnectionError, OctoBotAuthError, OctoBotHttpError, OctoBotConflictError, OctoBotActionError, OctoBotTimeoutError, OctoBotScopeError, isOctoBotError, } from './core/errors.js';
|
|
9
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,GAKf,MAAM,sBAAsB,CAAA;AAC7B,OAAO,EACL,qBAAqB,GAOtB,MAAM,uBAAuB,CAAA;AAQ9B,OAAO,EAAyE,aAAa,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AACxI,OAAO,EACL,mBAAmB,EACnB,yBAAyB,GAI1B,MAAM,6BAA6B,CAAA;AACpC,OAAO,EACL,oBAAoB,EACpB,gBAAgB,EAChB,kBAAkB,EAClB,mBAAmB,GAEpB,MAAM,0BAA0B,CAAA;AACjC,OAAO,EACL,sBAAsB,EACtB,qBAAqB,EACrB,wBAAwB,GAKzB,MAAM,2BAA2B,CAAA;AAClC,OAAO,EACL,mBAAmB,EACnB,iBAAiB,EACjB,iBAAiB,EACjB,iBAAiB,GAElB,MAAM,mCAAmC,CAAA;AAC1C,OAAO,EACL,YAAY,EACZ,kBAAkB,EAClB,sBAAsB,EACtB,gBAAgB,EAChB,gBAAgB,EAChB,oBAAoB,EACpB,kBAAkB,EAClB,mBAAmB,EACnB,iBAAiB,EACjB,cAAc,GAEf,MAAM,kBAAkB,CAAA"}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Node collections the space-mirror can offer — the canonical definition this
|
|
3
|
+
* feature's per-platform copies (mobile2's `cloudSyncCollections.ts`, the node
|
|
4
|
+
* web UI's `cloud-sync-collections.ts`) are meant to eventually source from
|
|
5
|
+
* instead of duplicating. Ids are the SAME wire collection names the node's own
|
|
6
|
+
* sync layer uses (`wire-contract.md`'s `Collections` enum values).
|
|
7
|
+
*
|
|
8
|
+
* `visibility` is who can ever reach a collection's mirrored copy:
|
|
9
|
+
*
|
|
10
|
+
* - `"private"` — the wallet's own devices only. A pairing grant can never
|
|
11
|
+
* include it, no matter what the user enables.
|
|
12
|
+
* - `"shared"` — E2EE under the node's OWN keyring, reachable by a per-node
|
|
13
|
+
* pairing grant the user hands out (the website-pairing flow).
|
|
14
|
+
* - `"public"` — world-readable plaintext. Nothing is `"public"` today.
|
|
15
|
+
*
|
|
16
|
+
* `user-accounts-auth` (exchange credentials) is intentionally absent: never a
|
|
17
|
+
* configurable mirror-eligible option, at any layer.
|
|
18
|
+
*
|
|
19
|
+
* See `docs/content/client-sdk/website-pairing.md` for the access model.
|
|
20
|
+
*/
|
|
21
|
+
export type MirrorVisibility = 'private' | 'shared' | 'public';
|
|
22
|
+
export interface MirrorCollection {
|
|
23
|
+
id: string;
|
|
24
|
+
defaultEnabled: boolean;
|
|
25
|
+
visibility: MirrorVisibility;
|
|
26
|
+
}
|
|
27
|
+
export declare const MIRROR_COLLECTIONS: readonly MirrorCollection[];
|
|
28
|
+
export type MirrorCollectionId = (typeof MIRROR_COLLECTIONS)[number]['id'];
|
|
29
|
+
export declare const DEFAULT_MIRROR_COLLECTIONS: MirrorCollectionId[];
|
|
30
|
+
export declare const THIRD_PARTY_ELIGIBLE_MIRROR_COLLECTIONS: MirrorCollectionId[];
|
|
31
|
+
export declare function isKnownMirrorCollection(id: string): id is MirrorCollectionId;
|
|
32
|
+
/** An UNKNOWN id resolves to `"private"` — the safe end of the enum, so a
|
|
33
|
+
* typo'd or stale id can never read as grant-reachable or world-readable. */
|
|
34
|
+
export declare function mirrorVisibilityFor(id: string): MirrorVisibility;
|
|
35
|
+
/** DERIVED from `visibility`: "can a pairing grant ever reach this". */
|
|
36
|
+
export declare function isThirdPartyEligible(id: string): boolean;
|
|
37
|
+
export declare function isPublicMirrorCollection(id: string): boolean;
|
|
38
|
+
/** Whether a collection's node is sealed under its own per-node keyring — the
|
|
39
|
+
* grantable ones. Drives both the writer's tier and the grant minting. */
|
|
40
|
+
export declare function isIsolatedMirrorCollection(id: string): boolean;
|
|
41
|
+
/** `SpaceMirrorTier` as `starfish-replica/space` spells it: the storage axes a
|
|
42
|
+
* node is created under. `"shared"` maps to `"isolated"` rather than getting
|
|
43
|
+
* its own tier name — upstream names the access model, not our audience. */
|
|
44
|
+
export type MirrorStorageTier = 'private' | 'isolated' | 'public';
|
|
45
|
+
/**
|
|
46
|
+
* Everything one `visibility` decides, as ONE table rather than ternaries
|
|
47
|
+
* scattered across this module and the writer. Every row is a security
|
|
48
|
+
* decision, so they are stated together where they can be tested against each
|
|
49
|
+
* other.
|
|
50
|
+
*
|
|
51
|
+
* - `tier` — the storage axes handed to `createSpaceMirrorChannel`.
|
|
52
|
+
* - `storage` — which content collection the node's document lives in:
|
|
53
|
+
* `docs` (`objdoc`, space-keyring E2EE), `invite` (`objinv`, per-node-keyring
|
|
54
|
+
* E2EE, cap-readable), `pub` (`objpub`, world-readable plaintext).
|
|
55
|
+
* - `opaqueTitle` — whether the node's title must NOT name the collection,
|
|
56
|
+
* because Infra republishes a public node's title world-readable.
|
|
57
|
+
*/
|
|
58
|
+
export interface MirrorVisibilityRouting {
|
|
59
|
+
tier: MirrorStorageTier;
|
|
60
|
+
storage: 'docs' | 'invite' | 'pub';
|
|
61
|
+
opaqueTitle: boolean;
|
|
62
|
+
}
|
|
63
|
+
export declare const MIRROR_ROUTING_BY_VISIBILITY: Readonly<Record<MirrorVisibility, MirrorVisibilityRouting>>;
|
|
64
|
+
/**
|
|
65
|
+
* ONE space per wallet, holding every mirrored collection whatever its
|
|
66
|
+
* visibility. Found by name in the wallet's own space registry (`readSpaces()`)
|
|
67
|
+
* — `starfish-spaces`' `Space` has no `meta`/`kind` field, so the name is the
|
|
68
|
+
* marker; `createSpace` mints the id.
|
|
69
|
+
*
|
|
70
|
+
* This used to be three spaces, one per visibility, because a space keyring is
|
|
71
|
+
* space-wide and a `space:member` grant reaches every enc node in the space —
|
|
72
|
+
* so the only way to keep `user-settings` out of a website grant was to put it
|
|
73
|
+
* in a different space. Per-node keyrings (`tier: "isolated"`) make that
|
|
74
|
+
* unnecessary: a grant now reaches exactly one node. See
|
|
75
|
+
* `docs/content/client-sdk/website-pairing.md`.
|
|
76
|
+
*/
|
|
77
|
+
export declare const MIRROR_SPACE_NAME = "octobot-mirror";
|
|
78
|
+
/** Every routing decision for one collection, via its `visibility`. An unknown
|
|
79
|
+
* id inherits `mirrorVisibilityFor`'s safe `"private"` fallback. */
|
|
80
|
+
export declare function mirrorRoutingFor(collectionId: string): MirrorVisibilityRouting;
|
|
81
|
+
/** The `SpaceMirrorTier` a collection's node is created under. */
|
|
82
|
+
export declare function mirrorTierFor(collectionId: string): MirrorStorageTier;
|
|
83
|
+
/**
|
|
84
|
+
* The node's content path. The collection id comes FIRST because that is the
|
|
85
|
+
* shape `starfish-replica/space` widened both `SpaceMirrorChannel.docPath` and
|
|
86
|
+
* `readIsolatedSpaceMirror.docPath` to — one function literal shared by the writer and
|
|
87
|
+
* the website-side reader, so a tier can never be written to one path and read
|
|
88
|
+
* from another.
|
|
89
|
+
*
|
|
90
|
+
* `objinv` is the odd shape (`objects/n/{nodeId}/content`, not
|
|
91
|
+
* `objects/{seg}/{nodeId}`) because it is per-node-scoped server-side: its
|
|
92
|
+
* read roles are `space:member` OR `cap:read:objinv`, which is exactly what
|
|
93
|
+
* lets a per-node grant holder fetch it without space membership. `objdoc`
|
|
94
|
+
* has no cap fallback at all, which is why the isolated tier cannot use it.
|
|
95
|
+
*/
|
|
96
|
+
export declare function mirrorDocPath(collectionId: string, spaceId: string, nodeId: string): string;
|
|
97
|
+
/** The visibility-level primitive `mirrorDocPath` is a lookup in front of.
|
|
98
|
+
* Exported so the `"public"` branch is exercisable NOW — no collection has
|
|
99
|
+
* `visibility:"public"` yet, and the half that would leak is the one left
|
|
100
|
+
* unproven until someone flips a collection. */
|
|
101
|
+
export declare function mirrorDocPathForVisibility(visibility: MirrorVisibility, spaceId: string, nodeId: string): string;
|
|
102
|
+
export declare function mirrorDocPullPath(collectionId: string, spaceId: string, nodeId: string): string;
|
|
103
|
+
export declare function mirrorDocPushPath(collectionId: string, spaceId: string, nodeId: string): string;
|
|
104
|
+
/**
|
|
105
|
+
* The title a newly-created PUBLIC mirror node is given, in place of the
|
|
106
|
+
* collection id `starfish-replica/space` would otherwise default to.
|
|
107
|
+
*
|
|
108
|
+
* `_project_objindex_public` republishes a public node's `title` into the
|
|
109
|
+
* world-readable projection, so a descriptive one ("user-strategies") tells any
|
|
110
|
+
* anonymous reader exactly what a wallet publishes. One constant shared by
|
|
111
|
+
* every public collection carries zero bits about which collection a node
|
|
112
|
+
* holds. Private and isolated titles live only in `objindex`, which is
|
|
113
|
+
* `space:member` and unreachable by a per-node grant holder.
|
|
114
|
+
*/
|
|
115
|
+
export declare const MIRROR_PUBLIC_NODE_TITLE = "public";
|
|
116
|
+
/** Title for a newly-created mirror node: opaque for public collections, the
|
|
117
|
+
* collection id (upstream's default) otherwise. */
|
|
118
|
+
export declare function mirrorNodeTitleFor(collectionId: string): string;
|
|
119
|
+
/** The visibility-level primitive behind `mirrorNodeTitleFor`, exported for the
|
|
120
|
+
* same reason as `mirrorDocPathForVisibility`. */
|
|
121
|
+
export declare function mirrorNodeTitleForVisibility(visibility: MirrorVisibility, collectionId: string): string;
|
|
122
|
+
/** `ObjectNode.type` for a mirror node is the collection id itself — one
|
|
123
|
+
* identifier space, nothing extra to keep in sync (see the module doc). */
|
|
124
|
+
export type MirrorNodeType = MirrorCollectionId;
|
|
125
|
+
//# sourceMappingURL=collections.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"collections.d.ts","sourceRoot":"","sources":["../../../src/client/mirror/collections.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,MAAM,gBAAgB,GAAG,SAAS,GAAG,QAAQ,GAAG,QAAQ,CAAA;AAE9D,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAA;IACV,cAAc,EAAE,OAAO,CAAA;IACvB,UAAU,EAAE,gBAAgB,CAAA;CAC7B;AAED,eAAO,MAAM,kBAAkB,EAAE,SAAS,gBAAgB,EAMhD,CAAA;AAEV,MAAM,MAAM,kBAAkB,GAAG,CAAC,OAAO,kBAAkB,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAA;AAE1E,eAAO,MAAM,0BAA0B,EAAE,kBAAkB,EAExC,CAAA;AAEnB,eAAO,MAAM,uCAAuC,EAAE,kBAAkB,EAErD,CAAA;AAEnB,wBAAgB,uBAAuB,CAAC,EAAE,EAAE,MAAM,GAAG,EAAE,IAAI,kBAAkB,CAE5E;AAED;8EAC8E;AAC9E,wBAAgB,mBAAmB,CAAC,EAAE,EAAE,MAAM,GAAG,gBAAgB,CAEhE;AAED,wEAAwE;AACxE,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAExD;AAED,wBAAgB,wBAAwB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAE5D;AAED;2EAC2E;AAC3E,wBAAgB,0BAA0B,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAE9D;AAED;;6EAE6E;AAC7E,MAAM,MAAM,iBAAiB,GAAG,SAAS,GAAG,UAAU,GAAG,QAAQ,CAAA;AAEjE;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,iBAAiB,CAAA;IACvB,OAAO,EAAE,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAA;IAClC,WAAW,EAAE,OAAO,CAAA;CACrB;AAED,eAAO,MAAM,4BAA4B,EAAE,QAAQ,CACjD,MAAM,CAAC,gBAAgB,EAAE,uBAAuB,CAAC,CAKzC,CAAA;AAEV;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,iBAAiB,mBAAmB,CAAA;AAEjD;qEACqE;AACrE,wBAAgB,gBAAgB,CAAC,YAAY,EAAE,MAAM,GAAG,uBAAuB,CAE9E;AAED,kEAAkE;AAClE,wBAAgB,aAAa,CAAC,YAAY,EAAE,MAAM,GAAG,iBAAiB,CAErE;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,aAAa,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAE3F;AAED;;;iDAGiD;AACjD,wBAAgB,0BAA0B,CACxC,UAAU,EAAE,gBAAgB,EAC5B,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,GACb,MAAM,CAKR;AAED,wBAAgB,iBAAiB,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAE/F;AAED,wBAAgB,iBAAiB,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAE/F;AAED;;;;;;;;;;GAUG;AACH,eAAO,MAAM,wBAAwB,WAAW,CAAA;AAEhD;oDACoD;AACpD,wBAAgB,kBAAkB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAE/D;AAED;mDACmD;AACnD,wBAAgB,4BAA4B,CAC1C,UAAU,EAAE,gBAAgB,EAC5B,YAAY,EAAE,MAAM,GACnB,MAAM,CAIR;AAED;4EAC4E;AAC5E,MAAM,MAAM,cAAc,GAAG,kBAAkB,CAAA"}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
export const MIRROR_COLLECTIONS = [
|
|
2
|
+
{ id: 'user-accounts', defaultEnabled: true, visibility: 'shared' },
|
|
3
|
+
{ id: 'user-data', defaultEnabled: true, visibility: 'shared' },
|
|
4
|
+
{ id: 'user-strategies', defaultEnabled: true, visibility: 'shared' },
|
|
5
|
+
{ id: 'user-accounts-trading', defaultEnabled: false, visibility: 'shared' },
|
|
6
|
+
{ id: 'user-settings', defaultEnabled: false, visibility: 'private' },
|
|
7
|
+
];
|
|
8
|
+
export const DEFAULT_MIRROR_COLLECTIONS = MIRROR_COLLECTIONS
|
|
9
|
+
.filter((c) => c.defaultEnabled)
|
|
10
|
+
.map((c) => c.id);
|
|
11
|
+
export const THIRD_PARTY_ELIGIBLE_MIRROR_COLLECTIONS = MIRROR_COLLECTIONS
|
|
12
|
+
.filter((c) => c.visibility !== 'private')
|
|
13
|
+
.map((c) => c.id);
|
|
14
|
+
export function isKnownMirrorCollection(id) {
|
|
15
|
+
return MIRROR_COLLECTIONS.some((c) => c.id === id);
|
|
16
|
+
}
|
|
17
|
+
/** An UNKNOWN id resolves to `"private"` — the safe end of the enum, so a
|
|
18
|
+
* typo'd or stale id can never read as grant-reachable or world-readable. */
|
|
19
|
+
export function mirrorVisibilityFor(id) {
|
|
20
|
+
return MIRROR_COLLECTIONS.find((c) => c.id === id)?.visibility ?? 'private';
|
|
21
|
+
}
|
|
22
|
+
/** DERIVED from `visibility`: "can a pairing grant ever reach this". */
|
|
23
|
+
export function isThirdPartyEligible(id) {
|
|
24
|
+
return mirrorVisibilityFor(id) !== 'private';
|
|
25
|
+
}
|
|
26
|
+
export function isPublicMirrorCollection(id) {
|
|
27
|
+
return mirrorVisibilityFor(id) === 'public';
|
|
28
|
+
}
|
|
29
|
+
/** Whether a collection's node is sealed under its own per-node keyring — the
|
|
30
|
+
* grantable ones. Drives both the writer's tier and the grant minting. */
|
|
31
|
+
export function isIsolatedMirrorCollection(id) {
|
|
32
|
+
return mirrorVisibilityFor(id) === 'shared';
|
|
33
|
+
}
|
|
34
|
+
export const MIRROR_ROUTING_BY_VISIBILITY = {
|
|
35
|
+
private: { tier: 'private', storage: 'docs', opaqueTitle: false },
|
|
36
|
+
shared: { tier: 'isolated', storage: 'invite', opaqueTitle: false },
|
|
37
|
+
public: { tier: 'public', storage: 'pub', opaqueTitle: true },
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* ONE space per wallet, holding every mirrored collection whatever its
|
|
41
|
+
* visibility. Found by name in the wallet's own space registry (`readSpaces()`)
|
|
42
|
+
* — `starfish-spaces`' `Space` has no `meta`/`kind` field, so the name is the
|
|
43
|
+
* marker; `createSpace` mints the id.
|
|
44
|
+
*
|
|
45
|
+
* This used to be three spaces, one per visibility, because a space keyring is
|
|
46
|
+
* space-wide and a `space:member` grant reaches every enc node in the space —
|
|
47
|
+
* so the only way to keep `user-settings` out of a website grant was to put it
|
|
48
|
+
* in a different space. Per-node keyrings (`tier: "isolated"`) make that
|
|
49
|
+
* unnecessary: a grant now reaches exactly one node. See
|
|
50
|
+
* `docs/content/client-sdk/website-pairing.md`.
|
|
51
|
+
*/
|
|
52
|
+
export const MIRROR_SPACE_NAME = 'octobot-mirror';
|
|
53
|
+
/** Every routing decision for one collection, via its `visibility`. An unknown
|
|
54
|
+
* id inherits `mirrorVisibilityFor`'s safe `"private"` fallback. */
|
|
55
|
+
export function mirrorRoutingFor(collectionId) {
|
|
56
|
+
return MIRROR_ROUTING_BY_VISIBILITY[mirrorVisibilityFor(collectionId)];
|
|
57
|
+
}
|
|
58
|
+
/** The `SpaceMirrorTier` a collection's node is created under. */
|
|
59
|
+
export function mirrorTierFor(collectionId) {
|
|
60
|
+
return mirrorRoutingFor(collectionId).tier;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* The node's content path. The collection id comes FIRST because that is the
|
|
64
|
+
* shape `starfish-replica/space` widened both `SpaceMirrorChannel.docPath` and
|
|
65
|
+
* `readIsolatedSpaceMirror.docPath` to — one function literal shared by the writer and
|
|
66
|
+
* the website-side reader, so a tier can never be written to one path and read
|
|
67
|
+
* from another.
|
|
68
|
+
*
|
|
69
|
+
* `objinv` is the odd shape (`objects/n/{nodeId}/content`, not
|
|
70
|
+
* `objects/{seg}/{nodeId}`) because it is per-node-scoped server-side: its
|
|
71
|
+
* read roles are `space:member` OR `cap:read:objinv`, which is exactly what
|
|
72
|
+
* lets a per-node grant holder fetch it without space membership. `objdoc`
|
|
73
|
+
* has no cap fallback at all, which is why the isolated tier cannot use it.
|
|
74
|
+
*/
|
|
75
|
+
export function mirrorDocPath(collectionId, spaceId, nodeId) {
|
|
76
|
+
return mirrorDocPathForVisibility(mirrorVisibilityFor(collectionId), spaceId, nodeId);
|
|
77
|
+
}
|
|
78
|
+
/** The visibility-level primitive `mirrorDocPath` is a lookup in front of.
|
|
79
|
+
* Exported so the `"public"` branch is exercisable NOW — no collection has
|
|
80
|
+
* `visibility:"public"` yet, and the half that would leak is the one left
|
|
81
|
+
* unproven until someone flips a collection. */
|
|
82
|
+
export function mirrorDocPathForVisibility(visibility, spaceId, nodeId) {
|
|
83
|
+
const { storage } = MIRROR_ROUTING_BY_VISIBILITY[visibility];
|
|
84
|
+
return storage === 'invite'
|
|
85
|
+
? `spaces/${spaceId}/objects/n/${nodeId}/content`
|
|
86
|
+
: `spaces/${spaceId}/objects/${storage}/${nodeId}`;
|
|
87
|
+
}
|
|
88
|
+
export function mirrorDocPullPath(collectionId, spaceId, nodeId) {
|
|
89
|
+
return `/pull/${mirrorDocPath(collectionId, spaceId, nodeId)}`;
|
|
90
|
+
}
|
|
91
|
+
export function mirrorDocPushPath(collectionId, spaceId, nodeId) {
|
|
92
|
+
return `/push/${mirrorDocPath(collectionId, spaceId, nodeId)}`;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* The title a newly-created PUBLIC mirror node is given, in place of the
|
|
96
|
+
* collection id `starfish-replica/space` would otherwise default to.
|
|
97
|
+
*
|
|
98
|
+
* `_project_objindex_public` republishes a public node's `title` into the
|
|
99
|
+
* world-readable projection, so a descriptive one ("user-strategies") tells any
|
|
100
|
+
* anonymous reader exactly what a wallet publishes. One constant shared by
|
|
101
|
+
* every public collection carries zero bits about which collection a node
|
|
102
|
+
* holds. Private and isolated titles live only in `objindex`, which is
|
|
103
|
+
* `space:member` and unreachable by a per-node grant holder.
|
|
104
|
+
*/
|
|
105
|
+
export const MIRROR_PUBLIC_NODE_TITLE = 'public';
|
|
106
|
+
/** Title for a newly-created mirror node: opaque for public collections, the
|
|
107
|
+
* collection id (upstream's default) otherwise. */
|
|
108
|
+
export function mirrorNodeTitleFor(collectionId) {
|
|
109
|
+
return mirrorNodeTitleForVisibility(mirrorVisibilityFor(collectionId), collectionId);
|
|
110
|
+
}
|
|
111
|
+
/** The visibility-level primitive behind `mirrorNodeTitleFor`, exported for the
|
|
112
|
+
* same reason as `mirrorDocPathForVisibility`. */
|
|
113
|
+
export function mirrorNodeTitleForVisibility(visibility, collectionId) {
|
|
114
|
+
return MIRROR_ROUTING_BY_VISIBILITY[visibility].opaqueTitle
|
|
115
|
+
? MIRROR_PUBLIC_NODE_TITLE
|
|
116
|
+
: collectionId;
|
|
117
|
+
}
|
|
118
|
+
//# sourceMappingURL=collections.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"collections.js","sourceRoot":"","sources":["../../../src/client/mirror/collections.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { MIRROR_COLLECTIONS, DEFAULT_MIRROR_COLLECTIONS, THIRD_PARTY_ELIGIBLE_MIRROR_COLLECTIONS, MIRROR_SPACE_NAME, MIRROR_PUBLIC_NODE_TITLE, MIRROR_ROUTING_BY_VISIBILITY, isIsolatedMirrorCollection, isKnownMirrorCollection, isPublicMirrorCollection, isThirdPartyEligible, mirrorDocPath, mirrorDocPathForVisibility, mirrorDocPullPath, mirrorDocPushPath, mirrorNodeTitleFor, mirrorNodeTitleForVisibility, mirrorRoutingFor, mirrorTierFor, mirrorVisibilityFor, type MirrorCollection, type MirrorCollectionId, type MirrorNodeType, type MirrorStorageTier, type MirrorVisibility, type MirrorVisibilityRouting, } from './collections.js';
|
|
2
|
+
export { findOrCreateSpace as findOrCreateMirrorSpace } from '@drakkar.software/starfish-replica/space';
|
|
3
|
+
export { syncCloudMirror, type SyncCloudMirrorOptions, type SyncCloudMirrorResult, } from './writer.js';
|
|
4
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/client/mirror/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,0BAA0B,EAC1B,uCAAuC,EACvC,iBAAiB,EACjB,wBAAwB,EACxB,4BAA4B,EAC5B,0BAA0B,EAC1B,uBAAuB,EACvB,wBAAwB,EACxB,oBAAoB,EACpB,aAAa,EACb,0BAA0B,EAC1B,iBAAiB,EACjB,iBAAiB,EACjB,kBAAkB,EAClB,4BAA4B,EAC5B,gBAAgB,EAChB,aAAa,EACb,mBAAmB,EACnB,KAAK,gBAAgB,EACrB,KAAK,kBAAkB,EACvB,KAAK,cAAc,EACnB,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,KAAK,uBAAuB,GAC7B,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAAE,iBAAiB,IAAI,uBAAuB,EAAE,MAAM,0CAA0C,CAAA;AACvG,OAAO,EACL,eAAe,EACf,KAAK,sBAAsB,EAC3B,KAAK,qBAAqB,GAC3B,MAAM,aAAa,CAAA"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { MIRROR_COLLECTIONS, DEFAULT_MIRROR_COLLECTIONS, THIRD_PARTY_ELIGIBLE_MIRROR_COLLECTIONS, MIRROR_SPACE_NAME, MIRROR_PUBLIC_NODE_TITLE, MIRROR_ROUTING_BY_VISIBILITY, isIsolatedMirrorCollection, isKnownMirrorCollection, isPublicMirrorCollection, isThirdPartyEligible, mirrorDocPath, mirrorDocPathForVisibility, mirrorDocPullPath, mirrorDocPushPath, mirrorNodeTitleFor, mirrorNodeTitleForVisibility, mirrorRoutingFor, mirrorTierFor, mirrorVisibilityFor, } from './collections.js';
|
|
2
|
+
export { findOrCreateSpace as findOrCreateMirrorSpace } from '@drakkar.software/starfish-replica/space';
|
|
3
|
+
export { syncCloudMirror, } from './writer.js';
|
|
4
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/client/mirror/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,0BAA0B,EAC1B,uCAAuC,EACvC,iBAAiB,EACjB,wBAAwB,EACxB,4BAA4B,EAC5B,0BAA0B,EAC1B,uBAAuB,EACvB,wBAAwB,EACxB,oBAAoB,EACpB,aAAa,EACb,0BAA0B,EAC1B,iBAAiB,EACjB,iBAAiB,EACjB,kBAAkB,EAClB,4BAA4B,EAC5B,gBAAgB,EAChB,aAAa,EACb,mBAAmB,GAOpB,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAAE,iBAAiB,IAAI,uBAAuB,EAAE,MAAM,0CAA0C,CAAA;AACvG,OAAO,EACL,eAAe,GAGhB,MAAM,aAAa,CAAA"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { Session } from '@drakkar.software/starfish-spaces';
|
|
2
|
+
import { type MirrorCollectionId } from './collections.js';
|
|
3
|
+
export interface SyncCloudMirrorOptions {
|
|
4
|
+
session: Session;
|
|
5
|
+
/** Collection ids the user has currently enabled (`cloudSyncCollections`).
|
|
6
|
+
* Unknown ids are silently ignored — this function is not the place a
|
|
7
|
+
* malformed setting gets rejected, the settings layer already owns that. */
|
|
8
|
+
enabledCollectionIds: readonly string[];
|
|
9
|
+
/** Pull the CURRENT raw document for one enabled collection from its real
|
|
10
|
+
* source (the node, or a local store in the no-node case) — this
|
|
11
|
+
* function's caller owns how, `starfish-replica/space` owns only the
|
|
12
|
+
* CAS-write into the mirror space. Called once per collection being
|
|
13
|
+
* written, never for a collection being cleared. */
|
|
14
|
+
readSourceCollection: (collectionId: MirrorCollectionId) => Promise<unknown>;
|
|
15
|
+
}
|
|
16
|
+
export interface SyncCloudMirrorResult {
|
|
17
|
+
/** `null` when the space was never created (nothing has ever been enabled)
|
|
18
|
+
* — not an error, just "nothing to report". */
|
|
19
|
+
spaceId: string | null;
|
|
20
|
+
created: MirrorCollectionId[];
|
|
21
|
+
written: MirrorCollectionId[];
|
|
22
|
+
cleared: MirrorCollectionId[];
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* One full cloud-mirror sync cycle: find-or-create the wallet's mirror space,
|
|
26
|
+
* plan what changed since last cycle, create any newly-enabled collections'
|
|
27
|
+
* nodes, write every currently-enabled collection's projection, and clear any
|
|
28
|
+
* collection the user just disabled.
|
|
29
|
+
*
|
|
30
|
+
* The space/node mechanics live in `starfish-replica/space`'s
|
|
31
|
+
* `createSpaceMirrorChannel` — this is a thin adapter wiring the
|
|
32
|
+
* `MIRROR_COLLECTIONS` registry and its tier routing into it.
|
|
33
|
+
*
|
|
34
|
+
* Callers (the node's writer, the mobile no-node writer) gate this behind the
|
|
35
|
+
* `cloudSyncEnabled` setting themselves; this function assumes it was only
|
|
36
|
+
* called because the setting is on.
|
|
37
|
+
*/
|
|
38
|
+
export declare function syncCloudMirror(options: SyncCloudMirrorOptions): Promise<SyncCloudMirrorResult>;
|
|
39
|
+
//# sourceMappingURL=writer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"writer.d.ts","sourceRoot":"","sources":["../../../src/client/mirror/writer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mCAAmC,CAAA;AAEhE,OAAO,EAML,KAAK,kBAAkB,EACxB,MAAM,kBAAkB,CAAA;AAEzB,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,OAAO,CAAA;IAChB;;iFAE6E;IAC7E,oBAAoB,EAAE,SAAS,MAAM,EAAE,CAAA;IACvC;;;;yDAIqD;IACrD,oBAAoB,EAAE,CAAC,YAAY,EAAE,kBAAkB,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;CAC7E;AAED,MAAM,WAAW,qBAAqB;IACpC;oDACgD;IAChD,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;IACtB,OAAO,EAAE,kBAAkB,EAAE,CAAA;IAC7B,OAAO,EAAE,kBAAkB,EAAE,CAAA;IAC7B,OAAO,EAAE,kBAAkB,EAAE,CAAA;CAC9B;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,eAAe,CACnC,OAAO,EAAE,sBAAsB,GAC9B,OAAO,CAAC,qBAAqB,CAAC,CAkChC"}
|