@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,50 @@
1
+ import { createSpaceMirrorChannel } from '@drakkar.software/starfish-replica/space';
2
+ import { mirrorDocPath, mirrorNodeTitleFor, mirrorTierFor, MIRROR_COLLECTIONS, MIRROR_SPACE_NAME, } from './collections.js';
3
+ /**
4
+ * One full cloud-mirror sync cycle: find-or-create the wallet's mirror space,
5
+ * plan what changed since last cycle, create any newly-enabled collections'
6
+ * nodes, write every currently-enabled collection's projection, and clear any
7
+ * collection the user just disabled.
8
+ *
9
+ * The space/node mechanics live in `starfish-replica/space`'s
10
+ * `createSpaceMirrorChannel` — this is a thin adapter wiring the
11
+ * `MIRROR_COLLECTIONS` registry and its tier routing into it.
12
+ *
13
+ * Callers (the node's writer, the mobile no-node writer) gate this behind the
14
+ * `cloudSyncEnabled` setting themselves; this function assumes it was only
15
+ * called because the setting is on.
16
+ */
17
+ export async function syncCloudMirror(options) {
18
+ const { session, enabledCollectionIds, readSourceCollection } = options;
19
+ const channel = createSpaceMirrorChannel({
20
+ name: 'octobot-cloud-mirror',
21
+ session,
22
+ // One space; `tier` is what separates the audiences within it. "shared"
23
+ // -> "isolated" (own per-node keyring, so a grant reaches exactly that
24
+ // node), "private" -> the space keyring, "public" -> world-readable
25
+ // plaintext.
26
+ collections: MIRROR_COLLECTIONS.map((c) => ({
27
+ id: c.id,
28
+ spaceName: MIRROR_SPACE_NAME,
29
+ tier: mirrorTierFor(c.id),
30
+ })),
31
+ enabledIds: () => enabledCollectionIds,
32
+ readSource: (id) => readSourceCollection(id),
33
+ // Shared with the website-side reader so a tier is never written to one
34
+ // path and read from another.
35
+ docPath: mirrorDocPath,
36
+ // Opaque for public nodes: their title is republished world-readable, so
37
+ // it must not name the collection. See `mirrorNodeTitleFor`.
38
+ title: mirrorNodeTitleFor,
39
+ });
40
+ // A direct app call, not a scheduler-driven one.
41
+ await channel.sync({ callKind: 'classic' });
42
+ const { spaces, created, written, cleared } = channel.result;
43
+ return {
44
+ spaceId: spaces[MIRROR_SPACE_NAME] ?? null,
45
+ created: created,
46
+ written: written,
47
+ cleared: cleared,
48
+ };
49
+ }
50
+ //# sourceMappingURL=writer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"writer.js","sourceRoot":"","sources":["../../../src/client/mirror/writer.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,wBAAwB,EAAE,MAAM,0CAA0C,CAAA;AACnF,OAAO,EACL,aAAa,EACb,kBAAkB,EAClB,aAAa,EACb,kBAAkB,EAClB,iBAAiB,GAElB,MAAM,kBAAkB,CAAA;AAyBzB;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,OAA+B;IAE/B,MAAM,EAAE,OAAO,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,GAAG,OAAO,CAAA;IAEvE,MAAM,OAAO,GAAG,wBAAwB,CAAC;QACvC,IAAI,EAAE,sBAAsB;QAC5B,OAAO;QACP,wEAAwE;QACxE,uEAAuE;QACvE,oEAAoE;QACpE,aAAa;QACb,WAAW,EAAE,kBAAkB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YAC1C,EAAE,EAAE,CAAC,CAAC,EAAE;YACR,SAAS,EAAE,iBAAiB;YAC5B,IAAI,EAAE,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC;SAC1B,CAAC,CAAC;QACH,UAAU,EAAE,GAAG,EAAE,CAAC,oBAAoB;QACtC,UAAU,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,oBAAoB,CAAC,EAAE,CAAC;QAC5C,wEAAwE;QACxE,8BAA8B;QAC9B,OAAO,EAAE,aAAa;QACtB,yEAAyE;QACzE,6DAA6D;QAC7D,KAAK,EAAE,kBAAkB;KAC1B,CAAC,CAAA;IACF,iDAAiD;IACjD,MAAM,OAAO,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,CAAA;IAE3C,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,MAAM,CAAA;IAC5D,OAAO;QACL,OAAO,EAAE,MAAM,CAAC,iBAAiB,CAAC,IAAI,IAAI;QAC1C,OAAO,EAAE,OAA+B;QACxC,OAAO,EAAE,OAA+B;QACxC,OAAO,EAAE,OAA+B;KACzC,CAAA;AACH,CAAC"}
@@ -0,0 +1,91 @@
1
+ import { type Session } from '@drakkar.software/starfish-spaces';
2
+ import type { CapCert } from '@drakkar.software/starfish-protocol';
3
+ import type { PairingRequestPayload } from '../../identity/pairingRequest.js';
4
+ import { type MirrorCollectionId } from '../mirror/index.js';
5
+ /**
6
+ * Rebuild the `{edPub, kemPub, userId, kemSig}` "join request" JSON
7
+ * `starfish-spaces`' `inviteToNode`/`parseJoinRequest` expect, from a
8
+ * `PairingRequestPayload`'s already-public `devEdPub`/`devKemPub` plus the
9
+ * `joinRequestKemSig` it carries. The website computes `joinRequestKemSig`
10
+ * once (via `signKemSig`) when it generates its ephemeral device keys in
11
+ * `startPairingRequest` — this just reassembles the same shape
12
+ * `makeJoinRequest(session)` would have produced, without the website ever
13
+ * needing a full `starfish-spaces` `Session` for an identity it has no
14
+ * wallet to derive (it's a website, not a wallet holder).
15
+ */
16
+ export declare function buildJoinRequestJson(request: PairingRequestPayload): Promise<string>;
17
+ export declare class NothingToShareError extends Error {
18
+ constructor();
19
+ }
20
+ /** One granted collection, as the website needs it to read that node: the two
21
+ * caps `inviteToNode(..., {isolated: true})` mints — `contentCap` (`objinv`)
22
+ * to fetch the document, `keyringCap` (`nodekeyring`) to open it. */
23
+ export interface MirrorGrantNode {
24
+ collectionId: MirrorCollectionId;
25
+ nodeId: string;
26
+ contentCap: CapCert;
27
+ keyringCap: CapCert;
28
+ }
29
+ /** The grant document, published sealed through the pairing rendezvous. `v`
30
+ * is a wire version: a website built against the old space-member grant sees
31
+ * a shape it cannot parse and must say so, rather than silently reading
32
+ * nothing. */
33
+ export interface MirrorGrantDoc {
34
+ v: 1;
35
+ spaceId: string;
36
+ nodes: MirrorGrantNode[];
37
+ }
38
+ export interface MintedPairingGrant {
39
+ /** JSON-stringified `MirrorGrantDoc`. One grant per collection, each
40
+ * reaching exactly one node — never the whole space. */
41
+ bundle: string;
42
+ spaceId: string;
43
+ /** `defaultUserIdFromEdPub(request.devEdPub)`. The website is NOT added to
44
+ * the space roster (that is the point of the isolated tier), so this is an
45
+ * identifier for bookkeeping, not a membership record. */
46
+ memberUserId: string;
47
+ /** The website's ephemeral KEM pubkey — the recipient entry
48
+ * `revokePairingGrant` removes from each node's keyring. */
49
+ memberKemPub: string;
50
+ /** Exactly what this grant covers. Unlike the old space-wide grant this is
51
+ * not a snapshot that can silently widen: a collection enabled later gets
52
+ * no grant until the user pairs again. */
53
+ coveredCollections: MirrorCollectionId[];
54
+ /** The granted node ids, in the same order — what `revokePairingGrant`
55
+ * takes, so a caller never has to re-parse `bundle`. */
56
+ grantedNodeIds: string[];
57
+ }
58
+ /**
59
+ * Phone side: mint a read-only grant for a paired website — one per-node
60
+ * invite for each currently-mirrored, third-party-eligible collection.
61
+ *
62
+ * The website joins no space roster. Each invite carries a cap for that one
63
+ * node's content plus a recipient slot in that one node's keyring, so the
64
+ * grant reaches exactly the collections shown in the pairing UI and nothing
65
+ * else — `user-settings` (`visibility: "private"`, space keyring) and
66
+ * `user-accounts-auth` (never mirrored at all) are unreachable by
67
+ * construction rather than by policy.
68
+ *
69
+ * Throws `NothingToShareError` when no eligible collection has a mirror node
70
+ * yet (i.e. `syncCloudMirror` has not run with one enabled).
71
+ */
72
+ export declare function mintPairingGrant(session: Session, request: PairingRequestPayload): Promise<MintedPairingGrant>;
73
+ /**
74
+ * Phone side: revoke a previously-minted grant by removing the website's
75
+ * ephemeral KEM key from each granted node's keyring, which also rotates that
76
+ * keyring to a new epoch. Everything written afterwards is sealed to an epoch
77
+ * the site is not a recipient of.
78
+ *
79
+ * Two honest caveats, both inherent to the model rather than to this code.
80
+ * The site keeps a valid `objinv` cap, so it can still FETCH those nodes'
81
+ * bytes — it simply cannot decrypt anything written after this call; making
82
+ * the fetch itself fail needs the cap-revocation-list plumbing, which is not
83
+ * reachable on the deployed server (same finding the space-member design
84
+ * recorded). And this cannot erase what the site already fetched and
85
+ * decrypted — the caveat every revocation design in this package documents.
86
+ *
87
+ * Per-node, unlike the space-member grant it replaces: revoking one
88
+ * collection leaves the others working.
89
+ */
90
+ export declare function revokePairingGrant(session: Session, spaceId: string, nodeIds: readonly string[], memberKemPub: string): Promise<void>;
91
+ //# sourceMappingURL=mirrorGrant.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mirrorGrant.d.ts","sourceRoot":"","sources":["../../../src/client/pairing/mirrorGrant.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,OAAO,EACb,MAAM,mCAAmC,CAAA;AAE1C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qCAAqC,CAAA;AAClE,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,kCAAkC,CAAA;AAC7E,OAAO,EAKL,KAAK,kBAAkB,EACxB,MAAM,oBAAoB,CAAA;AAE3B;;;;;;;;;;GAUG;AACH,wBAAsB,oBAAoB,CAAC,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,MAAM,CAAC,CAQ1F;AAED,qBAAa,mBAAoB,SAAQ,KAAK;;CAK7C;AAED;;sEAEsE;AACtE,MAAM,WAAW,eAAe;IAC9B,YAAY,EAAE,kBAAkB,CAAA;IAChC,MAAM,EAAE,MAAM,CAAA;IACd,UAAU,EAAE,OAAO,CAAA;IACnB,UAAU,EAAE,OAAO,CAAA;CACpB;AAED;;;eAGe;AACf,MAAM,WAAW,cAAc;IAC7B,CAAC,EAAE,CAAC,CAAA;IACJ,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,EAAE,eAAe,EAAE,CAAA;CACzB;AAED,MAAM,WAAW,kBAAkB;IACjC;6DACyD;IACzD,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,MAAM,CAAA;IACf;;+DAE2D;IAC3D,YAAY,EAAE,MAAM,CAAA;IACpB;iEAC6D;IAC7D,YAAY,EAAE,MAAM,CAAA;IACpB;;+CAE2C;IAC3C,kBAAkB,EAAE,kBAAkB,EAAE,CAAA;IACxC;6DACyD;IACzD,cAAc,EAAE,MAAM,EAAE,CAAA;CACzB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,qBAAqB,GAC7B,OAAO,CAAC,kBAAkB,CAAC,CA2C7B;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,SAAS,MAAM,EAAE,EAC1B,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,IAAI,CAAC,CAIf"}
@@ -0,0 +1,99 @@
1
+ import { inviteToNode, readObjectTree, removeNodeKeyringRecipient, } from '@drakkar.software/starfish-spaces';
2
+ import { defaultUserIdFromEdPub } from '@drakkar.software/starfish-spaces';
3
+ import { findOrCreateMirrorSpace, isIsolatedMirrorCollection, isKnownMirrorCollection, MIRROR_SPACE_NAME, } from '../mirror/index.js';
4
+ /**
5
+ * Rebuild the `{edPub, kemPub, userId, kemSig}` "join request" JSON
6
+ * `starfish-spaces`' `inviteToNode`/`parseJoinRequest` expect, from a
7
+ * `PairingRequestPayload`'s already-public `devEdPub`/`devKemPub` plus the
8
+ * `joinRequestKemSig` it carries. The website computes `joinRequestKemSig`
9
+ * once (via `signKemSig`) when it generates its ephemeral device keys in
10
+ * `startPairingRequest` — this just reassembles the same shape
11
+ * `makeJoinRequest(session)` would have produced, without the website ever
12
+ * needing a full `starfish-spaces` `Session` for an identity it has no
13
+ * wallet to derive (it's a website, not a wallet holder).
14
+ */
15
+ export async function buildJoinRequestJson(request) {
16
+ const userId = await defaultUserIdFromEdPub(request.devEdPub);
17
+ return JSON.stringify({
18
+ edPub: request.devEdPub,
19
+ kemPub: request.devKemPub,
20
+ userId,
21
+ kemSig: request.joinRequestKemSig,
22
+ });
23
+ }
24
+ export class NothingToShareError extends Error {
25
+ constructor() {
26
+ super('cloud sync: nothing enabled to share yet — enable at least one collection before pairing');
27
+ this.name = 'NothingToShareError';
28
+ }
29
+ }
30
+ /**
31
+ * Phone side: mint a read-only grant for a paired website — one per-node
32
+ * invite for each currently-mirrored, third-party-eligible collection.
33
+ *
34
+ * The website joins no space roster. Each invite carries a cap for that one
35
+ * node's content plus a recipient slot in that one node's keyring, so the
36
+ * grant reaches exactly the collections shown in the pairing UI and nothing
37
+ * else — `user-settings` (`visibility: "private"`, space keyring) and
38
+ * `user-accounts-auth` (never mirrored at all) are unreachable by
39
+ * construction rather than by policy.
40
+ *
41
+ * Throws `NothingToShareError` when no eligible collection has a mirror node
42
+ * yet (i.e. `syncCloudMirror` has not run with one enabled).
43
+ */
44
+ export async function mintPairingGrant(session, request) {
45
+ const joinRequestJson = await buildJoinRequestJson(request);
46
+ const space = await findOrCreateMirrorSpace(session, MIRROR_SPACE_NAME);
47
+ const tree = await readObjectTree(session, space.id);
48
+ const grantable = tree.filter((node) => isKnownMirrorCollection(node.type) && isIsolatedMirrorCollection(node.type));
49
+ if (grantable.length === 0)
50
+ throw new NothingToShareError();
51
+ const nodes = [];
52
+ for (const node of grantable) {
53
+ // `isolated: true` is what keeps this off the space roster and off the
54
+ // space keyring; `write: false` is what makes it read-only.
55
+ const bundleJson = await inviteToNode(session, space.id, node.id, joinRequestJson, { enc: true }, node.type, { isolated: true, write: false });
56
+ const bundle = JSON.parse(bundleJson);
57
+ if (!bundle.nodeCap || !bundle.keyringCap) {
58
+ throw new Error(`pairing grant: incomplete invite bundle for ${node.type}`);
59
+ }
60
+ nodes.push({
61
+ collectionId: node.type,
62
+ nodeId: node.id,
63
+ contentCap: bundle.nodeCap,
64
+ keyringCap: bundle.keyringCap,
65
+ });
66
+ }
67
+ const doc = { v: 1, spaceId: space.id, nodes };
68
+ return {
69
+ bundle: JSON.stringify(doc),
70
+ spaceId: space.id,
71
+ memberUserId: await defaultUserIdFromEdPub(request.devEdPub),
72
+ memberKemPub: request.devKemPub,
73
+ coveredCollections: nodes.map((n) => n.collectionId),
74
+ grantedNodeIds: nodes.map((n) => n.nodeId),
75
+ };
76
+ }
77
+ /**
78
+ * Phone side: revoke a previously-minted grant by removing the website's
79
+ * ephemeral KEM key from each granted node's keyring, which also rotates that
80
+ * keyring to a new epoch. Everything written afterwards is sealed to an epoch
81
+ * the site is not a recipient of.
82
+ *
83
+ * Two honest caveats, both inherent to the model rather than to this code.
84
+ * The site keeps a valid `objinv` cap, so it can still FETCH those nodes'
85
+ * bytes — it simply cannot decrypt anything written after this call; making
86
+ * the fetch itself fail needs the cap-revocation-list plumbing, which is not
87
+ * reachable on the deployed server (same finding the space-member design
88
+ * recorded). And this cannot erase what the site already fetched and
89
+ * decrypted — the caveat every revocation design in this package documents.
90
+ *
91
+ * Per-node, unlike the space-member grant it replaces: revoking one
92
+ * collection leaves the others working.
93
+ */
94
+ export async function revokePairingGrant(session, spaceId, nodeIds, memberKemPub) {
95
+ for (const nodeId of nodeIds) {
96
+ await removeNodeKeyringRecipient(session, spaceId, nodeId, [memberKemPub]);
97
+ }
98
+ }
99
+ //# sourceMappingURL=mirrorGrant.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mirrorGrant.js","sourceRoot":"","sources":["../../../src/client/pairing/mirrorGrant.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,99 @@
1
+ import type { CapCert, PushSuccess } from '@drakkar.software/starfish-protocol';
2
+ import { type MirrorCollectionId } from '../mirror/index.js';
3
+ /** The grant document `mintPairingGrant` publishes (sealed) and this module
4
+ * unpacks: one entry per granted collection, each naming the node and the
5
+ * two caps that reach it. The node list is carried IN the grant because a
6
+ * per-node grant holder cannot read `objindex` to discover it. */
7
+ export interface MirrorGrantBundle {
8
+ spaceId: string;
9
+ nodes: MirrorGrantNodeRef[];
10
+ }
11
+ export interface MirrorGrantNodeRef {
12
+ collectionId: MirrorCollectionId;
13
+ nodeId: string;
14
+ contentCap: CapCert;
15
+ keyringCap: CapCert;
16
+ }
17
+ export declare function parseMirrorGrantBundle(bundleJson: string): MirrorGrantBundle;
18
+ export interface ReadMirrorCollectionsOptions {
19
+ rendezvous: {
20
+ baseUrl: string;
21
+ namespace: string;
22
+ };
23
+ spaceId: string;
24
+ /** From `parseMirrorGrantBundle` — exactly the nodes this grant covers. */
25
+ nodes: readonly MirrorGrantNodeRef[];
26
+ /** The website's own ephemeral Ed25519 private key (hex) — from the same
27
+ * `device` the site generated in `startPairingRequest`; every cap was
28
+ * minted for exactly this device's pubkey. */
29
+ devEdPrivHex: string;
30
+ /** The website's own ephemeral X25519 KEM private key (hex) — same `device`
31
+ * as `devEdPrivHex`. Each `inviteToNode` added this device's KEM pubkey as
32
+ * a recipient of THAT node's own keyring; content is sealed under those,
33
+ * not under the caps. */
34
+ devKemPrivHex: string;
35
+ fetch?: typeof fetch;
36
+ timeoutMs?: number;
37
+ }
38
+ /**
39
+ * Website side, session-less: pull every collection the grant covers. A REAL
40
+ * live read, not a point-in-time export — call it again any time to see the
41
+ * latest write, bounded only by how often the wallet's writer refreshes.
42
+ *
43
+ * A collection whose node was cleared (the user disabled it) or whose keyring
44
+ * recipient was removed (the user revoked it) simply won't appear, so this
45
+ * reflects CURRENT state rather than a snapshot of grant time.
46
+ *
47
+ * A thin adapter over `starfish-replica/space`'s `readIsolatedSpaceMirror`;
48
+ * this module owns only the `mirrorDocPath` template and the timeout-wrapped
49
+ * fetch.
50
+ */
51
+ export declare function readMirrorCollections(opts: ReadMirrorCollectionsOptions): Promise<Partial<Record<MirrorCollectionId, unknown>>>;
52
+ export interface AttemptDirectMirrorWriteOptions {
53
+ rendezvous: {
54
+ baseUrl: string;
55
+ namespace: string;
56
+ };
57
+ spaceId: string;
58
+ cap: CapCert;
59
+ /** The website's own ephemeral Ed25519 private key (hex) — same device the
60
+ * cap was minted for. */
61
+ devEdPrivHex: string;
62
+ /** Which mirror collection to target, e.g. `'user-data'` (automations) or
63
+ * `'user-accounts'`. */
64
+ collectionId: MirrorCollectionId;
65
+ /** A fresh node id — this always targets a node that does not exist yet,
66
+ * matching "write a new automation/account", not an edit of one that's
67
+ * already there. */
68
+ nodeId: string;
69
+ /** Plain (unsealed) JSON body to push. Since the grant is expected to be
70
+ * read-only, the request is rejected before content ever matters — this
71
+ * never needs to be a validly-sealed document. */
72
+ doc: Record<string, unknown>;
73
+ fetch?: typeof fetch;
74
+ timeoutMs?: number;
75
+ }
76
+ /**
77
+ * Website side, session-less: try to write a brand-new node directly into
78
+ * the paired mirror space, using nothing but the grant `mintPairingGrant`
79
+ * already handed this site (`opts.cap` + `opts.devEdPrivHex` — the exact
80
+ * credentials `readMirrorCollections` reads with). No session, no
81
+ * `addObject`/index update — just one raw `push` at the collection's own
82
+ * path, the smallest possible probe of what the cap actually authorizes.
83
+ *
84
+ * **This call is expected to fail.** `mintPairingGrant` always mints with
85
+ * `canWrite: false` (see `mirrorGrant.ts`), so the cap's `ops` is
86
+ * `['read', 'list']` — no `'write'` — and the server rejects the push before
87
+ * looking at the body. That is the point of exposing this: a paired website
88
+ * holding only a read grant cannot unilaterally create or change anything in
89
+ * the user's node. Making a change requires asking the user (the phone,
90
+ * which holds the actual writable session) to approve it and publish the
91
+ * write itself — this function is not, and is never meant to become, a
92
+ * second write path around that approval.
93
+ *
94
+ * Returns the server's raw response on the (unexpected) chance it succeeds,
95
+ * or rethrows the `StarfishHttpError` (or plain fetch failure) so a caller
96
+ * can show the real rejection rather than a synthesized one.
97
+ */
98
+ export declare function attemptDirectMirrorWrite(opts: AttemptDirectMirrorWriteOptions): Promise<PushSuccess>;
99
+ //# sourceMappingURL=mirrorReader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mirrorReader.d.ts","sourceRoot":"","sources":["../../../src/client/pairing/mirrorReader.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,qCAAqC,CAAA;AAK/E,OAAO,EAA6D,KAAK,kBAAkB,EAAE,MAAM,oBAAoB,CAAA;AAEvH;;;mEAGmE;AACnE,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,EAAE,kBAAkB,EAAE,CAAA;CAC5B;AAED,MAAM,WAAW,kBAAkB;IACjC,YAAY,EAAE,kBAAkB,CAAA;IAChC,MAAM,EAAE,MAAM,CAAA;IACd,UAAU,EAAE,OAAO,CAAA;IACnB,UAAU,EAAE,OAAO,CAAA;CACpB;AAED,wBAAgB,sBAAsB,CAAC,UAAU,EAAE,MAAM,GAAG,iBAAiB,CAkC5E;AAED,MAAM,WAAW,4BAA4B;IAC3C,UAAU,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAA;IAClD,OAAO,EAAE,MAAM,CAAA;IACf,2EAA2E;IAC3E,KAAK,EAAE,SAAS,kBAAkB,EAAE,CAAA;IACpC;;mDAE+C;IAC/C,YAAY,EAAE,MAAM,CAAA;IACpB;;;8BAG0B;IAC1B,aAAa,EAAE,MAAM,CAAA;IACrB,KAAK,CAAC,EAAE,OAAO,KAAK,CAAA;IACpB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,qBAAqB,CACzC,IAAI,EAAE,4BAA4B,GACjC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,kBAAkB,EAAE,OAAO,CAAC,CAAC,CAAC,CAUvD;AAkBD,MAAM,WAAW,+BAA+B;IAC9C,UAAU,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAA;IAClD,OAAO,EAAE,MAAM,CAAA;IACf,GAAG,EAAE,OAAO,CAAA;IACZ;8BAC0B;IAC1B,YAAY,EAAE,MAAM,CAAA;IACpB;6BACyB;IACzB,YAAY,EAAE,kBAAkB,CAAA;IAChC;;yBAEqB;IACrB,MAAM,EAAE,MAAM,CAAA;IACd;;uDAEmD;IACnD,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC5B,KAAK,CAAC,EAAE,OAAO,KAAK,CAAA;IACpB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAsB,wBAAwB,CAC5C,IAAI,EAAE,+BAA+B,GACpC,OAAO,CAAC,WAAW,CAAC,CAStB"}
@@ -0,0 +1,117 @@
1
+ import { readIsolatedSpaceMirror } from '@drakkar.software/starfish-replica/space';
2
+ import { StarfishClient } from '@drakkar.software/starfish-client';
3
+ import { createTimeoutFetch } from '../../transport/syncClient.js';
4
+ import { SYNC_FETCH_TIMEOUT_MS } from '../../crypto/wireConstants.js';
5
+ import { isKnownMirrorCollection, mirrorDocPushPath, mirrorDocPath } from '../mirror/index.js';
6
+ export function parseMirrorGrantBundle(bundleJson) {
7
+ let parsed;
8
+ try {
9
+ parsed = JSON.parse(bundleJson);
10
+ }
11
+ catch {
12
+ throw new Error('pairing grant: bundle is not valid JSON');
13
+ }
14
+ if (typeof parsed !== 'object' || parsed === null)
15
+ throw new Error('pairing grant: malformed bundle');
16
+ const b = parsed;
17
+ if (typeof b.spaceId !== 'string' || !b.spaceId)
18
+ throw new Error('pairing grant: missing spaceId');
19
+ // A pre-per-node grant (one space-wide `cap`, no `nodes`) is not something
20
+ // this reader can silently treat as "nothing shared" — say so instead.
21
+ if (!Array.isArray(b.nodes)) {
22
+ throw new Error('pairing grant: missing nodes — this grant was issued by an older, incompatible version');
23
+ }
24
+ const nodes = b.nodes.map((raw, i) => {
25
+ const n = raw;
26
+ if (typeof n?.collectionId !== 'string' || typeof n?.nodeId !== 'string') {
27
+ throw new Error(`pairing grant: malformed node at index ${i}`);
28
+ }
29
+ if (typeof n.contentCap !== 'object' || n.contentCap === null) {
30
+ throw new Error(`pairing grant: node ${n.collectionId} is missing its content cap`);
31
+ }
32
+ if (typeof n.keyringCap !== 'object' || n.keyringCap === null) {
33
+ throw new Error(`pairing grant: node ${n.collectionId} is missing its keyring cap`);
34
+ }
35
+ return {
36
+ collectionId: n.collectionId,
37
+ nodeId: n.nodeId,
38
+ contentCap: n.contentCap,
39
+ keyringCap: n.keyringCap,
40
+ };
41
+ });
42
+ return { spaceId: b.spaceId, nodes };
43
+ }
44
+ /**
45
+ * Website side, session-less: pull every collection the grant covers. A REAL
46
+ * live read, not a point-in-time export — call it again any time to see the
47
+ * latest write, bounded only by how often the wallet's writer refreshes.
48
+ *
49
+ * A collection whose node was cleared (the user disabled it) or whose keyring
50
+ * recipient was removed (the user revoked it) simply won't appear, so this
51
+ * reflects CURRENT state rather than a snapshot of grant time.
52
+ *
53
+ * A thin adapter over `starfish-replica/space`'s `readIsolatedSpaceMirror`;
54
+ * this module owns only the `mirrorDocPath` template and the timeout-wrapped
55
+ * fetch.
56
+ */
57
+ export async function readMirrorCollections(opts) {
58
+ return readIsolatedSpaceMirror({
59
+ rendezvous: opts.rendezvous,
60
+ spaceId: opts.spaceId,
61
+ nodes: opts.nodes.filter((n) => isKnownMirrorCollection(n.collectionId)),
62
+ devEdPrivHex: opts.devEdPrivHex,
63
+ devKemPrivHex: opts.devKemPrivHex,
64
+ docPath: mirrorDocPath,
65
+ fetch: createTimeoutFetch(opts.timeoutMs ?? SYNC_FETCH_TIMEOUT_MS, opts.fetch ?? globalThis.fetch),
66
+ });
67
+ }
68
+ /** Returns the SAME `{cap, devEdPrivHex}` on every call — a paired website
69
+ * holds one grant for one ephemeral device, never rotates it, so there is
70
+ * nothing to refresh. Shared shape between the write attempt below and
71
+ * `readIsolatedSpaceMirror`'s own private cap provider (that one lives inside
72
+ * `starfish-replica` and isn't exported, so this is a narrow duplicate, not
73
+ * a reused import). */
74
+ class StaticMirrorCapProvider {
75
+ cap;
76
+ devEdPrivHex;
77
+ constructor(cap, devEdPrivHex) {
78
+ this.cap = cap;
79
+ this.devEdPrivHex = devEdPrivHex;
80
+ }
81
+ async getCap() {
82
+ return { cap: this.cap, devEdPrivHex: this.devEdPrivHex };
83
+ }
84
+ }
85
+ /**
86
+ * Website side, session-less: try to write a brand-new node directly into
87
+ * the paired mirror space, using nothing but the grant `mintPairingGrant`
88
+ * already handed this site (`opts.cap` + `opts.devEdPrivHex` — the exact
89
+ * credentials `readMirrorCollections` reads with). No session, no
90
+ * `addObject`/index update — just one raw `push` at the collection's own
91
+ * path, the smallest possible probe of what the cap actually authorizes.
92
+ *
93
+ * **This call is expected to fail.** `mintPairingGrant` always mints with
94
+ * `canWrite: false` (see `mirrorGrant.ts`), so the cap's `ops` is
95
+ * `['read', 'list']` — no `'write'` — and the server rejects the push before
96
+ * looking at the body. That is the point of exposing this: a paired website
97
+ * holding only a read grant cannot unilaterally create or change anything in
98
+ * the user's node. Making a change requires asking the user (the phone,
99
+ * which holds the actual writable session) to approve it and publish the
100
+ * write itself — this function is not, and is never meant to become, a
101
+ * second write path around that approval.
102
+ *
103
+ * Returns the server's raw response on the (unexpected) chance it succeeds,
104
+ * or rethrows the `StarfishHttpError` (or plain fetch failure) so a caller
105
+ * can show the real rejection rather than a synthesized one.
106
+ */
107
+ export async function attemptDirectMirrorWrite(opts) {
108
+ const client = new StarfishClient({
109
+ baseUrl: opts.rendezvous.baseUrl,
110
+ namespace: opts.rendezvous.namespace,
111
+ fetch: createTimeoutFetch(opts.timeoutMs ?? SYNC_FETCH_TIMEOUT_MS, opts.fetch ?? globalThis.fetch),
112
+ capProvider: new StaticMirrorCapProvider(opts.cap, opts.devEdPrivHex),
113
+ });
114
+ const path = mirrorDocPushPath(opts.collectionId, opts.spaceId, opts.nodeId);
115
+ return client.push(path, opts.doc, null);
116
+ }
117
+ //# sourceMappingURL=mirrorReader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mirrorReader.js","sourceRoot":"","sources":["../../../src/client/pairing/mirrorReader.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,135 @@
1
+ import { type SealerKeys } from '@drakkar.software/starfish-keyring';
2
+ import type { GeneratedDeviceKeys } from '@drakkar.software/starfish-identities';
3
+ import type { PairingRequestPayload } from '../../identity/pairingRequest.js';
4
+ import { type MirrorGrantNodeRef } from './mirrorReader.js';
5
+ import type { MintedPairingGrant } from './mirrorGrant.js';
6
+ import type { MirrorCollectionId } from '../mirror/index.js';
7
+ /** Phone side, step 2: seal and publish the minted grant to the request's
8
+ * `code` slot — this OVERWRITES the request doc still published there,
9
+ * since request and grant now share one address.
10
+ *
11
+ * `rendezvous` is the caller's OWN trusted server config — the same one it
12
+ * used to look up `request` via `fetchPairingRequestByCode` — never
13
+ * `request.rendezvous`. That field rides inside a document anyone can
14
+ * publish to the public `joinsessions` collection, so trusting it here
15
+ * would let a malicious "website" party point this phone's outbound POST at
16
+ * an arbitrary host of its choosing.
17
+ *
18
+ * `baseHash` MUST be the `hash` `fetchPairingRequestByCode` returned
19
+ * alongside `request` — this is what makes "claim this specific, exact
20
+ * request" atomic: the push only succeeds if the slot still holds exactly
21
+ * the request doc this caller read, so a request that was swapped or
22
+ * already claimed by someone else between the read and this write is
23
+ * detected as a conflict rather than silently overwritten. There is no
24
+ * longer a meaningful "first publish, baseHash: null" case the way the
25
+ * retired sessionId-keyed design had one — the slot is never empty by the
26
+ * time a caller reaches this function, it already holds the request. A
27
+ * caller legitimately RE-publishing later (a refresh) must pass back the
28
+ * hash THIS function returned from its own previous call. Returns the
29
+ * resulting hash for exactly that purpose. */
30
+ export declare function publishPairingGrant(opts: {
31
+ request: PairingRequestPayload;
32
+ sealer: SealerKeys;
33
+ grant: MintedPairingGrant;
34
+ rendezvous: {
35
+ baseUrl: string;
36
+ namespace: string;
37
+ };
38
+ baseHash: string | null;
39
+ fetch?: typeof fetch;
40
+ timeoutMs?: number;
41
+ }): Promise<{
42
+ hash: string;
43
+ }>;
44
+ /** Phone side: stop publishing and clear the current slot — since request
45
+ * and grant share one address, this clears BOTH together (there is no way
46
+ * to clear one but keep the other). It stops future reads but cannot
47
+ * recall a grant a website already fetched — with this design, "cannot
48
+ * recall" is narrow: the grant itself only proves space membership, and
49
+ * `removeSpaceMember`-based revocation (real, immediate, checked live on
50
+ * every request) is the actual unpair mechanism a caller should use
51
+ * ALONGSIDE this, not instead of it — this only stops the CODE from
52
+ * resolving to a usable grant again, it does not by itself revoke a grant
53
+ * already handed out. */
54
+ export declare function clearPairingGrant(opts: {
55
+ request: PairingRequestPayload;
56
+ rendezvous: {
57
+ baseUrl: string;
58
+ namespace: string;
59
+ };
60
+ fetch?: typeof fetch;
61
+ timeoutMs?: number;
62
+ }): Promise<{
63
+ hash: string;
64
+ }>;
65
+ export interface UnsealedPairingGrant {
66
+ spaceId: string;
67
+ /** Live read of every mirror collection the grant currently covers — a
68
+ * real pull, not a cached/point-in-time value; call `readMirrorCollections`
69
+ * again directly for a later refresh rather than re-fetching the grant. */
70
+ collections: Partial<Record<MirrorCollectionId, unknown>>;
71
+ /** The Ed25519 pubkey that actually sealed this grant, verified via the
72
+ * wrap entry's signature (never merely claimed — `unseal` always checks
73
+ * it). A trust-on-first-use pin: record it after the FIRST successful
74
+ * call and pass it back as `expectedSealer` on every later poll for this
75
+ * session, so a later writer to the same slot cannot silently replace an
76
+ * established pairing's grant with their own. Nothing pins WHO this key
77
+ * belongs to on the very first read — that trust comes from the grant
78
+ * write itself being a compare-and-swap against the exact request hash
79
+ * `fetchPairingRequestByCode` returned (see `publishPairingGrant`), which
80
+ * only the party that actually read the live, unclaimed request could
81
+ * have supplied. */
82
+ sealedBy: string;
83
+ /** The per-node grants this bundle unwrapped to — the SAME ones
84
+ * `readMirrorCollections` above just used to pull `collections`. Exposed
85
+ * so a caller can make its own authenticated calls (e.g.
86
+ * `attemptDirectMirrorWrite`) without re-fetching and re-unsealing the
87
+ * grant. Always read-only in practice: `mintPairingGrant` mints with
88
+ * `write: false`, so no cap here carries `'write'`. */
89
+ nodes: MirrorGrantNodeRef[];
90
+ }
91
+ /** Website side: read whatever is currently published at this session's
92
+ * slot. Three outcomes:
93
+ * - nothing published (wrong/expired code) → `null`, "keep waiting".
94
+ * - still `kind: 'octobot-pairing-request'` (the phone hasn't approved
95
+ * yet) → also `null`, "keep waiting" — this is the normal, expected
96
+ * state for most of the polling loop's life, NOT an error.
97
+ * - `kind: 'octobot-pairing-grant'` → unseal it and immediately do a live
98
+ * read of every mirror collection it covers.
99
+ * Anything else (an unrecognized `kind`, or a `kind: 'octobot-pairing-grant'`
100
+ * doc whose `sealed` field isn't actually a sealed blob) throws — that's a
101
+ * genuine malformed-document case, not a wait state. */
102
+ export declare function fetchPairingGrant(session: {
103
+ code: string;
104
+ device: GeneratedDeviceKeys;
105
+ rendezvous: {
106
+ baseUrl: string;
107
+ namespace: string;
108
+ };
109
+ }, opts?: {
110
+ expectedSealer?: string;
111
+ fetch?: typeof fetch;
112
+ timeoutMs?: number;
113
+ }): Promise<UnsealedPairingGrant | null>;
114
+ /** Website side: poll until the phone's FIRST approval publishes a grant,
115
+ * or `timeoutMs` elapses. This is the initial-approval wait, not an ongoing
116
+ * refresh loop — for later refreshes call `readMirrorCollections` directly.
117
+ *
118
+ * A `fetchPairingGrant` failure (a network blip, a transient server error)
119
+ * does NOT end the wait — it's swallowed and retried on the next tick, same
120
+ * as `fetchPairingGrant` returning `null` for "nothing published yet". Only
121
+ * reaching `deadline` ends it: with the last error if there was one (more
122
+ * informative than a bare timeout), else the generic timeout. */
123
+ export declare function awaitPairingGrant(session: {
124
+ code: string;
125
+ device: GeneratedDeviceKeys;
126
+ rendezvous: {
127
+ baseUrl: string;
128
+ namespace: string;
129
+ };
130
+ }, opts?: {
131
+ timeoutMs?: number;
132
+ signal?: AbortSignal;
133
+ fetch?: typeof fetch;
134
+ }): Promise<UnsealedPairingGrant>;
135
+ //# sourceMappingURL=pairingGrantExchange.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pairingGrantExchange.d.ts","sourceRoot":"","sources":["../../../src/client/pairing/pairingGrantExchange.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,UAAU,EAAmB,MAAM,oCAAoC,CAAA;AAGnG,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,uCAAuC,CAAA;AAChF,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,kCAAkC,CAAA;AAW7E,OAAO,EAGL,KAAK,kBAAkB,EACxB,MAAM,mBAAmB,CAAA;AAC1B,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AAC1D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAA;AA+C5D;;;;;;;;;;;;;;;;;;;;;;+CAsB+C;AAC/C,wBAAsB,mBAAmB,CAAC,IAAI,EAAE;IAC9C,OAAO,EAAE,qBAAqB,CAAA;IAC9B,MAAM,EAAE,UAAU,CAAA;IAClB,KAAK,EAAE,kBAAkB,CAAA;IACzB,UAAU,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAA;IAClD,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB,KAAK,CAAC,EAAE,OAAO,KAAK,CAAA;IACpB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,GAAG,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CA4B5B;AAED;;;;;;;;;0BAS0B;AAC1B,wBAAsB,iBAAiB,CAAC,IAAI,EAAE;IAC5C,OAAO,EAAE,qBAAqB,CAAA;IAC9B,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;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAY5B;AAED,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,MAAM,CAAA;IACf;;gFAE4E;IAC5E,WAAW,EAAE,OAAO,CAAC,MAAM,CAAC,kBAAkB,EAAE,OAAO,CAAC,CAAC,CAAA;IACzD;;;;;;;;;;yBAUqB;IACrB,QAAQ,EAAE,MAAM,CAAA;IAChB;;;;;4DAKwD;IACxD,KAAK,EAAE,kBAAkB,EAAE,CAAA;CAC5B;AAED;;;;;;;;;;yDAUyD;AACzD,wBAAsB,iBAAiB,CACrC,OAAO,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,mBAAmB,CAAC;IAAC,UAAU,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,EAC1G,IAAI,GAAE;IAAE,cAAc,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAO,GAC/E,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC,CA2CtC;AAED;;;;;;;;kEAQkE;AAClE,wBAAsB,iBAAiB,CACrC,OAAO,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,mBAAmB,CAAC;IAAC,UAAU,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,EAC1G,IAAI,GAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,WAAW,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,KAAK,CAAA;CAAO,GAC5E,OAAO,CAAC,oBAAoB,CAAC,CAiB/B"}