@zio.dev/zio-blocks 0.0.51 → 0.0.55

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 (164) hide show
  1. package/adr/2026-07-18-data-migration.md +123 -0
  2. package/guides/async-getting-started.md +687 -0
  3. package/guides/compile-time-resource-safety-with-scope.md +6 -0
  4. package/guides/getting-started-with-mux.md +0 -112
  5. package/guides/query-dsl-extending.md +1 -1
  6. package/guides/query-dsl-fluent-builder.md +1 -1
  7. package/guides/query-dsl-reified-optics.md +1 -1
  8. package/guides/query-dsl-sql.md +395 -1
  9. package/guides/sql-checked-interpolation.md +173 -0
  10. package/guides/sql-transactions.md +286 -0
  11. package/guides/telemetry-guide.md +131 -70
  12. package/guides/zio-schema-migration.md +6 -6
  13. package/index.md +200 -583
  14. package/package.json +1 -1
  15. package/reference/async.md +1379 -531
  16. package/reference/chunk.md +3 -3
  17. package/reference/codegen/index.md +1 -1
  18. package/reference/combinators.md +4 -4
  19. package/reference/config/config-decoder.md +460 -0
  20. package/reference/config/config-source.md +489 -0
  21. package/reference/config/errors.md +278 -0
  22. package/reference/config/flags.md +369 -0
  23. package/reference/config/formats.md +314 -0
  24. package/reference/config/index.md +304 -0
  25. package/reference/config/rollout.md +336 -0
  26. package/reference/context.md +6 -49
  27. package/reference/data-migration.md +269 -0
  28. package/reference/datastar/attributes.md +302 -0
  29. package/reference/datastar/events.md +234 -0
  30. package/reference/datastar/index.md +256 -0
  31. package/reference/datastar/signals.md +230 -0
  32. package/reference/datastar/sse.md +295 -0
  33. package/reference/datastar.md +2 -2
  34. package/reference/docs.md +2 -2
  35. package/reference/endpoint/bulk-creation.md +96 -0
  36. package/reference/endpoint/index.md +9 -89
  37. package/reference/endpoint/path-codec.md +12 -24
  38. package/reference/endpoint/route-pattern.md +4 -6
  39. package/reference/endpoint/segment-codec.md +19 -32
  40. package/reference/html.md +313 -9
  41. package/reference/htmx/index.md +4 -52
  42. package/reference/htmx/response-headers.md +240 -0
  43. package/reference/http-model/headers.md +735 -0
  44. package/reference/http-model/index.md +3 -1
  45. package/reference/http-model/model.md +107 -71
  46. package/reference/http-model/schema-codecs.md +522 -0
  47. package/reference/http-model/schema.md +6 -3
  48. package/reference/http-model/server-sent-event.md +341 -0
  49. package/reference/jwt.md +195 -0
  50. package/reference/maybe.md +128 -11
  51. package/reference/media-type.md +2 -2
  52. package/reference/mux.md +254 -0
  53. package/reference/mux.mdx +7 -2
  54. package/reference/openapi.md +3 -3
  55. package/reference/projection.md +654 -0
  56. package/reference/resource-management/resource.md +2 -98
  57. package/reference/resource-management/scope.md +1 -209
  58. package/reference/resource-management/wire.md +4 -50
  59. package/reference/ringbuffer/advanced.mdx +1 -1
  60. package/reference/ringbuffer/index.mdx +3 -3
  61. package/reference/ringbuffer/mpmc.mdx +38 -4
  62. package/reference/ringbuffer/mpsc.mdx +36 -4
  63. package/reference/ringbuffer/spmc.mdx +1 -1
  64. package/reference/ringbuffer/spsc.mdx +87 -15
  65. package/reference/schema/allows.md +0 -96
  66. package/reference/schema/binding.md +2 -2
  67. package/reference/schema/built-in-codecs/avro.md +2 -2
  68. package/reference/schema/built-in-codecs/bson.md +50 -20
  69. package/reference/schema/built-in-codecs/csv.md +2 -2
  70. package/reference/schema/built-in-codecs/index.md +3 -3
  71. package/reference/schema/built-in-codecs/json/index.md +2 -2
  72. package/reference/schema/built-in-codecs/messagepack.md +3 -3
  73. package/reference/schema/built-in-codecs/thrift.md +2 -2
  74. package/reference/schema/built-in-codecs/toon.md +3 -3
  75. package/reference/schema/built-in-codecs/yaml.md +2 -2
  76. package/reference/schema/codec.md +11 -11
  77. package/reference/schema/dynamic-optic.md +48 -3
  78. package/reference/schema/dynamic-schema.md +3 -3
  79. package/reference/schema/index.md +2 -0
  80. package/reference/schema/path-interpolator.md +2 -0
  81. package/reference/schema/reflect-transformer.md +140 -0
  82. package/reference/schema/schema-evolution/as.md +4 -4
  83. package/reference/schema/schema-evolution/into.md +2 -2
  84. package/reference/schema/schema-expr.md +2 -2
  85. package/reference/schema/schema-search.md +263 -0
  86. package/reference/schema/schema.md +10 -2
  87. package/reference/schema/type-class-derivation.md +1 -1
  88. package/reference/smithy.md +502 -3
  89. package/reference/sql/db-codec-deriver.md +3 -3
  90. package/reference/sql/db-codec.md +22 -22
  91. package/reference/sql/db-con.md +4 -4
  92. package/reference/sql/db-connection.md +1 -1
  93. package/reference/sql/db-param.md +1 -1
  94. package/reference/sql/db-result-reader.md +4 -2
  95. package/reference/sql/db-tx.md +46 -14
  96. package/reference/sql/ddl.md +1 -1
  97. package/reference/sql/frag.md +44 -10
  98. package/reference/sql/index.md +7 -7
  99. package/reference/sql/repo.md +15 -15
  100. package/reference/sql/sql-dialect.md +1 -1
  101. package/reference/sql/sql-logger.md +1 -1
  102. package/reference/sql/sql-name-mapper.md +3 -3
  103. package/reference/sql/table-metadata.md +3 -3
  104. package/reference/sql/table.md +10 -10
  105. package/reference/sql/transactor-zio.md +1 -1
  106. package/reference/sql/transactor.md +21 -11
  107. package/reference/sql-zio.md +1 -1
  108. package/reference/streams/core/index.md +32 -0
  109. package/reference/streams/{pipeline.md → core/pipeline.md} +210 -74
  110. package/reference/streams/{sink.md → core/sink.md} +331 -353
  111. package/reference/streams/{stream.md → core/stream.md} +919 -209
  112. package/reference/streams/execution-and-compatibility/async-execution.md +822 -0
  113. package/reference/streams/execution-and-compatibility/index.md +35 -0
  114. package/reference/streams/execution-and-compatibility/platform-differences.md +297 -0
  115. package/reference/streams/execution-and-compatibility/scala-2-compatibility.md +88 -0
  116. package/reference/streams/execution-and-compatibility/zero-boxing.md +393 -0
  117. package/reference/streams/index.md +140 -67
  118. package/reference/streams/primitives/index.md +30 -0
  119. package/reference/streams/primitives/reader.md +1992 -0
  120. package/reference/streams/{writer.md → primitives/writer.md} +254 -98
  121. package/reference/telemetry/common/any-value.md +90 -0
  122. package/reference/telemetry/common/attribute-key.md +87 -0
  123. package/reference/telemetry/common/attributes.md +118 -0
  124. package/reference/telemetry/common/index.md +39 -0
  125. package/reference/telemetry/common/instrumentation-scope.md +24 -0
  126. package/reference/telemetry/common/resource.md +34 -0
  127. package/reference/telemetry/index.md +311 -0
  128. package/reference/telemetry/logging/index.md +197 -0
  129. package/reference/telemetry/logging/log-enrichment.md +72 -0
  130. package/reference/telemetry/logging/log-formatter.md +100 -0
  131. package/reference/telemetry/logging/log-record-processor.md +56 -0
  132. package/reference/telemetry/logging/log-record.md +44 -0
  133. package/reference/telemetry/logging/log-writer.md +64 -0
  134. package/reference/telemetry/logging/logger-provider.md +142 -0
  135. package/reference/telemetry/logging/logger.md +83 -0
  136. package/reference/telemetry/logging/severity.md +62 -0
  137. package/reference/telemetry/metrics/index.md +150 -0
  138. package/reference/telemetry/metrics/instruments.md +183 -0
  139. package/reference/telemetry/metrics/labeled-instruments.md +74 -0
  140. package/reference/telemetry/metrics/meter-provider.md +76 -0
  141. package/reference/telemetry/metrics/meter.md +98 -0
  142. package/reference/telemetry/metrics/metric-data.md +57 -0
  143. package/reference/telemetry/otel/custom-exporter.md +216 -0
  144. package/reference/telemetry/otel/index.md +212 -0
  145. package/reference/telemetry/tracing/index.md +155 -0
  146. package/reference/telemetry/tracing/sampler.md +89 -0
  147. package/reference/telemetry/tracing/span-builder.md +57 -0
  148. package/reference/telemetry/tracing/span-context.md +39 -0
  149. package/reference/telemetry/tracing/span-data.md +32 -0
  150. package/reference/telemetry/tracing/span-kind.md +55 -0
  151. package/reference/telemetry/tracing/span-processor.md +53 -0
  152. package/reference/telemetry/tracing/span-status.md +47 -0
  153. package/reference/telemetry/tracing/span.md +117 -0
  154. package/reference/telemetry/tracing/tracer-provider.md +91 -0
  155. package/reference/telemetry/tracing/tracer.md +52 -0
  156. package/reference/typeid.md +0 -64
  157. package/sidebars.js +150 -12
  158. package/undocumented-report.md +528 -270
  159. package/reference/config.md +0 -158
  160. package/reference/streams/concurrent-operators.md +0 -106
  161. package/reference/streams/reader.md +0 -1284
  162. package/reference/streams/scala-2-compatibility.md +0 -55
  163. package/reference/streams/zero-boxing.md +0 -275
  164. package/reference/telemetry.md +0 -693
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  id: index
3
- title: "Endpoint (Module)"
3
+ title: "Endpoint"
4
4
  ---
5
5
 
6
6
  `zio-blocks-endpoint` is a **pure, type-safe HTTP endpoint descriptor** for building clients, servers, and API documentation from a single source of truth. It provides composable types that describe every part of an HTTP surface — routes, query parameters, headers, request bodies, response bodies, error shapes, and authentication — without committing to any particular server or client implementation.
@@ -41,18 +41,18 @@ The endpoint module is a cross-platform library (JVM + Scala.js). Add the depend
41
41
 
42
42
  **JVM (Scala 3.x):**
43
43
  ```scala
44
- libraryDependencies += "dev.zio" %% "zio-blocks-endpoint" % "0.0.51"
44
+ libraryDependencies += "dev.zio" %% "zio-blocks-endpoint" % "0.0.55"
45
45
  ```
46
46
 
47
47
  **Scala.js (Scala 3.x):**
48
48
  ```scala
49
- libraryDependencies += "dev.zio" %%% "zio-blocks-endpoint" % "0.0.51"
49
+ libraryDependencies += "dev.zio" %%% "zio-blocks-endpoint" % "0.0.55"
50
50
  ```
51
51
 
52
52
  **For Scala 3.7+**, the module name is rewritten to `zio-blocks-next-endpoint`:
53
53
  ```scala
54
- libraryDependencies += "dev.zio" %% "zio-blocks-next-endpoint" % "0.0.51" // JVM
55
- libraryDependencies += "dev.zio" %%% "zio-blocks-next-endpoint" % "0.0.51" // Scala.js
54
+ libraryDependencies += "dev.zio" %% "zio-blocks-next-endpoint" % "0.0.55" // JVM
55
+ libraryDependencies += "dev.zio" %%% "zio-blocks-next-endpoint" % "0.0.55" // Scala.js
56
56
  ```
57
57
 
58
58
  Supported Scala versions: 3.x (Scala 3 only — the endpoint module uses Scala 3-only DSL and macro code).
@@ -227,22 +227,6 @@ cd zio-blocks
227
227
  Constructs `Endpoint` values from `RoutePattern` and chains request body, query parameters, headers, success outputs, response headers, and typed error variants using the builder DSL.
228
228
 
229
229
  ```scala title="endpoint-examples/src/main/scala/endpointexamples/BasicEndpointDefinition.scala"
230
- /*
231
- * Copyright 2024-2026 John A. De Goes and the ZIO Contributors
232
- *
233
- * Licensed under the Apache License, Version 2.0 (the "License");
234
- * you may not use this file except in compliance with the License.
235
- * You may obtain a copy of the License at
236
- *
237
- * http://www.apache.org/licenses/LICENSE-2.0
238
- *
239
- * Unless required by applicable law or agreed to in writing, software
240
- * distributed under the License is distributed on an "AS IS" BASIS,
241
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
242
- * See the License for the specific language governing permissions and
243
- * limitations under the License.
244
- */
245
-
246
230
  package endpointexamples
247
231
 
248
232
  import scala.language.implicitConversions
@@ -316,22 +300,6 @@ sbt "endpoint-examples/runMain endpointexamples.BasicEndpointDefinition"
316
300
  Builds `HttpCodec` atoms for query parameters, request headers, response headers, request bodies, response bodies, and status codes. Shows sequential composition with `++` and alternative composition with `|`.
317
301
 
318
302
  ```scala title="endpoint-examples/src/main/scala/endpointexamples/HttpCodecConstruction.scala"
319
- /*
320
- * Copyright 2024-2026 John A. De Goes and the ZIO Contributors
321
- *
322
- * Licensed under the Apache License, Version 2.0 (the "License");
323
- * you may not use this file except in compliance with the License.
324
- * You may obtain a copy of the License at
325
- *
326
- * http://www.apache.org/licenses/LICENSE-2.0
327
- *
328
- * Unless required by applicable law or agreed to in writing, software
329
- * distributed under the License is distributed on an "AS IS" BASIS,
330
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
331
- * See the License for the specific language governing permissions and
332
- * limitations under the License.
333
- */
334
-
335
303
  package endpointexamples
336
304
 
337
305
  import zio.blocks.chunk.Chunk
@@ -432,22 +400,6 @@ sbt "endpoint-examples/runMain endpointexamples.HttpCodecConstruction"
432
400
  Demonstrates all `SegmentCodec` kinds, intra-segment composition with `~` for patterns like `v42`, bidirectional `PathCodec` decode and format, `RoutePattern` matching, `nest` for version prefixes, and `transform`/`transformOrFail` for domain type mapping.
433
401
 
434
402
  ```scala title="endpoint-examples/src/main/scala/endpointexamples/PathAndSegmentCodecs.scala"
435
- /*
436
- * Copyright 2024-2026 John A. De Goes and the ZIO Contributors
437
- *
438
- * Licensed under the Apache License, Version 2.0 (the "License");
439
- * you may not use this file except in compliance with the License.
440
- * You may obtain a copy of the License at
441
- *
442
- * http://www.apache.org/licenses/LICENSE-2.0
443
- *
444
- * Unless required by applicable law or agreed to in writing, software
445
- * distributed under the License is distributed on an "AS IS" BASIS,
446
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
447
- * See the License for the specific language governing permissions and
448
- * limitations under the License.
449
- */
450
-
451
403
  package endpointexamples
452
404
 
453
405
  import scala.language.implicitConversions
@@ -535,7 +487,7 @@ import zio.http.{Method, Path}
535
487
  final case class UserId(value: Int)
536
488
 
537
489
  val userIdCodec: PathCodec[UserId] =
538
- PathCodec.int("id").transform[UserId](UserId(_), _.value)
490
+ PathCodec.int("id").transform(UserId(_), _.value)
539
491
 
540
492
  val decodedUserId = userIdCodec.decode(Path("/99"))
541
493
  println(s"UserId decoded: $decodedUserId")
@@ -544,9 +496,9 @@ import zio.http.{Method, Path}
544
496
  val positiveInt: PathCodec[Int] =
545
497
  PathCodec
546
498
  .int("count")
547
- .transformOrFail[Int](
499
+ .transformOrFail(
548
500
  n => if (n > 0) Right(n) else Left(s"Expected positive, got $n"),
549
- n => Right(n)
501
+ (n: Int) => Right(n)
550
502
  )
551
503
 
552
504
  println(s"Positive decode 5: ${positiveInt.decode(Path("/5"))}")
@@ -567,22 +519,6 @@ sbt "endpoint-examples/runMain endpointexamples.PathAndSegmentCodecs"
567
519
  Shows all built-in `AuthType` variants (None, Basic, Bearer, Digest), a custom API-key variant, OR composition with `|`, scoped bearer tokens for OAuth scope metadata, and overriding the default unauthorized status.
568
520
 
569
521
  ```scala title="endpoint-examples/src/main/scala/endpointexamples/AuthTypePatterns.scala"
570
- /*
571
- * Copyright 2024-2026 John A. De Goes and the ZIO Contributors
572
- *
573
- * Licensed under the Apache License, Version 2.0 (the "License");
574
- * you may not use this file except in compliance with the License.
575
- * You may obtain a copy of the License at
576
- *
577
- * http://www.apache.org/licenses/LICENSE-2.0
578
- *
579
- * Unless required by applicable law or agreed to in writing, software
580
- * distributed under the License is distributed on an "AS IS" BASIS,
581
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
582
- * See the License for the specific language governing permissions and
583
- * limitations under the License.
584
- */
585
-
586
522
  package endpointexamples
587
523
 
588
524
  import scala.language.implicitConversions
@@ -673,22 +609,6 @@ sbt "endpoint-examples/runMain endpointexamples.AuthTypePatterns"
673
609
  Assembles a full users CRUD API combining `Endpoint`, `RoutePattern`, `PathCodec`, `SegmentCodec`, `HttpCodec`, `AuthType`, and `RouteTree`. Demonstrates versioned routes via `nest`, Scala 3 union error types via `orOutError`, and `RouteTree` lookup priority for efficient O(depth) dispatch.
674
610
 
675
611
  ```scala title="endpoint-examples/src/main/scala/endpointexamples/CompleteApiDefinition.scala"
676
- /*
677
- * Copyright 2024-2026 John A. De Goes and the ZIO Contributors
678
- *
679
- * Licensed under the Apache License, Version 2.0 (the "License");
680
- * you may not use this file except in compliance with the License.
681
- * You may obtain a copy of the License at
682
- *
683
- * http://www.apache.org/licenses/LICENSE-2.0
684
- *
685
- * Unless required by applicable law or agreed to in writing, software
686
- * distributed under the License is distributed on an "AS IS" BASIS,
687
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
688
- * See the License for the specific language governing permissions and
689
- * limitations under the License.
690
- */
691
-
692
612
  package endpointexamples
693
613
 
694
614
  import scala.language.implicitConversions
@@ -715,7 +635,7 @@ import zio.http.{Method, Path, Status}
715
635
  final case class UserId(value: Int)
716
636
 
717
637
  val userIdPath: PathCodec[UserId] =
718
- PathCodec.int("id").transform[UserId](UserId(_), _.value)
638
+ PathCodec.int("id").transform(UserId(_), _.value)
719
639
 
720
640
  // --- Endpoint definitions ---
721
641
 
@@ -3,16 +3,12 @@ id: path-codec
3
3
  title: "PathCodec"
4
4
  ---
5
5
 
6
- `PathCodec[A]` is a composable descriptor for URL path structures. It holds a tree of segment codecs connected by concatenation and fallback nodes, and provides bidirectional path conversion: `PathCodec#decode` extracts a typed value from a `Path`, returning `Either[String, A]` (the typed value or error), and `PathCodec#format` formats a typed value back to a `Path`, returning `Either[String, Path]` (the path or error). In addition to its runtime value type `A`, each codec also carries a phantom `PathVars` track that records the ordered list of declared path-variable markers contributed by its dynamic segments. Its definition begins:
6
+ `PathCodec[A]` is a composable descriptor for URL path structures. It holds a tree of segment codecs connected by concatenation and fallback nodes, and provides bidirectional path conversion: `PathCodec#decode` extracts a typed value from a `Path`, returning `Either[String, A]` (the typed value or error), and `PathCodec#format` formats a typed value back to a `Path`, returning `Either[String, Path]` (the path or error). Its definition begins:
7
7
 
8
8
  ```scala
9
- sealed trait PathCodec[A] {
10
- type PathVars
11
- }
9
+ sealed trait PathCodec[A]
12
10
  ```
13
11
 
14
- `PathVars` is purely type-level: it has zero runtime footprint and does not affect decoding or formatting. It exists so downstream tooling (for example, handler macros or static checks) can recover which named path variables a route declared, in order, and whether any of them were explicitly marked as ignored.
15
-
16
12
  ## Motivation
17
13
 
18
14
  URL paths need both matching and generation. A routing library that only matches paths requires a separate URL-builder for links and redirects, leading to duplication and drift. `PathCodec` is bidirectional: every codec that can decode `/users/42` into `42: Int` can also format `42` back into `/users/42`. This makes it safe to use the same path definition for routing, link generation, and OpenAPI path parameter documentation.
@@ -49,9 +45,7 @@ val boolFlag: PathCodec[Boolean] = PathCodec.bool("enabled")
49
45
  val rest: PathCodec[zio.http.Path] = PathCodec.trailing
50
46
  ```
51
47
 
52
- `PathCodec.literal` is a macro that validates the value at compile time — it rejects empty strings and strings containing `/` or characters requiring URL encoding.
53
-
54
- For literal names like `PathCodec.int("id")`, the name is preserved as a singleton type inside `PathVars`, so the phantom track remembers not just that the codec captures an `Int`, but that it came from the path variable named `"id"`.
48
+ `PathCodec.literal` validates the value — it rejects empty strings and strings containing `/` or characters requiring URL encoding.
55
49
 
56
50
  ### From a string
57
51
 
@@ -79,27 +73,21 @@ val combined = PathCodec(SegmentCodec.literal("v") ~ SegmentCodec.int("version")
79
73
 
80
74
  There is also an implicit conversion from `SegmentCodec[A]` to `PathCodec[A]` and from `String` to `PathCodec[Unit]`, so both can appear directly in `/` expressions.
81
75
 
82
- ## Phantom `PathVars` Track and `.unused`
83
-
84
- Every dynamic path segment contributes one phantom marker to `PathCodec#PathVars`:
76
+ ## Marking a capture as unused with `.unused`
85
77
 
86
- - `PathCodec.int("id")` contributes `PathVar["id", Int]`
87
- - `PathCodec.uuid("orderId")` contributes `PathVar["orderId", UUID]`
88
- - literal segments and `PathCodec.trailing` contribute no markers
89
-
90
- Sequential composition with `/` or `++` concatenates those markers in declaration order, matching the left-to-right route shape.
91
-
92
- Sometimes a route needs to capture a segment for matching or formatting, but a downstream handler intentionally does not consume that variable. For that case, single-variable codecs expose `.unused`, which keeps the runtime behavior identical while relabeling the phantom marker to `PathVar.Ignored[Name, Type]`:
78
+ Sometimes a route needs to capture a segment for matching or formatting, but a downstream handler intentionally does not consume that variable. `PathCodec` instances expose `.unused`, which converts the value type to `Unit` while keeping the same path shape:
93
79
 
94
80
  ```scala
95
81
  import zio.blocks.endpoint._
96
82
  import zio.blocks.endpoint.RoutePattern._
97
83
 
98
84
  val userId: PathCodec[Int] = PathCodec.int("id")
99
- val ignoredUserId: PathCodec[Int] = PathCodec.int("id").unused
85
+ val ignoredUserId: PathCodec[Unit] = PathCodec.int("id").unused
100
86
  ```
101
87
 
102
- `.unused` has zero runtime cost: decoding, formatting, rendering, and matching all behave exactly the same as the non-`.unused` codec. The only difference is the phantom `PathVars` marker, which tells tooling that this declared path variable was intentionally ignored.
88
+ `.unused` converts the path codec's value type to `Unit`: the route still matches the same shape and renders `{name}` placeholders, but decoding yields `Unit` instead of the captured value, so no handler parameter is required. `format` on an unused path fails because there is no value to encode back into the ignored segment.
89
+
90
+ `PathCodec.unused` composes normally with `/` and is unaffected by `transform` / `transformOrFail` lifting.
103
91
 
104
92
  ## Composition
105
93
 
@@ -204,7 +192,7 @@ import zio.blocks.endpoint.PathCodec._
204
192
  final case class UserId(value: Int)
205
193
 
206
194
  val userIdCodec: PathCodec[UserId] =
207
- PathCodec.int("id").transform[UserId](UserId(_), _.value)
195
+ PathCodec.int("id").transform(UserId(_), _.value)
208
196
  ```
209
197
 
210
198
  ### `PathCodec#transformOrFail`
@@ -216,9 +204,9 @@ import zio.blocks.endpoint._
216
204
  import zio.blocks.endpoint.RoutePattern._
217
205
 
218
206
  val nonNegativeInt: PathCodec[Int] =
219
- PathCodec.int("count").transformOrFail[Int](
207
+ PathCodec.int("count").transformOrFail(
220
208
  n => if (n >= 0) Right(n) else Left(s"Expected non-negative, got $n"),
221
- n => Right(n)
209
+ (n: Int) => Right(n)
222
210
  )
223
211
  ```
224
212
 
@@ -3,7 +3,7 @@ id: route-pattern
3
3
  title: "RoutePattern"
4
4
  ---
5
5
 
6
- `RoutePattern[A]` pairs an HTTP method with a typed path pattern. It is the primary routing descriptor in `zio-blocks-endpoint`: every `Endpoint` carries a `RoutePattern` that determines which HTTP method and URL path it matches. Like `PathCodec`, it also carries a phantom `PathVars` track that mirrors the ordered path-variable declarations contributed by its path codec. Its shape is:
6
+ `RoutePattern[A]` pairs an HTTP method with a typed path pattern. It is the primary routing descriptor in `zio-blocks-endpoint`: every `Endpoint` carries a `RoutePattern` that determines which HTTP method and URL path it matches. Its shape is:
7
7
 
8
8
  ```scala
9
9
  final case class RoutePattern[A](
@@ -13,13 +13,11 @@ final case class RoutePattern[A](
13
13
  )
14
14
  ```
15
15
 
16
- The `PathVars` track is not a constructor parameter because it is purely type-level: it has zero runtime footprint and is derived from `pathCodec`. A literal-only route contributes no path-variable markers; a route with dynamic segments preserves them in declaration order.
17
-
18
16
  ## Motivation
19
17
 
20
18
  HTTP routing requires matching both a method (GET, POST, …) and a path (`/users/42`). `RoutePattern` holds both in a single typed value. The type parameter `A` is the type of values extracted from the dynamic path segments — `Unit` for fully-literal paths, `Int` for a single integer segment, `(String, UUID)` for two dynamic segments, and so on.
21
19
 
22
- Using a typed route pattern means route construction and path extraction are verified at compile time: the type of the extracted path value is always consistent with the path codec definition. The phantom `PathVars` track keeps the declared path-variable names and ignored-variable markers available to tooling without changing runtime behavior.
20
+ Using a typed route pattern means route construction and path extraction are verified at compile time: the type of the extracted path value is always consistent with the path codec definition.
23
21
 
24
22
  ## Construction
25
23
 
@@ -85,7 +83,7 @@ val catchAll: RoutePattern[Path] = RoutePattern.any
85
83
  val getAny: RoutePattern[Path] = RoutePattern.any(Method.GET)
86
84
  ```
87
85
 
88
- These helpers preserve `PathVars = SegmentCodec.NoPathVars`: a trailing catch-all captures a `zio.http.Path` runtime value, but it does not declare any named path variables.
86
+ A trailing catch-all captures a `zio.http.Path` runtime value without declaring any named path variables.
89
87
 
90
88
  ## Path Composition with `/`
91
89
 
@@ -99,7 +97,7 @@ import zio.http.Method
99
97
  val route = Method.GET / "users" / PathCodec.int("id") / "posts"
100
98
  ```
101
99
 
102
- Each `/` call produces a new `RoutePattern` with a widened type. The type is automatically flattened, eliminating `Unit` components: `Unit / Int / Unit` becomes `Int`, not `((Unit, Int), Unit)`. At the same time, the phantom `PathVars` track is concatenated left-to-right, so a route like `Method.GET / PathCodec.int("id") / PathCodec.string("slug")` preserves the declaration order of `"id"` then `"slug"` for downstream tooling.
100
+ Each `/` call produces a new `RoutePattern` with a widened type. The type is automatically flattened, eliminating `Unit` components: `Unit / Int / Unit` becomes `Int`, not `((Unit, Int), Unit)`.
103
101
 
104
102
  ## Decoding and Encoding
105
103
 
@@ -3,19 +3,13 @@ id: segment-codec
3
3
  title: "SegmentCodec"
4
4
  ---
5
5
 
6
- `SegmentCodec[A]` describes a single URL path segment. It supports basic typed segment kinds — `SegmentCodec.bool`, `SegmentCodec.int`, `SegmentCodec.long`, `SegmentCodec.string`, `SegmentCodec.uuid`, and `SegmentCodec.literal` — as well as intra-segment composition via `~`, which combines multiple typed parts within a single path segment (for example, `v42` as a literal prefix followed by an integer). Ambiguous combinations are rejected at compile time by a Scala 3 macro. Alongside the runtime decoded value type `A`, every segment codec also carries phantom metadata describing its boundary behavior and any declared path variable. The core type-level shape is:
6
+ `SegmentCodec[A]` describes a single URL path segment. It supports basic typed segment kinds — `SegmentCodec.bool`, `SegmentCodec.int`, `SegmentCodec.long`, `SegmentCodec.string`, `SegmentCodec.uuid`, and `SegmentCodec.literal` — as well as intra-segment composition via `~`, which combines multiple typed parts within a single path segment (for example, `v42` as a literal prefix followed by an integer). Ambiguous adjacencies (`string ~ string`, numeric ~ numeric in any `Int`/`Long` order, anything involving `Trailing`) are rejected at runtime with `IllegalArgumentException`. Combine representation first, then transform: `transform` / `transformOrFail` lift a segment into a `PathCodec`, ending intra-segment composition. The core type-level shape is:
7
7
 
8
8
  ```scala
9
- sealed trait SegmentCodec[A] {
10
- type Prefix <: SegmentCodec.BoundaryTag
11
- type Suffix <: SegmentCodec.BoundaryTag
12
- type PathVars
13
- }
9
+ sealed trait SegmentCodec[A]
14
10
  ```
15
11
 
16
- `PathVars` is purely type-level: it has zero runtime footprint. Capturing segments contribute one marker (for example `PathVar["id", Int]`), while non-capturing segments like `literal` and `Trailing` contribute none.
17
-
18
- (The trait also includes additional members for documentation, examples, formatting, and rendering.)
12
+ (The trait also includes methods for `~` composition, `transform` lifting, documentation, examples, formatting, and rendering.)
19
13
 
20
14
  ## Motivation
21
15
 
@@ -23,7 +17,7 @@ Standard routing libraries treat path segments as plain strings, deferring all p
23
17
 
24
18
  - **Type-safe path building**: `PathCodec.int("id")` produces a `PathCodec[Int]`, not `PathCodec[String]`.
25
19
  - **Bidirectional conversion**: every `SegmentCodec` can both decode a string into `A` and format an `A` back to a string.
26
- - **Compile-time combination validation**: the `~` operator is a macro that validates boundary constraints, rejecting combinations like `string ~ string` before the code compiles.
20
+ - **Fail-fast combination validation**: the `~` operator rejects ambiguous adjacencies (`string ~ string`, numeric ~ numeric) at composition time, so bad splits surface immediately instead of misrouting.
27
21
 
28
22
  ## Segment Kinds
29
23
 
@@ -57,19 +51,16 @@ val stringSeg: SegmentCodec[String] = SegmentCodec.string("slug")
57
51
  val uuidSeg: SegmentCodec[java.util.UUID] = SegmentCodec.uuid("id")
58
52
  ```
59
53
 
60
- When the name is written as a literal string, that literal is preserved in the phantom `PathVars` marker. For example, `SegmentCodec.int("id")` contributes `PathVar["id", Int]`.
61
-
62
- If a route should keep a captured segment for matching/formatting but explicitly mark it as intentionally unused for downstream tooling, the leaf dynamic segment codecs expose `.unused`:
54
+ If a route should capture a segment for matching or formatting but the handler intentionally does not consume the variable, the leaf dynamic segment codecs expose `.unused`:
63
55
 
64
56
  ```scala
65
- import zio.blocks.endpoint._
66
- import zio.blocks.endpoint.RoutePattern._
57
+ import zio.blocks.endpoint.SegmentCodec
67
58
 
68
- val requiredId: SegmentCodec[Int] = SegmentCodec.int("id")
69
- val ignoredId: SegmentCodec[Int] = SegmentCodec.int("id").unused
59
+ val requiredId = SegmentCodec.int("id")
60
+ val ignoredId = SegmentCodec.int("id").unused
70
61
  ```
71
62
 
72
- `.unused` keeps decoding, formatting, rendering, and composition identical, but changes the phantom marker from `PathVar[Name, Type]` to `PathVar.Ignored[Name, Type]`.
63
+ `.unused` keeps decoding, formatting, rendering, and composition identical. The only difference is at the type level: downstream tooling (handler macros, static checks) sees the variable as intentionally unused and does not require the handler to bind it.
73
64
 
74
65
  The ordering of match priority in the routing trie follows the kind: `Literal` matches first, then `Int`, `Long`, `UUID`, `Bool`, `String`, `Combined`, and `Trailing` last.
75
66
 
@@ -99,14 +90,14 @@ val versionSeg: SegmentCodec[Int] =
99
90
 
100
91
  The type is automatically flattened (eliminating `Unit` from the literal), so the resulting codec decodes `"v42"` into `42` and formats `42` back to `"v42"`.
101
92
 
102
- ### Compile-time boundary validation
93
+ ### Runtime adjacency validation
103
94
 
104
- The `~` operator is a macro that checks `BoundaryTag` phantom types at compile time. Two categories of combination are always rejected:
95
+ The `~` operator checks the physical adjacency at composition time. Two categories of combination are always rejected with `IllegalArgumentException`:
105
96
 
106
97
  - **Two string segments**: `SegmentCodec.string("a") ~ SegmentCodec.string("b")` — both are unbounded greedy matchers; the parser cannot know where one ends and the other begins.
107
- - **Two numeric segments**: `SegmentCodec.int("a") ~ SegmentCodec.int("b")` — numeric segments are also ambiguously bounded.
98
+ - **Two numeric segments**: `SegmentCodec.int("a") ~ SegmentCodec.int("b")` — numeric segments are also ambiguously bounded (any `Int`/`Long` order, including through a flattened combined tail).
108
99
 
109
- Combinations that are safe compile successfully:
100
+ Anything involving `Trailing` is likewise rejected. Combinations that are safe compose normally:
110
101
 
111
102
  ```scala
112
103
  import zio.blocks.endpoint._
@@ -122,11 +113,11 @@ val prefixedUuid =
122
113
  SegmentCodec.string("prefix") ~ SegmentCodec.uuid("id") ~ SegmentCodec.string("suffix")
123
114
  ```
124
115
 
125
- Attempting an ambiguous combination like `string ~ string` produces a compiler error describing the constraint violation, not a runtime failure.
116
+ Attempting an ambiguous combination like `string ~ string` throws `IllegalArgumentException` at composition time, not a silent misroute.
126
117
 
127
118
  ## Type Transformations
128
119
 
129
- Use these methods to remap the value a codec decodes or encodes without changing the underlying segment structure or its compile-time boundary tags.
120
+ Combine representation first, then transform: `transform` / `transformOrFail` map the decoded segment value into a domain type and lift the segment into a `PathCodec`, ending intra-segment composition (a transformed codec no longer offers `~`; compose with `/` instead).
130
121
 
131
122
  ### `SegmentCodec#transform`
132
123
 
@@ -138,14 +129,10 @@ import zio.blocks.endpoint.RoutePattern._
138
129
 
139
130
  final case class UserId(value: java.util.UUID)
140
131
 
141
- val userIdSeg: SegmentCodec[UserId] =
142
- SegmentCodec.uuid("id").transform[UserId](UserId(_), _.value)
132
+ val userIdCodec: PathCodec[UserId] =
133
+ SegmentCodec.uuid("id").transform(UserId(_), _.value)
143
134
  ```
144
135
 
145
- `SegmentCodec#transform` preserves the `BoundaryTag` types of the original codec, so transformed codecs still participate in compile-time `~` boundary validation.
146
-
147
- It also preserves the original `PathVars` marker unchanged: transforming a captured `SegmentCodec.int("id")` into a domain type still records that the segment came from the declared `"id"` path variable.
148
-
149
136
  ### `SegmentCodec#transformOrFail`
150
137
 
151
138
  When decoding can fail, use `SegmentCodec#transformOrFail`. A `Left` result causes segment matching to fail for that candidate:
@@ -156,8 +143,8 @@ import zio.blocks.endpoint.RoutePattern._
156
143
 
157
144
  final case class PositiveInt(value: Int)
158
145
 
159
- val positiveIntSeg: SegmentCodec[PositiveInt] =
160
- SegmentCodec.int("count").transformOrFail[PositiveInt](
146
+ val positiveIntCodec: PathCodec[PositiveInt] =
147
+ SegmentCodec.int("count").transformOrFail(
161
148
  n => if (n > 0) Right(PositiveInt(n)) else Left(s"Expected positive, got $n"),
162
149
  p => Right(p.value)
163
150
  )