@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.
Files changed (306) hide show
  1. package/README.md +140 -0
  2. package/dist/client/adapters/accounts.d.ts +66 -0
  3. package/dist/client/adapters/accounts.d.ts.map +1 -0
  4. package/dist/client/adapters/accounts.js +214 -0
  5. package/dist/client/adapters/accounts.js.map +1 -0
  6. package/dist/client/adapters/actionHandle.d.ts +29 -0
  7. package/dist/client/adapters/actionHandle.d.ts.map +1 -0
  8. package/dist/client/adapters/actionHandle.js +34 -0
  9. package/dist/client/adapters/actionHandle.js.map +1 -0
  10. package/dist/client/adapters/automations.d.ts +31 -0
  11. package/dist/client/adapters/automations.d.ts.map +1 -0
  12. package/dist/client/adapters/automations.js +79 -0
  13. package/dist/client/adapters/automations.js.map +1 -0
  14. package/dist/client/adapters/documents.d.ts +55 -0
  15. package/dist/client/adapters/documents.d.ts.map +1 -0
  16. package/dist/client/adapters/documents.js +66 -0
  17. package/dist/client/adapters/documents.js.map +1 -0
  18. package/dist/client/adapters/nodeApi.d.ts +25 -0
  19. package/dist/client/adapters/nodeApi.d.ts.map +1 -0
  20. package/dist/client/adapters/nodeApi.js +81 -0
  21. package/dist/client/adapters/nodeApi.js.map +1 -0
  22. package/dist/client/adapters/settings.d.ts +16 -0
  23. package/dist/client/adapters/settings.d.ts.map +1 -0
  24. package/dist/client/adapters/settings.js +43 -0
  25. package/dist/client/adapters/settings.js.map +1 -0
  26. package/dist/client/adapters/strategies.d.ts +17 -0
  27. package/dist/client/adapters/strategies.d.ts.map +1 -0
  28. package/dist/client/adapters/strategies.js +75 -0
  29. package/dist/client/adapters/strategies.js.map +1 -0
  30. package/dist/client/connect/connect.d.ts +40 -0
  31. package/dist/client/connect/connect.d.ts.map +1 -0
  32. package/dist/client/connect/connect.js +133 -0
  33. package/dist/client/connect/connect.js.map +1 -0
  34. package/dist/client/connect/readOnly.d.ts +97 -0
  35. package/dist/client/connect/readOnly.d.ts.map +1 -0
  36. package/dist/client/connect/readOnly.js +167 -0
  37. package/dist/client/connect/readOnly.js.map +1 -0
  38. package/dist/client/core/errors.d.ts +80 -0
  39. package/dist/client/core/errors.d.ts.map +1 -0
  40. package/dist/client/core/errors.js +154 -0
  41. package/dist/client/core/errors.js.map +1 -0
  42. package/dist/client/core/options.d.ts +44 -0
  43. package/dist/client/core/options.d.ts.map +1 -0
  44. package/dist/client/core/options.js +2 -0
  45. package/dist/client/core/options.js.map +1 -0
  46. package/dist/client/core/session.d.ts +90 -0
  47. package/dist/client/core/session.d.ts.map +1 -0
  48. package/dist/client/core/session.js +72 -0
  49. package/dist/client/core/session.js.map +1 -0
  50. package/dist/client/core/views.d.ts +40 -0
  51. package/dist/client/core/views.d.ts.map +1 -0
  52. package/dist/client/core/views.js +32 -0
  53. package/dist/client/core/views.js.map +1 -0
  54. package/dist/client/index.d.ts +16 -0
  55. package/dist/client/index.d.ts.map +1 -0
  56. package/dist/client/index.js +9 -0
  57. package/dist/client/index.js.map +1 -0
  58. package/dist/client/mirror/collections.d.ts +125 -0
  59. package/dist/client/mirror/collections.d.ts.map +1 -0
  60. package/dist/client/mirror/collections.js +118 -0
  61. package/dist/client/mirror/collections.js.map +1 -0
  62. package/dist/client/mirror/index.d.ts +4 -0
  63. package/dist/client/mirror/index.d.ts.map +1 -0
  64. package/dist/client/mirror/index.js +4 -0
  65. package/dist/client/mirror/index.js.map +1 -0
  66. package/dist/client/mirror/writer.d.ts +39 -0
  67. package/dist/client/mirror/writer.d.ts.map +1 -0
  68. package/dist/client/mirror/writer.js +50 -0
  69. package/dist/client/mirror/writer.js.map +1 -0
  70. package/dist/client/pairing/mirrorGrant.d.ts +91 -0
  71. package/dist/client/pairing/mirrorGrant.d.ts.map +1 -0
  72. package/dist/client/pairing/mirrorGrant.js +99 -0
  73. package/dist/client/pairing/mirrorGrant.js.map +1 -0
  74. package/dist/client/pairing/mirrorReader.d.ts +99 -0
  75. package/dist/client/pairing/mirrorReader.d.ts.map +1 -0
  76. package/dist/client/pairing/mirrorReader.js +117 -0
  77. package/dist/client/pairing/mirrorReader.js.map +1 -0
  78. package/dist/client/pairing/pairingGrantExchange.d.ts +135 -0
  79. package/dist/client/pairing/pairingGrantExchange.d.ts.map +1 -0
  80. package/dist/client/pairing/pairingGrantExchange.js +186 -0
  81. package/dist/client/pairing/pairingGrantExchange.js.map +1 -0
  82. package/dist/client/pairing/pairingRequest.d.ts +82 -0
  83. package/dist/client/pairing/pairingRequest.d.ts.map +1 -0
  84. package/dist/client/pairing/pairingRequest.js +120 -0
  85. package/dist/client/pairing/pairingRequest.js.map +1 -0
  86. package/dist/client/strategy.d.ts +36 -0
  87. package/dist/client/strategy.d.ts.map +1 -0
  88. package/dist/client/strategy.js +26 -0
  89. package/dist/client/strategy.js.map +1 -0
  90. package/dist/collections/index.d.ts +3 -0
  91. package/dist/collections/index.d.ts.map +1 -0
  92. package/dist/collections/index.js +3 -0
  93. package/dist/collections/index.js.map +1 -0
  94. package/dist/collections/nodeCollections.d.ts +57 -0
  95. package/dist/collections/nodeCollections.d.ts.map +1 -0
  96. package/dist/collections/nodeCollections.js +40 -0
  97. package/dist/collections/nodeCollections.js.map +1 -0
  98. package/dist/collections/paths.d.ts +7 -0
  99. package/dist/collections/paths.d.ts.map +1 -0
  100. package/dist/collections/paths.js +13 -0
  101. package/dist/collections/paths.js.map +1 -0
  102. package/dist/crypto/collectionKeys.d.ts +28 -0
  103. package/dist/crypto/collectionKeys.d.ts.map +1 -0
  104. package/dist/crypto/collectionKeys.js +53 -0
  105. package/dist/crypto/collectionKeys.js.map +1 -0
  106. package/dist/crypto/hkdf.d.ts +14 -0
  107. package/dist/crypto/hkdf.d.ts.map +1 -0
  108. package/dist/crypto/hkdf.js +19 -0
  109. package/dist/crypto/hkdf.js.map +1 -0
  110. package/dist/crypto/index.d.ts +5 -0
  111. package/dist/crypto/index.d.ts.map +1 -0
  112. package/dist/crypto/index.js +5 -0
  113. package/dist/crypto/index.js.map +1 -0
  114. package/dist/crypto/secretEncryptor.d.ts +20 -0
  115. package/dist/crypto/secretEncryptor.d.ts.map +1 -0
  116. package/dist/crypto/secretEncryptor.js +82 -0
  117. package/dist/crypto/secretEncryptor.js.map +1 -0
  118. package/dist/crypto/wireConstants.d.ts +14 -0
  119. package/dist/crypto/wireConstants.d.ts.map +1 -0
  120. package/dist/crypto/wireConstants.js +17 -0
  121. package/dist/crypto/wireConstants.js.map +1 -0
  122. package/dist/identity/address.d.ts +3 -0
  123. package/dist/identity/address.d.ts.map +1 -0
  124. package/dist/identity/address.js +17 -0
  125. package/dist/identity/address.js.map +1 -0
  126. package/dist/identity/bip39-wordlist.d.ts +2 -0
  127. package/dist/identity/bip39-wordlist.d.ts.map +1 -0
  128. package/dist/identity/bip39-wordlist.js +2051 -0
  129. package/dist/identity/bip39-wordlist.js.map +1 -0
  130. package/dist/identity/capProvider.d.ts +45 -0
  131. package/dist/identity/capProvider.d.ts.map +1 -0
  132. package/dist/identity/capProvider.js +80 -0
  133. package/dist/identity/capProvider.js.map +1 -0
  134. package/dist/identity/derivationSchemes.d.ts +25 -0
  135. package/dist/identity/derivationSchemes.d.ts.map +1 -0
  136. package/dist/identity/derivationSchemes.js +34 -0
  137. package/dist/identity/derivationSchemes.js.map +1 -0
  138. package/dist/identity/evm.d.ts +8 -0
  139. package/dist/identity/evm.d.ts.map +1 -0
  140. package/dist/identity/evm.js +78 -0
  141. package/dist/identity/evm.js.map +1 -0
  142. package/dist/identity/index.d.ts +10 -0
  143. package/dist/identity/index.d.ts.map +1 -0
  144. package/dist/identity/index.js +10 -0
  145. package/dist/identity/index.js.map +1 -0
  146. package/dist/identity/keys.d.ts +17 -0
  147. package/dist/identity/keys.d.ts.map +1 -0
  148. package/dist/identity/keys.js +36 -0
  149. package/dist/identity/keys.js.map +1 -0
  150. package/dist/identity/mnemonic.d.ts +4 -0
  151. package/dist/identity/mnemonic.d.ts.map +1 -0
  152. package/dist/identity/mnemonic.js +93 -0
  153. package/dist/identity/mnemonic.js.map +1 -0
  154. package/dist/identity/pairing.d.ts +45 -0
  155. package/dist/identity/pairing.d.ts.map +1 -0
  156. package/dist/identity/pairing.js +91 -0
  157. package/dist/identity/pairing.js.map +1 -0
  158. package/dist/identity/pairingRequest.d.ts +99 -0
  159. package/dist/identity/pairingRequest.d.ts.map +1 -0
  160. package/dist/identity/pairingRequest.js +217 -0
  161. package/dist/identity/pairingRequest.js.map +1 -0
  162. package/dist/identity/secret.d.ts +32 -0
  163. package/dist/identity/secret.d.ts.map +1 -0
  164. package/dist/identity/secret.js +54 -0
  165. package/dist/identity/secret.js.map +1 -0
  166. package/dist/index.d.ts +9 -0
  167. package/dist/index.d.ts.map +1 -0
  168. package/dist/index.js +18 -0
  169. package/dist/index.js.map +1 -0
  170. package/dist/internal/bytes.d.ts +11 -0
  171. package/dist/internal/bytes.d.ts.map +1 -0
  172. package/dist/internal/bytes.js +38 -0
  173. package/dist/internal/bytes.js.map +1 -0
  174. package/dist/node-api/dexPair.d.ts +24 -0
  175. package/dist/node-api/dexPair.d.ts.map +1 -0
  176. package/dist/node-api/dexPair.js +39 -0
  177. package/dist/node-api/dexPair.js.map +1 -0
  178. package/dist/node-api/dsl.d.ts +10 -0
  179. package/dist/node-api/dsl.d.ts.map +1 -0
  180. package/dist/node-api/dsl.js +7 -0
  181. package/dist/node-api/dsl.js.map +1 -0
  182. package/dist/node-api/exchanges.d.ts +49 -0
  183. package/dist/node-api/exchanges.d.ts.map +1 -0
  184. package/dist/node-api/exchanges.js +32 -0
  185. package/dist/node-api/exchanges.js.map +1 -0
  186. package/dist/node-api/index.d.ts +12 -0
  187. package/dist/node-api/index.d.ts.map +1 -0
  188. package/dist/node-api/index.js +12 -0
  189. package/dist/node-api/index.js.map +1 -0
  190. package/dist/node-api/marketMaking.d.ts +39 -0
  191. package/dist/node-api/marketMaking.d.ts.map +1 -0
  192. package/dist/node-api/marketMaking.js +44 -0
  193. package/dist/node-api/marketMaking.js.map +1 -0
  194. package/dist/node-api/octobots.d.ts +14 -0
  195. package/dist/node-api/octobots.d.ts.map +1 -0
  196. package/dist/node-api/octobots.js +16 -0
  197. package/dist/node-api/octobots.js.map +1 -0
  198. package/dist/node-api/orderBookPreview.d.ts +11 -0
  199. package/dist/node-api/orderBookPreview.d.ts.map +1 -0
  200. package/dist/node-api/orderBookPreview.js +7 -0
  201. package/dist/node-api/orderBookPreview.js.map +1 -0
  202. package/dist/node-api/pairing.d.ts +39 -0
  203. package/dist/node-api/pairing.d.ts.map +1 -0
  204. package/dist/node-api/pairing.js +61 -0
  205. package/dist/node-api/pairing.js.map +1 -0
  206. package/dist/node-api/pairs.d.ts +32 -0
  207. package/dist/node-api/pairs.d.ts.map +1 -0
  208. package/dist/node-api/pairs.js +72 -0
  209. package/dist/node-api/pairs.js.map +1 -0
  210. package/dist/node-api/requiredFunds.d.ts +11 -0
  211. package/dist/node-api/requiredFunds.d.ts.map +1 -0
  212. package/dist/node-api/requiredFunds.js +7 -0
  213. package/dist/node-api/requiredFunds.js.map +1 -0
  214. package/dist/node-api/setup.d.ts +25 -0
  215. package/dist/node-api/setup.d.ts.map +1 -0
  216. package/dist/node-api/setup.js +13 -0
  217. package/dist/node-api/setup.js.map +1 -0
  218. package/dist/node-api/wallet.d.ts +55 -0
  219. package/dist/node-api/wallet.d.ts.map +1 -0
  220. package/dist/node-api/wallet.js +87 -0
  221. package/dist/node-api/wallet.js.map +1 -0
  222. package/dist/protocol/actions.d.ts +40 -0
  223. package/dist/protocol/actions.d.ts.map +1 -0
  224. package/dist/protocol/actions.js +118 -0
  225. package/dist/protocol/actions.js.map +1 -0
  226. package/dist/protocol/documents.d.ts +25 -0
  227. package/dist/protocol/documents.d.ts.map +1 -0
  228. package/dist/protocol/documents.js +2 -0
  229. package/dist/protocol/documents.js.map +1 -0
  230. package/dist/protocol/index.d.ts +10 -0
  231. package/dist/protocol/index.d.ts.map +1 -0
  232. package/dist/protocol/index.js +12 -0
  233. package/dist/protocol/index.js.map +1 -0
  234. package/dist/protocol/orchestration/createAutomation.d.ts +61 -0
  235. package/dist/protocol/orchestration/createAutomation.d.ts.map +1 -0
  236. package/dist/protocol/orchestration/createAutomation.js +71 -0
  237. package/dist/protocol/orchestration/createAutomation.js.map +1 -0
  238. package/dist/protocol/poll.d.ts +4 -0
  239. package/dist/protocol/poll.d.ts.map +1 -0
  240. package/dist/protocol/poll.js +4 -0
  241. package/dist/protocol/poll.js.map +1 -0
  242. package/dist/protocol/proposal.d.ts +36 -0
  243. package/dist/protocol/proposal.d.ts.map +1 -0
  244. package/dist/protocol/proposal.js +39 -0
  245. package/dist/protocol/proposal.js.map +1 -0
  246. package/dist/protocol/state.d.ts +87 -0
  247. package/dist/protocol/state.d.ts.map +1 -0
  248. package/dist/protocol/state.js +303 -0
  249. package/dist/protocol/state.js.map +1 -0
  250. package/dist/protocol/strategy/build.d.ts +44 -0
  251. package/dist/protocol/strategy/build.d.ts.map +1 -0
  252. package/dist/protocol/strategy/build.js +50 -0
  253. package/dist/protocol/strategy/build.js.map +1 -0
  254. package/dist/protocol/strategy/builders.d.ts +252 -0
  255. package/dist/protocol/strategy/builders.d.ts.map +1 -0
  256. package/dist/protocol/strategy/builders.js +382 -0
  257. package/dist/protocol/strategy/builders.js.map +1 -0
  258. package/dist/protocol/strategy/index.d.ts +5 -0
  259. package/dist/protocol/strategy/index.d.ts.map +1 -0
  260. package/dist/protocol/strategy/index.js +4 -0
  261. package/dist/protocol/strategy/index.js.map +1 -0
  262. package/dist/protocol/strategy/kinds.d.ts +2 -0
  263. package/dist/protocol/strategy/kinds.d.ts.map +1 -0
  264. package/dist/protocol/strategy/kinds.js +2 -0
  265. package/dist/protocol/strategy/kinds.js.map +1 -0
  266. package/dist/protocol/strategy/patch.d.ts +59 -0
  267. package/dist/protocol/strategy/patch.d.ts.map +1 -0
  268. package/dist/protocol/strategy/patch.js +253 -0
  269. package/dist/protocol/strategy/patch.js.map +1 -0
  270. package/dist/protocol/symbols.d.ts +8 -0
  271. package/dist/protocol/symbols.d.ts.map +1 -0
  272. package/dist/protocol/symbols.js +11 -0
  273. package/dist/protocol/symbols.js.map +1 -0
  274. package/dist/transport/constants.d.ts +8 -0
  275. package/dist/transport/constants.d.ts.map +1 -0
  276. package/dist/transport/constants.js +8 -0
  277. package/dist/transport/constants.js.map +1 -0
  278. package/dist/transport/documents.d.ts +27 -0
  279. package/dist/transport/documents.d.ts.map +1 -0
  280. package/dist/transport/documents.js +34 -0
  281. package/dist/transport/documents.js.map +1 -0
  282. package/dist/transport/index.d.ts +8 -0
  283. package/dist/transport/index.d.ts.map +1 -0
  284. package/dist/transport/index.js +8 -0
  285. package/dist/transport/index.js.map +1 -0
  286. package/dist/transport/probe.d.ts +44 -0
  287. package/dist/transport/probe.d.ts.map +1 -0
  288. package/dist/transport/probe.js +121 -0
  289. package/dist/transport/probe.js.map +1 -0
  290. package/dist/transport/rendezvous.d.ts +116 -0
  291. package/dist/transport/rendezvous.d.ts.map +1 -0
  292. package/dist/transport/rendezvous.js +139 -0
  293. package/dist/transport/rendezvous.js.map +1 -0
  294. package/dist/transport/rest.d.ts +35 -0
  295. package/dist/transport/rest.d.ts.map +1 -0
  296. package/dist/transport/rest.js +58 -0
  297. package/dist/transport/rest.js.map +1 -0
  298. package/dist/transport/syncClient.d.ts +14 -0
  299. package/dist/transport/syncClient.d.ts.map +1 -0
  300. package/dist/transport/syncClient.js +30 -0
  301. package/dist/transport/syncClient.js.map +1 -0
  302. package/dist/transport/urls.d.ts +35 -0
  303. package/dist/transport/urls.d.ts.map +1 -0
  304. package/dist/transport/urls.js +126 -0
  305. package/dist/transport/urls.js.map +1 -0
  306. package/package.json +55 -0
@@ -0,0 +1,186 @@
1
+ import { seal, unseal } from '@drakkar.software/starfish-keyring';
2
+ import { ConflictError } from '@drakkar.software/starfish-client';
3
+ import { createRendezvousClient, pullRendezvousDoc, pushRendezvousDoc, clearRendezvousDoc, joinSessionPath, } from '../../transport/rendezvous.js';
4
+ import { pollDelay } from '../../protocol/poll.js';
5
+ import { abortableSleep } from './pairingRequest.js';
6
+ import { OctoBotConnectionError, OctoBotConflictError, rethrowAsOctoBotError } from '../core/errors.js';
7
+ import { readMirrorCollections, parseMirrorGrantBundle, } from './mirrorReader.js';
8
+ /**
9
+ * Website↔phone exchange for the read-only-device grant this package mints
10
+ * against the space-mirror (see `mirrorGrant.ts`). This replaced an older
11
+ * sealed data-snapshot exchange, which has since been deleted.
12
+ *
13
+ * Request and grant now share ONE rendezvous address, `joinSessionPath(code)`
14
+ * (the `joinsessions` collection — see `transport/rendezvous.ts`), not two
15
+ * separate collections. `startPairingRequest`/`fetchPairingRequestByCode`
16
+ * publish/read the "request" phase there; this file's `publishPairingGrant`
17
+ * OVERWRITES that same doc with the "grant" phase once the phone approves.
18
+ * The sealing mechanism itself is unchanged (`starfish-keyring`'s
19
+ * `seal`/`unseal`, sealed to the website's ephemeral KEM key, signed by the
20
+ * wallet's own root key) — what's new is the OUTER wire envelope
21
+ * (`v`/`kind`/`sealed`, see `JoinSessionGrantDoc` below) wrapping the sealed
22
+ * blob, so a poller can tell "still just a request" from "a grant has been
23
+ * published" by reading one unsealed field, without attempting `unseal()`
24
+ * on a doc that might not even be sealed yet.
25
+ */
26
+ const GRANT_ENVELOPE_KIND = 'octobot-pairing-grant';
27
+ const GRANT_ENVELOPE_VERSION = 1;
28
+ /** Phone side, step 2: seal and publish the minted grant to the request's
29
+ * `code` slot — this OVERWRITES the request doc still published there,
30
+ * since request and grant now share one address.
31
+ *
32
+ * `rendezvous` is the caller's OWN trusted server config — the same one it
33
+ * used to look up `request` via `fetchPairingRequestByCode` — never
34
+ * `request.rendezvous`. That field rides inside a document anyone can
35
+ * publish to the public `joinsessions` collection, so trusting it here
36
+ * would let a malicious "website" party point this phone's outbound POST at
37
+ * an arbitrary host of its choosing.
38
+ *
39
+ * `baseHash` MUST be the `hash` `fetchPairingRequestByCode` returned
40
+ * alongside `request` — this is what makes "claim this specific, exact
41
+ * request" atomic: the push only succeeds if the slot still holds exactly
42
+ * the request doc this caller read, so a request that was swapped or
43
+ * already claimed by someone else between the read and this write is
44
+ * detected as a conflict rather than silently overwritten. There is no
45
+ * longer a meaningful "first publish, baseHash: null" case the way the
46
+ * retired sessionId-keyed design had one — the slot is never empty by the
47
+ * time a caller reaches this function, it already holds the request. A
48
+ * caller legitimately RE-publishing later (a refresh) must pass back the
49
+ * hash THIS function returned from its own previous call. Returns the
50
+ * resulting hash for exactly that purpose. */
51
+ export async function publishPairingGrant(opts) {
52
+ const client = createRendezvousClient({
53
+ baseUrl: opts.rendezvous.baseUrl,
54
+ namespace: opts.rendezvous.namespace,
55
+ fetch: opts.fetch,
56
+ timeoutMs: opts.timeoutMs,
57
+ });
58
+ try {
59
+ const envelope = {
60
+ v: GRANT_ENVELOPE_VERSION,
61
+ kind: GRANT_ENVELOPE_KIND,
62
+ bundle: opts.grant.bundle,
63
+ };
64
+ const plaintext = new TextEncoder().encode(JSON.stringify(envelope));
65
+ const sealed = await seal(plaintext, opts.request.devKemPub, opts.sealer, opts.request.code);
66
+ const doc = { v: GRANT_ENVELOPE_VERSION, kind: GRANT_ENVELOPE_KIND, sealed };
67
+ return await pushRendezvousDoc(client, joinSessionPath(opts.request.code), doc, opts.baseHash);
68
+ }
69
+ catch (err) {
70
+ if (err instanceof ConflictError) {
71
+ throw new OctoBotConflictError(err.currentHash || null, err, 'pairing request slot was modified since it was read — this pairing may be compromised, or someone else already claimed it');
72
+ }
73
+ rethrowAsOctoBotError(err);
74
+ }
75
+ }
76
+ /** Phone side: stop publishing and clear the current slot — since request
77
+ * and grant share one address, this clears BOTH together (there is no way
78
+ * to clear one but keep the other). It stops future reads but cannot
79
+ * recall a grant a website already fetched — with this design, "cannot
80
+ * recall" is narrow: the grant itself only proves space membership, and
81
+ * `removeSpaceMember`-based revocation (real, immediate, checked live on
82
+ * every request) is the actual unpair mechanism a caller should use
83
+ * ALONGSIDE this, not instead of it — this only stops the CODE from
84
+ * resolving to a usable grant again, it does not by itself revoke a grant
85
+ * already handed out. */
86
+ export async function clearPairingGrant(opts) {
87
+ const client = createRendezvousClient({
88
+ baseUrl: opts.rendezvous.baseUrl,
89
+ namespace: opts.rendezvous.namespace,
90
+ fetch: opts.fetch,
91
+ timeoutMs: opts.timeoutMs,
92
+ });
93
+ try {
94
+ return await clearRendezvousDoc(client, joinSessionPath(opts.request.code));
95
+ }
96
+ catch (err) {
97
+ rethrowAsOctoBotError(err);
98
+ }
99
+ }
100
+ /** Website side: read whatever is currently published at this session's
101
+ * slot. Three outcomes:
102
+ * - nothing published (wrong/expired code) → `null`, "keep waiting".
103
+ * - still `kind: 'octobot-pairing-request'` (the phone hasn't approved
104
+ * yet) → also `null`, "keep waiting" — this is the normal, expected
105
+ * state for most of the polling loop's life, NOT an error.
106
+ * - `kind: 'octobot-pairing-grant'` → unseal it and immediately do a live
107
+ * read of every mirror collection it covers.
108
+ * Anything else (an unrecognized `kind`, or a `kind: 'octobot-pairing-grant'`
109
+ * doc whose `sealed` field isn't actually a sealed blob) throws — that's a
110
+ * genuine malformed-document case, not a wait state. */
111
+ export async function fetchPairingGrant(session, opts = {}) {
112
+ const client = createRendezvousClient({
113
+ baseUrl: session.rendezvous.baseUrl,
114
+ namespace: session.rendezvous.namespace,
115
+ fetch: opts.fetch,
116
+ timeoutMs: opts.timeoutMs,
117
+ });
118
+ const doc = await pullRendezvousDoc(client, joinSessionPath(session.code));
119
+ if (!doc)
120
+ return null;
121
+ const data = doc.data;
122
+ if (data.kind === 'octobot-pairing-request')
123
+ return null;
124
+ if (data.v !== GRANT_ENVELOPE_VERSION || data.kind !== GRANT_ENVELOPE_KIND) {
125
+ throw new Error('pairing grant: unrecognized document at this code\'s slot');
126
+ }
127
+ if (typeof data.sealed !== 'object' || data.sealed === null || typeof data.sealed.entry !== 'object' || data.sealed.entry === null) {
128
+ throw new Error('pairing grant: malformed sealed blob at this code\'s slot');
129
+ }
130
+ const sealed = data.sealed;
131
+ const plaintext = await unseal(sealed, session.device.kemPriv, {
132
+ aad: session.code,
133
+ ...(opts.expectedSealer !== undefined ? { requireSealer: opts.expectedSealer } : {}),
134
+ });
135
+ const envelopeRaw = JSON.parse(new TextDecoder().decode(plaintext));
136
+ if (typeof envelopeRaw !== 'object' || envelopeRaw === null
137
+ || envelopeRaw.v !== GRANT_ENVELOPE_VERSION
138
+ || envelopeRaw.kind !== GRANT_ENVELOPE_KIND
139
+ || typeof envelopeRaw.bundle !== 'string') {
140
+ throw new Error('pairing grant: malformed grant envelope');
141
+ }
142
+ const { spaceId, nodes } = parseMirrorGrantBundle(envelopeRaw.bundle);
143
+ const sealedBy = sealed.entry.addedBy;
144
+ const collections = await readMirrorCollections({
145
+ rendezvous: session.rendezvous,
146
+ spaceId,
147
+ nodes,
148
+ devEdPrivHex: session.device.edPriv,
149
+ devKemPrivHex: session.device.kemPriv,
150
+ fetch: opts.fetch,
151
+ timeoutMs: opts.timeoutMs,
152
+ });
153
+ return { spaceId, collections, sealedBy, nodes };
154
+ }
155
+ /** Website side: poll until the phone's FIRST approval publishes a grant,
156
+ * or `timeoutMs` elapses. This is the initial-approval wait, not an ongoing
157
+ * refresh loop — for later refreshes call `readMirrorCollections` directly.
158
+ *
159
+ * A `fetchPairingGrant` failure (a network blip, a transient server error)
160
+ * does NOT end the wait — it's swallowed and retried on the next tick, same
161
+ * as `fetchPairingGrant` returning `null` for "nothing published yet". Only
162
+ * reaching `deadline` ends it: with the last error if there was one (more
163
+ * informative than a bare timeout), else the generic timeout. */
164
+ export async function awaitPairingGrant(session, opts = {}) {
165
+ const deadline = Date.now() + (opts.timeoutMs ?? 5 * 60 * 1000);
166
+ let lastErr;
167
+ for (let attempt = 0;; attempt++) {
168
+ if (opts.signal?.aborted)
169
+ throw new DOMException('aborted', 'AbortError');
170
+ try {
171
+ const result = await fetchPairingGrant(session, { fetch: opts.fetch });
172
+ if (result)
173
+ return result;
174
+ }
175
+ catch (err) {
176
+ lastErr = err;
177
+ }
178
+ if (Date.now() >= deadline) {
179
+ if (lastErr)
180
+ rethrowAsOctoBotError(lastErr);
181
+ throw new OctoBotConnectionError('timeout', 'timed out waiting for the pairing to be approved');
182
+ }
183
+ await abortableSleep(pollDelay(attempt), opts.signal);
184
+ }
185
+ }
186
+ //# sourceMappingURL=pairingGrantExchange.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pairingGrantExchange.js","sourceRoot":"","sources":["../../../src/client/pairing/pairingGrantExchange.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,82 @@
1
+ import type { GeneratedDeviceKeys } from '@drakkar.software/starfish-identities';
2
+ import { type PairingRequestPayload } from '../../identity/pairingRequest.js';
3
+ import type { NodeCollectionKey } from '../../collections/nodeCollections.js';
4
+ export type StartPairingRequestOptions = {
5
+ origin: string;
6
+ rendezvous: {
7
+ baseUrl: string;
8
+ namespace: string;
9
+ };
10
+ label?: string;
11
+ requestedCollections?: NodeCollectionKey[];
12
+ ttlSec?: number;
13
+ /** See `PairingRequestPayload.requesterKind`. Defaults to `'website'`. */
14
+ requesterKind?: 'website' | 'device';
15
+ fetch?: typeof fetch;
16
+ timeoutMs?: number;
17
+ };
18
+ /** A website's own end of a device-code pairing: its request record plus
19
+ * everything needed to publish it and later unseal the phone's response.
20
+ * `code` is what the site displays for the user to type into their OctoBot
21
+ * app — this package never renders it, just returns the string. Carries its
22
+ * own `rendezvous` (the same value passed to `startPairingRequest`) so
23
+ * `awaitPairingGrant`/`fetchPairingGrant` can take the session directly,
24
+ * with no re-spreading required at the call site. */
25
+ export interface PairingRequestSession {
26
+ request: PairingRequestPayload;
27
+ device: GeneratedDeviceKeys;
28
+ code: string;
29
+ rendezvous: {
30
+ baseUrl: string;
31
+ namespace: string;
32
+ };
33
+ /** Publish (or re-publish) the request record to the rendezvous. */
34
+ publish(): Promise<void>;
35
+ }
36
+ /**
37
+ * Website side, step 1: create and publish a pairing request.
38
+ *
39
+ * ```ts
40
+ * const rendezvous = { baseUrl: 'https://sync.drakkar.software/sync', namespace: 'dk' }
41
+ * const session = await startPairingRequest({ origin: 'https://myapp.example', rendezvous })
42
+ * await session.publish()
43
+ * showCodeToUser(session.code)
44
+ * const grant = await awaitPairingGrant(session)
45
+ * ```
46
+ */
47
+ export declare function startPairingRequest(opts: StartPairingRequestOptions): Promise<PairingRequestSession>;
48
+ /** The result of a request lookup: the parsed request plus the pulled
49
+ * document's `hash`. The hash matters — it's what the phone must pass as
50
+ * `baseHash` when it later mints and publishes a grant, so that write is a
51
+ * compare-and-swap against the EXACT request doc it read, not a blind
52
+ * overwrite. See `client/pairing/pairingGrantExchange.ts`'s
53
+ * `publishPairingGrant`. */
54
+ export interface PairingRequestLookup {
55
+ request: PairingRequestPayload;
56
+ hash: string;
57
+ }
58
+ /** Phone side, step 1: look up a request by the code the user typed. Returns
59
+ * `null` only when nothing is published under that code at all (wrong code,
60
+ * or the rendezvous slot's own TTL already reclaimed it). A request that IS
61
+ * still present but past its own `expiresAt` does NOT return `null` — it
62
+ * throws (via `parsePairingRequest`), so the caller can tell "wrong code"
63
+ * apart from "right code, but it expired" and say so accurately. If the
64
+ * slot has ALREADY moved past the request phase (a grant is published
65
+ * there — `kind === 'octobot-pairing-grant'`, detectable without unsealing
66
+ * anything, see `pairingGrantExchange.ts`), this throws a distinct
67
+ * `OctoBotConflictError` rather than a generic parse failure, so a caller
68
+ * re-checking an already-approved code gets an accurate "already used"
69
+ * signal instead of "malformed pairing request payload". */
70
+ export declare function fetchPairingRequestByCode(opts: {
71
+ code: string;
72
+ rendezvous: {
73
+ baseUrl: string;
74
+ namespace: string;
75
+ };
76
+ fetch?: typeof fetch;
77
+ timeoutMs?: number;
78
+ }): Promise<PairingRequestLookup | null>;
79
+ /** Shared by `pairingGrantExchange.ts`'s polling loops — keep the
80
+ * abort/timeout/cleanup semantics in exactly one place. */
81
+ export declare function abortableSleep(ms: number, signal?: AbortSignal): Promise<void>;
82
+ //# sourceMappingURL=pairingRequest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pairingRequest.d.ts","sourceRoot":"","sources":["../../../src/client/pairing/pairingRequest.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,uCAAuC,CAAA;AAChF,OAAO,EAGL,KAAK,qBAAqB,EAC3B,MAAM,kCAAkC,CAAA;AAQzC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,sCAAsC,CAAA;AAE7E,MAAM,MAAM,0BAA0B,GAAG;IACvC,MAAM,EAAE,MAAM,CAAA;IACd,UAAU,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAA;IAClD,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,oBAAoB,CAAC,EAAE,iBAAiB,EAAE,CAAA;IAC1C,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,0EAA0E;IAC1E,aAAa,CAAC,EAAE,SAAS,GAAG,QAAQ,CAAA;IACpC,KAAK,CAAC,EAAE,OAAO,KAAK,CAAA;IACpB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,CAAA;AAED;;;;;;sDAMsD;AACtD,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,qBAAqB,CAAA;IAC9B,MAAM,EAAE,mBAAmB,CAAA;IAC3B,IAAI,EAAE,MAAM,CAAA;IACZ,UAAU,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAA;IAClD,oEAAoE;IACpE,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;CACzB;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,mBAAmB,CAAC,IAAI,EAAE,0BAA0B,GAAG,OAAO,CAAC,qBAAqB,CAAC,CA2D1G;AAED;;;;;6BAK6B;AAC7B,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,qBAAqB,CAAA;IAC9B,IAAI,EAAE,MAAM,CAAA;CACb;AAED;;;;;;;;;;;6DAW6D;AAC7D,wBAAsB,yBAAyB,CAAC,IAAI,EAAE;IACpD,IAAI,EAAE,MAAM,CAAA;IACZ,UAAU,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAA;IAClD,KAAK,CAAC,EAAE,OAAO,KAAK,CAAA;IACpB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,GAAG,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC,CAmBvC;AAED;4DAC4D;AAC5D,wBAAgB,cAAc,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAS9E"}
@@ -0,0 +1,120 @@
1
+ import { ConflictError } from '@drakkar.software/starfish-client';
2
+ import { createPairingRequest, parsePairingRequest, } from '../../identity/pairingRequest.js';
3
+ import { createRendezvousClient, pullRendezvousDoc, pushRendezvousDoc, joinSessionPath, } from '../../transport/rendezvous.js';
4
+ import { OctoBotConflictError, rethrowAsOctoBotError } from '../core/errors.js';
5
+ /**
6
+ * Website side, step 1: create and publish a pairing request.
7
+ *
8
+ * ```ts
9
+ * const rendezvous = { baseUrl: 'https://sync.drakkar.software/sync', namespace: 'dk' }
10
+ * const session = await startPairingRequest({ origin: 'https://myapp.example', rendezvous })
11
+ * await session.publish()
12
+ * showCodeToUser(session.code)
13
+ * const grant = await awaitPairingGrant(session)
14
+ * ```
15
+ */
16
+ export async function startPairingRequest(opts) {
17
+ const { request, device, code } = await createPairingRequest(opts);
18
+ const client = createRendezvousClient({
19
+ baseUrl: opts.rendezvous.baseUrl,
20
+ namespace: opts.rendezvous.namespace,
21
+ fetch: opts.fetch,
22
+ timeoutMs: opts.timeoutMs,
23
+ });
24
+ // This session's own remembered hash from its last successful publish —
25
+ // starts null (a fresh code has nothing published under it yet, so the
26
+ // FIRST publish() is create-only: it fails rather than silently adopting
27
+ // whatever's already occupying the slot). Every later publish() call uses
28
+ // its own remembered hash instead of re-pulling and trusting whatever the
29
+ // server currently reports, so a hostile overwrite between two publish()
30
+ // calls surfaces as a loud conflict instead of silently becoming this
31
+ // session's new baseline.
32
+ let lastHash = null;
33
+ // Serializes overlapping publish() calls on the SAME session — without
34
+ // this, two calls in flight at once both read the same lastHash before
35
+ // either awaits, so the one the server processes second gets a real
36
+ // ConflictError caused only by this session's own overlapping write, not
37
+ // third-party tampering, yet (post-own-write-CAS) it hits the exact same
38
+ // "treat this code as compromised" error a genuine hijack would.
39
+ let queue = Promise.resolve();
40
+ async function doPublish() {
41
+ try {
42
+ const result = await pushRendezvousDoc(client, joinSessionPath(code), request, lastHash);
43
+ lastHash = result.hash;
44
+ }
45
+ catch (err) {
46
+ if (err instanceof ConflictError) {
47
+ // Thrown as OctoBotConflictError directly (not wrapped in a plain
48
+ // Error then run through rethrowAsOctoBotError) so `code === 'conflict'`
49
+ // and `instanceof OctoBotConflictError` survive — the documented
50
+ // "switch on code" convention callers rely on to distinguish a
51
+ // tampered slot from a generic unreachable-node failure.
52
+ throw new OctoBotConflictError(err.currentHash || null, err, 'pairing request was modified by another party — treat this code as compromised');
53
+ }
54
+ rethrowAsOctoBotError(err);
55
+ }
56
+ }
57
+ return {
58
+ request,
59
+ device,
60
+ code,
61
+ rendezvous: opts.rendezvous,
62
+ publish() {
63
+ const run = queue.then(() => doPublish());
64
+ // Swallow so a failed publish() doesn't permanently wedge the queue
65
+ // for the NEXT caller's publish() — each call still observes its own
66
+ // rejection via the returned promise.
67
+ queue = run.catch(() => { });
68
+ return run;
69
+ },
70
+ };
71
+ }
72
+ /** Phone side, step 1: look up a request by the code the user typed. Returns
73
+ * `null` only when nothing is published under that code at all (wrong code,
74
+ * or the rendezvous slot's own TTL already reclaimed it). A request that IS
75
+ * still present but past its own `expiresAt` does NOT return `null` — it
76
+ * throws (via `parsePairingRequest`), so the caller can tell "wrong code"
77
+ * apart from "right code, but it expired" and say so accurately. If the
78
+ * slot has ALREADY moved past the request phase (a grant is published
79
+ * there — `kind === 'octobot-pairing-grant'`, detectable without unsealing
80
+ * anything, see `pairingGrantExchange.ts`), this throws a distinct
81
+ * `OctoBotConflictError` rather than a generic parse failure, so a caller
82
+ * re-checking an already-approved code gets an accurate "already used"
83
+ * signal instead of "malformed pairing request payload". */
84
+ export async function fetchPairingRequestByCode(opts) {
85
+ const client = createRendezvousClient({
86
+ baseUrl: opts.rendezvous.baseUrl,
87
+ namespace: opts.rendezvous.namespace,
88
+ fetch: opts.fetch,
89
+ timeoutMs: opts.timeoutMs,
90
+ });
91
+ try {
92
+ const doc = await pullRendezvousDoc(client, joinSessionPath(opts.code));
93
+ if (!doc)
94
+ return null;
95
+ if (doc.data.kind === 'octobot-pairing-grant') {
96
+ throw new OctoBotConflictError(doc.hash, undefined, 'this code has already been used to complete a pairing');
97
+ }
98
+ const request = parsePairingRequest(JSON.stringify(doc.data), opts.code);
99
+ return { request, hash: doc.hash };
100
+ }
101
+ catch (err) {
102
+ if (err instanceof OctoBotConflictError)
103
+ throw err;
104
+ rethrowAsOctoBotError(err);
105
+ }
106
+ }
107
+ /** Shared by `pairingGrantExchange.ts`'s polling loops — keep the
108
+ * abort/timeout/cleanup semantics in exactly one place. */
109
+ export function abortableSleep(ms, signal) {
110
+ return new Promise((resolve, reject) => {
111
+ if (signal?.aborted)
112
+ return reject(new DOMException('aborted', 'AbortError'));
113
+ const timer = setTimeout(resolve, ms);
114
+ signal?.addEventListener('abort', () => {
115
+ clearTimeout(timer);
116
+ reject(new DOMException('aborted', 'AbortError'));
117
+ });
118
+ });
119
+ }
120
+ //# sourceMappingURL=pairingRequest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pairingRequest.js","sourceRoot":"","sources":["../../../src/client/pairing/pairingRequest.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ import type { Strategy as ProtocolStrategy } from '@drakkar.software/octobot-protocol';
2
+ import { type BuildStrategyOptions, type StrategyInput, type MmInput, type GridInput, type DcaInput, type IndexInput, type CopyInput, type SignalInput, type StrategyInputPatch } from '../protocol/strategy/index.js';
3
+ /** Pure, synchronous(-ish — everything here is actually sync, `Promise`-free),
4
+ * zero-I/O strategy builders. Needs no connection: build a strategy, then
5
+ * pass it to `client.automations.create()` or `client.strategies.create()`. */
6
+ export interface StrategyBuilders {
7
+ dca(input: DcaInput, opts?: BuildStrategyOptions): ProtocolStrategy;
8
+ grid(input: GridInput, opts?: BuildStrategyOptions): ProtocolStrategy;
9
+ index(input: IndexInput, opts?: BuildStrategyOptions): ProtocolStrategy;
10
+ marketMaking(input: MmInput, opts?: BuildStrategyOptions): ProtocolStrategy;
11
+ copy(input: CopyInput, opts?: BuildStrategyOptions): ProtocolStrategy;
12
+ signal(input: SignalInput, opts?: BuildStrategyOptions): ProtocolStrategy;
13
+ genericProcess(opts?: BuildStrategyOptions): ProtocolStrategy;
14
+ /** The discriminated-union entry point (`{ kind: 'dca', dca: {...} }`),
15
+ * for callers that already have a `StrategyInput` rather than picking a
16
+ * kind-specific method. */
17
+ build(input: StrategyInput, opts?: BuildStrategyOptions): ProtocolStrategy;
18
+ /** Recover an editable input from a strategy the node returned — the
19
+ * inverse of every builder above. Feed the result's fields into a new
20
+ * `strategy.dca(...)`/etc call (with `bumpVersion` applied) to edit it. */
21
+ toInput(existing: ProtocolStrategy): StrategyInputPatch;
22
+ /** Bump a `MAJOR.MINOR.PATCH` version string's patch component by one. */
23
+ bumpVersion(version: string): string;
24
+ }
25
+ /** Needs no `ClientSession` — unlike every other `create*Api` in
26
+ * `client/adapters/`, these builders do no I/O and touch no connection,
27
+ * so there is nothing to construct them from. Kept as a factory anyway, for
28
+ * the same reason those are: `strategy` below is just `createStrategyBuilders()`
29
+ * called once, so the object literal isn't duplicated between this module's
30
+ * own export and a hypothetical future caller that wants its own instance. */
31
+ export declare function createStrategyBuilders(): StrategyBuilders;
32
+ /** The public entry point every caller uses — `strategy.dca(...)`, etc. A
33
+ * single shared instance, since these builders carry no state and creating
34
+ * a fresh one per call would be pointless. */
35
+ export declare const strategy: StrategyBuilders;
36
+ //# sourceMappingURL=strategy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"strategy.d.ts","sourceRoot":"","sources":["../../src/client/strategy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,IAAI,gBAAgB,EAAE,MAAM,oCAAoC,CAAA;AACtF,OAAO,EAEL,KAAK,oBAAoB,EACzB,KAAK,aAAa,EAClB,KAAK,OAAO,EACZ,KAAK,SAAS,EACd,KAAK,QAAQ,EACb,KAAK,UAAU,EACf,KAAK,SAAS,EACd,KAAK,WAAW,EAGhB,KAAK,kBAAkB,EACxB,MAAM,+BAA+B,CAAA;AAEtC;;gFAEgF;AAChF,MAAM,WAAW,gBAAgB;IAC/B,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAE,IAAI,CAAC,EAAE,oBAAoB,GAAG,gBAAgB,CAAA;IACnE,IAAI,CAAC,KAAK,EAAE,SAAS,EAAE,IAAI,CAAC,EAAE,oBAAoB,GAAG,gBAAgB,CAAA;IACrE,KAAK,CAAC,KAAK,EAAE,UAAU,EAAE,IAAI,CAAC,EAAE,oBAAoB,GAAG,gBAAgB,CAAA;IACvE,YAAY,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,oBAAoB,GAAG,gBAAgB,CAAA;IAC3E,IAAI,CAAC,KAAK,EAAE,SAAS,EAAE,IAAI,CAAC,EAAE,oBAAoB,GAAG,gBAAgB,CAAA;IACrE,MAAM,CAAC,KAAK,EAAE,WAAW,EAAE,IAAI,CAAC,EAAE,oBAAoB,GAAG,gBAAgB,CAAA;IACzE,cAAc,CAAC,IAAI,CAAC,EAAE,oBAAoB,GAAG,gBAAgB,CAAA;IAC7D;;gCAE4B;IAC5B,KAAK,CAAC,KAAK,EAAE,aAAa,EAAE,IAAI,CAAC,EAAE,oBAAoB,GAAG,gBAAgB,CAAA;IAC1E;;gFAE4E;IAC5E,OAAO,CAAC,QAAQ,EAAE,gBAAgB,GAAG,kBAAkB,CAAA;IACvD,0EAA0E;IAC1E,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAA;CACrC;AAED;;;;;+EAK+E;AAC/E,wBAAgB,sBAAsB,IAAI,gBAAgB,CAazD;AAED;;+CAE+C;AAC/C,eAAO,MAAM,QAAQ,EAAE,gBAA2C,CAAA"}
@@ -0,0 +1,26 @@
1
+ import { buildStrategy, protocolStrategyToInput, bumpStrategyPatchVersion, } from '../protocol/strategy/index.js';
2
+ /** Needs no `ClientSession` — unlike every other `create*Api` in
3
+ * `client/adapters/`, these builders do no I/O and touch no connection,
4
+ * so there is nothing to construct them from. Kept as a factory anyway, for
5
+ * the same reason those are: `strategy` below is just `createStrategyBuilders()`
6
+ * called once, so the object literal isn't duplicated between this module's
7
+ * own export and a hypothetical future caller that wants its own instance. */
8
+ export function createStrategyBuilders() {
9
+ return {
10
+ dca: (input, opts) => buildStrategy({ kind: 'dca', dca: input }, opts),
11
+ grid: (input, opts) => buildStrategy({ kind: 'grid', grid: input }, opts),
12
+ index: (input, opts) => buildStrategy({ kind: 'basket', basket: input }, opts),
13
+ marketMaking: (input, opts) => buildStrategy({ kind: 'mm', mm: input }, opts),
14
+ copy: (input, opts) => buildStrategy({ kind: 'copy', copy: input }, opts),
15
+ signal: (input, opts) => buildStrategy({ kind: 'signal', signal: input }, opts),
16
+ genericProcess: (opts) => buildStrategy({ kind: 'custom' }, opts),
17
+ build: (input, opts) => buildStrategy(input, opts),
18
+ toInput: (existing) => protocolStrategyToInput(existing),
19
+ bumpVersion: (version) => bumpStrategyPatchVersion(version),
20
+ };
21
+ }
22
+ /** The public entry point every caller uses — `strategy.dca(...)`, etc. A
23
+ * single shared instance, since these builders carry no state and creating
24
+ * a fresh one per call would be pointless. */
25
+ export const strategy = createStrategyBuilders();
26
+ //# sourceMappingURL=strategy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"strategy.js","sourceRoot":"","sources":["../../src/client/strategy.ts"],"names":[],"mappings":"AACA,OAAO,EACL,aAAa,EASb,uBAAuB,EACvB,wBAAwB,GAEzB,MAAM,+BAA+B,CAAA;AAyBtC;;;;;+EAK+E;AAC/E,MAAM,UAAU,sBAAsB;IACpC,OAAO;QACL,GAAG,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,aAAa,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE,IAAI,CAAC;QACtE,IAAI,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,aAAa,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,IAAI,CAAC;QACzE,KAAK,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,aAAa,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,IAAI,CAAC;QAC9E,YAAY,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,aAAa,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,IAAI,CAAC;QAC7E,IAAI,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,aAAa,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,IAAI,CAAC;QACzE,MAAM,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,aAAa,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,IAAI,CAAC;QAC/E,cAAc,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,aAAa,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,IAAI,CAAC;QACjE,KAAK,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,aAAa,CAAC,KAAK,EAAE,IAAI,CAAC;QAClD,OAAO,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,uBAAuB,CAAC,QAAQ,CAAC;QACxD,WAAW,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,wBAAwB,CAAC,OAAO,CAAC;KAC5D,CAAA;AACH,CAAC;AAED;;+CAE+C;AAC/C,MAAM,CAAC,MAAM,QAAQ,GAAqB,sBAAsB,EAAE,CAAA"}
@@ -0,0 +1,3 @@
1
+ export { resolveStoragePath, pullPath, pushPath } from './paths.js';
2
+ export { NODE_COLLECTIONS, type NodeCollectionInfo, type NodeCollectionKey } from './nodeCollections.js';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/collections/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AACnE,OAAO,EAAE,gBAAgB,EAAE,KAAK,kBAAkB,EAAE,KAAK,iBAAiB,EAAE,MAAM,sBAAsB,CAAA"}
@@ -0,0 +1,3 @@
1
+ export { resolveStoragePath, pullPath, pushPath } from './paths.js';
2
+ export { NODE_COLLECTIONS } from './nodeCollections.js';
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/collections/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AACnE,OAAO,EAAE,gBAAgB,EAAmD,MAAM,sBAAsB,CAAA"}
@@ -0,0 +1,57 @@
1
+ /** The collections a self-hosted OctoBot node actually serves under
2
+ * `users/{identity}/...`. Each `encryptionInfo` is the HKDF `info` string the
3
+ * node derives its per-collection key from — it MUST equal
4
+ * `'octobot-sync-' + <node's own Collections enum value>`.
5
+ * @see packages/sync/octobot_sync/enums.py — Collections
6
+ * @see packages/sync/octobot_sync/crypto.py */
7
+ export type NodeCollectionInfo = {
8
+ name: string;
9
+ storagePath: string;
10
+ encryptionInfo: string;
11
+ /** Node never accepts a push for this collection — pull only. */
12
+ pullOnly?: boolean;
13
+ /** Append-only, push-only: each push publishes ONE queue element the node
14
+ * consumes and executes. Re-sending an element is re-executing it. */
15
+ appendOnly?: boolean;
16
+ };
17
+ export declare const NODE_COLLECTIONS: {
18
+ /** Bundles the node-computed `automations`/`user_actions` fields alongside
19
+ * whatever else a higher-level client stores in the same document. */
20
+ readonly userData: {
21
+ readonly name: "user-data";
22
+ readonly storagePath: "users/{identity}/data";
23
+ readonly encryptionInfo: "octobot-sync-user-data";
24
+ };
25
+ readonly accounts: {
26
+ readonly name: "accounts";
27
+ readonly storagePath: "users/{identity}/accounts";
28
+ readonly encryptionInfo: "octobot-sync-user-accounts";
29
+ };
30
+ /** The node stores this encrypted and opaque — it never reads a field. */
31
+ readonly settings: {
32
+ readonly name: "settings";
33
+ readonly storagePath: "users/{identity}/settings";
34
+ readonly encryptionInfo: "octobot-sync-user-settings";
35
+ };
36
+ readonly strategies: {
37
+ readonly name: "strategies";
38
+ readonly storagePath: "users/{identity}/strategies";
39
+ readonly encryptionInfo: "octobot-sync-user-strategies";
40
+ };
41
+ readonly actions: {
42
+ readonly name: "actions";
43
+ readonly storagePath: "users/{identity}/actions";
44
+ readonly encryptionInfo: "octobot-sync-user-actions";
45
+ readonly appendOnly: true;
46
+ };
47
+ /** One document per exchange account — fan out over `{accountId}` yourself;
48
+ * there is no single "list all trading docs" pull. */
49
+ readonly accountTrading: {
50
+ readonly name: "user-accounts-trading";
51
+ readonly storagePath: "users/{identity}/accounts/{accountId}/trading";
52
+ readonly encryptionInfo: "octobot-sync-user-accounts-trading";
53
+ readonly pullOnly: true;
54
+ };
55
+ };
56
+ export type NodeCollectionKey = keyof typeof NODE_COLLECTIONS;
57
+ //# sourceMappingURL=nodeCollections.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nodeCollections.d.ts","sourceRoot":"","sources":["../../src/collections/nodeCollections.ts"],"names":[],"mappings":"AAAA;;;;;gDAKgD;AAChD,MAAM,MAAM,kBAAkB,GAAG;IAC/B,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;IACnB,cAAc,EAAE,MAAM,CAAA;IACtB,iEAAiE;IACjE,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB;2EACuE;IACvE,UAAU,CAAC,EAAE,OAAO,CAAA;CACrB,CAAA;AAED,eAAO,MAAM,gBAAgB;IAC3B;2EACuE;;;;;;;;;;;IAWvE,0EAA0E;;;;;;;;;;;;;;;;;IAiB1E;2DACuD;;;;;;;CAOF,CAAA;AAEvD,MAAM,MAAM,iBAAiB,GAAG,MAAM,OAAO,gBAAgB,CAAA"}
@@ -0,0 +1,40 @@
1
+ export const NODE_COLLECTIONS = {
2
+ /** Bundles the node-computed `automations`/`user_actions` fields alongside
3
+ * whatever else a higher-level client stores in the same document. */
4
+ userData: {
5
+ name: 'user-data',
6
+ storagePath: 'users/{identity}/data',
7
+ encryptionInfo: 'octobot-sync-user-data',
8
+ },
9
+ accounts: {
10
+ name: 'accounts',
11
+ storagePath: 'users/{identity}/accounts',
12
+ encryptionInfo: 'octobot-sync-user-accounts',
13
+ },
14
+ /** The node stores this encrypted and opaque — it never reads a field. */
15
+ settings: {
16
+ name: 'settings',
17
+ storagePath: 'users/{identity}/settings',
18
+ encryptionInfo: 'octobot-sync-user-settings',
19
+ },
20
+ strategies: {
21
+ name: 'strategies',
22
+ storagePath: 'users/{identity}/strategies',
23
+ encryptionInfo: 'octobot-sync-user-strategies',
24
+ },
25
+ actions: {
26
+ name: 'actions',
27
+ storagePath: 'users/{identity}/actions',
28
+ encryptionInfo: 'octobot-sync-user-actions',
29
+ appendOnly: true,
30
+ },
31
+ /** One document per exchange account — fan out over `{accountId}` yourself;
32
+ * there is no single "list all trading docs" pull. */
33
+ accountTrading: {
34
+ name: 'user-accounts-trading',
35
+ storagePath: 'users/{identity}/accounts/{accountId}/trading',
36
+ encryptionInfo: 'octobot-sync-user-accounts-trading',
37
+ pullOnly: true,
38
+ },
39
+ };
40
+ //# sourceMappingURL=nodeCollections.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nodeCollections.js","sourceRoot":"","sources":["../../src/collections/nodeCollections.ts"],"names":[],"mappings":"AAiBA,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B;2EACuE;IACvE,QAAQ,EAAE;QACR,IAAI,EAAE,WAAW;QACjB,WAAW,EAAE,uBAAuB;QACpC,cAAc,EAAE,wBAAwB;KACzC;IACD,QAAQ,EAAE;QACR,IAAI,EAAE,UAAU;QAChB,WAAW,EAAE,2BAA2B;QACxC,cAAc,EAAE,4BAA4B;KAC7C;IACD,0EAA0E;IAC1E,QAAQ,EAAE;QACR,IAAI,EAAE,UAAU;QAChB,WAAW,EAAE,2BAA2B;QACxC,cAAc,EAAE,4BAA4B;KAC7C;IACD,UAAU,EAAE;QACV,IAAI,EAAE,YAAY;QAClB,WAAW,EAAE,6BAA6B;QAC1C,cAAc,EAAE,8BAA8B;KAC/C;IACD,OAAO,EAAE;QACP,IAAI,EAAE,SAAS;QACf,WAAW,EAAE,0BAA0B;QACvC,cAAc,EAAE,2BAA2B;QAC3C,UAAU,EAAE,IAAI;KACjB;IACD;2DACuD;IACvD,cAAc,EAAE;QACd,IAAI,EAAE,uBAAuB;QAC7B,WAAW,EAAE,+CAA+C;QAC5D,cAAc,EAAE,oCAAoC;QACpD,QAAQ,EAAE,IAAI;KACf;CACoD,CAAA"}
@@ -0,0 +1,7 @@
1
+ /** Substitutes `{key}` placeholders in a storage-path template, e.g.
2
+ * `resolveStoragePath('users/{identity}/accounts', { identity: userId })`.
3
+ * Generic — carries no product knowledge of which collections exist. */
4
+ export declare function resolveStoragePath(storagePath: string, params: Record<string, string>): string;
5
+ export declare function pullPath(storagePath: string, params: Record<string, string>): string;
6
+ export declare function pushPath(storagePath: string, params: Record<string, string>): string;
7
+ //# sourceMappingURL=paths.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../src/collections/paths.ts"],"names":[],"mappings":"AAAA;;yEAEyE;AACzE,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAK9F;AAED,wBAAgB,QAAQ,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAEpF;AAED,wBAAgB,QAAQ,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAEpF"}
@@ -0,0 +1,13 @@
1
+ /** Substitutes `{key}` placeholders in a storage-path template, e.g.
2
+ * `resolveStoragePath('users/{identity}/accounts', { identity: userId })`.
3
+ * Generic — carries no product knowledge of which collections exist. */
4
+ export function resolveStoragePath(storagePath, params) {
5
+ return Object.entries(params).reduce((path, [key, value]) => path.replaceAll(`{${key}}`, encodeURIComponent(value)), storagePath);
6
+ }
7
+ export function pullPath(storagePath, params) {
8
+ return `/pull/${resolveStoragePath(storagePath, params)}`;
9
+ }
10
+ export function pushPath(storagePath, params) {
11
+ return `/push/${resolveStoragePath(storagePath, params)}`;
12
+ }
13
+ //# sourceMappingURL=paths.js.map