effect 4.1.0 → 4.1.2

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 (445) hide show
  1. package/README.md +30 -0
  2. package/THIRD_PARTY_NOTICES.md +62 -0
  3. package/ai-docs/package.json +2 -2
  4. package/dist/BigDecimal.d.ts +139 -7
  5. package/dist/BigDecimal.d.ts.map +1 -1
  6. package/dist/BigDecimal.js +83 -14
  7. package/dist/BigDecimal.js.map +1 -1
  8. package/dist/ByteSize.d.ts.map +1 -1
  9. package/dist/ByteSize.js +27 -14
  10. package/dist/ByteSize.js.map +1 -1
  11. package/dist/Equal.d.ts +2 -2
  12. package/dist/Equal.d.ts.map +1 -1
  13. package/dist/Equal.js +3 -3
  14. package/dist/Equal.js.map +1 -1
  15. package/dist/Hash.d.ts +3 -2
  16. package/dist/Hash.d.ts.map +1 -1
  17. package/dist/Hash.js +5 -4
  18. package/dist/Hash.js.map +1 -1
  19. package/dist/Iterable.d.ts.map +1 -1
  20. package/dist/Iterable.js +38 -32
  21. package/dist/Iterable.js.map +1 -1
  22. package/dist/JsonSchema.d.ts.map +1 -1
  23. package/dist/JsonSchema.js +27 -6
  24. package/dist/JsonSchema.js.map +1 -1
  25. package/dist/MutableRef.d.ts.map +1 -1
  26. package/dist/MutableRef.js +0 -7
  27. package/dist/MutableRef.js.map +1 -1
  28. package/dist/Path.d.ts.map +1 -1
  29. package/dist/Path.js +5 -1
  30. package/dist/Path.js.map +1 -1
  31. package/dist/Pool.d.ts.map +1 -1
  32. package/dist/Pool.js +2 -1
  33. package/dist/Pool.js.map +1 -1
  34. package/dist/Ref.d.ts.map +1 -1
  35. package/dist/Ref.js +0 -8
  36. package/dist/Ref.js.map +1 -1
  37. package/dist/Schedule.d.ts.map +1 -1
  38. package/dist/Schedule.js +8 -3
  39. package/dist/Schedule.js.map +1 -1
  40. package/dist/Schema.d.ts +2 -1
  41. package/dist/Schema.d.ts.map +1 -1
  42. package/dist/Schema.js +2 -1
  43. package/dist/Schema.js.map +1 -1
  44. package/dist/SchemaRepresentation.d.ts +4 -2
  45. package/dist/SchemaRepresentation.d.ts.map +1 -1
  46. package/dist/SchemaRepresentation.js +4 -2
  47. package/dist/SchemaRepresentation.js.map +1 -1
  48. package/dist/SchemaTransformation.d.ts +2 -2
  49. package/dist/SchemaTransformation.js +2 -2
  50. package/dist/Stream.d.ts.map +1 -1
  51. package/dist/Stream.js +6 -5
  52. package/dist/Stream.js.map +1 -1
  53. package/dist/ai/McpClient.d.ts +171 -19
  54. package/dist/ai/McpClient.d.ts.map +1 -1
  55. package/dist/ai/McpClient.js +277 -66
  56. package/dist/ai/McpClient.js.map +1 -1
  57. package/dist/ai/McpSchema.d.ts +108 -0
  58. package/dist/ai/McpSchema.d.ts.map +1 -1
  59. package/dist/ai/McpSchema.js +99 -0
  60. package/dist/ai/McpSchema.js.map +1 -1
  61. package/dist/ai/McpServer.d.ts +120 -6
  62. package/dist/ai/McpServer.d.ts.map +1 -1
  63. package/dist/ai/McpServer.js +258 -49
  64. package/dist/ai/McpServer.js.map +1 -1
  65. package/dist/ai/Prompt.d.ts.map +1 -1
  66. package/dist/ai/Prompt.js +20 -11
  67. package/dist/ai/Prompt.js.map +1 -1
  68. package/dist/ai/Tool.d.ts.map +1 -1
  69. package/dist/ai/Tool.js +5 -7
  70. package/dist/ai/Tool.js.map +1 -1
  71. package/dist/ai/internal/mcpCore.js +72 -3
  72. package/dist/ai/internal/mcpCore.js.map +1 -1
  73. package/dist/ai/internal/mcpProtocol/v2024_11_05.js +3 -1
  74. package/dist/ai/internal/mcpProtocol/v2024_11_05.js.map +1 -1
  75. package/dist/ai/internal/mcpProtocol/v2025_03_26.js +3 -1
  76. package/dist/ai/internal/mcpProtocol/v2025_03_26.js.map +1 -1
  77. package/dist/ai/internal/mcpProtocol/v2025_06_18.js +3 -1
  78. package/dist/ai/internal/mcpProtocol/v2025_06_18.js.map +1 -1
  79. package/dist/ai/internal/mcpProtocol/v2025_11_25.js +3 -1
  80. package/dist/ai/internal/mcpProtocol/v2025_11_25.js.map +1 -1
  81. package/dist/ai/internal/mcpProtocol/v2026_07_28.js +44 -8
  82. package/dist/ai/internal/mcpProtocol/v2026_07_28.js.map +1 -1
  83. package/dist/ai/internal/mcpProtocol.js +12 -0
  84. package/dist/ai/internal/mcpProtocol.js.map +1 -1
  85. package/dist/ai/internal/mcpRuntime.js +3 -3
  86. package/dist/ai/internal/mcpRuntime.js.map +1 -1
  87. package/dist/ai/internal/mcpSkills.d.ts +2 -0
  88. package/dist/ai/internal/mcpSkills.d.ts.map +1 -0
  89. package/dist/ai/internal/mcpSkills.js +428 -0
  90. package/dist/ai/internal/mcpSkills.js.map +1 -0
  91. package/dist/ai/internal/structured-output.js +11 -2
  92. package/dist/ai/internal/structured-output.js.map +1 -1
  93. package/dist/cluster/ClusterWorkflowEngine.d.ts.map +1 -1
  94. package/dist/cluster/ClusterWorkflowEngine.js +30 -11
  95. package/dist/cluster/ClusterWorkflowEngine.js.map +1 -1
  96. package/dist/cluster/Entity.d.ts +26 -0
  97. package/dist/cluster/Entity.d.ts.map +1 -1
  98. package/dist/cluster/Entity.js.map +1 -1
  99. package/dist/cluster/MessageStorage.d.ts +6 -6
  100. package/dist/cluster/MessageStorage.d.ts.map +1 -1
  101. package/dist/cluster/MessageStorage.js +1 -3
  102. package/dist/cluster/MessageStorage.js.map +1 -1
  103. package/dist/cluster/Reply.d.ts +1 -1
  104. package/dist/cluster/Reply.d.ts.map +1 -1
  105. package/dist/cluster/Reply.js.map +1 -1
  106. package/dist/cluster/Runners.d.ts.map +1 -1
  107. package/dist/cluster/Runners.js +13 -2
  108. package/dist/cluster/Runners.js.map +1 -1
  109. package/dist/cluster/Sharding.d.ts +13 -0
  110. package/dist/cluster/Sharding.d.ts.map +1 -1
  111. package/dist/cluster/Sharding.js +4 -1
  112. package/dist/cluster/Sharding.js.map +1 -1
  113. package/dist/cluster/internal/clusterAbandon.d.ts.map +1 -1
  114. package/dist/cluster/internal/clusterAbandon.js +6 -4
  115. package/dist/cluster/internal/clusterAbandon.js.map +1 -1
  116. package/dist/cluster/internal/entityManager.js +63 -11
  117. package/dist/cluster/internal/entityManager.js.map +1 -1
  118. package/dist/cluster/internal/transactionNotifications.d.ts +5 -0
  119. package/dist/cluster/internal/transactionNotifications.d.ts.map +1 -0
  120. package/dist/cluster/internal/transactionNotifications.js +5 -0
  121. package/dist/cluster/internal/transactionNotifications.js.map +1 -0
  122. package/dist/crypto/Aead.d.ts +2 -1
  123. package/dist/crypto/Aead.d.ts.map +1 -1
  124. package/dist/crypto/Aead.js +2 -2
  125. package/dist/crypto/Aead.js.map +1 -1
  126. package/dist/crypto/Cipher.d.ts +2 -1
  127. package/dist/crypto/Cipher.d.ts.map +1 -1
  128. package/dist/crypto/Cipher.js +2 -2
  129. package/dist/crypto/Cipher.js.map +1 -1
  130. package/dist/crypto/KeyAgreement.d.ts +3 -2
  131. package/dist/crypto/KeyAgreement.d.ts.map +1 -1
  132. package/dist/crypto/KeyAgreement.js +2 -2
  133. package/dist/crypto/KeyAgreement.js.map +1 -1
  134. package/dist/crypto/KeyFormat.d.ts +33 -1
  135. package/dist/crypto/KeyFormat.d.ts.map +1 -1
  136. package/dist/crypto/KeyFormat.js.map +1 -1
  137. package/dist/crypto/KeyWrap.d.ts +4 -3
  138. package/dist/crypto/KeyWrap.d.ts.map +1 -1
  139. package/dist/crypto/KeyWrap.js +2 -2
  140. package/dist/crypto/KeyWrap.js.map +1 -1
  141. package/dist/crypto/Mac.d.ts +2 -1
  142. package/dist/crypto/Mac.d.ts.map +1 -1
  143. package/dist/crypto/Mac.js +2 -2
  144. package/dist/crypto/Mac.js.map +1 -1
  145. package/dist/crypto/Signature.d.ts +3 -2
  146. package/dist/crypto/Signature.d.ts.map +1 -1
  147. package/dist/crypto/Signature.js +2 -2
  148. package/dist/crypto/Signature.js.map +1 -1
  149. package/dist/crypto/WebCrypto.d.ts +19 -0
  150. package/dist/crypto/WebCrypto.d.ts.map +1 -1
  151. package/dist/crypto/WebCrypto.js.map +1 -1
  152. package/dist/crypto/internal/asymmetric.js.map +1 -1
  153. package/dist/crypto/internal/key.js +3 -2
  154. package/dist/crypto/internal/key.js.map +1 -1
  155. package/dist/encoding/Base64Url.d.ts.map +1 -1
  156. package/dist/encoding/Base64Url.js +26 -3
  157. package/dist/encoding/Base64Url.js.map +1 -1
  158. package/dist/encoding/Json5.d.ts +44 -0
  159. package/dist/encoding/Json5.d.ts.map +1 -0
  160. package/dist/encoding/Json5.js +56 -0
  161. package/dist/encoding/Json5.js.map +1 -0
  162. package/dist/encoding/Jsonc.d.ts +47 -0
  163. package/dist/encoding/Jsonc.d.ts.map +1 -0
  164. package/dist/encoding/Jsonc.js +120 -0
  165. package/dist/encoding/Jsonc.js.map +1 -0
  166. package/dist/encoding/Ndjson.d.ts +5 -4
  167. package/dist/encoding/Ndjson.d.ts.map +1 -1
  168. package/dist/encoding/Ndjson.js +6 -5
  169. package/dist/encoding/Ndjson.js.map +1 -1
  170. package/dist/encoding/SchemaBinary.d.ts +94 -0
  171. package/dist/encoding/SchemaBinary.d.ts.map +1 -1
  172. package/dist/encoding/SchemaBinary.js +219 -6
  173. package/dist/encoding/SchemaBinary.js.map +1 -1
  174. package/dist/encoding/Sse.d.ts +3 -1
  175. package/dist/encoding/Sse.d.ts.map +1 -1
  176. package/dist/encoding/Sse.js +5 -3
  177. package/dist/encoding/Sse.js.map +1 -1
  178. package/dist/encoding/index.d.ts +10 -0
  179. package/dist/encoding/index.d.ts.map +1 -1
  180. package/dist/encoding/index.js +10 -0
  181. package/dist/encoding/index.js.map +1 -1
  182. package/dist/eventlog/EventLog.d.ts +7 -0
  183. package/dist/eventlog/EventLog.d.ts.map +1 -1
  184. package/dist/eventlog/EventLog.js +7 -0
  185. package/dist/eventlog/EventLog.js.map +1 -1
  186. package/dist/eventlog/EventLogServer.d.ts +7 -1
  187. package/dist/eventlog/EventLogServer.d.ts.map +1 -1
  188. package/dist/eventlog/EventLogServer.js +55 -24
  189. package/dist/eventlog/EventLogServer.js.map +1 -1
  190. package/dist/eventlog/EventLogServerEncrypted.d.ts +10 -0
  191. package/dist/eventlog/EventLogServerEncrypted.d.ts.map +1 -1
  192. package/dist/eventlog/EventLogServerEncrypted.js.map +1 -1
  193. package/dist/eventlog/EventLogServerUnencrypted.d.ts +17 -0
  194. package/dist/eventlog/EventLogServerUnencrypted.d.ts.map +1 -1
  195. package/dist/eventlog/EventLogServerUnencrypted.js +14 -2
  196. package/dist/eventlog/EventLogServerUnencrypted.js.map +1 -1
  197. package/dist/eventlog/EventLogSessionAuth.d.ts +21 -0
  198. package/dist/eventlog/EventLogSessionAuth.d.ts.map +1 -1
  199. package/dist/eventlog/EventLogSessionAuth.js +22 -0
  200. package/dist/eventlog/EventLogSessionAuth.js.map +1 -1
  201. package/dist/graphql/GraphQLClient.d.ts +3 -1
  202. package/dist/graphql/GraphQLClient.d.ts.map +1 -1
  203. package/dist/graphql/GraphQLClient.js.map +1 -1
  204. package/dist/graphql/GraphQLClientError.d.ts +14 -9
  205. package/dist/graphql/GraphQLClientError.d.ts.map +1 -1
  206. package/dist/graphql/GraphQLClientError.js +14 -21
  207. package/dist/graphql/GraphQLClientError.js.map +1 -1
  208. package/dist/graphql/GraphQLProtocol.d.ts +12 -3
  209. package/dist/graphql/GraphQLProtocol.d.ts.map +1 -1
  210. package/dist/graphql/GraphQLProtocol.js +4 -1
  211. package/dist/graphql/GraphQLProtocol.js.map +1 -1
  212. package/dist/http/HttpClient.d.ts +204 -16
  213. package/dist/http/HttpClient.d.ts.map +1 -1
  214. package/dist/http/HttpClient.js +93 -13
  215. package/dist/http/HttpClient.js.map +1 -1
  216. package/dist/http/HttpServerRequest.d.ts.map +1 -1
  217. package/dist/http/HttpServerRequest.js +38 -22
  218. package/dist/http/HttpServerRequest.js.map +1 -1
  219. package/dist/http/internal/mimeTypes.d.ts +4 -1
  220. package/dist/http/internal/mimeTypes.d.ts.map +1 -1
  221. package/dist/http/internal/mimeTypes.js +4 -1
  222. package/dist/http/internal/mimeTypes.js.map +1 -1
  223. package/dist/http-api/HttpApiSchema.js +1 -1
  224. package/dist/http-api/HttpApiSchema.js.map +1 -1
  225. package/dist/internal/dateTime.js +66 -27
  226. package/dist/internal/dateTime.js.map +1 -1
  227. package/dist/internal/effect.js +10 -0
  228. package/dist/internal/effect.js.map +1 -1
  229. package/dist/internal/glob.js +234 -56
  230. package/dist/internal/glob.js.map +1 -1
  231. package/dist/internal/graphql.js +21 -7
  232. package/dist/internal/graphql.js.map +1 -1
  233. package/dist/internal/graphqlHeaders.d.ts +7 -0
  234. package/dist/internal/graphqlHeaders.d.ts.map +1 -1
  235. package/dist/internal/graphqlHeaders.js +11 -0
  236. package/dist/internal/graphqlHeaders.js.map +1 -1
  237. package/dist/internal/jsonParser.d.ts +5 -0
  238. package/dist/internal/jsonParser.d.ts.map +1 -0
  239. package/dist/internal/jsonParser.js +280 -0
  240. package/dist/internal/jsonParser.js.map +1 -0
  241. package/dist/internal/persistence.js +8 -1
  242. package/dist/internal/persistence.js.map +1 -1
  243. package/dist/internal/request.js +29 -42
  244. package/dist/internal/request.js.map +1 -1
  245. package/dist/internal/schema/fromJsonSchemaDocument.js +7 -8
  246. package/dist/internal/schema/fromJsonSchemaDocument.js.map +1 -1
  247. package/dist/internal/sql.js +16 -0
  248. package/dist/internal/sql.js.map +1 -1
  249. package/dist/internal/version.js +1 -1
  250. package/dist/jose/JoseError.d.ts +285 -0
  251. package/dist/jose/JoseError.d.ts.map +1 -0
  252. package/dist/jose/JoseError.js +269 -0
  253. package/dist/jose/JoseError.js.map +1 -0
  254. package/dist/jose/Jwe.d.ts +128 -0
  255. package/dist/jose/Jwe.d.ts.map +1 -0
  256. package/dist/jose/Jwe.js +134 -0
  257. package/dist/jose/Jwe.js.map +1 -0
  258. package/dist/jose/Jwk.d.ts +597 -0
  259. package/dist/jose/Jwk.d.ts.map +1 -0
  260. package/dist/jose/Jwk.js +503 -0
  261. package/dist/jose/Jwk.js.map +1 -0
  262. package/dist/jose/Jwks.d.ts +236 -0
  263. package/dist/jose/Jwks.d.ts.map +1 -0
  264. package/dist/jose/Jwks.js +306 -0
  265. package/dist/jose/Jwks.js.map +1 -0
  266. package/dist/jose/Jws.d.ts +177 -0
  267. package/dist/jose/Jws.d.ts.map +1 -0
  268. package/dist/jose/Jws.js +183 -0
  269. package/dist/jose/Jws.js.map +1 -0
  270. package/dist/jose/Jwt.d.ts +270 -0
  271. package/dist/jose/Jwt.d.ts.map +1 -0
  272. package/dist/jose/Jwt.js +293 -0
  273. package/dist/jose/Jwt.js.map +1 -0
  274. package/dist/jose/index.d.ts +51 -0
  275. package/dist/jose/index.d.ts.map +1 -0
  276. package/dist/jose/index.js +52 -0
  277. package/dist/jose/index.js.map +1 -0
  278. package/dist/jose/internal/compact.d.ts +2 -0
  279. package/dist/jose/internal/compact.d.ts.map +1 -0
  280. package/dist/jose/internal/compact.js +179 -0
  281. package/dist/jose/internal/compact.js.map +1 -0
  282. package/dist/net/Host.d.ts.map +1 -1
  283. package/dist/net/Host.js +5 -10
  284. package/dist/net/Host.js.map +1 -1
  285. package/dist/observability/OtlpExporter.d.ts +4 -0
  286. package/dist/observability/OtlpExporter.d.ts.map +1 -1
  287. package/dist/observability/OtlpExporter.js +40 -12
  288. package/dist/observability/OtlpExporter.js.map +1 -1
  289. package/dist/observability/OtlpSerialization.d.ts +1 -1
  290. package/dist/observability/OtlpSerialization.d.ts.map +1 -1
  291. package/dist/observability/OtlpSerialization.js +10 -4
  292. package/dist/observability/OtlpSerialization.js.map +1 -1
  293. package/dist/observability/internal/otlpProtobuf.js +3 -3
  294. package/dist/observability/internal/otlpProtobuf.js.map +1 -1
  295. package/dist/observability/internal/protobuf.js +6 -0
  296. package/dist/observability/internal/protobuf.js.map +1 -1
  297. package/dist/persistence/CircuitBreaker.d.ts +98 -38
  298. package/dist/persistence/CircuitBreaker.d.ts.map +1 -1
  299. package/dist/persistence/CircuitBreaker.js +67 -29
  300. package/dist/persistence/CircuitBreaker.js.map +1 -1
  301. package/dist/persistence/RateLimiter.d.ts +15 -0
  302. package/dist/persistence/RateLimiter.d.ts.map +1 -1
  303. package/dist/persistence/RateLimiter.js +76 -16
  304. package/dist/persistence/RateLimiter.js.map +1 -1
  305. package/dist/persistence/index.d.ts +1 -1
  306. package/dist/persistence/index.js +1 -1
  307. package/dist/reactivity/AtomRegistry.js +17 -7
  308. package/dist/reactivity/AtomRegistry.js.map +1 -1
  309. package/dist/rpc/Rpc.d.ts +1 -1
  310. package/dist/rpc/Rpc.d.ts.map +1 -1
  311. package/dist/rpc/Rpc.js.map +1 -1
  312. package/dist/rpc/RpcClient.d.ts +14 -2
  313. package/dist/rpc/RpcClient.d.ts.map +1 -1
  314. package/dist/rpc/RpcClient.js +38 -21
  315. package/dist/rpc/RpcClient.js.map +1 -1
  316. package/dist/rpc/RpcMessage.d.ts +3 -2
  317. package/dist/rpc/RpcMessage.d.ts.map +1 -1
  318. package/dist/rpc/RpcMessage.js.map +1 -1
  319. package/dist/rpc/RpcServer.d.ts.map +1 -1
  320. package/dist/rpc/RpcServer.js +10 -1
  321. package/dist/rpc/RpcServer.js.map +1 -1
  322. package/dist/sql/Migrator.d.ts +9 -1
  323. package/dist/sql/Migrator.d.ts.map +1 -1
  324. package/dist/sql/Migrator.js +18 -6
  325. package/dist/sql/Migrator.js.map +1 -1
  326. package/dist/sql/SqlClient.d.ts +46 -3
  327. package/dist/sql/SqlClient.d.ts.map +1 -1
  328. package/dist/sql/SqlClient.js +40 -15
  329. package/dist/sql/SqlClient.js.map +1 -1
  330. package/dist/sql/Statement.d.ts +46 -3
  331. package/dist/sql/Statement.d.ts.map +1 -1
  332. package/dist/sql/Statement.js +32 -26
  333. package/dist/sql/Statement.js.map +1 -1
  334. package/dist/workflow/Workflow.d.ts +4 -0
  335. package/dist/workflow/Workflow.d.ts.map +1 -1
  336. package/dist/workflow/Workflow.js.map +1 -1
  337. package/dist/workflow/WorkflowEngine.d.ts.map +1 -1
  338. package/dist/workflow/WorkflowEngine.js +5 -0
  339. package/dist/workflow/WorkflowEngine.js.map +1 -1
  340. package/package.json +7 -3
  341. package/src/BigDecimal.ts +170 -16
  342. package/src/ByteSize.ts +29 -14
  343. package/src/Equal.ts +3 -3
  344. package/src/Hash.ts +5 -4
  345. package/src/Iterable.ts +28 -19
  346. package/src/JsonSchema.ts +45 -7
  347. package/src/MutableRef.ts +1 -8
  348. package/src/Path.ts +6 -1
  349. package/src/Pool.ts +2 -1
  350. package/src/Ref.ts +0 -8
  351. package/src/Schedule.ts +8 -6
  352. package/src/Schema.ts +3 -2
  353. package/src/SchemaRepresentation.ts +4 -2
  354. package/src/SchemaTransformation.ts +2 -2
  355. package/src/Stream.ts +6 -5
  356. package/src/ai/McpClient.ts +488 -91
  357. package/src/ai/McpSchema.ts +119 -0
  358. package/src/ai/McpServer.ts +302 -56
  359. package/src/ai/Prompt.ts +16 -11
  360. package/src/ai/Tool.ts +5 -10
  361. package/src/ai/internal/mcpCore.ts +165 -12
  362. package/src/ai/internal/mcpProtocol/v2024_11_05.ts +3 -1
  363. package/src/ai/internal/mcpProtocol/v2025_03_26.ts +3 -1
  364. package/src/ai/internal/mcpProtocol/v2025_06_18.ts +3 -1
  365. package/src/ai/internal/mcpProtocol/v2025_11_25.ts +3 -1
  366. package/src/ai/internal/mcpProtocol/v2026_07_28.ts +42 -9
  367. package/src/ai/internal/mcpProtocol.ts +15 -0
  368. package/src/ai/internal/mcpRuntime.ts +6 -3
  369. package/src/ai/internal/mcpSkills.ts +480 -0
  370. package/src/ai/internal/structured-output.ts +10 -4
  371. package/src/cluster/ClusterWorkflowEngine.ts +48 -33
  372. package/src/cluster/Entity.ts +52 -0
  373. package/src/cluster/MessageStorage.ts +3 -6
  374. package/src/cluster/Reply.ts +1 -1
  375. package/src/cluster/Runners.ts +16 -2
  376. package/src/cluster/Sharding.ts +17 -1
  377. package/src/cluster/internal/clusterAbandon.ts +7 -7
  378. package/src/cluster/internal/entityManager.ts +89 -15
  379. package/src/cluster/internal/transactionNotifications.ts +7 -0
  380. package/src/crypto/Aead.ts +3 -3
  381. package/src/crypto/Cipher.ts +3 -3
  382. package/src/crypto/KeyAgreement.ts +4 -4
  383. package/src/crypto/KeyFormat.ts +30 -1
  384. package/src/crypto/KeyWrap.ts +6 -6
  385. package/src/crypto/Mac.ts +3 -3
  386. package/src/crypto/Signature.ts +4 -4
  387. package/src/crypto/WebCrypto.ts +20 -0
  388. package/src/crypto/internal/asymmetric.ts +2 -1
  389. package/src/crypto/internal/key.ts +12 -5
  390. package/src/encoding/Base64Url.ts +27 -3
  391. package/src/encoding/Json5.ts +59 -0
  392. package/src/encoding/Jsonc.ts +126 -0
  393. package/src/encoding/Ndjson.ts +6 -5
  394. package/src/encoding/SchemaBinary.ts +228 -7
  395. package/src/encoding/Sse.ts +5 -3
  396. package/src/encoding/index.ts +12 -0
  397. package/src/eventlog/EventLog.ts +7 -0
  398. package/src/eventlog/EventLogServer.ts +67 -24
  399. package/src/eventlog/EventLogServerEncrypted.ts +5 -0
  400. package/src/eventlog/EventLogServerUnencrypted.ts +19 -2
  401. package/src/eventlog/EventLogSessionAuth.ts +26 -0
  402. package/src/graphql/GraphQLClient.ts +3 -1
  403. package/src/graphql/GraphQLClientError.ts +15 -22
  404. package/src/graphql/GraphQLProtocol.ts +12 -3
  405. package/src/http/HttpClient.ts +244 -33
  406. package/src/http/HttpServerRequest.ts +61 -23
  407. package/src/http/internal/mimeTypes.ts +4 -1
  408. package/src/http-api/HttpApiSchema.ts +1 -1
  409. package/src/internal/dateTime.ts +80 -27
  410. package/src/internal/effect.ts +6 -0
  411. package/src/internal/glob.ts +279 -63
  412. package/src/internal/graphql.ts +27 -9
  413. package/src/internal/graphqlHeaders.ts +13 -0
  414. package/src/internal/jsonParser.ts +307 -0
  415. package/src/internal/persistence.ts +9 -1
  416. package/src/internal/request.ts +51 -58
  417. package/src/internal/schema/fromJsonSchemaDocument.ts +11 -10
  418. package/src/internal/sql.ts +25 -0
  419. package/src/internal/version.ts +1 -1
  420. package/src/jose/JoseError.ts +329 -0
  421. package/src/jose/Jwe.ts +196 -0
  422. package/src/jose/Jwk.ts +777 -0
  423. package/src/jose/Jwks.ts +418 -0
  424. package/src/jose/Jws.ts +312 -0
  425. package/src/jose/Jwt.ts +493 -0
  426. package/src/jose/index.ts +58 -0
  427. package/src/jose/internal/compact.ts +195 -0
  428. package/src/net/Host.ts +5 -10
  429. package/src/observability/OtlpExporter.ts +42 -18
  430. package/src/observability/OtlpSerialization.ts +13 -5
  431. package/src/observability/internal/otlpProtobuf.ts +6 -6
  432. package/src/observability/internal/protobuf.ts +10 -0
  433. package/src/persistence/CircuitBreaker.ts +113 -48
  434. package/src/persistence/RateLimiter.ts +97 -19
  435. package/src/persistence/index.ts +1 -1
  436. package/src/reactivity/AtomRegistry.ts +19 -8
  437. package/src/rpc/Rpc.ts +3 -1
  438. package/src/rpc/RpcClient.ts +44 -24
  439. package/src/rpc/RpcMessage.ts +3 -2
  440. package/src/rpc/RpcServer.ts +12 -1
  441. package/src/sql/Migrator.ts +35 -18
  442. package/src/sql/SqlClient.ts +91 -22
  443. package/src/sql/Statement.ts +60 -35
  444. package/src/workflow/Workflow.ts +4 -0
  445. package/src/workflow/WorkflowEngine.ts +5 -0
@@ -972,6 +972,139 @@ export function fieldId(id: number) {
972
972
 
973
973
  const FIELD_ID_ANNOTATION_KEY = "~effect/encoding/SchemaBinary/fieldId"
974
974
 
975
+ // Marks the check that opts a number or bigint into a fixed-width encoding.
976
+ // It lives on a check, not the AST, so later annotations and checks keep it.
977
+ const FIXED_WIDTH_ANNOTATION_KEY = "~effect/encoding/SchemaBinary/fixedWidth"
978
+
979
+ type FixedWidthKind = "i32" | "u32" | "i64" | "u64"
980
+
981
+ const BIGINT_I64_MIN = BigInt("-9223372036854775808")
982
+ const BIGINT_I64_MAX = BigInt("9223372036854775807")
983
+ const BIGINT_U64_MAX = BigInt("18446744073709551615")
984
+
985
+ /**
986
+ * A 32-bit signed integer written as four little-endian bytes.
987
+ *
988
+ * **When to use**
989
+ *
990
+ * Use when values regularly need more than four bytes as a varint, such as
991
+ * hashes or full-range ids. Small values are cheaper as `Schema.Int`.
992
+ *
993
+ * **Details**
994
+ *
995
+ * Rejects non-integers and values outside -2147483648 through 2147483647
996
+ * instead of truncating them. `-0` is written as `0`.
997
+ *
998
+ * **Gotchas**
999
+ *
1000
+ * Switching a field between this, {@link uint32}, `Schema.Number` or
1001
+ * `Schema.Int` changes its encoding, so it is not a compatible evolution. In
1002
+ * default mode the other reader can decode a different value without an error,
1003
+ * for example after a signedness swap or inside an array of structs.
1004
+ * Fingerprint mode rejects the layout mismatch.
1005
+ *
1006
+ * **Example** (Declaring fixed-width integer fields)
1007
+ *
1008
+ * ```ts
1009
+ * import { Schema } from "effect"
1010
+ * import { SchemaBinary } from "effect/encoding"
1011
+ *
1012
+ * const Packet = Schema.Struct({
1013
+ * version: SchemaBinary.uint32,
1014
+ * offset: SchemaBinary.int32,
1015
+ * sequence: SchemaBinary.uint64,
1016
+ * timestamp: SchemaBinary.int64
1017
+ * })
1018
+ * ```
1019
+ *
1020
+ * @stability unstable
1021
+ * @category schemas
1022
+ * @since 4.0.0
1023
+ */
1024
+ export const int32: Schema.Number = Schema.Number.check(
1025
+ Schema.isInt32({ [FIXED_WIDTH_ANNOTATION_KEY]: "i32" })
1026
+ )
1027
+
1028
+ /**
1029
+ * A 32-bit unsigned integer written as four little-endian bytes.
1030
+ *
1031
+ * **Details**
1032
+ *
1033
+ * Rejects non-integers and values outside 0 through 4294967295 instead of
1034
+ * wrapping them. See {@link int32} for when a fixed width pays off.
1035
+ *
1036
+ * @stability unstable
1037
+ * @category schemas
1038
+ * @since 4.0.0
1039
+ */
1040
+ export const uint32: Schema.Number = Schema.Number.check(
1041
+ Schema.isUint32({ [FIXED_WIDTH_ANNOTATION_KEY]: "u32" })
1042
+ )
1043
+
1044
+ /**
1045
+ * A 64-bit signed integer, as a `bigint`, written as eight little-endian bytes.
1046
+ *
1047
+ * **Details**
1048
+ *
1049
+ * Rejects values outside -2^63 through 2^63 - 1 instead of wrapping them. As a
1050
+ * struct field it costs one length byte more than the payload, because the
1051
+ * eight-byte field kind belongs to floating-point numbers.
1052
+ *
1053
+ * **Gotchas**
1054
+ *
1055
+ * Switching a field between this, {@link uint64} or `Schema.BigInt` is not a
1056
+ * compatible evolution. All three are length-prefixed struct fields, and eight
1057
+ * bytes can be valid for each, so a default-mode reader may decode the other
1058
+ * form as a different value without an error. Fingerprint mode rejects the
1059
+ * layout mismatch.
1060
+ *
1061
+ * @stability unstable
1062
+ * @category schemas
1063
+ * @since 4.0.0
1064
+ */
1065
+ export const int64: Schema.BigInt = Schema.BigInt.check(
1066
+ Schema.isBetweenBigInt({ minimum: BIGINT_I64_MIN, maximum: BIGINT_I64_MAX }, {
1067
+ expected: "a 64-bit integer",
1068
+ [FIXED_WIDTH_ANNOTATION_KEY]: "i64"
1069
+ })
1070
+ )
1071
+
1072
+ /**
1073
+ * A 64-bit unsigned integer, as a `bigint`, written as eight little-endian
1074
+ * bytes.
1075
+ *
1076
+ * **Details**
1077
+ *
1078
+ * Rejects values outside 0 through 2^64 - 1 instead of wrapping them. See
1079
+ * {@link int64} for the struct field cost.
1080
+ *
1081
+ * **Gotchas**
1082
+ *
1083
+ * Switching a field between this, {@link int64} or `Schema.BigInt` can decode
1084
+ * as a different value without an error in default mode; see {@link int64}.
1085
+ *
1086
+ * @stability unstable
1087
+ * @category schemas
1088
+ * @since 4.0.0
1089
+ */
1090
+ export const uint64: Schema.BigInt = Schema.BigInt.check(
1091
+ Schema.isBetweenBigInt({ minimum: BigInt(0), maximum: BIGINT_U64_MAX }, {
1092
+ expected: "a 64-bit unsigned integer",
1093
+ [FIXED_WIDTH_ANNOTATION_KEY]: "u64"
1094
+ })
1095
+ )
1096
+
1097
+ // The fixed width the schema opted into, from any of its checks.
1098
+ function fixedWidthKind(ast: SchemaAST.AST): FixedWidthKind | undefined {
1099
+ const checks = ast.checks
1100
+ if (checks === undefined) return undefined
1101
+ for (const check of checks) {
1102
+ const kind = check.annotations?.[FIXED_WIDTH_ANNOTATION_KEY]
1103
+ if (kind !== undefined) return kind as FixedWidthKind
1104
+ }
1105
+ return undefined
1106
+ }
1107
+
975
1108
  // Bit 0 selects fingerprint mode; all other flag bits are reserved.
976
1109
  const ENVELOPE = 0x20 // version nibble 2, flags 0
977
1110
  const ENVELOPE_FINGERPRINT = 0x21 // version nibble 2, flag bit 0
@@ -1370,6 +1503,11 @@ class Writer {
1370
1503
  this.view.setBigInt64(this.start + this.len, n, true)
1371
1504
  this.len += 8
1372
1505
  }
1506
+ u64(n: bigint) {
1507
+ this.ensure(8)
1508
+ this.view.setBigUint64(this.start + this.len, n, true)
1509
+ this.len += 8
1510
+ }
1373
1511
  u32le(n: number) {
1374
1512
  this.ensure(4)
1375
1513
  this.view.setUint32(this.start + this.len, n >>> 0, true)
@@ -1801,6 +1939,12 @@ class Reader {
1801
1939
  this.pos += 8
1802
1940
  return value
1803
1941
  }
1942
+ u64(): bigint {
1943
+ if (this.pos + 8 > this.end) invalid("complete value", undefined, this.options)
1944
+ const value = (this.view ?? this.dataView()).getBigUint64(this.pos, true)
1945
+ this.pos += 8
1946
+ return value
1947
+ }
1804
1948
  u32le(): number {
1805
1949
  if (this.pos + 4 > this.end) invalid("complete value", undefined, this.options)
1806
1950
  const value = (this.view ?? this.dataView()).getUint32(this.pos, true)
@@ -1825,6 +1969,7 @@ type LeafKind =
1825
1969
  | "symbol"
1826
1970
  | "bytes"
1827
1971
  | "bigint"
1972
+ | FixedWidthKind
1828
1973
  | "json"
1829
1974
  | "duration"
1830
1975
  | "bigDecimal"
@@ -2007,7 +2152,12 @@ function packedSize(layout: Layout): number | undefined {
2007
2152
  return packedSize(layout.leaf)
2008
2153
  case "bool":
2009
2154
  return 1
2155
+ case "i32":
2156
+ case "u32":
2157
+ return 4
2010
2158
  case "int64":
2159
+ case "i64":
2160
+ case "u64":
2011
2161
  return 8
2012
2162
  default:
2013
2163
  return undefined
@@ -2318,10 +2468,15 @@ function compileLayout(root: SchemaAST.AST): CompiledLayout {
2318
2468
  case "Undefined":
2319
2469
  case "Void":
2320
2470
  return leaf("undefined")
2321
- case "Number":
2471
+ case "Number": {
2472
+ const fixed = fixedWidthKind(ast)
2473
+ if (fixed === "i32" || fixed === "u32") return leaf(fixed)
2322
2474
  return leaf(provesInteger(ast) ? "int" : "number")
2323
- case "BigInt":
2324
- return leaf("bigint")
2475
+ }
2476
+ case "BigInt": {
2477
+ const fixed = fixedWidthKind(ast)
2478
+ return leaf(fixed === "i64" || fixed === "u64" ? fixed : "bigint")
2479
+ }
2325
2480
  case "Literal":
2326
2481
  return literalLayout(leaf(literalKind(ast.literal)), [ast.literal])
2327
2482
  case "Unknown":
@@ -2685,7 +2840,7 @@ function isExact(root: SchemaAST.AST): boolean {
2685
2840
  const walked = new Map<SchemaAST.AST, boolean>()
2686
2841
  const exact = (ast: SchemaAST.AST): boolean => {
2687
2842
  if (
2688
- ast.encoding !== undefined || ast.checks !== undefined ||
2843
+ ast.encoding !== undefined || (ast.checks !== undefined && !isFixedWidthOnly(ast)) ||
2689
2844
  (ast as { readonly encodingChecks?: SchemaAST.Checks }).encodingChecks !== undefined
2690
2845
  ) {
2691
2846
  return false
@@ -2746,6 +2901,13 @@ function isExact(root: SchemaAST.AST): boolean {
2746
2901
  return exact(root)
2747
2902
  }
2748
2903
 
2904
+ // The binary layer enforces a fixed-width check on its own, so it is exact
2905
+ // when no other check rides along.
2906
+ function isFixedWidthOnly(ast: SchemaAST.AST): boolean {
2907
+ return (ast._tag === "Number" || ast._tag === "BigInt") && ast.checks?.length === 1 &&
2908
+ fixedWidthKind(ast) !== undefined
2909
+ }
2910
+
2749
2911
  // A clean Exit whose success schema is exact: the binary layer fully produces
2750
2912
  // and validates success exits, so only failure exits need the schema pass for
2751
2913
  // their cause's error and defect encodings.
@@ -2784,7 +2946,11 @@ const F = {
2784
2946
  exit: 22,
2785
2947
  cause: 23,
2786
2948
  causeReason: 24,
2787
- literal: 25
2949
+ literal: 25,
2950
+ i32: 26,
2951
+ u32: 27,
2952
+ i64: 28,
2953
+ u64: 29
2788
2954
  } as const
2789
2955
 
2790
2956
  // Hash the compiled layout graph, including cycle back-edge distances.
@@ -2828,6 +2994,10 @@ function layoutFingerprint(root: Layout): bigint {
2828
2994
  case "symbol":
2829
2995
  case "bytes":
2830
2996
  case "bigint":
2997
+ case "i32":
2998
+ case "u32":
2999
+ case "i64":
3000
+ case "u64":
2831
3001
  case "json":
2832
3002
  case "duration":
2833
3003
  case "bigDecimal":
@@ -2986,12 +3156,16 @@ function matchesLayout(layout: Layout, value: unknown): boolean {
2986
3156
  return value === undefined
2987
3157
  case "number":
2988
3158
  case "int":
3159
+ case "i32":
3160
+ case "u32":
2989
3161
  return typeof value === "number"
2990
3162
  case "string":
2991
3163
  return typeof value === "string"
2992
3164
  case "symbol":
2993
3165
  return typeof value === "symbol"
2994
3166
  case "bigint":
3167
+ case "i64":
3168
+ case "u64":
2995
3169
  return typeof value === "bigint"
2996
3170
  case "bytes":
2997
3171
  return value instanceof Uint8Array
@@ -3287,6 +3461,10 @@ function valueWireCode(layout: Layout, value: unknown, options: SchemaAST.ParseO
3287
3461
  case "int":
3288
3462
  if (!Number.isSafeInteger(value)) encodeFail("an integer", value, options)
3289
3463
  return FIELD_WIRE_VARINT
3464
+ // The payload write validates the value.
3465
+ case "i32":
3466
+ case "u32":
3467
+ return FIELD_WIRE_FIXED32
3290
3468
  default:
3291
3469
  return FIELD_WIRE_SIZED
3292
3470
  }
@@ -3295,8 +3473,8 @@ function valueWireCode(layout: Layout, value: unknown, options: SchemaAST.ParseO
3295
3473
  function encodeWirePayload(ctx: EncodeContext, layout: Layout, value: unknown, wire: number, w: Writer) {
3296
3474
  const kind = wire % FIELD_WIRE_FACTOR
3297
3475
  switch (kind) {
3298
- // EMPTY and FIXED32 are decoder-side skip support only; `valueWireCode`
3299
- // never produces them.
3476
+ // EMPTY is decoder-side skip support only; `valueWireCode` never produces
3477
+ // it.
3300
3478
  case FIELD_WIRE_FALSE:
3301
3479
  case FIELD_WIRE_TRUE:
3302
3480
  return
@@ -3306,6 +3484,9 @@ function encodeWirePayload(ctx: EncodeContext, layout: Layout, value: unknown, w
3306
3484
  case FIELD_WIRE_FIXED64:
3307
3485
  w.f64(value as number)
3308
3486
  return
3487
+ case FIELD_WIRE_FIXED32:
3488
+ encodeValue(ctx, layout, value, w)
3489
+ return
3309
3490
  case FIELD_WIRE_DECIMAL: {
3310
3491
  const scale = Math.floor(wire / FIELD_WIRE_FACTOR)
3311
3492
  w.numberVarint(Math.round((value as number) * POW10[scale]))
@@ -4010,6 +4191,29 @@ function encodeValue(ctx: EncodeContext, layout: Layout, value: unknown, w: Writ
4010
4191
  if (typeof value !== "bigint") encodeFail("a bigint", value, ctx.options)
4011
4192
  w.zigzag(value)
4012
4193
  return
4194
+ // `disableChecks` can bypass the range check used to select these layouts.
4195
+ case "i32":
4196
+ if (typeof value !== "number" || (value | 0) !== value) encodeFail("a 32-bit integer", value, ctx.options)
4197
+ w.i32le(value)
4198
+ return
4199
+ case "u32":
4200
+ if (typeof value !== "number" || value >>> 0 !== value) {
4201
+ encodeFail("a 32-bit unsigned integer", value, ctx.options)
4202
+ }
4203
+ w.u32le(value)
4204
+ return
4205
+ case "i64":
4206
+ if (typeof value !== "bigint" || value < BIGINT_I64_MIN || value > BIGINT_I64_MAX) {
4207
+ encodeFail("a 64-bit integer", value, ctx.options)
4208
+ }
4209
+ w.i64(value)
4210
+ return
4211
+ case "u64":
4212
+ if (typeof value !== "bigint" || value < BIGINT_ZERO || value > BIGINT_U64_MAX) {
4213
+ encodeFail("a 64-bit unsigned integer", value, ctx.options)
4214
+ }
4215
+ w.u64(value)
4216
+ return
4013
4217
  case "int64": {
4014
4218
  if (!matchesLayout(layout, value)) {
4015
4219
  encodeFail(layout.flavor === "date" ? "a Date" : "a DateTime.Utc", value, ctx.options)
@@ -4375,6 +4579,9 @@ function fieldWireMask(layout: Layout): number {
4375
4579
  return (1 << FIELD_WIRE_VARINT) | (1 << FIELD_WIRE_FIXED64) | (1 << FIELD_WIRE_DECIMAL)
4376
4580
  case "int":
4377
4581
  return 1 << FIELD_WIRE_VARINT
4582
+ case "i32":
4583
+ case "u32":
4584
+ return 1 << FIELD_WIRE_FIXED32
4378
4585
  default:
4379
4586
  return 1 << FIELD_WIRE_SIZED
4380
4587
  }
@@ -4406,6 +4613,8 @@ function decodeFieldPayload(layout: Layout, wireMask: number, kind: number, r: R
4406
4613
  skipFieldPayload(kind, r)
4407
4614
  return ABSENT
4408
4615
  }
4616
+ // Only the two 32-bit layouts accept this kind, so the payload needs no window.
4617
+ if (kind === FIELD_WIRE_FIXED32) return layout._ === "u32" ? r.u32le() : r.i32le()
4409
4618
  if (kind !== FIELD_WIRE_SIZED) {
4410
4619
  const value = decodeScalarField(kind, r)
4411
4620
  if (layout._ === "literal" && !hasLiteral(layout, value)) {
@@ -4993,6 +5202,18 @@ function decodeValueUnchecked(layout: Layout, r: Reader): unknown {
4993
5202
  return r.takeCopy(r.end - r.pos)
4994
5203
  case "bigint":
4995
5204
  return r.zigzag()
5205
+ case "i32":
5206
+ if (r.remaining !== 4) invalid("a 32-bit integer", undefined, r.options)
5207
+ return r.i32le()
5208
+ case "u32":
5209
+ if (r.remaining !== 4) invalid("a 32-bit unsigned integer", undefined, r.options)
5210
+ return r.u32le()
5211
+ case "i64":
5212
+ if (r.remaining !== 8) invalid("a 64-bit integer", undefined, r.options)
5213
+ return r.i64()
5214
+ case "u64":
5215
+ if (r.remaining !== 8) invalid("a 64-bit unsigned integer", undefined, r.options)
5216
+ return r.u64()
4996
5217
  case "int64": {
4997
5218
  if (r.remaining !== 8) invalid("int64", undefined, r.options)
4998
5219
  const millis = Number(r.i64())
@@ -667,7 +667,9 @@ export type AnyEvent = Event | Retry
667
667
  * **Details**
668
668
  *
669
669
  * It renders `Event` values as `id`, `event`, and `data` lines and renders
670
- * `Retry` values as `retry:` directives.
670
+ * `Retry` values as `retry:` directives. CR and LF are removed from `id` and
671
+ * `event`, and NUL is removed from `id`, so those values cannot inject fields
672
+ * or events.
671
673
  *
672
674
  * @stability unstable
673
675
  * @category encoding
@@ -679,10 +681,10 @@ export const encoder: Encoder = {
679
681
  case "Event": {
680
682
  let data = ""
681
683
  if (event.id !== undefined) {
682
- data += `id: ${event.id}\n`
684
+ data += `id: ${event.id.replace(/[\r\n\0]/g, "")}\n`
683
685
  }
684
686
  if (event.event !== "message") {
685
- data += `event: ${event.event}\n`
687
+ data += `event: ${event.event.replace(/[\r\n]/g, "")}\n`
686
688
  }
687
689
  data += `data: ${event.data.replace(/\r\n|\r|\n/g, "\ndata: ")}\n`
688
690
  return data + "\n"
@@ -41,12 +41,24 @@ export * as Hex from "./Hex.ts"
41
41
  */
42
42
  export * as Ini from "./Ini.ts"
43
43
 
44
+ /**
45
+ * @stability unstable
46
+ * @since 4.1.2
47
+ */
48
+ export * as Json5 from "./Json5.ts"
49
+
44
50
  /**
45
51
  * @stability unstable
46
52
  * @since 4.0.6
47
53
  */
48
54
  export * as JsonArray from "./JsonArray.ts"
49
55
 
56
+ /**
57
+ * @stability unstable
58
+ * @since 4.1.2
59
+ */
60
+ export * as Jsonc from "./Jsonc.ts"
61
+
50
62
  /**
51
63
  * @stability unstable
52
64
  * @since 4.0.0
@@ -303,6 +303,13 @@ export const layerRegistry = Layer.effect(
303
303
  * The identity is used by remote replication for authentication and by the
304
304
  * encryption service to derive signing and encryption keys.
305
305
  *
306
+ * **Gotchas**
307
+ *
308
+ * `publicKey` identifies the identity but is not a secret, and nothing ties it
309
+ * to the signing key derived from `privateKey`. A server binds the first
310
+ * signing key that authenticates for a `publicKey`, unless its authorization
311
+ * checks the presented signing key.
312
+ *
306
313
  * @stability unstable
307
314
  * @category services
308
315
  * @since 4.0.0
@@ -12,7 +12,9 @@
12
12
  import type { NonEmptyReadonlyArray } from "../Array.ts"
13
13
  import * as Arr from "../Array.ts"
14
14
  import * as Cache from "../Cache.ts"
15
+ import * as Clock from "../Clock.ts"
15
16
  import * as Context from "../Context.ts"
17
+ import * as Mac from "../crypto/Mac.ts"
16
18
  import * as Data from "../Data.ts"
17
19
  import * as Duration from "../Duration.ts"
18
20
  import * as Effect from "../Effect.ts"
@@ -21,7 +23,6 @@ import * as Exit from "../Exit.ts"
21
23
  import * as Hash from "../Hash.ts"
22
24
  import * as Uuid from "../internal/uuid.ts"
23
25
  import * as Layer from "../Layer.ts"
24
- import * as Option from "../Option.ts"
25
26
  import * as Redacted from "../Redacted.ts"
26
27
  import type * as Rpc from "../rpc/Rpc.ts"
27
28
  import type * as RpcGroup from "../rpc/RpcGroup.ts"
@@ -76,6 +77,12 @@ export const layerAuthMiddleware: Layer.Layer<
76
77
  * chunked writes, delegates write and change handling to the supplied callbacks,
77
78
  * and frames large change payloads into chunks.
78
79
  *
80
+ * `Authenticate` calls `authorizeIdentity` with the claimed public key and the
81
+ * presented signing public key, then verifies the signature against the
82
+ * presented key. Only a verified key is passed to
83
+ * `getOrCreateSessionAuthBinding`, and a key that differs from the identity's
84
+ * existing binding is rejected.
85
+ *
79
86
  * Use the connection's `ConnectionWrites.track` in `onWrite` and
80
87
  * `ConnectionWrites.filter` in `changes` to suppress its own write echoes.
81
88
  * `compaction` sets `HelloResponse.compaction`, advertising that the server
@@ -89,7 +96,10 @@ export const layerRpcHandlers = (options: {
89
96
  readonly remoteId: RemoteId
90
97
  readonly firstSequence?: number | undefined
91
98
  readonly compaction?: boolean | undefined
92
- readonly authorizeIdentity?: (publicKey: string) => Effect.Effect<void, EventLogProtocolError>
99
+ readonly authorizeIdentity?: (
100
+ publicKey: string,
101
+ signingPublicKey: Uint8Array<ArrayBuffer>
102
+ ) => Effect.Effect<void, EventLogProtocolError>
93
103
  readonly getOrCreateSessionAuthBinding: (
94
104
  publicKey: string,
95
105
  signingPublicKey: Uint8Array<ArrayBuffer>
@@ -109,11 +119,6 @@ export const layerRpcHandlers = (options: {
109
119
  Rpc.ToHandler<RpcGroup.Rpcs<typeof EventLogRemoteRpcs>> | EventLogAuthentication
110
120
  > =>
111
121
  EventLogRemoteRpcs.toLayer(Effect.gen(function*() {
112
- const clientChallenges = yield* Cache.make({
113
- lookup: (_clientId: number) => Effect.orDie(EventLogSessionAuth.makeSessionAuthChallenge),
114
- capacity: Number.MAX_SAFE_INTEGER,
115
- timeToLive: EventLogSessionAuth.SessionAuthChallengeTimeToLiveMillis
116
- })
117
122
  const toFrames = makeFramer()
118
123
 
119
124
  const persistedSigningPublicKeys = yield* Cache.makeWith(
@@ -138,17 +143,31 @@ export const layerRpcHandlers = (options: {
138
143
 
139
144
  return EventLogRemoteRpcs.of({
140
145
  "EventLog.Hello": Effect.fnUntraced(function*(_, { client }) {
141
- const challenge = yield* Cache.get(clientChallenges, client.id)
146
+ // Kept on the connection, so it is released when the client disconnects
147
+ // and shared by overlapping Hellos until `Authenticate` consumes it.
148
+ let pending = getPendingChallenge(client, yield* Clock.currentTimeMillis)
149
+ if (pending === undefined) {
150
+ const challenge = yield* Effect.orDie(EventLogSessionAuth.makeSessionAuthChallenge)
151
+ // Read the clock again, as generating the challenge can suspend. A
152
+ // concurrent Hello may have stored a challenge in the meantime.
153
+ const now = yield* Clock.currentTimeMillis
154
+ pending = getPendingChallenge(client, now) ?? {
155
+ challenge,
156
+ expiresAt: now + EventLogSessionAuth.SessionAuthChallengeTimeToLiveMillis
157
+ }
158
+ client.annotate(PendingChallenge, pending)
159
+ }
142
160
  return new HelloResponse({
143
161
  remoteId: options.remoteId,
144
- challenge,
162
+ challenge: pending.challenge,
145
163
  firstSequence: options.firstSequence,
146
164
  compaction: options.compaction === true ? true : undefined
147
165
  })
148
166
  }),
149
167
  "EventLog.Authenticate": Effect.fnUntraced(function*(request, { client }) {
150
- const challenge = Option.getOrNull(yield* Cache.getOption(clientChallenges, client.id))
151
- if (!challenge) {
168
+ const pending = getPendingChallenge(client, yield* Clock.currentTimeMillis)
169
+ client.annotate(PendingChallenge, undefined)
170
+ if (pending === undefined) {
152
171
  return yield* new EventLogProtocolError({
153
172
  requestTag: "Authenticate",
154
173
  publicKey: request.publicKey,
@@ -156,35 +175,41 @@ export const layerRpcHandlers = (options: {
156
175
  message: "Session auth challenge has expired"
157
176
  })
158
177
  }
159
- yield* Cache.invalidate(clientChallenges, client.id)
160
178
  if (options.authorizeIdentity) {
161
- yield* options.authorizeIdentity(request.publicKey)
179
+ yield* options.authorizeIdentity(request.publicKey, request.signingPublicKey)
162
180
  }
163
- const signingPublicKey = yield* Cache.get(
164
- persistedSigningPublicKeys,
165
- new SessionAuthCacheKey({
166
- publicKey: request.publicKey,
167
- signingPublicKey: request.signingPublicKey
168
- })
169
- )
170
181
  const verified = yield* EventLogSessionAuth.verifySessionAuthenticateRequest({
171
182
  remoteId: options.remoteId,
172
- challenge,
183
+ challenge: pending.challenge,
173
184
  publicKey: request.publicKey,
174
- signingPublicKey,
185
+ signingPublicKey: request.signingPublicKey,
175
186
  signature: request.signature,
176
187
  algorithm: request.algorithm
177
188
  }).pipe(
178
189
  Effect.catch(() => Effect.succeed(false))
179
190
  )
180
191
 
181
- if (!verified) {
182
- return yield* new EventLogProtocolError({
192
+ const verificationFailed = () =>
193
+ new EventLogProtocolError({
183
194
  requestTag: "Authenticate",
184
195
  publicKey: request.publicKey,
185
196
  code: "Forbidden",
186
197
  message: "Session auth signature verification failed"
187
198
  })
199
+ if (!verified) {
200
+ return yield* verificationFailed()
201
+ }
202
+ // Only a verified key reaches the binding. A key other than the
203
+ // identity's bound key is rejected like a bad signature.
204
+ const boundSigningPublicKey = yield* Cache.get(
205
+ persistedSigningPublicKeys,
206
+ new SessionAuthCacheKey({
207
+ publicKey: request.publicKey,
208
+ signingPublicKey: request.signingPublicKey
209
+ })
210
+ )
211
+ if (!Mac.timingSafeEqual(boundSigningPublicKey, request.signingPublicKey)) {
212
+ return yield* verificationFailed()
188
213
  }
189
214
 
190
215
  const authenticatedIdentities = new Set(
@@ -392,6 +417,22 @@ class ConnectionWritesState extends Context.Service<ConnectionWritesState, Conne
392
417
  "effect/eventlog/EventLogServer/ConnectionWrites"
393
418
  ) {}
394
419
 
420
+ // The connection's unconsumed `Hello` challenge, cleared by `Authenticate`.
421
+ const PendingChallenge = Context.Reference<
422
+ | {
423
+ readonly challenge: Uint8Array<ArrayBuffer>
424
+ readonly expiresAt: number
425
+ }
426
+ | undefined
427
+ >("effect/eventlog/EventLogServer/PendingChallenge", {
428
+ defaultValue: () => undefined
429
+ })
430
+
431
+ const getPendingChallenge = (client: Rpc.ServerClient, now: number) => {
432
+ const pending = Context.get(client.annotations, PendingChallenge)
433
+ return pending !== undefined && pending.expiresAt > now ? pending : undefined
434
+ }
435
+
395
436
  const getConnectionWrites = (client: Rpc.ServerClient): ConnectionWrites => {
396
437
  const existing = Context.getOrUndefined(client.annotations, ConnectionWritesState)
397
438
  if (existing !== undefined) return existing
@@ -411,6 +452,8 @@ export class AuthenticatedIdentities extends Context.Service<AuthenticatedIdenti
411
452
  "effect/eventlog/EventLogServer/AuthenticatedIdentities"
412
453
  ) {}
413
454
 
455
+ // Keyed by `publicKey` alone: the cache holds each identity's bound signing
456
+ // key, and `Authenticate` rejects any presented key that differs from it.
414
457
  class SessionAuthCacheKey extends Data.Class<{
415
458
  readonly publicKey: string
416
459
  readonly signingPublicKey: Uint8Array<ArrayBuffer>
@@ -503,6 +503,11 @@ export class Storage extends Context.Service<Storage, {
503
503
  * Lowest assigned sequence (default 0). Overestimating skips entries.
504
504
  */
505
505
  readonly firstSequence?: number | undefined
506
+ /**
507
+ * Returns the signing key bound to `publicKey`, binding `signingPublicKey`
508
+ * when none is bound yet. The server only passes keys whose signature it
509
+ * has verified, and rejects a key that differs from the returned binding.
510
+ */
506
511
  readonly getOrCreateSessionAuthBinding: (
507
512
  publicKey: string,
508
513
  signingPublicKey: Uint8Array<ArrayBuffer>
@@ -165,8 +165,8 @@ export const layerRpcHandlers: Layer.Layer<
165
165
  return EventLogServer.layerRpcHandlers({
166
166
  remoteId,
167
167
  firstSequence: storage.firstSequence,
168
- authorizeIdentity: (publicKey) =>
169
- auth.authorizeIdentity({ publicKey }).pipe(
168
+ authorizeIdentity: (publicKey, signingPublicKey) =>
169
+ auth.authorizeIdentity({ publicKey, signingPublicKey }).pipe(
170
170
  Effect.mapError((error) =>
171
171
  new EventLogProtocolError({
172
172
  requestTag: "Authenticate",
@@ -318,6 +318,17 @@ export class EventLogServerAuthError extends Data.TaggedError("EventLogServerAut
318
318
  * Use to provide authorization checks for plaintext event-log writes, reads,
319
319
  * and identity authentication.
320
320
  *
321
+ * **Gotchas**
322
+ *
323
+ * An identity's `publicKey` is an identifier, not a secret. The server binds
324
+ * the first signing key that authenticates for an identity and rejects any
325
+ * other key afterwards. `authorizeIdentity` also receives the presented
326
+ * `signingPublicKey`, so a deployment that records each identity's signing key
327
+ * at provisioning time, with `EventLogSessionAuth.deriveSigningPublicKey`, can
328
+ * reject every other key, including on first use. The server always supplies
329
+ * `signingPublicKey`; it is optional only so that existing callers keep
330
+ * compiling, and a policy that checks it should reject when it is missing.
331
+ *
321
332
  * @stability unstable
322
333
  * @category services
323
334
  * @since 4.0.0
@@ -334,6 +345,7 @@ export class EventLogServerAuthorization extends Context.Service<EventLogServerA
334
345
  }) => Effect.Effect<void, EventLogServerAuthError>
335
346
  readonly authorizeIdentity: (options: {
336
347
  readonly publicKey: string
348
+ readonly signingPublicKey?: Uint8Array<ArrayBuffer> | undefined
337
349
  }) => Effect.Effect<void, EventLogServerAuthError>
338
350
  }>()("effect/eventlog/EventLogServerUnencrypted/EventLogServerAuthorization") {}
339
351
 
@@ -422,6 +434,11 @@ export class Storage extends Context.Service<Storage, {
422
434
  * Lowest assigned sequence (default 0). Overestimating skips entries.
423
435
  */
424
436
  readonly firstSequence?: number | undefined
437
+ /**
438
+ * Returns the signing key bound to `publicKey`, binding `signingPublicKey`
439
+ * when none is bound yet. The server only passes keys whose signature it
440
+ * has verified, and rejects a key that differs from the returned binding.
441
+ */
425
442
  readonly getOrCreateSessionAuthBinding: (
426
443
  publicKey: string,
427
444
  signingPublicKey: Uint8Array<ArrayBuffer>