functype 1.0.1 → 1.2.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.
@@ -1,5 +1,5 @@
1
- import { t as Brand } from "./Brand-BJIRbUKB.js";
2
- import { c as Pipe, l as Foldable, o as Serializable, r as Typeable, t as Tuple, u as Type } from "./Tuple-De-FhPDq.js";
1
+ import { t as Brand } from "./Brand-bfnGXuum.js";
2
+ import { d as Type, l as Pipe, o as Serializable, r as Typeable, t as Tuple, u as Foldable } from "./Tuple-8yRldBty.js";
3
3
 
4
4
  //#region src/error/ParseError.d.ts
5
5
  declare const ParseError: (message?: string) => Error & {
@@ -200,6 +200,13 @@ declare const LazyList: (<A extends Type>(iterable: Iterable<A>) => LazyList<A>)
200
200
  * Create a LazyList from multiple values
201
201
  */
202
202
  from: <A extends Type>(...values: A[]) => LazyList<A>;
203
+ /**
204
+ * Reconstruct a LazyList from a JSON envelope emitted by `serialize().toJSON()`
205
+ * or instance `toJSON()`. Verifies `@functype === "LazyList"` when the marker
206
+ * is present (canonical from 1.2.0). The materialized array becomes the new
207
+ * LazyList's backing — laziness can't survive JSON serialization.
208
+ */
209
+ fromJSON: <A extends Type>(json: string) => LazyList<A>;
203
210
  /**
204
211
  * Create an infinite LazyList by repeatedly applying a function
205
212
  * @example
@@ -244,6 +251,190 @@ declare const LazyList: (<A extends Type>(iterable: Iterable<A>) => LazyList<A>)
244
251
  cycle: <A extends Type>(iterable: Iterable<A>) => LazyList<A>;
245
252
  };
246
253
  //#endregion
254
+ //#region src/serialization/error-envelope.d.ts
255
+ /**
256
+ * Canonical projection of `Error` to JSON, shared by every Serializable type
257
+ * that carries an `Error` in its failure branch (`Try.Failure`, `Task.Err`,
258
+ * `Lazy` with a thrown thunk).
259
+ *
260
+ * Round-trip guarantees:
261
+ * - `err.name` survives (preserves discriminator: `e.name === "TypeError"` works)
262
+ * - `err.message` survives
263
+ * - `err.stack` survives if present at serialize time
264
+ * - `err.cause` survives recursively (arbitrary nesting depth)
265
+ *
266
+ * What does NOT survive:
267
+ * - `instanceof TypeError` and other subclass identity checks (JSON cannot
268
+ * reconstruct user-defined classes without arbitrary code execution).
269
+ * - Custom Error-subclass fields (e.g. `HttpError.status`). The generic
270
+ * projection doesn't know about them; a future registry mechanism may
271
+ * address this.
272
+ *
273
+ * Use `e.name` for discriminator checks across the serialization boundary,
274
+ * not `e instanceof SomeError`.
275
+ */
276
+ type SerializedError = {
277
+ readonly name: string;
278
+ readonly message: string;
279
+ readonly stack?: string;
280
+ readonly cause?: SerializedError | string;
281
+ };
282
+ /**
283
+ * Project an arbitrary thrown value to the canonical SerializedError shape.
284
+ * Accepts both `Error` instances and non-Error throwables (strings, plain
285
+ * objects, etc.). Non-Error throwables get `name: "NonErrorThrowable"` and
286
+ * the best textual representation we can produce.
287
+ */
288
+ declare const serializeError: (err: unknown) => SerializedError;
289
+ /**
290
+ * Reconstruct an Error from a SerializedError. The reconstructed Error has
291
+ * the same `name`, `message`, `stack`, and `cause` chain as the original,
292
+ * but its prototype is always `Error.prototype` — subclass identity does
293
+ * not round-trip.
294
+ *
295
+ * A `string` is accepted as a shorthand for `{name: "Error", message: <string>}`,
296
+ * matching what `serializeCause` emits when a `cause` was a bare string.
297
+ */
298
+ declare const deserializeError: (s: SerializedError | string) => Error;
299
+ //#endregion
300
+ //#region src/serialization/SerializationCompanion.d.ts
301
+ /**
302
+ * Serialization result containing methods for different formats
303
+ */
304
+ interface SerializationResult {
305
+ /** Serializes to JSON string */
306
+ toJSON: () => string;
307
+ /** Serializes to YAML string */
308
+ toYAML: () => string;
309
+ /** Serializes to base64-encoded binary string */
310
+ toBinary: () => string;
311
+ }
312
+ /**
313
+ * The namespaced marker stamped on every functype envelope. Defends against
314
+ * `_tag` collisions with Effect/fp-ts (which use identical strings like
315
+ * `"Some"`, `"Left"`, `"Success"`). A value WITHOUT this marker is treated
316
+ * as "not ours" by `Serialization.deserialize`.
317
+ *
318
+ * See `docs/proposals/universal-deserialize-changes.md` Change 0 for the
319
+ * full rationale.
320
+ */
321
+ declare const FUNCTYPE_MARKER: "@functype";
322
+ /**
323
+ * Shape of every functype JSON envelope. The marker identifies the type,
324
+ * `_tag` (when present) discriminates variants within that type, and the
325
+ * remaining payload fields are type-specific (`value` for canonical cases,
326
+ * `error` for failure branches, etc.).
327
+ */
328
+ type FunctypeEnvelope = {
329
+ readonly [FUNCTYPE_MARKER]: string;
330
+ readonly _tag?: string;
331
+ readonly [key: string]: unknown;
332
+ };
333
+ /**
334
+ * Build the canonical `{@functype, _tag, value}` envelope OBJECT used by both
335
+ * the instance `toJSON()` (which returns it directly so native JSON.stringify
336
+ * can recurse) and the `serialize().toJSON()` method (which stringifies it).
337
+ *
338
+ * `_tag` is always emitted — variant-less types pass the same string for
339
+ * marker and tag (default behavior when tag is omitted). Keeping `_tag`
340
+ * across the board preserves back-compat for readers that did
341
+ * `if (parsed._tag === "List")` against 1.1.0 envelopes.
342
+ *
343
+ * @param marker - The `@functype` type marker, e.g. `"Either"`, `"Option"`.
344
+ * @param tag - The variant discriminator, e.g. `"Right"`, `"Some"`. Defaults
345
+ * to `marker` for types without variants (List, Map, etc.).
346
+ * @param value - The payload.
347
+ */
348
+ declare const envelope: (marker: string, tag: string | undefined, value: unknown) => FunctypeEnvelope;
349
+ /**
350
+ * Build a non-canonical envelope where the payload doesn't fit the standard
351
+ * `{value}` shape — e.g. `Try.Failure` carries `{error: SerializedError}`,
352
+ * `Lazy`-with-thrown-thunk carries the same.
353
+ *
354
+ * @param marker - The `@functype` type marker.
355
+ * @param tag - The variant discriminator (may be the same as marker for
356
+ * variant-less types).
357
+ * @param fields - Additional payload fields merged into the envelope.
358
+ */
359
+ declare const taggedEnvelope: (marker: string, tag: string, fields: Record<string, unknown>) => FunctypeEnvelope;
360
+ /**
361
+ * Creates a serializer for the canonical envelope shape, with the `@functype`
362
+ * marker stamped at the top level (Change 0 of the 1.2.0 universal-deserialize
363
+ * work). Two forms:
364
+ *
365
+ * createSerializer(marker, value) // variant-less types (List, Map, …)
366
+ * createSerializer(marker, tag, value) // variants (Either, Option, …)
367
+ *
368
+ * Variant-less envelopes are `{"@functype": marker, value}`. Variant envelopes
369
+ * are `{"@functype": marker, _tag: tag, value}`.
370
+ */
371
+ declare function createSerializer(marker: string, value: unknown): SerializationResult;
372
+ declare function createSerializer(marker: string, tag: string, value: unknown): SerializationResult;
373
+ /**
374
+ * Creates a serializer for non-canonical envelopes whose payload doesn't
375
+ * fit the `{value}` shape — e.g. failure branches that carry a structured
376
+ * `SerializedError`. The envelope still carries the `@functype` marker
377
+ * and `_tag` discriminator.
378
+ *
379
+ * @param marker - The `@functype` type marker.
380
+ * @param tag - The variant discriminator.
381
+ * @param fields - The payload fields (merged after marker + tag).
382
+ */
383
+ declare const createTaggedSerializer: (marker: string, tag: string, fields: Record<string, unknown>) => SerializationResult;
384
+ /**
385
+ * @deprecated Use `createTaggedSerializer` instead. Retained for backwards
386
+ * compatibility with any external callers; will be removed in a
387
+ * future major. The single internal caller (`Try.Failure`) has
388
+ * been migrated to `createTaggedSerializer`.
389
+ *
390
+ * Creates a serializer for complex objects with custom serialization logic.
391
+ * Note: this variant does NOT stamp the `@functype` marker — callers must
392
+ * include it in `data` themselves if they want envelope dispatch to work.
393
+ */
394
+ declare const createCustomSerializer: (data: Record<string, unknown>) => SerializationResult;
395
+ /**
396
+ * Generic deserializer from JSON. The `reconstructor` receives the full
397
+ * parsed envelope including any `@functype` marker; per-type companions
398
+ * verify the marker matches their expected value.
399
+ */
400
+ declare const fromJSON: <T>(json: string, reconstructor: (parsed: {
401
+ _tag?: string;
402
+ [key: string]: unknown;
403
+ }) => T) => T;
404
+ /**
405
+ * Generic deserializer from YAML (simple format)
406
+ * @param yaml - The YAML string to parse
407
+ * @param reconstructor - Function to reconstruct the type from parsed data
408
+ * @returns Reconstructed instance
409
+ */
410
+ declare const fromYAML: <T>(yaml: string, reconstructor: (parsed: {
411
+ _tag?: string;
412
+ [key: string]: unknown;
413
+ }) => T) => T;
414
+ /**
415
+ * Generic deserializer from binary (base64-encoded JSON)
416
+ * @param binary - The base64-encoded binary string
417
+ * @param reconstructor - Function to reconstruct the type from parsed data
418
+ * @returns Reconstructed instance
419
+ */
420
+ declare const fromBinary: <T>(binary: string, reconstructor: (parsed: {
421
+ _tag?: string;
422
+ [key: string]: unknown;
423
+ }) => T) => T;
424
+ /**
425
+ * Creates companion serialization methods for a type
426
+ * @param reconstructor - Function to reconstruct the type from parsed data
427
+ * @returns Companion methods object with fromJSON, fromYAML, and fromBinary
428
+ */
429
+ declare const createSerializationCompanion: <T>(reconstructor: (parsed: {
430
+ _tag?: string;
431
+ [key: string]: unknown;
432
+ }) => T) => {
433
+ fromJSON: (json: string) => T;
434
+ fromYAML: (yaml: string) => T;
435
+ fromBinary: (binary: string) => T;
436
+ };
437
+ //#endregion
247
438
  //#region src/typeclass/ContainerOps.d.ts
248
439
  /**
249
440
  * Universal operations that work on any container (single-value or collection).
@@ -570,6 +761,21 @@ interface Try<out T> extends FunctypeSum<T, TypeNames>, Extractable<T>, Pipe<T>,
570
761
  _tag: TypeNames;
571
762
  value: T | Error;
572
763
  };
764
+ /**
765
+ * Custom JSON serialization. Success emits `{"@functype":"Try","_tag":"Success","value":T}`.
766
+ * Failure emits `{"@functype":"Try","_tag":"Failure","error":SerializedError}` where
767
+ * SerializedError captures `name`, `message`, `stack`, and the full `cause` chain —
768
+ * `e.name` survives round-trip but `instanceof SomeError` does not.
769
+ */
770
+ toJSON(): {
771
+ "@functype": "Try";
772
+ _tag: "Success";
773
+ value: T;
774
+ } | {
775
+ "@functype": "Try";
776
+ _tag: "Failure";
777
+ error: SerializedError;
778
+ };
573
779
  }
574
780
  declare const Try: (<T>(f: () => T) => Try<T>) & {
575
781
  /**
@@ -1422,6 +1628,21 @@ interface TaskOutcome<out T> extends FunctypeBase<T, "Ok" | "Err">, Extractable<
1422
1628
  Ok: (value: T) => U;
1423
1629
  Err: (error: Throwable) => U;
1424
1630
  }) => U;
1631
+ /**
1632
+ * Custom JSON serialization. Ok emits `{"@functype":"Task","_tag":"Ok","value":T}`.
1633
+ * Err emits `{"@functype":"Task","_tag":"Err","error":SerializedError}` capturing the
1634
+ * Throwable's name, message, stack, and cause chain. See error-envelope.ts —
1635
+ * `instanceof` does NOT survive round-trip but `error.name` does.
1636
+ */
1637
+ toJSON(): {
1638
+ "@functype": "Task";
1639
+ _tag: "Ok";
1640
+ value: T;
1641
+ } | {
1642
+ "@functype": "Task";
1643
+ _tag: "Err";
1644
+ error: SerializedError;
1645
+ };
1425
1646
  }
1426
1647
  interface Ok<out T> extends TaskOutcome<T> {
1427
1648
  readonly _tag: "Ok";
@@ -1527,6 +1748,15 @@ declare const Task$1: (<T = unknown>(params?: TaskParams) => {
1527
1748
  * Preferred for new code
1528
1749
  */
1529
1750
  err: <T>(error: unknown, data?: unknown, params?: TaskParams) => Err<T>;
1751
+ /**
1752
+ * Reconstruct a TaskOutcome from a JSON envelope emitted by `serialize().toJSON()`
1753
+ * or instance `toJSON()`. Verifies `@functype === "Task"` and dispatches on `_tag`.
1754
+ *
1755
+ * Err reconstruction goes through `deserializeError` so `name`/`message`/`stack`/`cause`
1756
+ * survive; the resulting Throwable carries the deserialized Error as its underlying
1757
+ * error (subclass identity does NOT round-trip — see error-envelope.ts).
1758
+ */
1759
+ fromJSON: <T>(json: string) => TaskOutcome<T>;
1530
1760
  /**
1531
1761
  * Create TaskOutcome from Either
1532
1762
  * @param either - Either to convert
@@ -1618,6 +1848,131 @@ declare const Task$1: (<T = unknown>(params?: TaskParams) => {
1618
1848
  };
1619
1849
  type Task$1 = ReturnType<typeof Task$1>;
1620
1850
  //#endregion
1851
+ //#region src/decoder/DecoderError.d.ts
1852
+ /**
1853
+ * Recursive decoder error.
1854
+ *
1855
+ * `Leaf` represents a single decode failure at some `path` in the input.
1856
+ * `Composite` aggregates child failures (one per failed field of an object,
1857
+ * one per failed element of a list, etc.) and mirrors the structural shape
1858
+ * of the input — making it possible to render `user.name: expected string`
1859
+ * alongside `user.age: expected number` from a single response.
1860
+ *
1861
+ * Accumulation lives in the data, not in the wrapper. Combinators in
1862
+ * `DecoderCompanion` (object/list/map) produce `Composite` when more than
1863
+ * one child decoder fails, unwrapping single-child composites back to a
1864
+ * `Leaf` for cleaner error messages. The plain `Either<DecoderError, A>`
1865
+ * return type of `Decoder<A>` keeps composition with the rest of the
1866
+ * library uniform.
1867
+ *
1868
+ * Named `DecoderError` (not `DecodeError`) to avoid collision with the
1869
+ * existing `HttpError.DecodeError` variant — these are at different layers:
1870
+ * the HTTP variant is the outer wrapper, this is the structural inner cause.
1871
+ */
1872
+ type DecoderError = DecoderErrorLeaf | DecoderErrorComposite;
1873
+ type DecoderErrorLeaf = {
1874
+ readonly _tag: "Leaf";
1875
+ readonly path: ReadonlyArray<string>;
1876
+ readonly message: string;
1877
+ readonly cause?: unknown;
1878
+ };
1879
+ type DecoderErrorComposite = {
1880
+ readonly _tag: "Composite";
1881
+ readonly path: ReadonlyArray<string>;
1882
+ readonly children: List<DecoderError>;
1883
+ };
1884
+ declare const DecoderError: {
1885
+ readonly _tag: "DecoderError";
1886
+ } & {
1887
+ leaf: (path: ReadonlyArray<string>, message: string, cause?: unknown) => DecoderErrorLeaf;
1888
+ composite: (path: ReadonlyArray<string>, children: List<DecoderError>) => DecoderErrorComposite;
1889
+ isLeaf: (e: DecoderError) => e is DecoderErrorLeaf;
1890
+ isComposite: (e: DecoderError) => e is DecoderErrorComposite;
1891
+ match: <T>(e: DecoderError, patterns: {
1892
+ readonly Leaf: (e: DecoderErrorLeaf) => T;
1893
+ readonly Composite: (e: DecoderErrorComposite) => T;
1894
+ }) => T;
1895
+ prepend: (segment: string, e: DecoderError) => DecoderError;
1896
+ flatten: (e: DecoderError) => List<{
1897
+ readonly path: ReadonlyArray<string>;
1898
+ readonly message: string;
1899
+ }>;
1900
+ format: (e: DecoderError) => string;
1901
+ };
1902
+ //#endregion
1903
+ //#region src/decoder/Decoder.d.ts
1904
+ /**
1905
+ * A `Decoder<A>` converts an `unknown` value into either a typed `A` or a
1906
+ * structural `DecoderError`. The shape `(raw) => Either<DecoderError, A>` is
1907
+ * the canonical FP decoder contract (cf. circe `Decoder`, fp-ts `Decoder`,
1908
+ * Effect-TS `Schema.decodeUnknownEither`, Elm `Json.Decode.Decoder`).
1909
+ *
1910
+ * Any function matching this signature IS a decoder — there is no plugin
1911
+ * registration. Zod / TypeBox / Valibot / AJV / hand-rolled adapters are
1912
+ * ~15 lines each. The bundled combinators in `DecoderCompanion` cover the
1913
+ * functype-aware cases (Option, Either, List, etc.) that a generic schema
1914
+ * library cannot express.
1915
+ */
1916
+ type Decoder$1<A> = (raw: unknown) => Either<DecoderError, A>;
1917
+ //#endregion
1918
+ //#region src/decoder/index.d.ts
1919
+ /**
1920
+ * A `Decoder<A>` converts an `unknown` value into either a typed `A` or a
1921
+ * structural `DecoderError`. The shape `(raw) => Either<DecoderError, A>` is
1922
+ * the canonical FP decoder contract (cf. circe `Decoder`, fp-ts `Decoder`,
1923
+ * Effect-TS `Schema.decodeUnknownEither`, Elm `Json.Decode.Decoder`).
1924
+ *
1925
+ * Any function matching this signature IS a decoder — there is no plugin
1926
+ * registration. Zod / TypeBox / Valibot / AJV / hand-rolled adapters are
1927
+ * ~15 lines each. The bundled combinators in the `Decoder` value namespace
1928
+ * cover the functype-aware cases (Option, Either, List, etc.) that a
1929
+ * generic schema library cannot express.
1930
+ */
1931
+ type Decoder<A> = (raw: unknown) => Either<DecoderError, A>;
1932
+ /**
1933
+ * Decoder namespace: combinators for converting `unknown` into typed values.
1934
+ *
1935
+ * - `Decoder.string` / `.number` / `.boolean` / `.unknown` / `.nullable(inner)` — leaf primitives
1936
+ * - `Decoder.option(inner)` — null-bias Option (null → None, else inner → Some)
1937
+ * - `Decoder.either.envelope({ok, err})` / `.discriminated({...}, l, r)` — Either variants
1938
+ * - `Decoder.list(inner)` / `.array(inner)` / `.map(inner)` / `.object(shape)` — composites; accumulate child failures
1939
+ * - `Decoder.tagged.option/either/try/list/map/obj(inner?)` — round-trip the `{_tag, value}` shape
1940
+ * used by functype's built-in `.toJSON()` (for functype-to-functype services)
1941
+ */
1942
+ declare const Decoder: {
1943
+ readonly _tag: "Decoder";
1944
+ } & {
1945
+ tagged: {
1946
+ option: <A>(inner: Decoder$1<A>) => Decoder$1<Option<A>>;
1947
+ either: <L, R>(left: Decoder$1<L>, right: Decoder$1<R>) => Decoder$1<Either<L, R>>;
1948
+ try: <A>(inner: Decoder$1<A>) => Decoder$1<Try<A>>;
1949
+ list: <A>(inner: Decoder$1<A>) => Decoder$1<List<A>>;
1950
+ map: <V>(inner: Decoder$1<V>) => Decoder$1<Map$1<string, V>>;
1951
+ obj: <T extends Record<string, unknown>>(shape: { [K in keyof T]: Decoder$1<T[K]> }) => Decoder$1<T>;
1952
+ };
1953
+ string: Decoder$1<string>;
1954
+ number: Decoder$1<number>;
1955
+ boolean: Decoder$1<boolean>;
1956
+ unknown: Decoder$1<unknown>;
1957
+ nullable: <A>(inner: Decoder$1<A>) => Decoder$1<A | null>;
1958
+ option: <A>(inner: Decoder$1<A>) => Decoder$1<Option<A>>;
1959
+ either: {
1960
+ envelope: <L, R>(shape: {
1961
+ ok: Decoder$1<R>;
1962
+ err: Decoder$1<L>;
1963
+ }) => Decoder$1<Either<L, R>>;
1964
+ discriminated: <L, R>(config: {
1965
+ tag: string;
1966
+ leftTag: string;
1967
+ rightTag: string;
1968
+ }, left: Decoder$1<L>, right: Decoder$1<R>) => Decoder$1<Either<L, R>>;
1969
+ };
1970
+ list: <A>(inner: Decoder$1<A>) => Decoder$1<List<A>>;
1971
+ array: <A>(inner: Decoder$1<A>) => Decoder$1<A[]>;
1972
+ map: <V>(inner: Decoder$1<V>) => Decoder$1<Map$1<string, V>>;
1973
+ object: <T extends Record<string, unknown>>(shape: { [K in keyof T]: Decoder$1<T[K]> }) => Decoder$1<T>;
1974
+ };
1975
+ //#endregion
1621
1976
  //#region src/error/ErrorFormatter.d.ts
1622
1977
  /**
1623
1978
  * Type definition for task information that may be attached to errors
@@ -3316,6 +3671,14 @@ type HttpStatusError = {
3316
3671
  readonly statusText: string;
3317
3672
  readonly body: string;
3318
3673
  };
3674
+ /**
3675
+ * Raised when a successful HTTP response could not be decoded into the
3676
+ * caller's expected shape — JSON parse failure, a `decode: Decoder<T>` that
3677
+ * returned `Left(DecoderError)`, a throwing `decodeUnsafe` / `validate`, etc.
3678
+ * In practice `cause` is a `DecoderError` (when produced by the `decode`
3679
+ * path) or an `Error` (otherwise) — but the field is typed `unknown` for
3680
+ * back-compat with the 1.0.x runtime.
3681
+ */
3319
3682
  type DecodeError = {
3320
3683
  readonly _tag: "DecodeError";
3321
3684
  readonly url: string;
@@ -3323,6 +3686,13 @@ type DecodeError = {
3323
3686
  readonly body: string;
3324
3687
  readonly cause: unknown;
3325
3688
  };
3689
+ /**
3690
+ * More descriptive alias for `DecodeError` — clarifies that this is the
3691
+ * HTTP-level wrapper for response decoding failures, distinct from the
3692
+ * structural `DecoderError` tree it usually carries in `cause`. Both names
3693
+ * refer to the same `_tag: "DecodeError"` variant.
3694
+ */
3695
+ type ResponseDecodeError = DecodeError;
3326
3696
  type HttpError = NetworkError | HttpStatusError | DecodeError;
3327
3697
  declare const HttpError: {
3328
3698
  readonly _tag: "HttpError";
@@ -3349,14 +3719,47 @@ interface HttpRequestOptions<T = unknown> {
3349
3719
  readonly body?: unknown;
3350
3720
  readonly signal?: AbortSignal;
3351
3721
  readonly parseAs?: ParseMode;
3722
+ /**
3723
+ * Either-returning response decoder. Returns `Left(DecoderError)` on
3724
+ * failure; the framework maps that to `HttpError.DecodeError(cause: DecoderError)`.
3725
+ * The recursive `DecoderError` tree preserves structural failure info
3726
+ * (paths, child errors) for diagnosis and rendering.
3727
+ *
3728
+ * For adapters whose primary API throws (e.g. Zod's `.parse`), use an
3729
+ * adapter package (e.g. `functype-zod`'s `Decoder.fromZod(schema)`) or
3730
+ * wrap the throwing function in a tiny custom decoder. The deprecated
3731
+ * `validate` field is also still accepted for back-compat.
3732
+ */
3733
+ readonly decode?: Decoder$1<T>;
3734
+ /**
3735
+ * @deprecated Use `decode` (Either-returning). For throw-pattern adapters
3736
+ * like Zod's `.parse`, prefer an adapter package (`functype-zod`'s
3737
+ * `Decoder.fromZod`). `validate` is kept for back-compat with the 1.0.x
3738
+ * API and will be removed in a future major release. Throwing maps to
3739
+ * `HttpError.DecodeError(cause: Error)`.
3740
+ */
3352
3741
  readonly validate?: (data: unknown) => T;
3742
+ /**
3743
+ * Whether to flatten functype ADTs in the request body to their primitive
3744
+ * projections (Option → nullable, Either → right-value-or-throw-on-Left,
3745
+ * List → array, Try → success-value-or-throw, Map → record) before serializing.
3746
+ * Default `true` — matches the wire shape external JSON APIs expect.
3747
+ *
3748
+ * Set to `false` to emit each ADT's canonical `{_tag, value}` form via
3749
+ * `toValue()` for functype-to-functype services where both ends round-trip
3750
+ * the tagged shape via `Decoder.tagged.*`.
3751
+ */
3752
+ readonly flatten?: boolean;
3353
3753
  }
3354
3754
  interface HttpMethodOptions<T = unknown> {
3355
3755
  readonly headers?: Record<string, string>;
3356
3756
  readonly body?: unknown;
3357
3757
  readonly signal?: AbortSignal;
3358
3758
  readonly parseAs?: ParseMode;
3759
+ readonly decode?: Decoder$1<T>;
3760
+ /** @deprecated Use `decode` (Either-returning) or an adapter package for throw-pattern validators. */
3359
3761
  readonly validate?: (data: unknown) => T;
3762
+ readonly flatten?: boolean;
3360
3763
  }
3361
3764
  interface HttpResponse<T> {
3362
3765
  readonly data: T;
@@ -3368,8 +3771,10 @@ interface HttpResponse<T> {
3368
3771
  * The assembled, pre-wire view of a request that `HttpClientConfig.beforeRequest`
3369
3772
  * receives and may return a transformed copy of. URL is resolved against
3370
3773
  * `baseUrl`; headers reflect the `defaultHeaders` + per-call merge. The
3371
- * response-side `validate` function is intentionally not exposed here — it
3372
- * isn't part of the wire request and applies to the response.
3774
+ * response-side decoders (`decode` / `validate`) are intentionally not
3775
+ * exposed here — they aren't part of the wire request and apply to the
3776
+ * response. The `flatten` flag IS exposed because it affects how `body`
3777
+ * is serialized.
3373
3778
  */
3374
3779
  interface HttpRequestView {
3375
3780
  readonly url: string;
@@ -3378,6 +3783,7 @@ interface HttpRequestView {
3378
3783
  readonly body?: unknown;
3379
3784
  readonly signal?: AbortSignal;
3380
3785
  readonly parseAs?: ParseMode;
3786
+ readonly flatten?: boolean;
3381
3787
  }
3382
3788
  //#endregion
3383
3789
  //#region src/fetch/HttpClient.d.ts
@@ -3432,8 +3838,8 @@ type HttpMethods = {
3432
3838
  readonly put: <T = unknown>(url: string, options?: HttpMethodOptions<T>) => IO<never, HttpError, HttpResponse<T>>;
3433
3839
  readonly patch: <T = unknown>(url: string, options?: HttpMethodOptions<T>) => IO<never, HttpError, HttpResponse<T>>;
3434
3840
  readonly delete: <T = unknown>(url: string, options?: HttpMethodOptions<T>) => IO<never, HttpError, HttpResponse<T>>;
3435
- readonly head: (url: string, options?: HttpMethodOptions) => IO<never, HttpError, HttpResponse<void>>;
3436
- readonly options: (url: string, options?: HttpMethodOptions) => IO<never, HttpError, HttpResponse<void>>;
3841
+ readonly head: (url: string, options?: HttpMethodOptions<void>) => IO<never, HttpError, HttpResponse<void>>;
3842
+ readonly options: (url: string, options?: HttpMethodOptions<void>) => IO<never, HttpError, HttpResponse<void>>;
3437
3843
  };
3438
3844
  declare const Http: {
3439
3845
  readonly _tag: "Http";
@@ -3444,8 +3850,8 @@ declare const Http: {
3444
3850
  put: <T = unknown>(url: string, options?: HttpMethodOptions<T>) => IO<never, HttpError, HttpResponse<T>>;
3445
3851
  patch: <T = unknown>(url: string, options?: HttpMethodOptions<T>) => IO<never, HttpError, HttpResponse<T>>;
3446
3852
  delete: <T = unknown>(url: string, options?: HttpMethodOptions<T>) => IO<never, HttpError, HttpResponse<T>>;
3447
- head: (url: string, options?: HttpMethodOptions) => IO<never, HttpError, HttpResponse<void>>;
3448
- options: (url: string, options?: HttpMethodOptions) => IO<never, HttpError, HttpResponse<void>>;
3853
+ head: (url: string, options?: HttpMethodOptions<void>) => IO<never, HttpError, HttpResponse<void>>;
3854
+ options: (url: string, options?: HttpMethodOptions<void>) => IO<never, HttpError, HttpResponse<void>>;
3449
3855
  client: (config: HttpClientConfig) => HttpMethods;
3450
3856
  };
3451
3857
  //#endregion
@@ -3750,13 +4156,39 @@ interface Lazy<out T extends Type> extends FunctypeBase<T, "Lazy">, Extractable<
3750
4156
  */
3751
4157
  toString(): string;
3752
4158
  /**
3753
- * Converts the Lazy to a value object
3754
- * @returns Object representation of the Lazy with evaluation state
4159
+ * Converts the Lazy to a value object.
4160
+ *
4161
+ * **Forces the thunk** as a side effect — Lazy serialization (and projection
4162
+ * to a plain value object) cannot represent an unevaluated thunk in JSON;
4163
+ * forcing is the only way to produce a complete projection. If the thunk
4164
+ * threw, the failure is captured in the `error` field (real Error, with
4165
+ * full prototype intact for in-memory inspection — `toJSON` projects to
4166
+ * `SerializedError` for the wire).
4167
+ *
4168
+ * Changed in 1.2.0 — pre-1.2.0 Lazy emitted `{_tag, evaluated, value?}`
4169
+ * without forcing. See `docs/proposals/serializable-audit-q1-q2.md`.
3755
4170
  */
3756
4171
  toValue(): {
3757
4172
  _tag: "Lazy";
3758
- evaluated: boolean;
3759
- value?: T;
4173
+ value: T;
4174
+ } | {
4175
+ _tag: "Lazy";
4176
+ error: Error;
4177
+ };
4178
+ /**
4179
+ * Custom JSON serialization. Forces the thunk (see `toValue` for the
4180
+ * side-effect contract). Emits `{"@functype":"Lazy","_tag":"Lazy","value":T}`
4181
+ * on success, or `{"@functype":"Lazy","_tag":"Lazy","error":SerializedError}`
4182
+ * if the thunk threw — see error-envelope.ts for round-trip semantics.
4183
+ */
4184
+ toJSON(): {
4185
+ "@functype": "Lazy";
4186
+ _tag: "Lazy";
4187
+ value: T;
4188
+ } | {
4189
+ "@functype": "Lazy";
4190
+ _tag: "Lazy";
4191
+ error: SerializedError;
3760
4192
  };
3761
4193
  }
3762
4194
  /**
@@ -3842,6 +4274,24 @@ declare const Lazy: (<T extends Type>(thunk: () => T) => Lazy<T>) & {
3842
4274
  * @returns A new Lazy instance that throws the error
3843
4275
  */
3844
4276
  fail: <T extends Type>(error: unknown) => Lazy<T>;
4277
+ /**
4278
+ * Creates an already-evaluated Lazy. Used by `fromJSON` to reconstruct a
4279
+ * Lazy whose thunk was forced at serialize time — there is no original
4280
+ * thunk to defer because a closure cannot be JSON-serialized.
4281
+ *
4282
+ * Functionally equivalent to `Lazy.fromValue` but reads with intent at
4283
+ * the call site.
4284
+ */
4285
+ evaluated: <T extends Type>(value: T) => Lazy<T>;
4286
+ /**
4287
+ * Reconstruct a Lazy from a JSON envelope emitted by `serialize().toJSON()`
4288
+ * or instance `toJSON()`. Verifies `@functype === "Lazy"`. Success envelopes
4289
+ * become already-evaluated Lazies via `Lazy.evaluated`; failure envelopes
4290
+ * become Lazies whose forcing rethrows the deserialized Error (see
4291
+ * error-envelope.ts — `instanceof SomeError` does NOT survive but `name`
4292
+ * does).
4293
+ */
4294
+ fromJSON: <T extends Type>(json: string) => Lazy<T>;
3845
4295
  };
3846
4296
  //#endregion
3847
4297
  //#region src/traversable/Traversable.d.ts
@@ -4246,75 +4696,43 @@ declare const Ref: (<A extends Type>(initial: A) => Ref<A>) & {
4246
4696
  */
4247
4697
  of: <A extends Type>(initial: A) => Ref<A>;
4248
4698
  };
4249
- //#endregion
4250
- //#region src/serialization/SerializationCompanion.d.ts
4251
- /**
4252
- * Serialization result containing methods for different formats
4253
- */
4254
- interface SerializationResult {
4255
- /** Serializes to JSON string */
4256
- toJSON: () => string;
4257
- /** Serializes to YAML string */
4258
- toYAML: () => string;
4259
- /** Serializes to base64-encoded binary string */
4260
- toBinary: () => string;
4699
+ declare namespace Serialization_d_exports {
4700
+ export { deserialize, isFunctypeValue, serialize };
4261
4701
  }
4262
4702
  /**
4263
- * Creates a serializer for a simple tagged value
4264
- * @param tag - The type tag (e.g., "Some", "List", "Success")
4265
- * @param value - The value to serialize
4266
- * @returns Serialization methods
4267
- */
4268
- declare const createSerializer: (tag: string, value: unknown) => SerializationResult;
4269
- /**
4270
- * Creates a serializer for complex objects with custom serialization logic
4271
- * @param data - The data object to serialize (should include _tag)
4272
- * @returns Serialization methods
4703
+ * Reconstruct any value from a JSON string. Walks the parsed structure and
4704
+ * rebuilds functype envelopes via the dispatch table. Returns a `Try` so
4705
+ * malformed JSON or unknown markers are expressible values rather than
4706
+ * thrown matches the functype convention for expected-failure paths.
4707
+ *
4708
+ * @example
4709
+ * const result = Serialization.deserialize('{"@functype":"Either","_tag":"Right","value":5}')
4710
+ * result.fold(e => console.error(e), v => console.log(v)) // Right(5)
4711
+ *
4712
+ * // Plain (non-functype) values pass through:
4713
+ * Serialization.deserialize('{"name":"alice","age":30}') // → Success({name, age})
4273
4714
  */
4274
- declare const createCustomSerializer: (data: Record<string, unknown>) => SerializationResult;
4715
+ declare const deserialize: (json: string) => Try<unknown>;
4275
4716
  /**
4276
- * Generic deserializer from JSON
4277
- * @param json - The JSON string to parse
4278
- * @param reconstructor - Function to reconstruct the type from parsed data
4279
- * @returns Reconstructed instance
4280
- */
4281
- declare const fromJSON: <T>(json: string, reconstructor: (parsed: {
4282
- _tag: string;
4283
- [key: string]: unknown;
4284
- }) => T) => T;
4285
- /**
4286
- * Generic deserializer from YAML (simple format)
4287
- * @param yaml - The YAML string to parse
4288
- * @param reconstructor - Function to reconstruct the type from parsed data
4289
- * @returns Reconstructed instance
4290
- */
4291
- declare const fromYAML: <T>(yaml: string, reconstructor: (parsed: {
4292
- _tag: string;
4293
- [key: string]: unknown;
4294
- }) => T) => T;
4295
- /**
4296
- * Generic deserializer from binary (base64-encoded JSON)
4297
- * @param binary - The base64-encoded binary string
4298
- * @param reconstructor - Function to reconstruct the type from parsed data
4299
- * @returns Reconstructed instance
4717
+ * Serialize any value to a JSON string. Thin convenience over `JSON.stringify`
4718
+ * functype instances self-stringify via their instance `toJSON()` method,
4719
+ * which emits the `@functype`-marked envelope. Nested functype values
4720
+ * embedded in plain objects/arrays serialize correctly via the standard
4721
+ * JSON.stringify protocol with no walker needed.
4722
+ *
4723
+ * `undefined` is converted to `null` (matching the convention DBOS and
4724
+ * SuperJSON use; `JSON.stringify(undefined)` returns the string `undefined`
4725
+ * which is not valid JSON).
4300
4726
  */
4301
- declare const fromBinary: <T>(binary: string, reconstructor: (parsed: {
4302
- _tag: string;
4303
- [key: string]: unknown;
4304
- }) => T) => T;
4727
+ declare const serialize: (value: unknown) => string;
4305
4728
  /**
4306
- * Creates companion serialization methods for a type
4307
- * @param reconstructor - Function to reconstruct the type from parsed data
4308
- * @returns Companion methods object with fromJSON, fromYAML, and fromBinary
4729
+ * Runtime guard: is this a live functype Serializable? Checks for the
4730
+ * `serialize()` method plus the `_tag` field that every Serializable instance
4731
+ * carries. Use this when wrapping `serialize`/`deserialize` in a host
4732
+ * serializer that needs to distinguish functype values from foreign data
4733
+ * (e.g. `isApplicable` in a DBOS recipe).
4309
4734
  */
4310
- declare const createSerializationCompanion: <T>(reconstructor: (parsed: {
4311
- _tag: string;
4312
- [key: string]: unknown;
4313
- }) => T) => {
4314
- fromJSON: (json: string) => T;
4315
- fromYAML: (yaml: string) => T;
4316
- fromBinary: (binary: string) => T;
4317
- };
4735
+ declare const isFunctypeValue: (v: unknown) => v is Serializable<unknown>;
4318
4736
  //#endregion
4319
4737
  //#region src/set/Set.d.ts
4320
4738
  /**
@@ -4665,6 +5083,16 @@ interface Option<out T extends Type> extends Functype<T, "Some" | "None">, Promi
4665
5083
  _tag: "Some" | "None";
4666
5084
  value: T;
4667
5085
  };
5086
+ /**
5087
+ * Custom JSON serialization producing the canonical `@functype`-marked
5088
+ * envelope so native `JSON.stringify` recursion (e.g. inside a plain
5089
+ * object) emits a round-trip-able shape.
5090
+ */
5091
+ toJSON(): {
5092
+ "@functype": "Option";
5093
+ _tag: "Some" | "None";
5094
+ value: T | null;
5095
+ };
4668
5096
  /**
4669
5097
  * Pattern matches over the Option, applying a handler function based on the variant
4670
5098
  * @param patterns - Object with handler functions for Some and None variants
@@ -5029,9 +5457,14 @@ interface EitherBase<out L extends Type, out R extends Type> extends FunctypeSum
5029
5457
  value: L | R;
5030
5458
  };
5031
5459
  /**
5032
- * Custom JSON serialization that excludes getter properties
5460
+ * Custom JSON serialization that excludes getter properties.
5461
+ * Emits the canonical functype envelope with `@functype: "Either"` so
5462
+ * native `JSON.stringify` recursion (e.g. inside a plain object body)
5463
+ * produces a marker-bearing envelope that survives a round-trip through
5464
+ * `Serialization.deserialize`.
5033
5465
  */
5034
5466
  toJSON(): {
5467
+ "@functype": "Either";
5035
5468
  _tag: "Left" | "Right";
5036
5469
  value: L | R;
5037
5470
  };
@@ -5336,4 +5769,4 @@ interface FailureErrorType extends Error {
5336
5769
  }
5337
5770
  declare const FailureError: (cause: Error, message?: string) => FailureErrorType;
5338
5771
  //#endregion
5339
- export { Map$1 as $, reduceRightWiden as $n, TypedError as $t, Collection as A, UntypedMatch as An, RIO as At, SerializationResult as B, IntegerNumber as Bn, Context as Bt, isRight as C, createCancellationTokenSource as Cn, HttpStatusError as Ct, Functype as D, ThrowableType as Dn, TestContext as Dt, FunctypeSum as E, Throwable as En, TestClockTag as Et, Some as F, Companion as Fn, LayerError as Ft, fromJSON as G, PositiveNumber as Gn, FieldValidation as Gt, createSerializationCompanion as H, NonNegativeNumber as Hn, HasService as Ht, Stack as I, BoundedNumber as In, LayerInput as It, Obj as J, ValidatedBrand as Jn, ValidationRule as Jt, fromYAML as K, UUID as Kn, FormValidation as Kt, Valuable as L, BoundedString as Ln, LayerOutput as Lt, None as M, CompanionMethods as Mn, TimeoutError as Mt, Option as N, InstanceType as Nn, UIO as Nt, FunctypeBase as O, Base as On, IO as Ot, OptionConstructor as P, isCompanion as Pn, Layer as Pt, ESMapType as Q, Widen as Qn, ErrorStatus as Qt, ValuableParams as R, EmailAddress as Rn, Exit as Rt, isLeft as S, TaskSuccess as Sn, HttpMethod as St, tryCatchAsync as T, NAME as Tn, TestClock as Tt, createSerializer as U, PatternString as Un, Tag as Ut, createCustomSerializer as V, NonEmptyString as Vn, ContextServices as Vt, fromBinary as W, PositiveInteger as Wn, TagService as Wt, MatchableUtils as X, Try as Xn, ErrorCode as Xt, Matchable as Y, ValidatedBrandCompanion as Yn, Validator as Yt, ESMap as Z, TypeNames as Zn, ErrorMessage as Zt, Right as _, TaskFailure as _n, HttpRequestView as _t, EmptyListError as a, createErrorSerializer as an, Monad as ar, HKT as at, TypeCheckLeft as b, TaskParams as bn, DecodeError as bt, LeftError as c, safeStringify as cn, LazyList as cr, OptionKind as ct, isDoCapable as d, CancellationTokenSource as dn, DoResult as dr, FoldableUtils as dt, TypedErrorContext as en, reduceWiden as er, KVTraversable as et, unwrap as f, Err as fn, Doable as fr, Http as ft, LeftOf as g, Task$1 as gn, HttpRequestOptions as gt, Left as h, TaggedThrowable as hn, HttpMethodOptions as ht, DoGenerator as i, TaskErrorInfo as in, Functor as ir, EitherKind as it, List as j, Cond as jn, Task as jt, FunctypeCollection as k, Match as kn, InterruptedError as kt, LeftErrorType as l, Async as ln, Extractable as lr, TryKind as lt, EitherBase as m, Sync as mn, HttpClientConfig as mt, Do as n, ErrorFormatterOptions as nn, Applicative as nr, Lazy as nt, FailureError as o, formatError as on, CollectionOps as or, Kind as ot, Either as p, Ok as pn, ParseError as pr, HttpClient as pt, Ref as q, UrlString as qn, Validation as qt, DoAsync as r, ErrorWithTaskInfo as rn, AsyncMonad as rr, Identity as rt, FailureErrorType as s, formatStackTrace as sn, ContainerOps as sr, ListKind as st, $ as t, ErrorChainElement as tn, Promisable as tr, Traversable as tt, NoneError as u, CancellationToken as un, isExtractable as ur, UniversalContainer as ut, RightOf as v, TaskMetadata as vn, HttpResponse as vt, tryCatch as w, isTaggedThrowable as wn, NetworkError as wt, TypeCheckRight as x, TaskResult as xn, HttpError as xt, TestEither as y, TaskOutcome as yn, ParseMode as yt, Set as z, ISO8601Date as zn, ExitTag as zt };
5772
+ export { HKT as $, reduceWiden as $n, TaskErrorInfo as $t, Collection as A, Cond as An, LayerError as At, Serialization_d_exports as B, NonEmptyString as Bn, FieldValidation as Bt, isRight as C, isTaggedThrowable as Cn, Extractable as Cr, IO as Ct, Functype as D, Base as Dn, ParseError as Dr, TimeoutError as Dt, FunctypeSum as E, ThrowableType as En, Doable as Er, Task as Et, Some as F, BoundedNumber as Fn, Context as Ft, ESMap as G, UUID as Gn, ErrorCode as Gt, Obj as H, PatternString as Hn, Validation as Ht, Stack as I, BoundedString as In, ContextServices as It, KVTraversable as J, ValidatedBrandCompanion as Jn, TypedError as Jt, ESMapType as K, UrlString as Kn, ErrorMessage as Kt, Valuable as L, EmailAddress as Ln, HasService as Lt, None as M, InstanceType as Mn, LayerOutput as Mt, Option as N, isCompanion as Nn, Exit as Nt, FunctypeBase as O, Match as On, UIO as Ot, OptionConstructor as P, Companion as Pn, ExitTag as Pt, EitherKind as Q, reduceRightWiden as Qn, ErrorWithTaskInfo as Qt, ValuableParams as R, ISO8601Date as Rn, Tag as Rt, isLeft as S, createCancellationTokenSource as Sn, LazyList as Sr, TestContext as St, tryCatchAsync as T, Throwable as Tn, DoResult as Tr, RIO as Tt, Matchable as U, PositiveInteger as Un, ValidationRule as Ut, Ref as V, NonNegativeNumber as Vn, FormValidation as Vt, MatchableUtils as W, PositiveNumber as Wn, Validator as Wt, Lazy as X, TypeNames as Xn, ErrorChainElement as Xt, Traversable as Y, Try as Yn, TypedErrorContext as Yt, Identity as Z, Widen as Zn, ErrorFormatterOptions as Zt, Right as _, TaskMetadata as _n, fromYAML as _r, HttpStatusError as _t, EmptyListError as a, DecoderError as an, CollectionOps as ar, FoldableUtils as at, TypeCheckLeft as b, TaskResult as bn, deserializeError as br, TestClock as bt, LeftError as c, Async as cn, FunctypeEnvelope as cr, HttpClientConfig as ct, isDoCapable as d, Err as dn, createSerializationCompanion as dr, HttpRequestView as dt, createErrorSerializer as en, Promisable as er, Kind as et, unwrap as f, Ok as fn, createSerializer as fr, HttpResponse as ft, LeftOf as g, TaskFailure as gn, fromJSON as gr, HttpMethod as gt, Left as h, Task$1 as hn, fromBinary as hr, HttpError as ht, DoGenerator as i, Decoder as in, Monad as ir, UniversalContainer as it, List as j, CompanionMethods as jn, LayerInput as jt, FunctypeCollection as k, UntypedMatch as kn, Layer as kt, LeftErrorType as l, CancellationToken as ln, SerializationResult as lr, HttpMethodOptions as lt, EitherBase as m, TaggedThrowable as mn, envelope as mr, DecodeError as mt, Do as n, formatStackTrace as nn, AsyncMonad as nr, OptionKind as nt, FailureError as o, DecoderErrorComposite as on, ContainerOps as or, Http as ot, Either as p, Sync as pn, createTaggedSerializer as pr, ParseMode as pt, Map$1 as q, ValidatedBrand as qn, ErrorStatus as qt, DoAsync as r, safeStringify as rn, Functor as rr, TryKind as rt, FailureErrorType as s, DecoderErrorLeaf as sn, FUNCTYPE_MARKER as sr, HttpClient as st, $ as t, formatError as tn, Applicative as tr, ListKind as tt, NoneError as u, CancellationTokenSource as un, createCustomSerializer as ur, HttpRequestOptions as ut, RightOf as v, TaskOutcome as vn, taggedEnvelope as vr, NetworkError as vt, tryCatch as w, NAME as wn, isExtractable as wr, InterruptedError as wt, TypeCheckRight as x, TaskSuccess as xn, serializeError as xr, TestClockTag as xt, TestEither as y, TaskParams as yn, SerializedError as yr, ResponseDecodeError as yt, Set as z, IntegerNumber as zn, TagService as zt };