@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,116 @@
1
+ import { StarfishClient } from '@drakkar.software/starfish-client';
2
+ /** Storage path for a device-code pairing exchange — must match the
3
+ * `joinsessions` collection's `storagePath` template
4
+ * (`_pairing/session/{code}`, defined in
5
+ * `Infra/sync/server/drakkar_sync/apps/dk_spaces/collections.py`). ONE
6
+ * address serves BOTH phases of the exchange: the website's discovery
7
+ * "request" doc, and the phone's delivery "grant" doc that later overwrites
8
+ * it — keyed throughout by the same short human-typeable `code` (see
9
+ * `client/pairing/pairingRequest.ts` and `pairingGrantExchange.ts` for how
10
+ * the two phases are told apart on the wire). Replaces the retired
11
+ * two-collection, two-address design (`pairingrequests`/`pairingsnapshots`,
12
+ * a low-entropy code address plus a separate high-entropy session
13
+ * address) — that split bought no real confidentiality the grant's own
14
+ * sealing didn't already provide, only lifecycle bookkeeping this merge no
15
+ * longer needs. */
16
+ export declare function joinSessionPath(code: string): string;
17
+ export interface RendezvousDoc {
18
+ data: Record<string, unknown>;
19
+ hash: string;
20
+ }
21
+ /** A cap-less `StarfishClient` against a public rendezvous collection — a
22
+ * different namespace/host from the node client `createSyncClient` builds
23
+ * (the rendezvous lives on the shared Drakkar sync server, not the user's
24
+ * own node), and deliberately carries no `capProvider`: every request is
25
+ * anonymous, matching the deployed `joinsessions` collection's `public`
26
+ * read/write roles. */
27
+ export declare function createRendezvousClient(opts: {
28
+ baseUrl: string;
29
+ namespace: string;
30
+ fetch?: typeof fetch;
31
+ timeoutMs?: number;
32
+ }): StarfishClient;
33
+ /** Pull a rendezvous document. Returns `null` when nothing has been
34
+ * published to this slot yet — an unwritten collection document pulls with
35
+ * `data` as the STRING `"null"` (an observed real node's behavior for the
36
+ * standard collection pull path; this rendezvous server is a different,
37
+ * not-yet-deployed deployment, so a raw `null` or an empty `{}` are handled
38
+ * too rather than assumed away), not a 404 — so a nullish/empty `data` is
39
+ * the actual not-found signal here, not a thrown error. */
40
+ export declare function pullRendezvousDoc(client: StarfishClient, path: string): Promise<RendezvousDoc | null>;
41
+ /** Push a rendezvous document against an EXPLICIT `baseHash` — the caller's
42
+ * OWN remembered hash from its last successful write to this path, or
43
+ * `null` for a genuinely fresh slot nothing has been published to yet.
44
+ * Reimplements what `starfish-identities`' `pushPairingBundle` does
45
+ * internally, because that helper is hard-typed to a `PairingBundle` shape
46
+ * (`{capCert, rootEdPub, wrappedCEKs}`) this package's rendezvous documents
47
+ * don't have, and its sibling `fetchPairingBundle` returns `null` for
48
+ * anything without a top-level `capCert` — a document shaped like ours
49
+ * would never be recognized by it.
50
+ *
51
+ * Deliberately does NOT re-pull and adopt whatever's currently at `path` on
52
+ * a conflict (the previous version of this function did exactly that,
53
+ * retrying against the server's current hash) — that behavior is what let
54
+ * a hostile overwrite of this slot go undetected forever, including by the
55
+ * original publisher's own next write, which would silently treat the
56
+ * attacker's content as the new legitimate baseline. A `ConflictError` here
57
+ * means the document changed since THIS CALLER last wrote it, which the
58
+ * caller should treat as "this slot may have been tampered with", not
59
+ * retry past. Returns the resulting hash so the caller can remember it for
60
+ * its next write.
61
+ *
62
+ * This is still inherently last-write-wins at the slot level, not
63
+ * first-writer-wins — a concurrent anonymous writer who wins the race for
64
+ * a GENUINELY fresh slot (`baseHash: null`) is indistinguishable from the
65
+ * legitimate first writer. The defense against that is the human-typeable
66
+ * `code`'s entropy plus the collection's per-IP rate limit, which bound how
67
+ * fast an unknown code can be guessed — NOT address secrecy (this
68
+ * collection is public-read, so anyone who knows or guesses a code can
69
+ * read whatever is currently published there regardless of write history).
70
+ * What THIS change adds is detecting tampering on every write AFTER the
71
+ * first, which the previous blind-retry behavior could never do because it
72
+ * always treated "conflict" as "let me just adopt whatever's there now".
73
+ * It does NOT stop a writer who first PULLS the slot (learning its current
74
+ * hash, which is public information) and then pushes with that hash as
75
+ * `baseHash` — that is a legitimate-looking, non-blind overwrite as far as
76
+ * this primitive is concerned; the real protection against that shape of
77
+ * attack is `code`-bound `popSig` verification (see
78
+ * `identity/pairingRequest.ts`) rejecting any replacement request that
79
+ * isn't signed by keys the ORIGINAL requester controls, and the grant
80
+ * phase's own `baseHash` CAS against the exact request hash it read. */
81
+ export declare function pushRendezvousDoc(client: StarfishClient, path: string, data: Record<string, unknown>, baseHash: string | null): Promise<{
82
+ hash: string;
83
+ }>;
84
+ /** Overwrite a slot with an empty document, regardless of its current
85
+ * content — the one place blind-overwrite-and-retry semantics are still
86
+ * correct: unpair/cleanup must succeed even without a remembered hash
87
+ * (e.g. in-memory state was lost across a page reload), and "did someone
88
+ * else already overwrite this" isn't a meaningful question when the
89
+ * caller's whole intent is "nothing should be published here anymore".
90
+ * The deployed `joinsessions` collection's `ttl_ms` is an outer backstop,
91
+ * not a substitute for actually clearing on unpair — see the Infra
92
+ * collection's doc comment. Because request and grant now share one
93
+ * address, clearing this slot clears BOTH the original request and any
94
+ * published grant together — there's no way to clear one but keep the
95
+ * other.
96
+ *
97
+ * Deliberately pulls the RAW `client.pull()` result here, not
98
+ * `pullRendezvousDoc` — that function collapses an existing-but-empty doc
99
+ * (`{}`, which is exactly what THIS function itself writes) down to `null`,
100
+ * discarding its real hash. Deriving `baseHash` from that collapsed `null`
101
+ * would push `baseHash: null` against a slot that DOES have a hash — a
102
+ * guaranteed conflict, identically, on every one of the retries below.
103
+ * That made clearing an already-cleared slot (a benign double-unpair, or
104
+ * the very recovery path this package documents: unpair then re-approve)
105
+ * permanently fail. The raw hash exists whether or not the data is
106
+ * "empty", so blind-overwrite-and-retry works correctly in every case.
107
+ *
108
+ * Returns the resulting hash — same shape as `pushRendezvousDoc` — so a
109
+ * caller that legitimately needs to publish again right after clearing
110
+ * (e.g. re-approving the same session) can use it as its next `baseHash`
111
+ * instead of `null`, which would otherwise conflict against the very
112
+ * document this call just wrote. */
113
+ export declare function clearRendezvousDoc(client: StarfishClient, path: string): Promise<{
114
+ hash: string;
115
+ }>;
116
+ //# sourceMappingURL=rendezvous.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rendezvous.d.ts","sourceRoot":"","sources":["../../src/transport/rendezvous.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAiB,MAAM,mCAAmC,CAAA;AAOjF;;;;;;;;;;;;;oBAaoB;AACpB,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC7B,IAAI,EAAE,MAAM,CAAA;CACb;AAED;;;;;wBAKwB;AACxB,wBAAgB,sBAAsB,CAAC,IAAI,EAAE;IAC3C,OAAO,EAAE,MAAM,CAAA;IACf,SAAS,EAAE,MAAM,CAAA;IACjB,KAAK,CAAC,EAAE,OAAO,KAAK,CAAA;IACpB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,GAAG,cAAc,CAMjB;AAED;;;;;;4DAM4D;AAC5D,wBAAsB,iBAAiB,CAAC,MAAM,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAM3G;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;yEAuCyE;AACzE,wBAAsB,iBAAiB,CACrC,MAAM,EAAE,cAAc,EACtB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,QAAQ,EAAE,MAAM,GAAG,IAAI,GACtB,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAE3B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;qCA4BqC;AACrC,wBAAsB,kBAAkB,CAAC,MAAM,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAYxG"}
@@ -0,0 +1,139 @@
1
+ import { StarfishClient, ConflictError } from '@drakkar.software/starfish-client';
2
+ import { createTimeoutFetch } from './syncClient.js';
3
+ import { pullPath, pushPath } from '../collections/paths.js';
4
+ import { SYNC_FETCH_TIMEOUT_MS } from '../crypto/wireConstants.js';
5
+ const MAX_PUSH_RETRIES = 3;
6
+ /** Storage path for a device-code pairing exchange — must match the
7
+ * `joinsessions` collection's `storagePath` template
8
+ * (`_pairing/session/{code}`, defined in
9
+ * `Infra/sync/server/drakkar_sync/apps/dk_spaces/collections.py`). ONE
10
+ * address serves BOTH phases of the exchange: the website's discovery
11
+ * "request" doc, and the phone's delivery "grant" doc that later overwrites
12
+ * it — keyed throughout by the same short human-typeable `code` (see
13
+ * `client/pairing/pairingRequest.ts` and `pairingGrantExchange.ts` for how
14
+ * the two phases are told apart on the wire). Replaces the retired
15
+ * two-collection, two-address design (`pairingrequests`/`pairingsnapshots`,
16
+ * a low-entropy code address plus a separate high-entropy session
17
+ * address) — that split bought no real confidentiality the grant's own
18
+ * sealing didn't already provide, only lifecycle bookkeeping this merge no
19
+ * longer needs. */
20
+ export function joinSessionPath(code) {
21
+ return `_pairing/session/${encodeURIComponent(code)}`;
22
+ }
23
+ /** A cap-less `StarfishClient` against a public rendezvous collection — a
24
+ * different namespace/host from the node client `createSyncClient` builds
25
+ * (the rendezvous lives on the shared Drakkar sync server, not the user's
26
+ * own node), and deliberately carries no `capProvider`: every request is
27
+ * anonymous, matching the deployed `joinsessions` collection's `public`
28
+ * read/write roles. */
29
+ export function createRendezvousClient(opts) {
30
+ return new StarfishClient({
31
+ baseUrl: opts.baseUrl,
32
+ namespace: opts.namespace,
33
+ fetch: createTimeoutFetch(opts.timeoutMs ?? SYNC_FETCH_TIMEOUT_MS, opts.fetch ?? globalThis.fetch),
34
+ });
35
+ }
36
+ /** Pull a rendezvous document. Returns `null` when nothing has been
37
+ * published to this slot yet — an unwritten collection document pulls with
38
+ * `data` as the STRING `"null"` (an observed real node's behavior for the
39
+ * standard collection pull path; this rendezvous server is a different,
40
+ * not-yet-deployed deployment, so a raw `null` or an empty `{}` are handled
41
+ * too rather than assumed away), not a 404 — so a nullish/empty `data` is
42
+ * the actual not-found signal here, not a thrown error. */
43
+ export async function pullRendezvousDoc(client, path) {
44
+ const result = await client.pull(pullPath(path, {}));
45
+ const parsed = typeof result.data === 'string' ? JSON.parse(result.data) : result.data;
46
+ if (parsed == null || typeof parsed !== 'object' || Array.isArray(parsed))
47
+ return null;
48
+ if (Object.keys(parsed).length === 0)
49
+ return null;
50
+ return { data: parsed, hash: result.hash };
51
+ }
52
+ /** Push a rendezvous document against an EXPLICIT `baseHash` — the caller's
53
+ * OWN remembered hash from its last successful write to this path, or
54
+ * `null` for a genuinely fresh slot nothing has been published to yet.
55
+ * Reimplements what `starfish-identities`' `pushPairingBundle` does
56
+ * internally, because that helper is hard-typed to a `PairingBundle` shape
57
+ * (`{capCert, rootEdPub, wrappedCEKs}`) this package's rendezvous documents
58
+ * don't have, and its sibling `fetchPairingBundle` returns `null` for
59
+ * anything without a top-level `capCert` — a document shaped like ours
60
+ * would never be recognized by it.
61
+ *
62
+ * Deliberately does NOT re-pull and adopt whatever's currently at `path` on
63
+ * a conflict (the previous version of this function did exactly that,
64
+ * retrying against the server's current hash) — that behavior is what let
65
+ * a hostile overwrite of this slot go undetected forever, including by the
66
+ * original publisher's own next write, which would silently treat the
67
+ * attacker's content as the new legitimate baseline. A `ConflictError` here
68
+ * means the document changed since THIS CALLER last wrote it, which the
69
+ * caller should treat as "this slot may have been tampered with", not
70
+ * retry past. Returns the resulting hash so the caller can remember it for
71
+ * its next write.
72
+ *
73
+ * This is still inherently last-write-wins at the slot level, not
74
+ * first-writer-wins — a concurrent anonymous writer who wins the race for
75
+ * a GENUINELY fresh slot (`baseHash: null`) is indistinguishable from the
76
+ * legitimate first writer. The defense against that is the human-typeable
77
+ * `code`'s entropy plus the collection's per-IP rate limit, which bound how
78
+ * fast an unknown code can be guessed — NOT address secrecy (this
79
+ * collection is public-read, so anyone who knows or guesses a code can
80
+ * read whatever is currently published there regardless of write history).
81
+ * What THIS change adds is detecting tampering on every write AFTER the
82
+ * first, which the previous blind-retry behavior could never do because it
83
+ * always treated "conflict" as "let me just adopt whatever's there now".
84
+ * It does NOT stop a writer who first PULLS the slot (learning its current
85
+ * hash, which is public information) and then pushes with that hash as
86
+ * `baseHash` — that is a legitimate-looking, non-blind overwrite as far as
87
+ * this primitive is concerned; the real protection against that shape of
88
+ * attack is `code`-bound `popSig` verification (see
89
+ * `identity/pairingRequest.ts`) rejecting any replacement request that
90
+ * isn't signed by keys the ORIGINAL requester controls, and the grant
91
+ * phase's own `baseHash` CAS against the exact request hash it read. */
92
+ export async function pushRendezvousDoc(client, path, data, baseHash) {
93
+ return client.push(pushPath(path, {}), data, baseHash);
94
+ }
95
+ /** Overwrite a slot with an empty document, regardless of its current
96
+ * content — the one place blind-overwrite-and-retry semantics are still
97
+ * correct: unpair/cleanup must succeed even without a remembered hash
98
+ * (e.g. in-memory state was lost across a page reload), and "did someone
99
+ * else already overwrite this" isn't a meaningful question when the
100
+ * caller's whole intent is "nothing should be published here anymore".
101
+ * The deployed `joinsessions` collection's `ttl_ms` is an outer backstop,
102
+ * not a substitute for actually clearing on unpair — see the Infra
103
+ * collection's doc comment. Because request and grant now share one
104
+ * address, clearing this slot clears BOTH the original request and any
105
+ * published grant together — there's no way to clear one but keep the
106
+ * other.
107
+ *
108
+ * Deliberately pulls the RAW `client.pull()` result here, not
109
+ * `pullRendezvousDoc` — that function collapses an existing-but-empty doc
110
+ * (`{}`, which is exactly what THIS function itself writes) down to `null`,
111
+ * discarding its real hash. Deriving `baseHash` from that collapsed `null`
112
+ * would push `baseHash: null` against a slot that DOES have a hash — a
113
+ * guaranteed conflict, identically, on every one of the retries below.
114
+ * That made clearing an already-cleared slot (a benign double-unpair, or
115
+ * the very recovery path this package documents: unpair then re-approve)
116
+ * permanently fail. The raw hash exists whether or not the data is
117
+ * "empty", so blind-overwrite-and-retry works correctly in every case.
118
+ *
119
+ * Returns the resulting hash — same shape as `pushRendezvousDoc` — so a
120
+ * caller that legitimately needs to publish again right after clearing
121
+ * (e.g. re-approving the same session) can use it as its next `baseHash`
122
+ * instead of `null`, which would otherwise conflict against the very
123
+ * document this call just wrote. */
124
+ export async function clearRendezvousDoc(client, path) {
125
+ let lastConflict;
126
+ for (let attempt = 0; attempt < MAX_PUSH_RETRIES; attempt++) {
127
+ const current = await client.pull(pullPath(path, {}));
128
+ try {
129
+ return await client.push(pushPath(path, {}), {}, current.hash);
130
+ }
131
+ catch (err) {
132
+ if (!(err instanceof ConflictError))
133
+ throw err;
134
+ lastConflict = err;
135
+ }
136
+ }
137
+ throw new Error(`clearRendezvousDoc: too many baseHash conflicts at ${path}`, { cause: lastConflict });
138
+ }
139
+ //# sourceMappingURL=rendezvous.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rendezvous.js","sourceRoot":"","sources":["../../src/transport/rendezvous.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ import { type NodeEndpoint } from './urls.js';
2
+ /** A node answered, but with a non-2xx status. Carries the status so callers
3
+ * can branch on it (e.g. 501 = the node can't fetch volumes for this
4
+ * exchange) instead of parsing the message. */
5
+ export declare class NodeHttpError extends Error {
6
+ readonly status: number;
7
+ constructor(status: number);
8
+ }
9
+ /** HTTP Basic credentials for a node's REST API: the EVM address is the
10
+ * username (see the node's `CurrentUser` dependency). Only a node paired by an
11
+ * older QR has these — a current pairing code carries the wallet instead of a
12
+ * password, so nothing authenticates on its behalf. */
13
+ export type NodeCredentials = {
14
+ address: string;
15
+ password: string;
16
+ };
17
+ /** Unauthenticated `GET` against a node endpoint, combining an internal
18
+ * timeout with an optional caller `AbortSignal`. Throws `NodeHttpError` on a
19
+ * non-2xx answer. */
20
+ export declare function nodeRequest<T>(node: NodeEndpoint, path: string, options?: {
21
+ signal?: AbortSignal;
22
+ timeoutMs?: number;
23
+ fetch?: typeof fetch;
24
+ }): Promise<T>;
25
+ /** Authenticated call against a node endpoint (`path` is relative to
26
+ * `/api/v1`). Same internal timeout + caller-abort plumbing as `nodeRequest`,
27
+ * and the same `NodeHttpError` on a non-2xx answer. */
28
+ export declare function nodeAuthRequest<T>(node: NodeEndpoint, credentials: NodeCredentials, path: string, options?: {
29
+ method?: string;
30
+ body?: unknown;
31
+ signal?: AbortSignal;
32
+ timeoutMs?: number;
33
+ fetch?: typeof fetch;
34
+ }): Promise<T>;
35
+ //# sourceMappingURL=rest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rest.d.ts","sourceRoot":"","sources":["../../src/transport/rest.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,KAAK,YAAY,EAAE,MAAM,WAAW,CAAA;AAG1D;;gDAEgD;AAChD,qBAAa,aAAc,SAAQ,KAAK;IACtC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;gBACX,MAAM,EAAE,MAAM;CAK3B;AAED;;;wDAGwD;AACxD,MAAM,MAAM,eAAe,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAA;AA8BnE;;sBAEsB;AACtB,wBAAsB,WAAW,CAAC,CAAC,EACjC,IAAI,EAAE,YAAY,EAClB,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,WAAW,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,KAAK,CAAA;CAAO,GAC/E,OAAO,CAAC,CAAC,CAAC,CAEZ;AAED;;wDAEwD;AACxD,wBAAsB,eAAe,CAAC,CAAC,EACrC,IAAI,EAAE,YAAY,EAClB,WAAW,EAAE,eAAe,EAC5B,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,WAAW,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,KAAK,CAAA;CAAO,GAChH,OAAO,CAAC,CAAC,CAAC,CAcZ"}
@@ -0,0 +1,58 @@
1
+ import { nodeBaseUrl } from './urls.js';
2
+ import { EXCHANGES_TIMEOUT_MS } from './constants.js';
3
+ /** A node answered, but with a non-2xx status. Carries the status so callers
4
+ * can branch on it (e.g. 501 = the node can't fetch volumes for this
5
+ * exchange) instead of parsing the message. */
6
+ export class NodeHttpError extends Error {
7
+ status;
8
+ constructor(status) {
9
+ super(`Node request failed: HTTP ${status}`);
10
+ this.name = 'NodeHttpError';
11
+ this.status = status;
12
+ }
13
+ }
14
+ function basicAuthHeader({ address, password }) {
15
+ return `Basic ${btoa(`${address}:${password}`)}`;
16
+ }
17
+ /** Shared timeout/abort plumbing for `nodeRequest`/`nodeAuthRequest`: combines
18
+ * an internal timeout with an optional caller `AbortSignal` into one signal,
19
+ * fetches, and throws `NodeHttpError` on a non-2xx answer. */
20
+ async function fetchNodeJson(node, path, init, options) {
21
+ const fetchImpl = options.fetch ?? globalThis.fetch;
22
+ const internalController = new AbortController();
23
+ const timer = setTimeout(() => internalController.abort(), options.timeoutMs ?? EXCHANGES_TIMEOUT_MS);
24
+ const onCallerAbort = () => internalController.abort();
25
+ if (options.signal)
26
+ options.signal.addEventListener('abort', onCallerAbort);
27
+ try {
28
+ const res = await fetchImpl(`${nodeBaseUrl(node)}${path}`, { ...init, signal: internalController.signal });
29
+ if (!res.ok)
30
+ throw new NodeHttpError(res.status);
31
+ return (await res.json());
32
+ }
33
+ finally {
34
+ clearTimeout(timer);
35
+ if (options.signal)
36
+ options.signal.removeEventListener('abort', onCallerAbort);
37
+ }
38
+ }
39
+ /** Unauthenticated `GET` against a node endpoint, combining an internal
40
+ * timeout with an optional caller `AbortSignal`. Throws `NodeHttpError` on a
41
+ * non-2xx answer. */
42
+ export async function nodeRequest(node, path, options = {}) {
43
+ return fetchNodeJson(node, path, { method: 'GET' }, options);
44
+ }
45
+ /** Authenticated call against a node endpoint (`path` is relative to
46
+ * `/api/v1`). Same internal timeout + caller-abort plumbing as `nodeRequest`,
47
+ * and the same `NodeHttpError` on a non-2xx answer. */
48
+ export async function nodeAuthRequest(node, credentials, path, options = {}) {
49
+ return fetchNodeJson(node, path, {
50
+ method: options.method ?? 'GET',
51
+ headers: {
52
+ Authorization: basicAuthHeader(credentials),
53
+ ...(options.body === undefined ? {} : { 'Content-Type': 'application/json' }),
54
+ },
55
+ body: options.body === undefined ? undefined : JSON.stringify(options.body),
56
+ }, options);
57
+ }
58
+ //# sourceMappingURL=rest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rest.js","sourceRoot":"","sources":["../../src/transport/rest.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAqB,MAAM,WAAW,CAAA;AAC1D,OAAO,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAA;AAErD;;gDAEgD;AAChD,MAAM,OAAO,aAAc,SAAQ,KAAK;IAC7B,MAAM,CAAQ;IACvB,YAAY,MAAc;QACxB,KAAK,CAAC,6BAA6B,MAAM,EAAE,CAAC,CAAA;QAC5C,IAAI,CAAC,IAAI,GAAG,eAAe,CAAA;QAC3B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAA;IACtB,CAAC;CACF;AAQD,SAAS,eAAe,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAmB;IAC7D,OAAO,SAAS,IAAI,CAAC,GAAG,OAAO,IAAI,QAAQ,EAAE,CAAC,EAAE,CAAA;AAClD,CAAC;AAED;;+DAE+D;AAC/D,KAAK,UAAU,aAAa,CAC1B,IAAkB,EAClB,IAAY,EACZ,IAAiB,EACjB,OAA2E;IAE3E,MAAM,SAAS,GAAG,OAAO,CAAC,KAAK,IAAI,UAAU,CAAC,KAAK,CAAA;IACnD,MAAM,kBAAkB,GAAG,IAAI,eAAe,EAAE,CAAA;IAChD,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,kBAAkB,CAAC,KAAK,EAAE,EAAE,OAAO,CAAC,SAAS,IAAI,oBAAoB,CAAC,CAAA;IACrG,MAAM,aAAa,GAAG,GAAG,EAAE,CAAC,kBAAkB,CAAC,KAAK,EAAE,CAAA;IACtD,IAAI,OAAO,CAAC,MAAM;QAAE,OAAO,CAAC,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,aAAa,CAAC,CAAA;IAC3E,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,SAAS,CAAC,GAAG,WAAW,CAAC,IAAI,CAAC,GAAG,IAAI,EAAE,EAAE,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,kBAAkB,CAAC,MAAM,EAAE,CAAC,CAAA;QAC1G,IAAI,CAAC,GAAG,CAAC,EAAE;YAAE,MAAM,IAAI,aAAa,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;QAChD,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAM,CAAA;IAChC,CAAC;YAAS,CAAC;QACT,YAAY,CAAC,KAAK,CAAC,CAAA;QACnB,IAAI,OAAO,CAAC,MAAM;YAAE,OAAO,CAAC,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,aAAa,CAAC,CAAA;IAChF,CAAC;AACH,CAAC;AAED;;sBAEsB;AACtB,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,IAAkB,EAClB,IAAY,EACZ,UAA8E,EAAE;IAEhF,OAAO,aAAa,CAAI,IAAI,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,OAAO,CAAC,CAAA;AACjE,CAAC;AAED;;wDAEwD;AACxD,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,IAAkB,EAClB,WAA4B,EAC5B,IAAY,EACZ,UAA+G,EAAE;IAEjH,OAAO,aAAa,CAClB,IAAI,EACJ,IAAI,EACJ;QACE,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,KAAK;QAC/B,OAAO,EAAE;YACP,aAAa,EAAE,eAAe,CAAC,WAAW,CAAC;YAC3C,GAAG,CAAC,OAAO,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC;SAC9E;QACD,IAAI,EAAE,OAAO,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC;KAC5E,EACD,OAAO,CACR,CAAA;AACH,CAAC"}
@@ -0,0 +1,14 @@
1
+ import { StarfishClient, type StarfishCapProvider } from '@drakkar.software/starfish-client';
2
+ /** Bound every sync request with a timeout: without one, a pull to an
3
+ * offline node hangs for the OS TCP timeout (60s+). */
4
+ export declare function createTimeoutFetch(timeoutMs: number, baseFetch?: typeof fetch): typeof fetch;
5
+ /** A bare `StarfishClient` factory — no cache, no lifecycle. Callers that
6
+ * need per-node client caching (e.g. an offline sync engine juggling
7
+ * several nodes) own that themselves; this just builds one client. */
8
+ export declare function createSyncClient(opts: {
9
+ origin: string;
10
+ capProvider: StarfishCapProvider;
11
+ fetch?: typeof fetch;
12
+ timeoutMs?: number;
13
+ }): StarfishClient;
14
+ //# sourceMappingURL=syncClient.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"syncClient.d.ts","sourceRoot":"","sources":["../../src/transport/syncClient.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,KAAK,mBAAmB,EAAE,MAAM,mCAAmC,CAAA;AAO5F;wDACwD;AACxD,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,GAAE,OAAO,KAAwB,GAAG,OAAO,KAAK,CAU9G;AAED;;uEAEuE;AACvE,wBAAgB,gBAAgB,CAAC,IAAI,EAAE;IACrC,MAAM,EAAE,MAAM,CAAA;IACd,WAAW,EAAE,mBAAmB,CAAA;IAChC,KAAK,CAAC,EAAE,OAAO,KAAK,CAAA;IACpB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,GAAG,cAAc,CAQjB"}
@@ -0,0 +1,30 @@
1
+ import { StarfishClient } from '@drakkar.software/starfish-client';
2
+ import { SYNC_MOUNT_PATH, SYNC_NAMESPACE, SYNC_FETCH_TIMEOUT_MS } from '../crypto/wireConstants.js';
3
+ function buildSyncBaseUrl(origin) {
4
+ return `${origin.replace(/\/$/, '')}/${SYNC_MOUNT_PATH}`;
5
+ }
6
+ /** Bound every sync request with a timeout: without one, a pull to an
7
+ * offline node hangs for the OS TCP timeout (60s+). */
8
+ export function createTimeoutFetch(timeoutMs, baseFetch = globalThis.fetch) {
9
+ return (input, init) => {
10
+ const controller = new AbortController();
11
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
12
+ const callerSignal = init?.signal;
13
+ if (callerSignal)
14
+ callerSignal.addEventListener('abort', () => controller.abort());
15
+ return baseFetch(input, { ...init, signal: controller.signal }).finally(() => clearTimeout(timer));
16
+ };
17
+ }
18
+ /** A bare `StarfishClient` factory — no cache, no lifecycle. Callers that
19
+ * need per-node client caching (e.g. an offline sync engine juggling
20
+ * several nodes) own that themselves; this just builds one client. */
21
+ export function createSyncClient(opts) {
22
+ const baseFetch = opts.fetch ?? globalThis.fetch;
23
+ return new StarfishClient({
24
+ baseUrl: buildSyncBaseUrl(opts.origin),
25
+ namespace: SYNC_NAMESPACE,
26
+ capProvider: opts.capProvider,
27
+ fetch: createTimeoutFetch(opts.timeoutMs ?? SYNC_FETCH_TIMEOUT_MS, baseFetch),
28
+ });
29
+ }
30
+ //# sourceMappingURL=syncClient.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"syncClient.js","sourceRoot":"","sources":["../../src/transport/syncClient.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAA4B,MAAM,mCAAmC,CAAA;AAC5F,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAA;AAEnG,SAAS,gBAAgB,CAAC,MAAc;IACtC,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,eAAe,EAAE,CAAA;AAC1D,CAAC;AAED;wDACwD;AACxD,MAAM,UAAU,kBAAkB,CAAC,SAAiB,EAAE,YAA0B,UAAU,CAAC,KAAK;IAC9F,OAAO,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE;QACrB,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAA;QACxC,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,SAAS,CAAC,CAAA;QAC7D,MAAM,YAAY,GAAI,IAAgC,EAAE,MAAM,CAAA;QAC9D,IAAI,YAAY;YAAE,YAAY,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC,CAAA;QAClF,OAAO,SAAS,CAAC,KAAK,EAAE,EAAE,GAAI,IAAoB,EAAE,MAAM,EAAE,UAAU,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,CAC5F,YAAY,CAAC,KAAK,CAAC,CACpB,CAAA;IACH,CAAC,CAAA;AACH,CAAC;AAED;;uEAEuE;AACvE,MAAM,UAAU,gBAAgB,CAAC,IAKhC;IACC,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,IAAI,UAAU,CAAC,KAAK,CAAA;IAChD,OAAO,IAAI,cAAc,CAAC;QACxB,OAAO,EAAE,gBAAgB,CAAC,IAAI,CAAC,MAAM,CAAC;QACtC,SAAS,EAAE,cAAc;QACzB,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,KAAK,EAAE,kBAAkB,CAAC,IAAI,CAAC,SAAS,IAAI,qBAAqB,EAAE,SAAS,CAAC;KAC9E,CAAC,CAAA;AACJ,CAAC"}
@@ -0,0 +1,35 @@
1
+ /** The minimal address triple every node-facing call needs. Deliberately
2
+ * structural (not the caller's own "list of paired nodes" document type) —
3
+ * any `{ host, port, secure? }` works. */
4
+ export type NodeEndpoint = {
5
+ host: string;
6
+ port: number;
7
+ secure?: boolean;
8
+ };
9
+ export declare function nodeBaseUrl(node: NodeEndpoint): string;
10
+ export type NodeAddressSpace = 'loopback' | 'local' | 'public';
11
+ /** Parse a user-typed host string into a canonical { host, port, secure } triple.
12
+ * Accepts: `host`, `host:port`, `http://host:port`, `https://host`, `[::1]:5001`.
13
+ * A scheme is kept (drives `secure` and the scheme-derived default port below);
14
+ * no scheme falls back to `defaultPort` (plain HTTP), preserving legacy local-node
15
+ * behavior. Returns null on empty input or an out-of-range port. */
16
+ export declare function parseHostInput(raw: string, defaultPort?: number): {
17
+ host: string;
18
+ port: number;
19
+ secure: boolean;
20
+ } | null;
21
+ /** Inverse of {@link parseHostInput}: rebuild the editable host/port strings from a stored
22
+ * { host, port, secure } triple so that re-parsing them yields the same triple. The scheme
23
+ * is folded into the host field (there is no separate scheme control) and the port is left
24
+ * blank when it equals the scheme's implicit default (443 for https, 80 for http). */
25
+ export declare function formatHostInput(node: NodeEndpoint): {
26
+ host: string;
27
+ port: string;
28
+ };
29
+ /** Which IP address space a host belongs to, decided from the string alone — no
30
+ * DNS lookup, because the browsers that care about this decide the same way and
31
+ * at the same moment (before resolving). `public` therefore means "not knowable
32
+ * from the hostname", not "definitely on the internet": a DNS name pointing at a
33
+ * LAN box lands here, exactly as it does in Chrome. */
34
+ export declare function classifyAddressSpace(host: string): NodeAddressSpace;
35
+ //# sourceMappingURL=urls.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"urls.d.ts","sourceRoot":"","sources":["../../src/transport/urls.ts"],"names":[],"mappings":"AAEA;;2CAE2C;AAC3C,MAAM,MAAM,YAAY,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,CAAA;AAE3E,wBAAgB,WAAW,CAAC,IAAI,EAAE,YAAY,GAAG,MAAM,CAEtD;AAED,MAAM,MAAM,gBAAgB,GAAG,UAAU,GAAG,OAAO,GAAG,QAAQ,CAAA;AAI9D;;;;qEAIqE;AACrE,wBAAgB,cAAc,CAC5B,GAAG,EAAE,MAAM,EACX,WAAW,SAAoB,GAC9B;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,OAAO,CAAA;CAAE,GAAG,IAAI,CA+CxD;AAED;;;uFAGuF;AACvF,wBAAgB,eAAe,CAAC,IAAI,EAAE,YAAY,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAQlF;AAED;;;;wDAIwD;AACxD,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,gBAAgB,CAoCnE"}
@@ -0,0 +1,126 @@
1
+ import { API_PREFIX, DEFAULT_NODE_PORT } from './constants.js';
2
+ export function nodeBaseUrl(node) {
3
+ return `${node.secure ? 'https' : 'http'}://${node.host}:${node.port}${API_PREFIX}`;
4
+ }
5
+ const IPV4 = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/;
6
+ /** Parse a user-typed host string into a canonical { host, port, secure } triple.
7
+ * Accepts: `host`, `host:port`, `http://host:port`, `https://host`, `[::1]:5001`.
8
+ * A scheme is kept (drives `secure` and the scheme-derived default port below);
9
+ * no scheme falls back to `defaultPort` (plain HTTP), preserving legacy local-node
10
+ * behavior. Returns null on empty input or an out-of-range port. */
11
+ export function parseHostInput(raw, defaultPort = DEFAULT_NODE_PORT) {
12
+ const trimmed = raw.trim();
13
+ if (!trimmed)
14
+ return null;
15
+ // Detect + strip scheme
16
+ const schemeMatch = trimmed.match(/^(https?):\/\//i);
17
+ const secure = schemeMatch ? schemeMatch[1].toLowerCase() === 'https' : false;
18
+ const withoutScheme = trimmed.replace(/^https?:\/\//i, '');
19
+ // Strip trailing slashes and path
20
+ const withoutPath = withoutScheme.split('/')[0];
21
+ // Scheme present but no explicit port → the scheme's own default port
22
+ // (80/443); no scheme at all → the caller's local-node default.
23
+ const schemeDefaultPort = schemeMatch ? (secure ? 443 : 80) : defaultPort;
24
+ let host;
25
+ let port;
26
+ // IPv6 with brackets: [::1] or [::1]:5001
27
+ const ipv6Match = withoutPath.match(/^\[([^\]]+)\](?::(\d+))?$/);
28
+ if (ipv6Match) {
29
+ host = `[${ipv6Match[1]}]`;
30
+ port = ipv6Match[2] ? parseInt(ipv6Match[2], 10) : schemeDefaultPort;
31
+ }
32
+ else {
33
+ // host or host:port
34
+ const lastColon = withoutPath.lastIndexOf(':');
35
+ if (lastColon !== -1) {
36
+ const maybePart = withoutPath.slice(lastColon + 1);
37
+ if (/^\d+$/.test(maybePart)) {
38
+ // Explicit port number
39
+ host = withoutPath.slice(0, lastColon);
40
+ port = parseInt(maybePart, 10);
41
+ }
42
+ else if (maybePart.length > 0) {
43
+ // Non-empty, non-numeric after colon → invalid port spec
44
+ return null;
45
+ }
46
+ else {
47
+ host = withoutPath;
48
+ port = schemeDefaultPort;
49
+ }
50
+ }
51
+ else {
52
+ host = withoutPath;
53
+ port = schemeDefaultPort;
54
+ }
55
+ }
56
+ if (!host || port < 1 || port > 65535 || isNaN(port))
57
+ return null;
58
+ return { host, port, secure };
59
+ }
60
+ /** Inverse of {@link parseHostInput}: rebuild the editable host/port strings from a stored
61
+ * { host, port, secure } triple so that re-parsing them yields the same triple. The scheme
62
+ * is folded into the host field (there is no separate scheme control) and the port is left
63
+ * blank when it equals the scheme's implicit default (443 for https, 80 for http). */
64
+ export function formatHostInput(node) {
65
+ const secure = !!node.secure;
66
+ const schemeDefault = secure ? 443 : 80;
67
+ const scheme = secure ? 'https://' : node.port === 80 ? 'http://' : '';
68
+ return {
69
+ host: `${scheme}${node.host}`,
70
+ port: node.port === schemeDefault ? '' : String(node.port),
71
+ };
72
+ }
73
+ /** Which IP address space a host belongs to, decided from the string alone — no
74
+ * DNS lookup, because the browsers that care about this decide the same way and
75
+ * at the same moment (before resolving). `public` therefore means "not knowable
76
+ * from the hostname", not "definitely on the internet": a DNS name pointing at a
77
+ * LAN box lands here, exactly as it does in Chrome. */
78
+ export function classifyAddressSpace(host) {
79
+ // A trailing dot is the DNS root and does not change what the name refers to.
80
+ const trimmed = host.trim().toLowerCase().replace(/\.$/, '');
81
+ if (!trimmed)
82
+ return 'public';
83
+ // IPv6, bracketed (`[::1]`, the form parseHostInput keeps) or bare.
84
+ if (trimmed.startsWith('[') || trimmed.includes(':')) {
85
+ const v6 = trimmed.replace(/^\[/, '').replace(/\]$/, '').split('%')[0];
86
+ if (v6 === '::1')
87
+ return 'loopback';
88
+ // IPv4-mapped (`::ffff:127.0.0.1`) inherits the mapped address's own space.
89
+ const mapped = v6.match(/^::ffff:(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})$/);
90
+ if (mapped)
91
+ return classifyAddressSpace(mapped[1]);
92
+ if (/^f[cd][0-9a-f]{2}:/.test(v6))
93
+ return 'local'; // fc00::/7 unique-local
94
+ if (/^fe[89ab][0-9a-f]:/.test(v6))
95
+ return 'local'; // fe80::/10 link-local
96
+ return 'public';
97
+ }
98
+ const v4 = trimmed.match(IPV4);
99
+ if (v4) {
100
+ const octets = v4.slice(1, 5).map(Number);
101
+ // Out-of-range octets aren't an address literal at all; a browser would try
102
+ // to resolve the string as a name, so classify it the way a name is.
103
+ if (octets.some((o) => o > 255))
104
+ return 'public';
105
+ const [a, b] = octets;
106
+ if (a === 127)
107
+ return 'loopback';
108
+ if (a === 10)
109
+ return 'local';
110
+ if (a === 192 && b === 168)
111
+ return 'local';
112
+ if (a === 172 && b >= 16 && b <= 31)
113
+ return 'local';
114
+ if (a === 100 && b >= 64 && b <= 127)
115
+ return 'local'; // carrier-grade NAT
116
+ if (a === 169 && b === 254)
117
+ return 'local'; // link-local
118
+ return 'public';
119
+ }
120
+ if (trimmed === 'localhost' || trimmed.endsWith('.localhost'))
121
+ return 'loopback';
122
+ if (trimmed.endsWith('.local'))
123
+ return 'local'; // mDNS
124
+ return 'public';
125
+ }
126
+ //# sourceMappingURL=urls.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"urls.js","sourceRoot":"","sources":["../../src/transport/urls.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AAO9D,MAAM,UAAU,WAAW,CAAC,IAAkB;IAC5C,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,MAAM,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,GAAG,UAAU,EAAE,CAAA;AACrF,CAAC;AAID,MAAM,IAAI,GAAG,8CAA8C,CAAA;AAE3D;;;;qEAIqE;AACrE,MAAM,UAAU,cAAc,CAC5B,GAAW,EACX,WAAW,GAAG,iBAAiB;IAE/B,MAAM,OAAO,GAAG,GAAG,CAAC,IAAI,EAAE,CAAA;IAC1B,IAAI,CAAC,OAAO;QAAE,OAAO,IAAI,CAAA;IAEzB,wBAAwB;IACxB,MAAM,WAAW,GAAG,OAAO,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAA;IACpD,MAAM,MAAM,GAAG,WAAW,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,KAAK,OAAO,CAAC,CAAC,CAAC,KAAK,CAAA;IAC7E,MAAM,aAAa,GAAG,OAAO,CAAC,OAAO,CAAC,eAAe,EAAE,EAAE,CAAC,CAAA;IAC1D,kCAAkC;IAClC,MAAM,WAAW,GAAG,aAAa,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAA;IAC/C,sEAAsE;IACtE,gEAAgE;IAChE,MAAM,iBAAiB,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,WAAW,CAAA;IAEzE,IAAI,IAAY,CAAA;IAChB,IAAI,IAAY,CAAA;IAEhB,0CAA0C;IAC1C,MAAM,SAAS,GAAG,WAAW,CAAC,KAAK,CAAC,2BAA2B,CAAC,CAAA;IAChE,IAAI,SAAS,EAAE,CAAC;QACd,IAAI,GAAG,IAAI,SAAS,CAAC,CAAC,CAAC,GAAG,CAAA;QAC1B,IAAI,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,iBAAiB,CAAA;IACtE,CAAC;SAAM,CAAC;QACN,oBAAoB;QACpB,MAAM,SAAS,GAAG,WAAW,CAAC,WAAW,CAAC,GAAG,CAAC,CAAA;QAC9C,IAAI,SAAS,KAAK,CAAC,CAAC,EAAE,CAAC;YACrB,MAAM,SAAS,GAAG,WAAW,CAAC,KAAK,CAAC,SAAS,GAAG,CAAC,CAAC,CAAA;YAClD,IAAI,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;gBAC5B,uBAAuB;gBACvB,IAAI,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC,CAAA;gBACtC,IAAI,GAAG,QAAQ,CAAC,SAAS,EAAE,EAAE,CAAC,CAAA;YAChC,CAAC;iBAAM,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAChC,yDAAyD;gBACzD,OAAO,IAAI,CAAA;YACb,CAAC;iBAAM,CAAC;gBACN,IAAI,GAAG,WAAW,CAAA;gBAClB,IAAI,GAAG,iBAAiB,CAAA;YAC1B,CAAC;QACH,CAAC;aAAM,CAAC;YACN,IAAI,GAAG,WAAW,CAAA;YAClB,IAAI,GAAG,iBAAiB,CAAA;QAC1B,CAAC;IACH,CAAC;IAED,IAAI,CAAC,IAAI,IAAI,IAAI,GAAG,CAAC,IAAI,IAAI,GAAG,KAAK,IAAI,KAAK,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAA;IAEjE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,CAAA;AAC/B,CAAC;AAED;;;uFAGuF;AACvF,MAAM,UAAU,eAAe,CAAC,IAAkB;IAChD,MAAM,MAAM,GAAG,CAAC,CAAC,IAAI,CAAC,MAAM,CAAA;IAC5B,MAAM,aAAa,GAAG,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAA;IACvC,MAAM,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAA;IACtE,OAAO;QACL,IAAI,EAAE,GAAG,MAAM,GAAG,IAAI,CAAC,IAAI,EAAE;QAC7B,IAAI,EAAE,IAAI,CAAC,IAAI,KAAK,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC;KAC3D,CAAA;AACH,CAAC;AAED;;;;wDAIwD;AACxD,MAAM,UAAU,oBAAoB,CAAC,IAAY;IAC/C,8EAA8E;IAC9E,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAA;IAC5D,IAAI,CAAC,OAAO;QAAE,OAAO,QAAQ,CAAA;IAE7B,oEAAoE;IACpE,IAAI,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QACrD,MAAM,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAA;QACtE,IAAI,EAAE,KAAK,KAAK;YAAE,OAAO,UAAU,CAAA;QACnC,4EAA4E;QAC5E,MAAM,MAAM,GAAG,EAAE,CAAC,KAAK,CAAC,+CAA+C,CAAC,CAAA;QACxE,IAAI,MAAM;YAAE,OAAO,oBAAoB,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAA;QAClD,IAAI,oBAAoB,CAAC,IAAI,CAAC,EAAE,CAAC;YAAE,OAAO,OAAO,CAAA,CAAC,wBAAwB;QAC1E,IAAI,oBAAoB,CAAC,IAAI,CAAC,EAAE,CAAC;YAAE,OAAO,OAAO,CAAA,CAAC,uBAAuB;QACzE,OAAO,QAAQ,CAAA;IACjB,CAAC;IAED,MAAM,EAAE,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;IAC9B,IAAI,EAAE,EAAE,CAAC;QACP,MAAM,MAAM,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;QACzC,4EAA4E;QAC5E,qEAAqE;QACrE,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,GAAG,CAAC;YAAE,OAAO,QAAQ,CAAA;QAChD,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,MAAM,CAAA;QACrB,IAAI,CAAC,KAAK,GAAG;YAAE,OAAO,UAAU,CAAA;QAChC,IAAI,CAAC,KAAK,EAAE;YAAE,OAAO,OAAO,CAAA;QAC5B,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,GAAG;YAAE,OAAO,OAAO,CAAA;QAC1C,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE;YAAE,OAAO,OAAO,CAAA;QACnD,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,GAAG;YAAE,OAAO,OAAO,CAAA,CAAC,oBAAoB;QACzE,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,GAAG;YAAE,OAAO,OAAO,CAAA,CAAC,aAAa;QACxD,OAAO,QAAQ,CAAA;IACjB,CAAC;IAED,IAAI,OAAO,KAAK,WAAW,IAAI,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC;QAAE,OAAO,UAAU,CAAA;IAChF,IAAI,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC;QAAE,OAAO,OAAO,CAAA,CAAC,OAAO;IACtD,OAAO,QAAQ,CAAA;AACjB,CAAC"}