@floegence/flowersec-core 0.26.0 → 2.0.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 (270) hide show
  1. package/README.md +91 -22
  2. package/THIRD_PARTY_NOTICES.md +141 -0
  3. package/dist/browser/connectSession.d.ts +13 -0
  4. package/dist/browser/connectSession.js +40 -0
  5. package/dist/browser/index.d.ts +3 -10
  6. package/dist/browser/index.js +2 -5
  7. package/dist/browser/runtimeCapability.d.ts +13 -0
  8. package/dist/browser/runtimeCapability.js +27 -0
  9. package/dist/browser/sessionRuntime.d.ts +2 -0
  10. package/dist/browser/sessionRuntime.js +21 -0
  11. package/dist/browser/webTransportClient.d.ts +8 -0
  12. package/dist/browser/webTransportClient.js +55 -0
  13. package/dist/cli.d.ts +2 -0
  14. package/dist/cli.js +126 -0
  15. package/dist/cliSpendMarker.d.ts +1 -0
  16. package/dist/cliSpendMarker.js +22 -0
  17. package/dist/connectionController.d.ts +54 -0
  18. package/dist/connectionController.js +438 -0
  19. package/dist/connector/adapters/webSocketCandidate.d.ts +7 -0
  20. package/dist/connector/adapters/webSocketCandidate.js +116 -0
  21. package/dist/connector/adapters/webTransportCandidate.d.ts +5 -0
  22. package/dist/connector/adapters/webTransportCandidate.js +73 -0
  23. package/dist/connector/admissionCommit.d.ts +31 -0
  24. package/dist/connector/admissionCommit.js +239 -0
  25. package/dist/connector/sessionAcceptor.d.ts +16 -0
  26. package/dist/connector/sessionAcceptor.js +114 -0
  27. package/dist/connector/sessionConfig.d.ts +3 -0
  28. package/dist/connector/sessionConfig.js +30 -0
  29. package/dist/connector/sessionConnector.d.ts +45 -0
  30. package/dist/connector/sessionConnector.js +603 -0
  31. package/dist/defaults.d.ts +7 -7
  32. package/dist/defaults.js +7 -7
  33. package/dist/facade.d.ts +12 -30
  34. package/dist/facade.js +6 -30
  35. package/dist/node/connectSession.d.ts +21 -0
  36. package/dist/node/connectSession.js +62 -0
  37. package/dist/node/index.d.ts +3 -11
  38. package/dist/node/index.js +2 -8
  39. package/dist/node/runtimeCapability.d.ts +7 -0
  40. package/dist/node/runtimeCapability.js +10 -0
  41. package/dist/node/sessionRuntime.d.ts +2 -0
  42. package/dist/node/sessionRuntime.js +13 -0
  43. package/dist/node/webTransportClient.d.ts +9 -0
  44. package/dist/node/webTransportClient.js +56 -0
  45. package/dist/node/webTransportServer.d.ts +22 -0
  46. package/dist/node/webTransportServer.js +100 -0
  47. package/dist/node/wsFactory.d.ts +3 -1
  48. package/dist/node/wsFactory.js +4 -3
  49. package/dist/proxy/controllerGuard.d.ts +4 -4
  50. package/dist/proxy/controllerGuard.js +83 -177
  51. package/dist/proxy/disableUpstreamServiceWorkerRegister.d.ts +3 -1
  52. package/dist/proxy/disableUpstreamServiceWorkerRegister.js +19 -17
  53. package/dist/proxy/index.d.ts +16 -15
  54. package/dist/proxy/index.js +8 -14
  55. package/dist/proxy/integration.d.ts +23 -71
  56. package/dist/proxy/integration.js +37 -340
  57. package/dist/proxy/registerServiceWorker.d.ts +1 -10
  58. package/dist/proxy/registerServiceWorker.js +43 -105
  59. package/dist/proxy/runtime.d.ts +3 -63
  60. package/dist/proxy/runtime.js +349 -462
  61. package/dist/proxy/scope.d.ts +6 -0
  62. package/dist/proxy/scope.js +131 -0
  63. package/dist/proxy/serviceWorker.d.ts +5 -16
  64. package/dist/proxy/serviceWorker.js +230 -617
  65. package/dist/proxy/stream.d.ts +9 -0
  66. package/dist/proxy/stream.js +40 -0
  67. package/dist/proxy/types.d.ts +78 -30
  68. package/dist/proxy/windowBridge.d.ts +61 -0
  69. package/dist/proxy/windowBridge.js +344 -0
  70. package/dist/proxy/wsPatch.d.ts +4 -14
  71. package/dist/proxy/wsPatch.js +173 -268
  72. package/dist/public/artifact.d.ts +11 -0
  73. package/dist/public/artifact.js +44 -0
  74. package/dist/public/artifactLease.d.ts +10 -0
  75. package/dist/public/artifactLease.js +48 -0
  76. package/dist/public/connectError.d.ts +6 -0
  77. package/dist/public/connectError.js +9 -0
  78. package/dist/public/contract.d.ts +83 -0
  79. package/dist/public/contract.js +17 -0
  80. package/dist/public/streamMetadata.d.ts +10 -0
  81. package/dist/public/streamMetadata.js +40 -0
  82. package/dist/rpc/caller.d.ts +1 -1
  83. package/dist/rpc/client.d.ts +1 -4
  84. package/dist/rpc/client.js +0 -21
  85. package/dist/rpc/rpcProxy.d.ts +1 -1
  86. package/dist/rpc/server.d.ts +1 -1
  87. package/dist/rpc/validate.d.ts +1 -1
  88. package/dist/rpc/wire.d.ts +15 -0
  89. package/dist/runtime/errors.d.ts +6 -0
  90. package/dist/runtime/errors.js +10 -0
  91. package/dist/transport/webSocketAdapter.d.ts +24 -0
  92. package/dist/transport/webSocketAdapter.js +234 -0
  93. package/dist/transport/webTransportAdapter.d.ts +27 -0
  94. package/dist/transport/webTransportAdapter.js +519 -0
  95. package/dist/utils/errors.d.ts +2 -20
  96. package/dist/utils/errors.js +73 -20
  97. package/dist/v2/admissionError.d.ts +4 -0
  98. package/dist/v2/admissionError.js +8 -0
  99. package/dist/v2/artifact.d.ts +128 -0
  100. package/dist/v2/artifact.js +1126 -0
  101. package/dist/v2/artifactLease.d.ts +1 -0
  102. package/dist/v2/artifactLease.js +7 -0
  103. package/dist/v2/capability.d.ts +29 -0
  104. package/dist/v2/capability.js +190 -0
  105. package/dist/v2/carrier.d.ts +79 -0
  106. package/dist/v2/carrier.js +405 -0
  107. package/dist/v2/contract.d.ts +37 -0
  108. package/dist/v2/contract.js +1 -0
  109. package/dist/v2/handshake.d.ts +80 -0
  110. package/dist/v2/handshake.js +470 -0
  111. package/dist/v2/opaqueArtifact.d.ts +1 -0
  112. package/dist/v2/opaqueArtifact.js +2 -0
  113. package/dist/v2/protocol.d.ts +99 -0
  114. package/dist/v2/protocol.js +739 -0
  115. package/dist/v2/publicSession.d.ts +1 -0
  116. package/dist/v2/publicSession.js +179 -0
  117. package/dist/v2/retryDisposition.d.ts +16 -0
  118. package/dist/v2/retryDisposition.js +30 -0
  119. package/dist/v2/session.d.ts +277 -0
  120. package/dist/v2/session.js +1879 -0
  121. package/dist/v2/streamLifetimeLedger.d.ts +31 -0
  122. package/dist/v2/streamLifetimeLedger.js +131 -0
  123. package/dist/v2/streamMetadata.d.ts +1 -0
  124. package/dist/v2/streamMetadata.js +7 -0
  125. package/dist/v2/unreliableMessage.d.ts +43 -0
  126. package/dist/v2/unreliableMessage.js +252 -0
  127. package/dist/vendor/tr46.d.ts +10 -0
  128. package/dist/vendor/tr46.js +501 -0
  129. package/dist/ws-client/binaryTransport.d.ts +0 -3
  130. package/dist/ws-client/binaryTransport.js +15 -39
  131. package/dist/yamux/errors.d.ts +0 -4
  132. package/dist/yamux/errors.js +0 -9
  133. package/dist/yamux/session.d.ts +0 -5
  134. package/dist/yamux/session.js +4 -70
  135. package/dist/yamux/stream.d.ts +1 -0
  136. package/dist/yamux/stream.js +4 -0
  137. package/package.json +29 -83
  138. package/sbom/cyclonedx.json +2764 -0
  139. package/sbom/spdx.json +1947 -0
  140. package/YAMUX_ALIGNMENT.md +0 -127
  141. package/dist/_examples/flowersec/demo/v1.facade.gen.d.ts +0 -12
  142. package/dist/_examples/flowersec/demo/v1.facade.gen.js +0 -15
  143. package/dist/_examples/flowersec/demo/v1.gen.d.ts +0 -16
  144. package/dist/_examples/flowersec/demo/v1.gen.js +0 -86
  145. package/dist/_examples/flowersec/demo/v1.rpc.gen.d.ts +0 -11
  146. package/dist/_examples/flowersec/demo/v1.rpc.gen.js +0 -22
  147. package/dist/browser/connect.d.ts +0 -12
  148. package/dist/browser/connect.js +0 -31
  149. package/dist/browser/controlplane.d.ts +0 -15
  150. package/dist/browser/controlplane.js +0 -64
  151. package/dist/browser/reconnectConfig.d.ts +0 -15
  152. package/dist/browser/reconnectConfig.js +0 -20
  153. package/dist/client-connect/common.d.ts +0 -26
  154. package/dist/client-connect/common.js +0 -167
  155. package/dist/client-connect/connectCore.d.ts +0 -61
  156. package/dist/client-connect/connectCore.js +0 -572
  157. package/dist/client-connect/contract.d.ts +0 -8
  158. package/dist/client-connect/contract.js +0 -51
  159. package/dist/client-connect/termination.d.ts +0 -6
  160. package/dist/client-connect/termination.js +0 -7
  161. package/dist/client-connect/transportSecurity.d.ts +0 -27
  162. package/dist/client-connect/transportSecurity.js +0 -199
  163. package/dist/client-connect/tunnelAttachCloseReason.d.ts +0 -3
  164. package/dist/client-connect/tunnelAttachCloseReason.js +0 -23
  165. package/dist/client.d.ts +0 -23
  166. package/dist/connect/artifact.d.ts +0 -37
  167. package/dist/connect/artifact.js +0 -217
  168. package/dist/connect/internalNormalize.d.ts +0 -22
  169. package/dist/connect/internalNormalize.js +0 -173
  170. package/dist/controlplane/channelInit.d.ts +0 -27
  171. package/dist/controlplane/channelInit.js +0 -116
  172. package/dist/controlplane/http.d.ts +0 -16
  173. package/dist/controlplane/http.js +0 -59
  174. package/dist/controlplane/index.d.ts +0 -6
  175. package/dist/controlplane/index.js +0 -5
  176. package/dist/controlplane/issuer.d.ts +0 -18
  177. package/dist/controlplane/issuer.js +0 -113
  178. package/dist/controlplane/request.d.ts +0 -51
  179. package/dist/controlplane/request.js +0 -273
  180. package/dist/controlplane/token.d.ts +0 -33
  181. package/dist/controlplane/token.js +0 -119
  182. package/dist/direct-client/connect.d.ts +0 -9
  183. package/dist/direct-client/connect.js +0 -90
  184. package/dist/direct-client/index.d.ts +0 -1
  185. package/dist/direct-client/index.js +0 -1
  186. package/dist/e2ee/constants.d.ts +0 -9
  187. package/dist/e2ee/constants.js +0 -18
  188. package/dist/e2ee/errors.d.ts +0 -5
  189. package/dist/e2ee/errors.js +0 -8
  190. package/dist/e2ee/framing.d.ts +0 -12
  191. package/dist/e2ee/framing.js +0 -57
  192. package/dist/e2ee/handshake.d.ts +0 -88
  193. package/dist/e2ee/handshake.js +0 -353
  194. package/dist/e2ee/index.d.ts +0 -7
  195. package/dist/e2ee/index.js +0 -7
  196. package/dist/e2ee/kdf.d.ts +0 -15
  197. package/dist/e2ee/kdf.js +0 -39
  198. package/dist/e2ee/record.d.ts +0 -11
  199. package/dist/e2ee/record.js +0 -76
  200. package/dist/e2ee/secureChannel.d.ts +0 -92
  201. package/dist/e2ee/secureChannel.js +0 -328
  202. package/dist/e2ee/transcript.d.ts +0 -23
  203. package/dist/e2ee/transcript.js +0 -31
  204. package/dist/endpoint/index.d.ts +0 -84
  205. package/dist/endpoint/index.js +0 -557
  206. package/dist/endpoint/node.d.ts +0 -9
  207. package/dist/endpoint/node.js +0 -51
  208. package/dist/gen/flowersec/controlplane/v1.gen.d.ts +0 -36
  209. package/dist/gen/flowersec/controlplane/v1.gen.js +0 -135
  210. package/dist/gen/flowersec/direct/v1.gen.d.ts +0 -21
  211. package/dist/gen/flowersec/direct/v1.gen.js +0 -101
  212. package/dist/gen/flowersec/e2ee/v1.gen.d.ts +0 -68
  213. package/dist/gen/flowersec/e2ee/v1.gen.js +0 -194
  214. package/dist/gen/flowersec/rpc/v1.gen.d.ts +0 -30
  215. package/dist/gen/flowersec/rpc/v1.gen.js +0 -107
  216. package/dist/gen/flowersec/tunnel/v1.gen.d.ts +0 -23
  217. package/dist/gen/flowersec/tunnel/v1.gen.js +0 -104
  218. package/dist/index.d.ts +0 -22
  219. package/dist/index.js +0 -22
  220. package/dist/node/connect.d.ts +0 -12
  221. package/dist/node/connect.js +0 -29
  222. package/dist/node/reconnectConfig.d.ts +0 -16
  223. package/dist/node/reconnectConfig.js +0 -20
  224. package/dist/observability/index.d.ts +0 -1
  225. package/dist/observability/index.js +0 -1
  226. package/dist/observability/observer.d.ts +0 -52
  227. package/dist/observability/observer.js +0 -314
  228. package/dist/proxy/appWindow.d.ts +0 -37
  229. package/dist/proxy/appWindow.js +0 -273
  230. package/dist/proxy/bootstrap.d.ts +0 -35
  231. package/dist/proxy/bootstrap.js +0 -119
  232. package/dist/proxy/constants.d.ts +0 -7
  233. package/dist/proxy/constants.js +0 -8
  234. package/dist/proxy/controllerWindow.d.ts +0 -12
  235. package/dist/proxy/controllerWindow.js +0 -384
  236. package/dist/proxy/cookieJar.d.ts +0 -7
  237. package/dist/proxy/cookieJar.js +0 -136
  238. package/dist/proxy/headerPolicy.d.ts +0 -14
  239. package/dist/proxy/headerPolicy.js +0 -134
  240. package/dist/proxy/portStream.d.ts +0 -5
  241. package/dist/proxy/portStream.js +0 -256
  242. package/dist/proxy/preset.d.ts +0 -29
  243. package/dist/proxy/preset.js +0 -111
  244. package/dist/proxy/runtimeScope.d.ts +0 -57
  245. package/dist/proxy/runtimeScope.js +0 -218
  246. package/dist/proxy/server.d.ts +0 -28
  247. package/dist/proxy/server.js +0 -833
  248. package/dist/proxy/windowBridgeProtocol.d.ts +0 -65
  249. package/dist/proxy/windowBridgeProtocol.js +0 -11
  250. package/dist/reconnect/artifactControlplane.d.ts +0 -16
  251. package/dist/reconnect/artifactControlplane.js +0 -35
  252. package/dist/reconnect/index.d.ts +0 -36
  253. package/dist/reconnect/index.js +0 -388
  254. package/dist/rpc-proxy/index.d.ts +0 -1
  255. package/dist/rpc-proxy/index.js +0 -1
  256. package/dist/rpc-proxy/rpcProxy.d.ts +0 -1
  257. package/dist/rpc-proxy/rpcProxy.js +0 -1
  258. package/dist/streamhello/index.d.ts +0 -1
  259. package/dist/streamhello/index.js +0 -1
  260. package/dist/streamhello/streamHello.d.ts +0 -3
  261. package/dist/streamhello/streamHello.js +0 -13
  262. package/dist/streamio/index.d.ts +0 -32
  263. package/dist/streamio/index.js +0 -87
  264. package/dist/tunnel-client/connect.d.ts +0 -9
  265. package/dist/tunnel-client/connect.js +0 -157
  266. package/dist/tunnel-client/index.d.ts +0 -1
  267. package/dist/tunnel-client/index.js +0 -1
  268. package/dist/ws/index.d.ts +0 -1
  269. package/dist/ws/index.js +0 -1
  270. /package/dist/{client.js → rpc/wire.js} +0 -0
@@ -1,127 +0,0 @@
1
- # TS Yamux Alignment Status
2
-
3
- This repository contains a TypeScript implementation of the Yamux protocol in `flowersec-ts/src/yamux/`.
4
- It is designed to be interoperable with HashiCorp's Yamux (protocol version `0`) for the subset of
5
- features required by Flowersec: multiplexing multiple logical byte streams over a single encrypted
6
- transport.
7
-
8
- ## What “aligned” means here
9
-
10
- “Aligned” in this document means:
11
-
12
- - **Wire compatibility**: our frames can be understood by `github.com/hashicorp/yamux` and vice versa.
13
- - **Behavioral compatibility (subset)**: stream open/accept, data transfer, and basic flow control work
14
- correctly when interoperating with HashiCorp Yamux.
15
- - **Not a full spec clone**: some Yamux behaviors are intentionally simplified or currently unimplemented.
16
-
17
- ## Implemented protocol surface (TS)
18
-
19
- Source: `flowersec-ts/src/yamux/constants.ts`, `flowersec-ts/src/yamux/header.ts`, `flowersec-ts/src/yamux/session.ts`, `flowersec-ts/src/yamux/stream.ts`.
20
-
21
- ### Header & framing
22
-
23
- - 12-byte header (`HEADER_LEN=12`) with:
24
- - `version: u8`
25
- - `type: u8`
26
- - `flags: u16` (big-endian)
27
- - `stream_id: u32` (big-endian)
28
- - `length: u32` (big-endian)
29
- - Supported `version`: `0` (`YAMUX_VERSION=0`).
30
- - Unknown `type` or invalid `version` causes session close (strict).
31
-
32
- ### Frame types & flags
33
-
34
- - Types: `DATA(0)`, `WINDOW_UPDATE(1)`, `PING(2)`, `GO_AWAY(3)` (`flowersec-ts/src/yamux/constants.ts`).
35
- - Flags: `SYN(1)`, `ACK(2)`, `FIN(4)`, `RST(8)`.
36
-
37
- ### Stream IDs
38
-
39
- - Client opens **odd** stream IDs, server opens **even** stream IDs:
40
- - `opts.client=true` starts at `1`, step `+2`
41
- - `opts.client=false` starts at `2`, step `+2`
42
- - (`flowersec-ts/src/yamux/session.ts`)
43
-
44
- ### Stream open handshake
45
-
46
- - Opening a stream starts by sending a `WINDOW_UPDATE` with `SYN` (length may be `0`).
47
- - Peer creates the stream when it receives `SYN` on either `DATA` or `WINDOW_UPDATE`.
48
- - The peer responds with a `WINDOW_UPDATE` carrying `ACK`, moving both sides into “established”.
49
-
50
- ### Flow control (per-stream windows)
51
-
52
- - Default per-stream max window: `256 KiB` (`DEFAULT_MAX_STREAM_WINDOW=256*1024`).
53
- - Each stream maintains:
54
- - `recvWindow`: decremented by received `DATA` length; receiving beyond window triggers `RST`.
55
- - `sendWindow`: incremented by `WINDOW_UPDATE` deltas; writing waits if `sendWindow<=0`.
56
- - `WINDOW_UPDATE` generation strategy:
57
- - Always send for SYN/ACK transitions.
58
- - Otherwise, send when replenishment delta reaches at least half the max window.
59
-
60
- ### FIN/RST semantics
61
-
62
- - Local close sends a `WINDOW_UPDATE` with `FIN`.
63
- - Receiving `FIN` transitions the stream to a closed-ish state and unblocks pending reads.
64
- - `RST` is sent as `WINDOW_UPDATE` with `RST` (and length `0`) and terminates the stream.
65
- - If a frame references an unknown stream **without** `SYN`, TS sends `RST`.
66
-
67
- ### PING / GO_AWAY behavior
68
-
69
- - PING:
70
- - If `SYN` is set, TS replies with `ACK` and the same opaque `length`.
71
- - TS does not currently initiate pings or track RTT.
72
- - GO_AWAY:
73
- - Any `GO_AWAY` immediately closes the session (no reason code handling).
74
-
75
- ## Interop evidence (what is actually tested today)
76
-
77
- The TS Yamux implementation is exercised in real interop scenarios:
78
-
79
- - **TS client ↔ Go server (minimal Yamux over TCP)**:
80
- - Test: `flowersec-go/internal/cmd/flowersec-interop` with the TypeScript JSONL harness
81
- - Go reference: production `client`, `endpoint`, and Yamux-backed session APIs
82
- - Covers: window update race, RST handling, concurrent open/close, session close.
83
- - Notes: opt-in via `YAMUX_INTEROP=1` (runs Go harnesses).
84
- - Notes: sizes scale via `YAMUX_INTEROP_SCALE` (e.g. `2` => 20 streams / 1 MiB per stream).
85
- - Notes: client-initiated RST scenarios run when `YAMUX_INTEROP_CLIENT_RST=1`.
86
- - Notes: window-update and concurrent-open/close stress runs when `YAMUX_INTEROP_STRESS=1`.
87
- - **TS client ↔ Go server (full chain: E2EE + tunnel + Yamux)**:
88
- - Test: the Direct/Tunnel variants in `stability/interop_matrix.json`
89
- - Go harness: `flowersec-go/internal/cmd/flowersec-e2e-harness/main.go` with `-scenario`
90
- - Notes: reduced stream counts/payload sizes to keep end-to-end runtime bounded.
91
- - **Layered close/reset probes (memory + WS + full chain)**:
92
- - Test: the Go-reference smoke and stress profiles in `testdata/interop/v1/profiles.json`
93
- - Covers: session-close wakeup, FIN/RST delivery across SecureChannel + WebSocketBinaryTransport,
94
- and a full-chain FIN/RST probe on `rst_mid_write_go`.
95
- - Notes: gated by `YAMUX_INTEROP=1`; the full-chain probe additionally requires
96
- `YAMUX_INTEROP_DEBUG=1`.
97
- - **TS client ↔ Go server (RPC happy path)**:
98
- - Test: `flowersec-ts/src/e2e/go_integration.test.ts`
99
- - Go harness: `flowersec-go/internal/cmd/flowersec-e2e-harness/main.go`
100
- - Covers: single-stream RPC framing and basic window updates.
101
-
102
- These confirm wire-level interop and the correctness of the happy-path subset under real IO.
103
-
104
- ## Current gaps (not yet proven or intentionally simplified)
105
-
106
- These items are either untested or simplified compared to HashiCorp Yamux behavior:
107
-
108
- - **Multi-stream concurrency**: covered by interop tests, but fairness/priority under heavy contention
109
- is not proven.
110
- - **Large payload / fragmentation**: covered up to ~1 MiB per stream; larger payloads and pathological
111
- fragmentation are still untested.
112
- - **Stress & fuzz robustness**: no fuzz tests for invalid headers/flags/lengths and adversarial streams.
113
- - **Session-level behaviors**: GO_AWAY reason handling, keepalive/heartbeats, and more nuanced shutdown.
114
- - **Strictness differences**: unknown frame types trigger session close, which may be stricter than some
115
- implementations.
116
- - **Server-initiated streams**: Go-initiated streams are not covered by interop tests yet.
117
- - **Bidirectional window-update stress**: current window update tests run TS -> Go only.
118
-
119
- ## Practical alignment summary
120
-
121
- - **Aligned (high confidence)**:
122
- - Version 0 framing, stream ID parity, open handshake via SYN/ACK, basic DATA transfer, basic window
123
- updates, and interop with HashiCorp Yamux server for the Flowersec RPC use-case.
124
- - **Aligned but under-tested**:
125
- - FIN/RST edges, ping handling, and window boundary conditions.
126
- - **Not aligned / out of scope today**:
127
- - Full Yamux feature parity (advanced GO_AWAY semantics, keepalive, exhaustive error handling).
@@ -1,12 +0,0 @@
1
- import type { Client } from "../../../client.js";
2
- import type { DirectConnectOptions } from "../../../direct-client/connect.js";
3
- import type { TunnelConnectOptions } from "../../../tunnel-client/connect.js";
4
- import type { ChannelInitGrant } from "../../../gen/flowersec/controlplane/v1.gen.js";
5
- import type { DirectConnectInfo } from "../../../gen/flowersec/direct/v1.gen.js";
6
- import { createDemoClient } from "./v1.rpc.gen.js";
7
- export type DemoSession = Client & Readonly<{
8
- demo: ReturnType<typeof createDemoClient>;
9
- }>;
10
- export declare function createDemoSession(client: Client): DemoSession;
11
- export declare function connectDemoTunnel(grant: ChannelInitGrant, opts: TunnelConnectOptions): Promise<DemoSession>;
12
- export declare function connectDemoDirect(info: DirectConnectInfo, opts: DirectConnectOptions): Promise<DemoSession>;
@@ -1,15 +0,0 @@
1
- // Code generated by idlgen. DO NOT EDIT.
2
- import { connectDirect } from "../../../direct-client/connect.js";
3
- import { connectTunnel } from "../../../tunnel-client/connect.js";
4
- import { createDemoClient, } from "./v1.rpc.gen.js";
5
- export function createDemoSession(client) {
6
- return { ...client, demo: createDemoClient(client.rpc) };
7
- }
8
- export async function connectDemoTunnel(grant, opts) {
9
- const client = await connectTunnel(grant, opts);
10
- return createDemoSession(client);
11
- }
12
- export async function connectDemoDirect(info, opts) {
13
- const client = await connectDirect(info, opts);
14
- return createDemoSession(client);
15
- }
@@ -1,16 +0,0 @@
1
- /** Demo hello notification. */
2
- export interface HelloNotify {
3
- /** Hello message. */
4
- hello: string;
5
- }
6
- /** Demo ping request. */
7
- export interface PingRequest {
8
- }
9
- /** Demo ping response. */
10
- export interface PingResponse {
11
- /** Whether the request succeeded. */
12
- ok: boolean;
13
- }
14
- export declare function assertHelloNotify(v: unknown): HelloNotify;
15
- export declare function assertPingRequest(v: unknown): PingRequest;
16
- export declare function assertPingResponse(v: unknown): PingResponse;
@@ -1,86 +0,0 @@
1
- // Code generated by idlgen. DO NOT EDIT.
2
- function isRecord(v) {
3
- return typeof v === "object" && v != null && !Array.isArray(v);
4
- }
5
- function assertString(name, v) {
6
- if (typeof v !== "string")
7
- throw new Error(`bad ${name}`);
8
- return v;
9
- }
10
- function assertBoolean(name, v) {
11
- if (typeof v !== "boolean")
12
- throw new Error(`bad ${name}`);
13
- return v;
14
- }
15
- function assertSafeInt(name, v) {
16
- if (typeof v !== "number" || !Number.isSafeInteger(v))
17
- throw new Error(`bad ${name}`);
18
- return v;
19
- }
20
- function assertU32(name, v) {
21
- const n = assertSafeInt(name, v);
22
- if (n < 0 || n > 0xffffffff)
23
- throw new Error(`bad ${name}`);
24
- return n;
25
- }
26
- function assertU16(name, v) {
27
- const n = assertU32(name, v);
28
- if (n > 0xffff)
29
- throw new Error(`bad ${name}`);
30
- return n;
31
- }
32
- function assertU8(name, v) {
33
- const n = assertU32(name, v);
34
- if (n > 0xff)
35
- throw new Error(`bad ${name}`);
36
- return n;
37
- }
38
- function assertU64(name, v) {
39
- const n = assertSafeInt(name, v);
40
- if (n < 0)
41
- throw new Error(`bad ${name}`);
42
- return n;
43
- }
44
- function assertI32(name, v) {
45
- const n = assertSafeInt(name, v);
46
- if (n < -2147483648 || n > 2147483647)
47
- throw new Error(`bad ${name}`);
48
- return n;
49
- }
50
- function assertI64(name, v) {
51
- return assertSafeInt(name, v);
52
- }
53
- function assertStringMap(name, v) {
54
- if (!isRecord(v))
55
- throw new Error(`bad ${name}`);
56
- for (const [k, vv] of Object.entries(v)) {
57
- void k;
58
- if (typeof vv !== "string")
59
- throw new Error(`bad ${name}`);
60
- }
61
- return v;
62
- }
63
- export function assertHelloNotify(v) {
64
- if (!isRecord(v))
65
- throw new Error("bad HelloNotify");
66
- const o = v;
67
- if (o["hello"] === undefined)
68
- throw new Error("bad HelloNotify.hello");
69
- assertString("HelloNotify.hello", o["hello"]);
70
- return o;
71
- }
72
- export function assertPingRequest(v) {
73
- if (!isRecord(v))
74
- throw new Error("bad PingRequest");
75
- const o = v;
76
- return o;
77
- }
78
- export function assertPingResponse(v) {
79
- if (!isRecord(v))
80
- throw new Error("bad PingResponse");
81
- const o = v;
82
- if (o["ok"] === undefined)
83
- throw new Error("bad PingResponse.ok");
84
- assertBoolean("PingResponse.ok", o["ok"]);
85
- return o;
86
- }
@@ -1,11 +0,0 @@
1
- import type { RpcCaller } from "../../../rpc/caller.js";
2
- import { HelloNotify, PingRequest, PingResponse } from "./v1.gen.js";
3
- /** Demo service used by examples and integration tests. */
4
- export declare function createDemoClient(rpc: RpcCaller): {
5
- /** Hello notification. */
6
- onHello: (handler: (v: HelloNotify) => void) => () => void;
7
- /** Ping request/response. */
8
- ping: (req: PingRequest, opts?: Readonly<{
9
- signal?: AbortSignal;
10
- }>) => Promise<PingResponse>;
11
- };
@@ -1,22 +0,0 @@
1
- // Code generated by idlgen. DO NOT EDIT.
2
- import { RpcCallError } from "../../../rpc/callError.js";
3
- import { assertHelloNotify, assertPingRequest, assertPingResponse, } from "./v1.gen.js";
4
- /** Demo service used by examples and integration tests. */
5
- export function createDemoClient(rpc) {
6
- return {
7
- /** Hello notification. */
8
- onHello: (handler) => {
9
- return rpc.onNotify(2, (payload) => {
10
- handler(assertHelloNotify(payload));
11
- });
12
- },
13
- /** Ping request/response. */
14
- ping: async (req, opts = {}) => {
15
- const checkedReq = assertPingRequest(req);
16
- const resp = await rpc.call(1, checkedReq, opts.signal);
17
- if (resp.error != null)
18
- throw new RpcCallError(resp.error.code, resp.error.message, 1);
19
- return assertPingResponse(resp.payload);
20
- },
21
- };
22
- }
@@ -1,12 +0,0 @@
1
- import type { Client } from "../client.js";
2
- import type { DirectConnectOptions } from "../direct-client/connect.js";
3
- import type { TunnelConnectOptions } from "../tunnel-client/connect.js";
4
- import { type ConnectOptions } from "../facade.js";
5
- import type { ChannelInitGrant } from "../gen/flowersec/controlplane/v1.gen.js";
6
- import type { DirectConnectInfo } from "../gen/flowersec/direct/v1.gen.js";
7
- export type TunnelConnectBrowserOptions = Omit<TunnelConnectOptions, "origin" | "wsFactory">;
8
- export type DirectConnectBrowserOptions = Omit<DirectConnectOptions, "origin" | "wsFactory">;
9
- export type ConnectBrowserOptions = Omit<ConnectOptions, "origin" | "wsFactory">;
10
- export declare function connectBrowser(input: unknown, opts?: ConnectBrowserOptions): Promise<Client>;
11
- export declare function connectTunnelBrowser(grant: ChannelInitGrant, opts?: TunnelConnectBrowserOptions): Promise<Client>;
12
- export declare function connectDirectBrowser(info: DirectConnectInfo, opts?: DirectConnectBrowserOptions): Promise<Client>;
@@ -1,31 +0,0 @@
1
- import { connectDirect } from "../direct-client/connect.js";
2
- import { connectTunnel } from "../tunnel-client/connect.js";
3
- import { connect } from "../facade.js";
4
- import { FlowersecError } from "../utils/errors.js";
5
- function getBrowserOrigin() {
6
- if (typeof window === "undefined")
7
- return "";
8
- const o = window?.location?.origin;
9
- return typeof o === "string" ? o : "";
10
- }
11
- export async function connectBrowser(input, opts = {}) {
12
- const origin = getBrowserOrigin();
13
- if (origin === "") {
14
- throw new FlowersecError({ stage: "validate", code: "missing_origin", path: "auto", message: "missing browser origin" });
15
- }
16
- return await connect(input, { ...opts, origin });
17
- }
18
- export async function connectTunnelBrowser(grant, opts = {}) {
19
- const origin = getBrowserOrigin();
20
- if (origin === "") {
21
- throw new FlowersecError({ stage: "validate", code: "missing_origin", path: "tunnel", message: "missing browser origin" });
22
- }
23
- return await connectTunnel(grant, { ...opts, origin });
24
- }
25
- export async function connectDirectBrowser(info, opts = {}) {
26
- const origin = getBrowserOrigin();
27
- if (origin === "") {
28
- throw new FlowersecError({ stage: "validate", code: "missing_origin", path: "direct", message: "missing browser origin" });
29
- }
30
- return await connectDirect(info, { ...opts, origin });
31
- }
@@ -1,15 +0,0 @@
1
- import { type ChannelInitGrant } from "../facade.js";
2
- import type { ControlplaneBaseConfig as SharedControlplaneBaseConfig, RequestConnectArtifactInput, RequestEntryConnectArtifactInput } from "../controlplane/request.js";
3
- type BaseControlplaneRequestConfig = SharedControlplaneBaseConfig & Readonly<{
4
- endpointId: string;
5
- payload?: Record<string, unknown>;
6
- }>;
7
- export type ControlplaneConfig = BaseControlplaneRequestConfig;
8
- export type EntryControlplaneConfig = BaseControlplaneRequestConfig & Readonly<{
9
- entryTicket: string;
10
- }>;
11
- export type ConnectArtifactRequestConfig = RequestConnectArtifactInput;
12
- export type EntryConnectArtifactRequestConfig = RequestEntryConnectArtifactInput;
13
- export declare function requestChannelGrant(config: ControlplaneConfig): Promise<ChannelInitGrant>;
14
- export declare function requestEntryChannelGrant(config: EntryControlplaneConfig): Promise<ChannelInitGrant>;
15
- export {};
@@ -1,64 +0,0 @@
1
- import { assertChannelInitGrant } from "../facade.js";
2
- import { requestControlplaneJSON, } from "../controlplane/request.js";
3
- function buildURL(baseUrl, path) {
4
- const base = String(baseUrl ?? "").trim();
5
- if (base === "")
6
- return path;
7
- return `${base.replace(/\/+$/, "")}${path}`;
8
- }
9
- function buildPayload(endpointId, payload) {
10
- const id = String(endpointId ?? "").trim();
11
- if (id === "")
12
- throw new Error("endpointId is required");
13
- const out = { ...(payload ?? {}) };
14
- const raw = out.endpoint_id;
15
- if (raw !== undefined && String(raw ?? "").trim() !== id) {
16
- throw new Error("payload.endpoint_id must match endpointId");
17
- }
18
- out.endpoint_id = id;
19
- return out;
20
- }
21
- async function requestGrant(url, init) {
22
- return await requestControlplaneJSON(url, init);
23
- }
24
- export async function requestChannelGrant(config) {
25
- const headers = new Headers(config.headers);
26
- if (!headers.has("Content-Type")) {
27
- headers.set("Content-Type", "application/json");
28
- }
29
- const data = (await requestGrant(buildURL(config.baseUrl, "/v1/channel/init"), {
30
- ...(config.fetch === undefined ? {} : { fetch: config.fetch }),
31
- method: "POST",
32
- credentials: config.credentials ?? "omit",
33
- headers,
34
- body: JSON.stringify(buildPayload(config.endpointId, config.payload)),
35
- ...(config.signal === undefined ? {} : { signal: config.signal }),
36
- }));
37
- if (!data?.grant_client) {
38
- throw new Error("Invalid controlplane response: missing `grant_client`");
39
- }
40
- return assertChannelInitGrant(data.grant_client);
41
- }
42
- export async function requestEntryChannelGrant(config) {
43
- const entryTicket = String(config.entryTicket ?? "").trim();
44
- if (entryTicket === "")
45
- throw new Error("entryTicket is required");
46
- const endpointId = String(config.endpointId ?? "").trim();
47
- const headers = new Headers(config.headers);
48
- headers.set("Authorization", `Bearer ${entryTicket}`);
49
- if (!headers.has("Content-Type")) {
50
- headers.set("Content-Type", "application/json");
51
- }
52
- const data = (await requestGrant(buildURL(config.baseUrl, `/v1/channel/init/entry?endpoint_id=${encodeURIComponent(endpointId)}`), {
53
- ...(config.fetch === undefined ? {} : { fetch: config.fetch }),
54
- method: "POST",
55
- credentials: config.credentials ?? "omit",
56
- headers,
57
- body: JSON.stringify(buildPayload(endpointId, config.payload)),
58
- ...(config.signal === undefined ? {} : { signal: config.signal }),
59
- }));
60
- if (!data?.grant_client) {
61
- throw new Error("Invalid controlplane response: missing `grant_client`");
62
- }
63
- return assertChannelInitGrant(data.grant_client);
64
- }
@@ -1,15 +0,0 @@
1
- import type { ClientObserverLike } from "../observability/observer.js";
2
- import type { AutoReconnectConfig, ConnectConfig as ReconnectConnectConfig } from "../reconnect/index.js";
3
- import { type ArtifactSource } from "../reconnect/artifactControlplane.js";
4
- import type { DirectConnectBrowserOptions, TunnelConnectBrowserOptions } from "./connect.js";
5
- export type BrowserReconnectConfig = Readonly<{
6
- source: ArtifactSource;
7
- connect?: Omit<TunnelConnectBrowserOptions, "observer" | "signal"> | Omit<DirectConnectBrowserOptions, "observer" | "signal">;
8
- observer?: ClientObserverLike;
9
- autoReconnect?: AutoReconnectConfig;
10
- }>;
11
- export type TunnelBrowserReconnectConfig = BrowserReconnectConfig;
12
- export type DirectBrowserReconnectConfig = BrowserReconnectConfig;
13
- export declare function createBrowserReconnectConfig(config: BrowserReconnectConfig): ReconnectConnectConfig;
14
- export declare const createTunnelBrowserReconnectConfig: typeof createBrowserReconnectConfig;
15
- export declare const createDirectBrowserReconnectConfig: typeof createBrowserReconnectConfig;
@@ -1,20 +0,0 @@
1
- import { createArtifactResolver, updateTraceId } from "../reconnect/artifactControlplane.js";
2
- import { connectBrowser } from "./connect.js";
3
- export function createBrowserReconnectConfig(config) {
4
- if (config.source.kind === "once" && config.autoReconnect?.enabled) {
5
- throw new Error("automatic reconnect requires a refreshable artifact source");
6
- }
7
- let traceId = config.source.kind === "once" ? config.source.artifact.correlation?.trace_id : undefined;
8
- const acquire = createArtifactResolver(config.source);
9
- return {
10
- ...(config.observer === undefined ? {} : { observer: config.observer }),
11
- ...(config.autoReconnect === undefined ? {} : { autoReconnect: config.autoReconnect }),
12
- connectOnce: async ({ signal, observer }) => {
13
- const artifact = await acquire({ ...(traceId === undefined ? {} : { traceId }), signal });
14
- traceId = updateTraceId(traceId, artifact);
15
- return await connectBrowser(artifact, { ...(config.connect ?? {}), signal, observer });
16
- },
17
- };
18
- }
19
- export const createTunnelBrowserReconnectConfig = createBrowserReconnectConfig;
20
- export const createDirectBrowserReconnectConfig = createBrowserReconnectConfig;
@@ -1,26 +0,0 @@
1
- import type { WebSocketLike } from "../ws-client/binaryTransport.js";
2
- export declare class OriginMismatchError extends Error {
3
- readonly expected: string;
4
- readonly got: string;
5
- constructor(expected: string, got: string);
6
- }
7
- export declare class WsFactoryRequiredError extends Error {
8
- constructor();
9
- }
10
- export declare function createWebSocket(url: string, origin: string, wsFactory: ((url: string, origin: string) => WebSocketLike) | undefined): WebSocketLike;
11
- export declare function classifyConnectError(err: unknown): "websocket_error" | "websocket_closed" | "timeout" | "canceled";
12
- export declare function classifyHandshakeError(err: unknown): "auth_tag_mismatch" | "handshake_failed" | "invalid_suite" | "invalid_version" | "timestamp_after_init_exp" | "timestamp_out_of_skew" | "timeout" | "canceled";
13
- export declare function withAbortAndTimeout<T>(p: Promise<T>, opts: Readonly<{
14
- signal?: AbortSignal;
15
- timeoutMs?: number;
16
- onCancel?: () => void;
17
- }>): Promise<T>;
18
- export declare function waitOpen(ws: WebSocketLike, opts?: Readonly<{
19
- signal?: AbortSignal;
20
- timeoutMs?: number;
21
- }>): Promise<void>;
22
- export declare function randomBytes(n: number): Uint8Array;
23
- export declare function ioReadOpts(signal: AbortSignal | undefined, timeoutMs: number | undefined): {
24
- signal?: AbortSignal;
25
- timeoutMs?: number;
26
- };
@@ -1,167 +0,0 @@
1
- import { AbortError, TimeoutError, isAbortError, isTimeoutError, throwIfAborted } from "../utils/errors.js";
2
- import { E2EEHandshakeError } from "../e2ee/errors.js";
3
- class WebSocketClosedError extends Error {
4
- constructor() {
5
- super("websocket closed");
6
- this.name = "WebSocketClosedError";
7
- }
8
- }
9
- class WebSocketOpenError extends Error {
10
- constructor() {
11
- super("websocket error");
12
- this.name = "WebSocketOpenError";
13
- }
14
- }
15
- export class OriginMismatchError extends Error {
16
- expected;
17
- got;
18
- constructor(expected, got) {
19
- super(`origin mismatch: expected ${expected}, got ${got}`);
20
- this.name = "OriginMismatchError";
21
- this.expected = expected;
22
- this.got = got;
23
- }
24
- }
25
- export class WsFactoryRequiredError extends Error {
26
- constructor() {
27
- super("wsFactory is required outside the browser to set the Origin header (use connectTunnelNode/connectDirectNode or createNodeWsFactory from @floegence/flowersec-core/node)");
28
- this.name = "WsFactoryRequiredError";
29
- }
30
- }
31
- function defaultWebSocketFactory(url) {
32
- return new WebSocket(url);
33
- }
34
- function isBrowserEnv() {
35
- return typeof window !== "undefined" && typeof window.location !== "undefined" && typeof window.location.origin === "string";
36
- }
37
- export function createWebSocket(url, origin, wsFactory) {
38
- if (wsFactory != null)
39
- return wsFactory(url, origin);
40
- if (isBrowserEnv()) {
41
- if (window.location.origin !== origin)
42
- throw new OriginMismatchError(origin, window.location.origin);
43
- return defaultWebSocketFactory(url);
44
- }
45
- throw new WsFactoryRequiredError();
46
- }
47
- export function classifyConnectError(err) {
48
- if (isTimeoutError(err))
49
- return "timeout";
50
- if (isAbortError(err))
51
- return "canceled";
52
- if (err instanceof WebSocketClosedError)
53
- return "websocket_closed";
54
- return "websocket_error";
55
- }
56
- export function classifyHandshakeError(err) {
57
- if (isTimeoutError(err))
58
- return "timeout";
59
- if (isAbortError(err))
60
- return "canceled";
61
- if (err instanceof E2EEHandshakeError)
62
- return err.code;
63
- return "handshake_failed";
64
- }
65
- export async function withAbortAndTimeout(p, opts) {
66
- if (opts.signal?.aborted) {
67
- opts.onCancel?.();
68
- throw new AbortError("canceled");
69
- }
70
- const timeoutMs = Math.max(0, opts.timeoutMs ?? 0);
71
- if (timeoutMs <= 0 && opts.signal == null)
72
- return await p;
73
- return await new Promise((resolve, reject) => {
74
- let settled = false;
75
- const cleanup = () => {
76
- settled = true;
77
- if (timer != null)
78
- clearTimeout(timer);
79
- opts.signal?.removeEventListener("abort", onAbort);
80
- };
81
- const finish = (fn) => {
82
- if (settled)
83
- return;
84
- cleanup();
85
- fn();
86
- };
87
- const onAbort = () => {
88
- opts.onCancel?.();
89
- finish(() => reject(new AbortError("canceled")));
90
- };
91
- const timer = timeoutMs > 0
92
- ? setTimeout(() => {
93
- opts.onCancel?.();
94
- finish(() => reject(new TimeoutError("timeout")));
95
- }, timeoutMs)
96
- : undefined;
97
- opts.signal?.addEventListener("abort", onAbort);
98
- p.then((v) => finish(() => resolve(v)), (e) => finish(() => reject(e)));
99
- });
100
- }
101
- // waitOpen resolves when the websocket opens or rejects on error/close.
102
- export function waitOpen(ws, opts = {}) {
103
- return new Promise((resolve, reject) => {
104
- if (opts.signal?.aborted) {
105
- reject(new AbortError("connect aborted"));
106
- return;
107
- }
108
- const onOpen = () => {
109
- cleanup();
110
- resolve();
111
- };
112
- const onErr = () => {
113
- cleanup();
114
- reject(new WebSocketOpenError());
115
- };
116
- const onClose = () => {
117
- cleanup();
118
- reject(new WebSocketClosedError());
119
- };
120
- const onAbort = () => {
121
- cleanup();
122
- try {
123
- ws.close();
124
- }
125
- catch {
126
- // ignore
127
- }
128
- reject(new AbortError("connect aborted"));
129
- };
130
- const timeoutMs = Math.max(0, opts.timeoutMs ?? 0);
131
- const timer = timeoutMs > 0
132
- ? setTimeout(() => {
133
- cleanup();
134
- try {
135
- ws.close();
136
- }
137
- catch {
138
- // ignore
139
- }
140
- reject(new TimeoutError("connect timeout"));
141
- }, timeoutMs)
142
- : undefined;
143
- const cleanup = () => {
144
- if (timer != null)
145
- clearTimeout(timer);
146
- ws.removeEventListener("open", onOpen);
147
- ws.removeEventListener("error", onErr);
148
- ws.removeEventListener("close", onClose);
149
- opts.signal?.removeEventListener("abort", onAbort);
150
- };
151
- ws.addEventListener("open", onOpen);
152
- ws.addEventListener("error", onErr);
153
- ws.addEventListener("close", onClose);
154
- opts.signal?.addEventListener("abort", onAbort);
155
- });
156
- }
157
- // randomBytes uses the Web Crypto API for nonces and IDs.
158
- export function randomBytes(n) {
159
- const out = new Uint8Array(n);
160
- crypto.getRandomValues(out);
161
- return out;
162
- }
163
- export function ioReadOpts(signal, timeoutMs) {
164
- throwIfAborted(signal, "operation aborted");
165
- const ms = timeoutMs == null ? undefined : Math.max(0, timeoutMs);
166
- return signal != null ? { signal, ...(ms !== undefined ? { timeoutMs: ms } : {}) } : ms !== undefined ? { timeoutMs: ms } : {};
167
- }