@fanfare-io/fanfare-sdk-contracts 0.18.0 → 0.19.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.
package/README.md CHANGED
@@ -19,13 +19,21 @@ npm install @fanfare-io/fanfare-sdk-contracts
19
19
 
20
20
  ## Response schema compatibility
21
21
 
22
- Choose the Valibot object mode based on the compatibility contract of the payload:
22
+ Response schemas tolerate unknown keys and strip them. A field added to a server response is validated away rather than rejected, so a server-side addition cannot break an SDK that is already released and running in the field. Nothing downstream re-serializes a parsed response, so unknown keys are dropped rather than preserved wherever a schema does not say otherwise: callers read only the fields the types declare.
23
23
 
24
- - `v.strictObject` rejects unknown keys. Use it only for deliberately closed contracts, and document why additive server fields must be rejected.
25
- - `v.object` validates known fields and strips unknown keys. Use it when callers should remain compatible with additive fields but should not receive them.
26
- - `v.looseObject` validates known fields and preserves unknown keys. Use it when forward-compatible fields must survive validation.
24
+ Request bodies stay strict, as do the contracts a service validates incoming payloads against. Rejecting a key the contract does not name is the point of a request contract, and those payloads are validated by the receiving service rather than by a released client.
27
25
 
28
- This choice is made per endpoint and may differ between a response root and its nested objects. SDK response parsing validates server payloads at runtime, so tightening a nested object can turn an otherwise additive server change into a client-visible validation failure. Treat such changes as coordinated contract changes rather than incidental schema cleanup.
26
+ The Valibot object modes that express this:
27
+
28
+ - `v.object` validates known fields and strips unknown keys. The default for every response schema.
29
+ - `v.strictObject` rejects unknown keys. Reserved for request bodies, server-validated contracts, and the rare union whose members are told apart by strictness alone — each carrying a comment saying which.
30
+ - `v.looseObject` validates known fields and preserves unknown keys. Use only where an unvalidated key genuinely has to survive validation.
31
+
32
+ A contract used in both directions is defined once and exported twice: the field entries live in one object, and the package exports a strict schema for the request and a tolerant one for the response. `SelectionChoiceSchema` and `SelectionPinRequestSchema` are the pair. Defining them separately would let the two spellings drift; giving both directions one schema would force a single strictness onto two contracts that need opposite ones.
33
+
34
+ Tolerance has a consequence worth stating plainly: phase exclusivity is no longer enforced by response parsing. A participating sequence that arrives carrying a `grant`, `checkout`, or `outcome` is parsed, not rejected — the out-of-phase key is simply stripped, and the parsed sequence is the phase it declared. Keeping those keys off the wire for the phases that do not own them is the server's contract to uphold; a client that tolerates additive fields cannot also police which ones belong.
35
+
36
+ This choice applies to a response root and its nested objects alike: SDK response parsing validates server payloads at runtime, so tightening a nested object turns an otherwise additive server change into a client-visible validation failure. Treat such a change as a coordinated contract change rather than incidental schema cleanup.
29
37
 
30
38
  ## License
31
39
 
package/dist/auction.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { InferOutput } from 'valibot';
2
2
  import * as v from "valibot";
3
- export declare const AuctionLiveSchema: v.VariantSchema<"auctionType", [v.StrictObjectSchema<{
3
+ export declare const AuctionLiveSchema: v.VariantSchema<"auctionType", [v.ObjectSchema<{
4
4
  readonly auctionType: v.LiteralSchema<"english", undefined>;
5
5
  readonly highestBid: v.NullableSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.RegexAction<string, undefined>]>, undefined>;
6
6
  readonly minNextBid: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.RegexAction<string, undefined>]>;
@@ -10,7 +10,7 @@ export declare const AuctionLiveSchema: v.VariantSchema<"auctionType", [v.Strict
10
10
  readonly autoExtended: v.BooleanSchema<undefined>;
11
11
  readonly reserveMet: v.BooleanSchema<undefined>;
12
12
  readonly ended: v.BooleanSchema<undefined>;
13
- }, undefined>, v.StrictObjectSchema<{
13
+ }, undefined>, v.ObjectSchema<{
14
14
  readonly auctionType: v.LiteralSchema<"dutch", undefined>;
15
15
  readonly currentPrice: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.RegexAction<string, undefined>]>;
16
16
  readonly remainingQuantity: v.NumberSchema<undefined>;
@@ -23,10 +23,9 @@ export declare const AuctionLiveSchema: v.VariantSchema<"auctionType", [v.Strict
23
23
  export type AuctionLive = InferOutput<typeof AuctionLiveSchema>;
24
24
  /**
25
25
  * The auction configuration read. These fifteen fields are an authored projection of the auction
26
- * row: checkout and operator fields never leave the server on this endpoint, so a key outside this
27
- * set is a contract drift, not an addition to tolerate.
26
+ * row: checkout and operator fields never leave the server on this endpoint.
28
27
  */
29
- export declare const AuctionDetailsResponseSchema: v.StrictObjectSchema<{
28
+ export declare const AuctionDetailsResponseSchema: v.ObjectSchema<{
30
29
  readonly id: v.StringSchema<undefined>;
31
30
  readonly timeZone: v.StringSchema<undefined>;
32
31
  readonly settleAt: v.StringSchema<undefined>;
@@ -44,7 +43,7 @@ export declare const AuctionDetailsResponseSchema: v.StrictObjectSchema<{
44
43
  readonly quantity: v.NullishSchema<v.SchemaWithPipe<readonly [v.NumberSchema<undefined>, v.IntegerAction<number, undefined>]>, undefined>;
45
44
  }, undefined>;
46
45
  export type AuctionDetailsResponse = InferOutput<typeof AuctionDetailsResponseSchema>;
47
- export declare const AuctionBidderStateResponseSchema: v.StrictObjectSchema<{
46
+ export declare const AuctionBidderStateResponseSchema: v.ObjectSchema<{
48
47
  readonly status: v.PicklistSchema<["NOT_BID", "WINNING", "OUTBID", "WON", "LOST"], undefined>;
49
48
  readonly lastBidAmount: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.RegexAction<string, undefined>]>, undefined>;
50
49
  readonly winningBidAmount: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.RegexAction<string, undefined>]>, undefined>;
@@ -59,7 +58,7 @@ export declare const AuctionBidderStateResponseSchema: v.StrictObjectSchema<{
59
58
  readonly releaseClass: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
60
59
  readonly outcome: v.OptionalSchema<v.PicklistSchema<["completed", "expired"], undefined>, undefined>;
61
60
  readonly degraded: v.OptionalSchema<v.BooleanSchema<undefined>, undefined>;
62
- readonly live: v.VariantSchema<"auctionType", [v.StrictObjectSchema<{
61
+ readonly live: v.VariantSchema<"auctionType", [v.ObjectSchema<{
63
62
  readonly auctionType: v.LiteralSchema<"english", undefined>;
64
63
  readonly highestBid: v.NullableSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.RegexAction<string, undefined>]>, undefined>;
65
64
  readonly minNextBid: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.RegexAction<string, undefined>]>;
@@ -69,7 +68,7 @@ export declare const AuctionBidderStateResponseSchema: v.StrictObjectSchema<{
69
68
  readonly autoExtended: v.BooleanSchema<undefined>;
70
69
  readonly reserveMet: v.BooleanSchema<undefined>;
71
70
  readonly ended: v.BooleanSchema<undefined>;
72
- }, undefined>, v.StrictObjectSchema<{
71
+ }, undefined>, v.ObjectSchema<{
73
72
  readonly auctionType: v.LiteralSchema<"dutch", undefined>;
74
73
  readonly currentPrice: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.RegexAction<string, undefined>]>;
75
74
  readonly remainingQuantity: v.NumberSchema<undefined>;
package/dist/auction.js CHANGED
@@ -1,8 +1,8 @@
1
1
  import * as e from "valibot";
2
- const t = e.string(), n = e.pipe(t, e.regex(/^\d{1,12}(\.\d{1,8})?$/)), i = e.picklist(["NOT_BID", "WINNING", "OUTBID", "WON", "LOST"]), o = e.object({
2
+ const t = e.string(), n = e.pipe(t, e.regex(/^\d{1,12}(\.\d{1,8})?$/)), o = e.picklist(["NOT_BID", "WINNING", "OUTBID", "WON", "LOST"]), i = e.object({
3
3
  productId: t,
4
4
  variantId: e.optional(t)
5
- }), l = e.strictObject({
5
+ }), l = e.object({
6
6
  auctionType: e.literal("english"),
7
7
  highestBid: e.nullable(n),
8
8
  minNextBid: n,
@@ -12,7 +12,7 @@ const t = e.string(), n = e.pipe(t, e.regex(/^\d{1,12}(\.\d{1,8})?$/)), i = e.pi
12
12
  autoExtended: e.boolean(),
13
13
  reserveMet: e.boolean(),
14
14
  ended: e.boolean()
15
- }), s = e.strictObject({
15
+ }), s = e.object({
16
16
  auctionType: e.literal("dutch"),
17
17
  currentPrice: n,
18
18
  remainingQuantity: e.number(),
@@ -21,7 +21,7 @@ const t = e.string(), n = e.pipe(t, e.regex(/^\d{1,12}(\.\d{1,8})?$/)), i = e.pi
21
21
  floorPrice: e.nullable(n),
22
22
  settleAt: t,
23
23
  ended: e.boolean()
24
- }), c = e.variant("auctionType", [l, s]), r = e.strictObject({
24
+ }), c = e.variant("auctionType", [l, s]), r = e.object({
25
25
  id: t,
26
26
  timeZone: t,
27
27
  settleAt: t,
@@ -37,8 +37,8 @@ const t = e.string(), n = e.pipe(t, e.regex(/^\d{1,12}(\.\d{1,8})?$/)), i = e.pi
37
37
  autoExtendSeconds: e.nullish(e.number()),
38
38
  priceDropIntervalSeconds: e.nullish(e.pipe(e.number(), e.integer())),
39
39
  quantity: e.nullish(e.pipe(e.number(), e.integer()))
40
- }), u = e.strictObject({
41
- status: i,
40
+ }), u = e.object({
41
+ status: o,
42
42
  lastBidAmount: e.optional(n),
43
43
  winningBidAmount: e.optional(n),
44
44
  bidCount: e.optional(e.number()),
@@ -46,7 +46,7 @@ const t = e.string(), n = e.pipe(t, e.regex(/^\d{1,12}(\.\d{1,8})?$/)), i = e.pi
46
46
  // WON: the grant's continuation deadline, as the admission register holds it.
47
47
  expiresAt: e.optional(t),
48
48
  // WON: the product the win is bound to.
49
- selection: e.optional(o),
49
+ selection: e.optional(i),
50
50
  // WON: the admission register's standing for this win, and the recorded cause when it is
51
51
  // `expired`. `outcome` is the terminal result derived from that standing — a WON bidder whose
52
52
  // admission was paid reads `completed`, one whose window closed reads `expired`.