api-ape 3.0.2 → 4.1.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 (186) hide show
  1. package/README.md +59 -572
  2. package/client/README.md +73 -14
  3. package/client/auth/crypto/aead.js +214 -0
  4. package/client/auth/crypto/constants.js +32 -0
  5. package/client/auth/crypto/encoding.js +104 -0
  6. package/client/auth/crypto/files.md +27 -0
  7. package/client/auth/crypto/kdf.js +217 -0
  8. package/client/auth/crypto-utils.js +118 -0
  9. package/client/auth/files.md +52 -0
  10. package/client/auth/key-recovery.js +288 -0
  11. package/client/auth/recovery/constants.js +37 -0
  12. package/client/auth/recovery/files.md +23 -0
  13. package/client/auth/recovery/key-derivation.js +61 -0
  14. package/client/auth/recovery/sss-browser.js +189 -0
  15. package/client/auth/share-storage.js +205 -0
  16. package/client/auth/storage/constants.js +18 -0
  17. package/client/auth/storage/db.js +132 -0
  18. package/client/auth/storage/files.md +27 -0
  19. package/client/auth/storage/keys.js +173 -0
  20. package/client/auth/storage/shares.js +200 -0
  21. package/client/browser.js +190 -23
  22. package/client/connectSocket.js +418 -988
  23. package/client/connection/README.md +23 -0
  24. package/client/connection/fileDownload.js +256 -0
  25. package/client/connection/fileHandling.js +450 -0
  26. package/client/connection/fileUtils.js +346 -0
  27. package/client/connection/files.md +71 -0
  28. package/client/connection/messageHandler.js +105 -0
  29. package/client/connection/network.js +350 -0
  30. package/client/connection/proxy.js +233 -0
  31. package/client/connection/sender.js +333 -0
  32. package/client/connection/state.js +321 -0
  33. package/client/connection/subscriptions.js +151 -0
  34. package/client/files.md +53 -0
  35. package/client/index.js +298 -142
  36. package/client/transports/README.md +50 -0
  37. package/client/transports/files.md +41 -0
  38. package/client/transports/streamParser.js +195 -0
  39. package/client/transports/streaming.js +555 -203
  40. package/dist/ape.js +6 -1
  41. package/dist/ape.js.map +4 -4
  42. package/index.d.ts +38 -16
  43. package/package.json +31 -6
  44. package/server/README.md +272 -67
  45. package/server/adapters/README.md +23 -14
  46. package/server/adapters/files.md +68 -0
  47. package/server/adapters/firebase.js +543 -160
  48. package/server/adapters/index.js +362 -112
  49. package/server/adapters/mongo.js +530 -140
  50. package/server/adapters/postgres.js +534 -155
  51. package/server/adapters/redis.js +508 -143
  52. package/server/adapters/supabase.js +555 -186
  53. package/server/client/README.md +43 -0
  54. package/server/client/connection.js +586 -0
  55. package/server/client/files.md +40 -0
  56. package/server/client/index.js +342 -0
  57. package/server/files.md +54 -0
  58. package/server/index.js +322 -71
  59. package/server/lib/README.md +26 -0
  60. package/server/lib/broadcast/clients.js +219 -0
  61. package/server/lib/broadcast/files.md +58 -0
  62. package/server/lib/broadcast/index.js +57 -0
  63. package/server/lib/broadcast/publishProxy.js +110 -0
  64. package/server/lib/broadcast/pubsub.js +137 -0
  65. package/server/lib/broadcast/sendProxy.js +103 -0
  66. package/server/lib/bun.js +315 -99
  67. package/server/lib/fileTransfer/README.md +63 -0
  68. package/server/lib/fileTransfer/files.md +30 -0
  69. package/server/lib/fileTransfer/streaming.js +435 -0
  70. package/server/lib/fileTransfer.js +710 -326
  71. package/server/lib/files.md +111 -0
  72. package/server/lib/httpUtils.js +283 -0
  73. package/server/lib/loader.js +208 -7
  74. package/server/lib/longPolling/README.md +63 -0
  75. package/server/lib/longPolling/files.md +44 -0
  76. package/server/lib/longPolling/getHandler.js +365 -0
  77. package/server/lib/longPolling/postHandler.js +327 -0
  78. package/server/lib/longPolling.js +174 -219
  79. package/server/lib/main.js +369 -532
  80. package/server/lib/runtimes/README.md +42 -0
  81. package/server/lib/runtimes/bun.js +586 -0
  82. package/server/lib/runtimes/files.md +56 -0
  83. package/server/lib/runtimes/node.js +511 -0
  84. package/server/lib/wiring.js +539 -98
  85. package/server/lib/ws/README.md +35 -0
  86. package/server/lib/ws/adapters/README.md +54 -0
  87. package/server/lib/ws/adapters/bun.js +538 -170
  88. package/server/lib/ws/adapters/deno.js +623 -149
  89. package/server/lib/ws/adapters/files.md +42 -0
  90. package/server/lib/ws/files.md +74 -0
  91. package/server/lib/ws/frames.js +532 -154
  92. package/server/lib/ws/index.js +207 -10
  93. package/server/lib/ws/server.js +385 -92
  94. package/server/lib/ws/socket.js +549 -181
  95. package/server/lib/wsProvider.js +363 -89
  96. package/server/plugins/binary.js +282 -0
  97. package/server/security/README.md +92 -0
  98. package/server/security/auth/README.md +319 -0
  99. package/server/security/auth/adapters/files.md +95 -0
  100. package/server/security/auth/adapters/ldap/constants.js +37 -0
  101. package/server/security/auth/adapters/ldap/files.md +19 -0
  102. package/server/security/auth/adapters/ldap/helpers.js +111 -0
  103. package/server/security/auth/adapters/ldap.js +353 -0
  104. package/server/security/auth/adapters/oauth2/constants.js +41 -0
  105. package/server/security/auth/adapters/oauth2/files.md +19 -0
  106. package/server/security/auth/adapters/oauth2/helpers.js +123 -0
  107. package/server/security/auth/adapters/oauth2.js +273 -0
  108. package/server/security/auth/adapters/opaque-handlers.js +314 -0
  109. package/server/security/auth/adapters/opaque.js +205 -0
  110. package/server/security/auth/adapters/saml/constants.js +52 -0
  111. package/server/security/auth/adapters/saml/files.md +19 -0
  112. package/server/security/auth/adapters/saml/helpers.js +74 -0
  113. package/server/security/auth/adapters/saml.js +173 -0
  114. package/server/security/auth/adapters/totp.js +703 -0
  115. package/server/security/auth/adapters/webauthn.js +625 -0
  116. package/server/security/auth/files.md +61 -0
  117. package/server/security/auth/framework/constants.js +27 -0
  118. package/server/security/auth/framework/files.md +23 -0
  119. package/server/security/auth/framework/handlers.js +272 -0
  120. package/server/security/auth/framework/socket-auth.js +177 -0
  121. package/server/security/auth/handlers/auth-messages.js +143 -0
  122. package/server/security/auth/handlers/files.md +28 -0
  123. package/server/security/auth/index.js +290 -0
  124. package/server/security/auth/mfa/crypto/aead.js +148 -0
  125. package/server/security/auth/mfa/crypto/constants.js +35 -0
  126. package/server/security/auth/mfa/crypto/files.md +27 -0
  127. package/server/security/auth/mfa/crypto/kdf.js +120 -0
  128. package/server/security/auth/mfa/crypto/utils.js +68 -0
  129. package/server/security/auth/mfa/crypto-utils.js +80 -0
  130. package/server/security/auth/mfa/files.md +77 -0
  131. package/server/security/auth/mfa/ledger/constants.js +75 -0
  132. package/server/security/auth/mfa/ledger/errors.js +73 -0
  133. package/server/security/auth/mfa/ledger/files.md +23 -0
  134. package/server/security/auth/mfa/ledger/share-record.js +32 -0
  135. package/server/security/auth/mfa/ledger.js +255 -0
  136. package/server/security/auth/mfa/recovery/constants.js +67 -0
  137. package/server/security/auth/mfa/recovery/files.md +19 -0
  138. package/server/security/auth/mfa/recovery/handlers.js +216 -0
  139. package/server/security/auth/mfa/recovery.js +191 -0
  140. package/server/security/auth/mfa/sss/constants.js +21 -0
  141. package/server/security/auth/mfa/sss/files.md +23 -0
  142. package/server/security/auth/mfa/sss/gf256.js +103 -0
  143. package/server/security/auth/mfa/sss/serialization.js +82 -0
  144. package/server/security/auth/mfa/sss.js +161 -0
  145. package/server/security/auth/mfa/two-of-three/constants.js +58 -0
  146. package/server/security/auth/mfa/two-of-three/files.md +23 -0
  147. package/server/security/auth/mfa/two-of-three/handlers.js +241 -0
  148. package/server/security/auth/mfa/two-of-three/helpers.js +71 -0
  149. package/server/security/auth/mfa/two-of-three.js +136 -0
  150. package/server/security/auth/nonce-manager.js +89 -0
  151. package/server/security/auth/state-machine-mfa.js +269 -0
  152. package/server/security/auth/state-machine.js +257 -0
  153. package/server/security/extractRootDomain.js +144 -16
  154. package/server/security/files.md +51 -0
  155. package/server/security/origin.js +197 -15
  156. package/server/security/reply.js +274 -16
  157. package/server/socket/README.md +119 -0
  158. package/server/socket/authMiddleware.js +299 -0
  159. package/server/socket/files.md +86 -0
  160. package/server/socket/open.js +154 -8
  161. package/server/socket/pluginHooks.js +334 -0
  162. package/server/socket/receive.js +184 -224
  163. package/server/socket/receiveContext.js +117 -0
  164. package/server/socket/send.js +416 -78
  165. package/server/socket/tagUtils.js +402 -0
  166. package/server/utils/README.md +19 -0
  167. package/server/utils/deepRequire.js +255 -30
  168. package/server/utils/files.md +57 -0
  169. package/server/utils/genId.js +182 -20
  170. package/server/utils/parseUserAgent.js +313 -251
  171. package/server/utils/userAgent/README.md +65 -0
  172. package/server/utils/userAgent/files.md +46 -0
  173. package/server/utils/userAgent/patterns.js +545 -0
  174. package/utils/README.md +21 -0
  175. package/utils/files.md +66 -0
  176. package/utils/jss/README.md +21 -0
  177. package/utils/jss/decode.js +471 -0
  178. package/utils/jss/encode.js +312 -0
  179. package/utils/jss/files.md +68 -0
  180. package/utils/jss/plugins.js +210 -0
  181. package/utils/jss.js +219 -273
  182. package/utils/messageHash.js +238 -35
  183. package/dist/api-ape.min.js +0 -2
  184. package/dist/api-ape.min.js.map +0 -7
  185. package/server/client.js +0 -311
  186. package/server/lib/broadcast.js +0 -146
@@ -1,135 +1,409 @@
1
1
  /**
2
- * WebSocket Provider
3
- * Detects runtime capabilities and provides appropriate WebSocket implementation
4
- *
5
- * Priority:
6
- * 1. Deno native WebSocket (Deno.upgradeWebSocket)
7
- * 2. Bun native WebSocket (Bun.serve websocket)
8
- * 3. Node.js 24+ stable native WebSocketServer (node:ws module)
9
- * 4. Custom polyfill (RFC 6455 compliant)
2
+ * @fileoverview WebSocket Provider - Runtime-Aware WebSocket Implementation
3
+ *
4
+ * This module provides automatic detection of the JavaScript runtime environment
5
+ * and returns the most appropriate WebSocket implementation. It abstracts away
6
+ * the differences between Deno, Bun, Node.js, and provides a fallback polyfill.
7
+ *
8
+ * Provider Selection Priority:
9
+ * 1. **Deno Native**: Uses `Deno.upgradeWebSocket()` for optimal performance
10
+ * 2. **Bun Native**: Uses Bun's built-in WebSocket server
11
+ * 3. **Node.js 24+ Native**: Uses the stable `node:ws` module (when available)
12
+ * 4. **Polyfill**: Uses our RFC 6455 compliant implementation
13
+ *
14
+ * The provider is cached after first detection to ensure consistent behavior
15
+ * throughout the application lifecycle.
16
+ *
17
+ * @module server/lib/wsProvider
18
+ * @see {@link module:server/lib/ws} - WebSocket polyfill implementation
19
+ * @see {@link module:server/lib/ws/adapters/bun} - Bun adapter
20
+ * @see {@link module:server/lib/ws/adapters/deno} - Deno adapter
21
+ *
22
+ * @example
23
+ * // Get the appropriate WebSocket provider for the current runtime
24
+ * const { getWebSocketProvider } = require('./wsProvider')
25
+ *
26
+ * const { type, WebSocketServer, runtime } = getWebSocketProvider()
27
+ * console.log(`Using ${type} WebSocket on ${runtime}`)
28
+ *
29
+ * // Create a WebSocket server
30
+ * const wss = new WebSocketServer({ noServer: true })
31
+ * wss.on('connection', (ws) => {
32
+ * console.log('Client connected')
33
+ * })
34
+ *
35
+ * @example
36
+ * // Check runtime environment
37
+ * const { getRuntime, isDeno, isBun } = require('./wsProvider')
38
+ *
39
+ * console.log('Runtime:', getRuntime())
40
+ * console.log('Is Deno:', isDeno())
41
+ * console.log('Is Bun:', isBun())
10
42
  */
11
43
 
12
44
  /**
13
- * Check if running in Deno runtime
14
- * @returns {boolean}
45
+ * @typedef {Object} WebSocketProvider
46
+ * Result from getWebSocketProvider() with runtime-appropriate WebSocket implementation.
47
+ *
48
+ * @property {string} type - The provider type identifier:
49
+ * - 'deno-native': Deno's built-in WebSocket
50
+ * - 'bun-native': Bun's built-in WebSocket
51
+ * - 'node-native': Node.js 24+ stable native WebSocket
52
+ * - 'polyfill': Our RFC 6455 compliant implementation
53
+ * @property {typeof import('./ws').WebSocketServer} WebSocketServer - WebSocket server constructor
54
+ * @property {string} runtime - The detected runtime ('deno', 'bun', 'node', 'unknown')
55
+ */
56
+
57
+ /**
58
+ * @typedef {'deno'|'bun'|'node'|'unknown'} RuntimeType
59
+ * The detected JavaScript runtime environment.
60
+ */
61
+
62
+ /**
63
+ * Runtime override for testing. Set to mock runtime detection.
64
+ * @private
65
+ * @type {{deno?: boolean, bun?: boolean, node24?: boolean}|null}
66
+ */
67
+ let _runtimeOverride = null;
68
+
69
+ /**
70
+ * Set runtime override for testing purposes.
71
+ * @param {{deno?: boolean, bun?: boolean, node24?: boolean}|null} override
72
+ */
73
+ function _setRuntimeOverride(override) {
74
+ _runtimeOverride = override;
75
+ // Clear cached provider when runtime changes
76
+ cachedProvider = null;
77
+ }
78
+
79
+ /**
80
+ * Get current runtime override (for testing).
81
+ * @returns {{deno?: boolean, bun?: boolean, node24?: boolean}|null}
82
+ */
83
+ function _getRuntimeOverride() {
84
+ return _runtimeOverride;
85
+ }
86
+
87
+ /**
88
+ * Checks if the code is running in the Deno runtime.
89
+ *
90
+ * Detection method: Checks for the global `Deno` object and its
91
+ * `upgradeWebSocket` function, which is Deno's WebSocket upgrade API.
92
+ *
93
+ * @function isDeno
94
+ * @returns {boolean} True if running in Deno
95
+ *
96
+ * @example
97
+ * if (isDeno()) {
98
+ * console.log('Running in Deno')
99
+ * // Use Deno-specific APIs
100
+ * }
15
101
  */
16
102
  function isDeno() {
17
- return typeof Deno !== 'undefined' && typeof Deno.upgradeWebSocket === 'function'
103
+ // Check test override first
104
+ if (_runtimeOverride?.deno !== undefined) {
105
+ return _runtimeOverride.deno;
106
+ }
107
+ // Actual runtime detection
108
+ return (
109
+ typeof Deno !== "undefined" && typeof Deno.upgradeWebSocket === "function"
110
+ );
18
111
  }
19
112
 
20
113
  /**
21
- * Check if running in Bun runtime
22
- * Uses process.versions.bun which is the recommended detection method
23
- * @returns {boolean}
114
+ * Checks if the code is running in the Bun runtime.
115
+ *
116
+ * Detection method: Checks `process.versions.bun`, which is the officially
117
+ * recommended way to detect Bun according to Bun's documentation.
118
+ *
119
+ * Note: Bun also sets `process.versions.node`, so checking for Node.js
120
+ * detection should exclude Bun first.
121
+ *
122
+ * @function isBun
123
+ * @returns {boolean} True if running in Bun
124
+ *
125
+ * @example
126
+ * if (isBun()) {
127
+ * console.log('Running in Bun version:', process.versions.bun)
128
+ * // Use Bun-specific APIs like Bun.serve()
129
+ * }
24
130
  */
25
131
  function isBun() {
26
- return typeof process !== 'undefined' && !!process.versions?.bun
132
+ // Check test override first
133
+ if (_runtimeOverride?.bun !== undefined) {
134
+ return _runtimeOverride.bun;
135
+ }
136
+ // Actual runtime detection
137
+ return typeof process !== "undefined" && !!process.versions?.bun;
27
138
  }
28
139
 
29
140
  /**
30
- * Check if Node.js version is 24+ stable (not pre-release)
31
- * @returns {boolean}
141
+ * Checks if running on Node.js version 24+ with stable WebSocket support.
142
+ *
143
+ * Node.js 24 introduced a stable, built-in WebSocket module (`node:ws`)
144
+ * that doesn't require external dependencies. This function checks:
145
+ *
146
+ * 1. That we're running in Node.js (not Bun, which also has `process.versions.node`)
147
+ * 2. That the major version is 24 or higher
148
+ * 3. That it's a stable release (not RC, alpha, or beta)
149
+ *
150
+ * Pre-release versions are identified by hyphens in the version string
151
+ * (e.g., "24.0.0-rc.1").
152
+ *
153
+ * @function isNode24Stable
154
+ * @returns {boolean} True if running on Node.js 24+ stable
155
+ *
156
+ * @example
157
+ * if (isNode24Stable()) {
158
+ * // Can use native node:ws module
159
+ * const { WebSocketServer } = require('node:ws')
160
+ * } else {
161
+ * // Fall back to polyfill or external package
162
+ * }
32
163
  */
33
164
  function isNode24Stable() {
34
- if (typeof process === 'undefined' || !process.versions || !process.versions.node) {
35
- return false
36
- }
165
+ // Check test override first
166
+ if (_runtimeOverride?.node24 !== undefined) {
167
+ return _runtimeOverride.node24;
168
+ }
37
169
 
38
- // Skip if this is actually Bun (Bun also has process.versions.node)
39
- if (isBun()) {
40
- return false
41
- }
170
+ // Actual runtime detection
171
+ /* istanbul ignore next 6 - only reachable in browser/non-Node environments */
172
+ if (
173
+ typeof process === "undefined" ||
174
+ !process.versions ||
175
+ !process.versions.node
176
+ ) {
177
+ return false;
178
+ }
42
179
 
43
- const versionStr = process.versions.node
44
- const majorVersion = parseInt(versionStr.split('.')[0], 10)
180
+ // Skip if this is actually Bun (Bun also sets process.versions.node)
181
+ if (isBun()) {
182
+ return false;
183
+ }
45
184
 
46
- // Must be Node 24+
47
- if (majorVersion < 24) {
48
- return false
49
- }
185
+ const versionStr = process.versions.node;
186
+ const majorVersion = parseInt(versionStr.split(".")[0], 10);
50
187
 
51
- // Check if this is a stable release (not RC, alpha, beta)
52
- // Pre-release versions contain hyphens like "24.0.0-rc.1"
53
- if (versionStr.includes('-')) {
54
- return false
55
- }
188
+ // Must be Node 24+
189
+ if (majorVersion < 24) {
190
+ return false;
191
+ }
56
192
 
57
- return true
193
+ // Check if this is a stable release (not RC, alpha, beta)
194
+ // Pre-release versions contain hyphens like "24.0.0-rc.1"
195
+ /* istanbul ignore next 3 - only reachable on Node 24+ */
196
+ if (versionStr.includes("-")) {
197
+ return false;
198
+ }
199
+
200
+ /* istanbul ignore next - only reachable on Node 24+ */
201
+ return true;
58
202
  }
59
203
 
60
204
  /**
61
- * Get the detected runtime type
62
- * @returns {'deno' | 'bun' | 'node' | 'unknown'}
205
+ * Gets the detected runtime type.
206
+ *
207
+ * Returns one of:
208
+ * - 'deno': Running in Deno runtime
209
+ * - 'bun': Running in Bun runtime
210
+ * - 'node': Running in Node.js (any version)
211
+ * - 'unknown': Unable to detect runtime
212
+ *
213
+ * @function getRuntime
214
+ * @returns {RuntimeType} The detected runtime identifier
215
+ *
216
+ * @example
217
+ * const runtime = getRuntime()
218
+ * switch (runtime) {
219
+ * case 'deno':
220
+ * console.log('Deno detected')
221
+ * break
222
+ * case 'bun':
223
+ * console.log('Bun detected')
224
+ * break
225
+ * case 'node':
226
+ * console.log('Node.js version:', process.versions.node)
227
+ * break
228
+ * default:
229
+ * console.log('Unknown runtime')
230
+ * }
63
231
  */
64
232
  function getRuntime() {
65
- if (isDeno()) return 'deno'
66
- if (isBun()) return 'bun'
67
- if (typeof process !== 'undefined' && process.versions?.node) return 'node'
68
- return 'unknown'
233
+ if (isDeno()) return "deno";
234
+ if (isBun()) return "bun";
235
+ if (typeof process !== "undefined" && process.versions?.node) return "node";
236
+ /* istanbul ignore next - only reachable in non-Node/Bun/Deno environments */
237
+ return "unknown";
69
238
  }
70
239
 
71
240
  /**
72
- * Get WebSocket provider based on runtime capabilities
73
- * @returns {{ type: string, WebSocketServer: typeof import('./ws').WebSocketServer, runtime: string }}
241
+ * Gets the WebSocket provider based on runtime capabilities.
242
+ *
243
+ * This function detects the current runtime and returns the most appropriate
244
+ * WebSocket implementation:
245
+ *
246
+ * 1. **Deno**: Returns `DenoWebSocketServer` adapter
247
+ * 2. **Bun**: Returns `BunWebSocketServer` adapter
248
+ * 3. **Node.js 24+**: Attempts to load native `node:ws` module
249
+ * 4. **Fallback**: Returns our RFC 6455 compliant polyfill
250
+ *
251
+ * The returned `WebSocketServer` constructor is compatible with the `ws`
252
+ * library API, allowing seamless integration with existing code.
253
+ *
254
+ * @function getWebSocketProvider
255
+ * @returns {WebSocketProvider} Provider object with type, WebSocketServer, and runtime
256
+ *
257
+ * @example
258
+ * const { type, WebSocketServer, runtime } = getWebSocketProvider()
259
+ *
260
+ * console.log(`Runtime: ${runtime}, Provider: ${type}`)
261
+ *
262
+ * // Create a WebSocket server with noServer mode
263
+ * const wss = new WebSocketServer({ noServer: true })
264
+ *
265
+ * // Handle HTTP upgrade requests
266
+ * server.on('upgrade', (req, socket, head) => {
267
+ * wss.handleUpgrade(req, socket, head, (ws) => {
268
+ * wss.emit('connection', ws, req)
269
+ * })
270
+ * })
271
+ *
272
+ * @example
273
+ * // Conditional logic based on provider type
274
+ * const provider = getWebSocketProvider()
275
+ *
276
+ * if (provider.type === 'polyfill') {
277
+ * console.log('Using polyfill - consider upgrading to Node.js 24+')
278
+ * }
74
279
  */
75
280
  function getWebSocketProvider() {
76
- const runtime = getRuntime()
77
-
78
- // 1. Check for Deno runtime
79
- if (runtime === 'deno') {
80
- try {
81
- const { DenoWebSocketServer } = require('./ws/adapters/deno')
82
- return { type: 'deno-native', WebSocketServer: DenoWebSocketServer, runtime }
83
- } catch {
84
- // Adapter not available, fall through to polyfill
85
- }
281
+ const runtime = getRuntime();
282
+
283
+ // 1. Check for Deno runtime
284
+ if (runtime === "deno") {
285
+ try {
286
+ const { DenoWebSocketServer } = require("./ws/adapters/deno");
287
+ return {
288
+ type: "deno-native",
289
+ WebSocketServer: DenoWebSocketServer,
290
+ runtime,
291
+ };
292
+ } catch {
293
+ // Adapter not available, fall through to polyfill
86
294
  }
295
+ }
87
296
 
88
- // 2. Check for Bun runtime
89
- if (runtime === 'bun') {
90
- try {
91
- const { BunWebSocketServer } = require('./ws/adapters/bun')
92
- return { type: 'bun-native', WebSocketServer: BunWebSocketServer, runtime }
93
- } catch {
94
- // Adapter not available, fall through to polyfill
95
- }
297
+ // 2. Check for Bun runtime
298
+ if (runtime === "bun") {
299
+ try {
300
+ const { BunWebSocketServer } = require("./ws/adapters/bun");
301
+ return {
302
+ type: "bun-native",
303
+ WebSocketServer: BunWebSocketServer,
304
+ runtime,
305
+ };
306
+ } catch {
307
+ // Adapter not available, fall through to polyfill
96
308
  }
309
+ }
97
310
 
98
- // 3. Try Node.js 24+ native WebSocketServer
99
- if (isNode24Stable()) {
100
- try {
101
- const { WebSocketServer } = require('node:ws')
102
- if (WebSocketServer) {
103
- return { type: 'node-native', WebSocketServer, runtime }
104
- }
105
- } catch {
106
- // node:ws not available, fall through
107
- }
311
+ // 3. Try Node.js 24+ native WebSocketServer
312
+ /* istanbul ignore next 9 - only reachable on Node 24+ with native WebSocket */
313
+ if (isNode24Stable()) {
314
+ try {
315
+ const { WebSocketServer } = require("node:ws");
316
+ if (WebSocketServer) {
317
+ return { type: "node-native", WebSocketServer, runtime };
318
+ }
319
+ } catch {
320
+ // node:ws not available, fall through to polyfill
108
321
  }
322
+ }
109
323
 
110
- // 4. Fall back to our polyfill
111
- const { WebSocketServer } = require('./ws/index')
112
- return { type: 'polyfill', WebSocketServer, runtime }
324
+ // 4. Fall back to our RFC 6455 compliant polyfill
325
+ const { WebSocketServer } = require("./ws/index");
326
+ return { type: "polyfill", WebSocketServer, runtime };
113
327
  }
114
328
 
115
- // Cache the provider for consistent usage
116
- let cachedProvider = null
329
+ /**
330
+ * Cached WebSocket provider instance.
331
+ * Populated on first call to getCachedProvider().
332
+ *
333
+ * @private
334
+ * @type {WebSocketProvider|null}
335
+ */
336
+ let cachedProvider = null;
117
337
 
118
338
  /**
119
- * Get cached WebSocket provider
120
- * @returns {{ type: string, WebSocketServer: typeof import('./ws').WebSocketServer, runtime: string }}
339
+ * Gets the cached WebSocket provider.
340
+ *
341
+ * This function caches the provider after first detection to ensure
342
+ * consistent behavior throughout the application lifecycle. The same
343
+ * provider is returned on subsequent calls.
344
+ *
345
+ * This is the primary export and should be used instead of calling
346
+ * getWebSocketProvider() directly unless you need to force re-detection.
347
+ *
348
+ * @function getCachedProvider
349
+ * @returns {WebSocketProvider} Cached provider object
350
+ *
351
+ * @example
352
+ * // Multiple calls return the same provider instance
353
+ * const provider1 = getWebSocketProvider()
354
+ * const provider2 = getWebSocketProvider()
355
+ * console.log(provider1 === provider2) // true
121
356
  */
122
357
  function getCachedProvider() {
123
- if (!cachedProvider) {
124
- cachedProvider = getWebSocketProvider()
125
- }
126
- return cachedProvider
358
+ if (!cachedProvider) {
359
+ cachedProvider = getWebSocketProvider();
360
+ }
361
+ return cachedProvider;
127
362
  }
128
363
 
129
364
  module.exports = {
130
- getWebSocketProvider: getCachedProvider,
131
- getRuntime,
132
- isDeno,
133
- isBun,
134
- isNode24Stable
135
- }
365
+ /**
366
+ * Get the cached WebSocket provider (recommended).
367
+ * Returns the same provider instance on subsequent calls.
368
+ * @function
369
+ */
370
+ getWebSocketProvider: getCachedProvider,
371
+
372
+ /**
373
+ * Get the detected runtime type.
374
+ * @function
375
+ */
376
+ getRuntime,
377
+
378
+ /**
379
+ * Check if running in Deno.
380
+ * @function
381
+ */
382
+ isDeno,
383
+
384
+ /**
385
+ * Check if running in Bun.
386
+ * @function
387
+ */
388
+ isBun,
389
+
390
+ /**
391
+ * Check if running on Node.js 24+ stable.
392
+ * @function
393
+ */
394
+ isNode24Stable,
395
+
396
+ /**
397
+ * Set runtime override for testing purposes.
398
+ * @function
399
+ * @private
400
+ */
401
+ _setRuntimeOverride,
402
+
403
+ /**
404
+ * Get current runtime override (for testing).
405
+ * @function
406
+ * @private
407
+ */
408
+ _getRuntimeOverride,
409
+ };