effect-app 4.0.0-beta.210 → 4.0.0-beta.212

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.
package/src/Schema.ts CHANGED
@@ -10,6 +10,102 @@ import { PhoneNumber as PhoneNumberT, type PhoneNumber as PhoneNumberType } from
10
10
  import { type AST } from "./Schema/schema.js"
11
11
  import { copy, extendM, type StructuralCopyOrigin } from "./utils.js"
12
12
 
13
+ // ---------------------------------------------------------------------------
14
+ // Default helpers — re-exported from effect/Schema
15
+ //
16
+ // The five helpers below are surfaced explicitly so the (important) policy
17
+ // around them lives next to the export. See also the file-level note in
18
+ // `./Schema/ext.ts` and the documented wrappers in
19
+ // `./Schema/ext.ts`, `./Schema/numbers.ts`, `./Schema/moreStrings.ts`,
20
+ // and `./ids.ts`.
21
+ //
22
+ // **Construction-only**: `withConstructorDefault` fills the field when it
23
+ // is omitted from `.make(...)` input. It is NOT applied during decode, so
24
+ // it CANNOT be used to just-in-time migrate database fields. A stored
25
+ // record missing the field will still fail to decode.
26
+ //
27
+ // **`withDecodingDefault*` is discouraged**: a missing field in persisted
28
+ // data is just as likely to be data corruption as it is an old-shape
29
+ // document; silently substituting a default hides the problem and can
30
+ // poison downstream aggregates. Prefer an explicit, preferably versioned
31
+ // migration of database data over shoving missing fields under the rug.
32
+ // ---------------------------------------------------------------------------
33
+
34
+ /**
35
+ * Attach a default value used **only** when constructing a value (e.g. via
36
+ * `.make(...)` or struct constructors) and the field is omitted from input.
37
+ *
38
+ * **Not applied during decode.** Decoding a payload that is missing the
39
+ * field will still raise a parse error. Do **not** rely on this to migrate
40
+ * database fields just-in-time — see the section header above.
41
+ *
42
+ * @see {@link withDecodingDefault} / {@link withDecodingDefaultType} —
43
+ * decode-time variants (discouraged for persisted data; use explicit,
44
+ * versioned migrations instead).
45
+ */
46
+ export { withConstructorDefault } from "effect/Schema"
47
+
48
+ /**
49
+ * Attach a default value used during decode when the field's `Encoded` value
50
+ * is missing **or** `undefined`. The default is specified as an `Encoded`
51
+ * value and threaded through the schema's decode step.
52
+ *
53
+ * **Discouraged for persisted data.** A missing field in a stored record is
54
+ * just as likely to be data corruption as it is an old-shape document;
55
+ * silently substituting a default hides the problem. Prefer an explicit,
56
+ * preferably versioned migration of database data — see the section header
57
+ * above.
58
+ *
59
+ * @see {@link withDecodingDefaultKey} — key-absent-only variant
60
+ * @see {@link withDecodingDefaultType} — `Type`-side variant
61
+ * @see {@link withConstructorDefault} — for `.make(...)`-time defaults
62
+ */
63
+ export { withDecodingDefault } from "effect/Schema"
64
+
65
+ /**
66
+ * Attach a default value used during decode when the field **key is absent**
67
+ * (note: not when present and `undefined`). The default is an `Encoded`
68
+ * value.
69
+ *
70
+ * **Discouraged for persisted data** — same reasoning as
71
+ * {@link withDecodingDefault}. Use explicit, preferably versioned migrations
72
+ * over decode-time fallbacks.
73
+ *
74
+ * @see {@link withDecodingDefault} — value-absent-or-undefined variant
75
+ * @see {@link withDecodingDefaultTypeKey} — `Type`-side variant
76
+ * @see {@link withConstructorDefault} — for `.make(...)`-time defaults
77
+ */
78
+ export { withDecodingDefaultKey } from "effect/Schema"
79
+
80
+ /**
81
+ * Attach a default value used during decode when the field is missing **or**
82
+ * `undefined`. The default is specified as a `Type` value (i.e. on the
83
+ * decoded side).
84
+ *
85
+ * **Discouraged for persisted data** — same reasoning as
86
+ * {@link withDecodingDefault}. Use explicit, preferably versioned migrations
87
+ * over decode-time fallbacks.
88
+ *
89
+ * @see {@link withDecodingDefault} — `Encoded`-side variant
90
+ * @see {@link withDecodingDefaultTypeKey} — key-absent-only variant
91
+ * @see {@link withConstructorDefault} — for `.make(...)`-time defaults
92
+ */
93
+ export { withDecodingDefaultType } from "effect/Schema"
94
+
95
+ /**
96
+ * Attach a default value used during decode when the field **key is absent**
97
+ * (note: not when present and `undefined`). The default is a `Type` value.
98
+ *
99
+ * **Discouraged for persisted data** — same reasoning as
100
+ * {@link withDecodingDefault}. Use explicit, preferably versioned migrations
101
+ * over decode-time fallbacks.
102
+ *
103
+ * @see {@link withDecodingDefaultKey} — `Encoded`-side variant
104
+ * @see {@link withDecodingDefaultType} — value-absent-or-undefined variant
105
+ * @see {@link withConstructorDefault} — for `.make(...)`-time defaults
106
+ */
107
+ export { withDecodingDefaultTypeKey } from "effect/Schema"
108
+
13
109
  export * from "effect/Schema"
14
110
 
15
111
  export * from "./Schema/Class.js"
package/src/ids.ts CHANGED
@@ -10,7 +10,16 @@ export interface RequestIdBrand extends StringIdBrand {
10
10
  }
11
11
 
12
12
  export type RequestId = NonEmptyString255
13
- // a request id may be made from a span id, which does not comply with StringId schema.
13
+ /**
14
+ * Schema for a request id.
15
+ *
16
+ * A request id may be made from a span id, which does not comply with the
17
+ * `StringId` schema (hence the looser `NonEmptyString255` base).
18
+ *
19
+ * `.withConstructorDefault` => fresh `StringId` (construction-only; not
20
+ * applied during decode — cannot be used to JIT-migrate database fields).
21
+ * See `./Schema/ext.ts` for the full policy note.
22
+ */
14
23
  export const RequestId = extendM(
15
24
  Object
16
25
  .assign(Object.create(NonEmptyString255) as {}, NonEmptyString255 as unknown as Codec<NonEmptyString255, string>),
@@ -18,7 +27,13 @@ export const RequestId = extendM(
18
27
  const make = StringId.make as () => NonEmptyString255
19
28
  return ({
20
29
  make,
21
- withDefault: S.withConstructorDefault(Effect.sync(make))(s as typeof s & S.WithoutConstructorDefault)
30
+ /**
31
+ * Construction-only default: fresh `StringId`. Applied only when the
32
+ * field is omitted from `.make(...)` input. NOT applied during decode —
33
+ * cannot be used to JIT-migrate database fields. See `./Schema/ext.ts`
34
+ * file-level note.
35
+ */
36
+ withConstructorDefault: S.withConstructorDefault(Effect.sync(make))(s as typeof s & S.WithoutConstructorDefault)
22
37
  })
23
38
  }
24
39
  )
@@ -26,4 +41,10 @@ export const RequestId = extendM(
26
41
 
27
42
  export interface UserProfileIdBrand extends Simplify<B.Brand<"UserProfileId"> & StringIdBrand> {}
28
43
  export type UserProfileId = string & UserProfileIdBrand
44
+ /**
45
+ * Branded `StringId` for user profiles.
46
+ *
47
+ * Exposes `.withConstructorDefault` (fresh id) — construction-only; not
48
+ * applied during decode. See `./Schema/ext.ts` for the full policy note.
49
+ */
29
50
  export const UserProfileId = brandedStringId<UserProfileId>()
@@ -18,11 +18,11 @@ test("literal default works", () => {
18
18
  const l = S.Literals(["a", "b"])
19
19
  expect(l.Default).toBe("a")
20
20
  expectTypeOf(l.Default).toEqualTypeOf<"a">()
21
- const s = S.Struct({ l: l.withDefault })
21
+ const s = S.Struct({ l: l.withConstructorDefault })
22
22
  expect(s.make({}).l).toBe("a")
23
23
 
24
24
  const l2 = l.changeDefault("b")
25
- const s2 = S.Struct({ l: l2.withDefault })
25
+ const s2 = S.Struct({ l: l2.withConstructorDefault })
26
26
  expect(s2.make({}).l).toBe("b")
27
27
  })
28
28
 
@@ -391,10 +391,10 @@ describe("ReadonlyMapFromArray", () => {
391
391
  })
392
392
  })
393
393
 
394
- describe("ReadonlySet (with withDefault)", () => {
395
- test("make provides withDefault", () => {
394
+ describe("ReadonlySet (with withConstructorDefault)", () => {
395
+ test("make provides withConstructorDefault", () => {
396
396
  const schema = S.ReadonlySet(S.NumberFromString)
397
- const struct = S.Struct({ items: schema.withDefault })
397
+ const struct = S.Struct({ items: schema.withConstructorDefault })
398
398
  const made = struct.make({})
399
399
  expect(made.items).toEqual(new Set())
400
400
  })
@@ -406,10 +406,10 @@ describe("ReadonlySet (with withDefault)", () => {
406
406
  })
407
407
  })
408
408
 
409
- describe("ReadonlyMap (with withDefault)", () => {
410
- test("make provides withDefault", () => {
409
+ describe("ReadonlyMap (with withConstructorDefault)", () => {
410
+ test("make provides withConstructorDefault", () => {
411
411
  const schema = S.ReadonlyMap({ key: S.NumberFromString, value: S.String })
412
- const struct = S.Struct({ items: schema.withDefault })
412
+ const struct = S.Struct({ items: schema.withConstructorDefault })
413
413
  const made = struct.make({})
414
414
  expect(made.items).toEqual(new Map())
415
415
  })