@vibedout/commerce 0.0.0-stage → 0.2.3

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.
@@ -0,0 +1,237 @@
1
+ import { n as CommerceProblem } from "./errors-DGzIIflf.mjs";
2
+ import { $ as StartPaymentResult, B as PortContext, D as LineAvailability, N as LineSource, Q as StartPaymentInput, d as DiscountInput, f as DiscountPort, nt as StockSubject, ot as TaxPort, tt as StockPort, u as Destination, w as HoldingLineSource, z as PaymentsPort } from "./types-BzlVbRp1.mjs";
3
+ //#region src/testing/context.d.ts
4
+ /** 2026-10-08 12:00 UTC: a fixed "now" for tests, so a hold that expires does so when the test says. */
5
+ declare const TEST_NOW: number;
6
+ /**
7
+ * A {@link PortContext} for a test double: a fixed clock, no environment, and a `db` whose every method throws, so a double that reaches for
8
+ * the database fails loudly. A port that really uses D1 is tested with the project's own `env.DB` instead.
9
+ */
10
+ declare function testContext(overrides?: Partial<PortContext>): PortContext;
11
+ //#endregion
12
+ //#region src/testing/tools.d.ts
13
+ /** The few matchers the suites use; vitest's `expect` fits. */
14
+ type TestExpect = (value: unknown) => {
15
+ toBe(expected: unknown): void;
16
+ toEqual(expected: unknown): void;
17
+ };
18
+ /** What a conformance suite needs from a test runner: pass `{ describe, it, expect }` from vitest. */
19
+ interface TestTools {
20
+ describe(name: string, fn: () => void): void;
21
+ it(name: string, fn: () => unknown, timeout?: number): void;
22
+ expect: TestExpect;
23
+ }
24
+ //#endregion
25
+ //#region src/testing/discount-conformance.d.ts
26
+ interface DiscountConformanceOptions {
27
+ /** Orders the provider's rules apply to, each named for the failure message. At least one. */
28
+ scenarios: readonly {
29
+ name: string;
30
+ input: DiscountInput;
31
+ }[];
32
+ /** An order that earns no discount: the answer's `applied` is empty. Optional. */
33
+ plain?: DiscountInput;
34
+ /** The context for a given clock. Default {@link testContext}; a provider that reads D1 passes one with the project's `env.DB`. */
35
+ context?: (now: number) => PortContext | Promise<PortContext>;
36
+ }
37
+ declare function runDiscountConformance(make: () => DiscountPort | Promise<DiscountPort>, tools: TestTools, options: DiscountConformanceOptions): void;
38
+ //#endregion
39
+ //#region src/testing/fake-discount.d.ts
40
+ interface FlatDiscountOptions {
41
+ /** Percent off a line, in basis points: 10% is 1000. Default 1000. */
42
+ percentBp?: number;
43
+ /** A line gets the discount from this quantity. Default 5. */
44
+ fromQuantity?: number;
45
+ /** The title of the discount. Default `Volume discount`. */
46
+ title?: string;
47
+ }
48
+ /**
49
+ * A discount port for tests: `percentBp` off every line of at least `fromQuantity`, with the lines it came off named. It knows no code, so a
50
+ * code a buyer typed is `rejected` as `unknown`. The reference `runDiscountConformance` is written from.
51
+ */
52
+ declare function createFlatDiscount(options?: FlatDiscountOptions): DiscountPort;
53
+ //#endregion
54
+ //#region src/testing/fake-tax.d.ts
55
+ interface FlatTaxOptions {
56
+ /** The one rate, in basis points: 16% is 1600. Default 1600. */
57
+ rateBp?: number;
58
+ /** The tax's name in the breakdown. Default `IVA`. */
59
+ code?: string;
60
+ }
61
+ /**
62
+ * A tax port for tests: one rate for everything, worked per line on what is paid (the line after its discount: `lineDiscountsMinor` when it is
63
+ * given, else the discount spread in proportion), shipping taxed on top. A line whose price includes the tax contributes to `includedMinor`
64
+ * (the tax inside the price), the others and the shipping to `addedMinor`. The rate and rounding are the money helpers', so it is also the
65
+ * small reference the conformance suite is written from.
66
+ */
67
+ declare function createFlatTax(options?: FlatTaxOptions): TaxPort;
68
+ //#endregion
69
+ //#region src/testing/slots.d.ts
70
+ /** The places of each ref (`{ slot_a: 3 }`). A ref that is not here is not sold. */
71
+ type SlotPlaces = Readonly<Record<string, number>>;
72
+ interface MemorySlotsOptions {
73
+ /** The price of one place of every slot, in centavos. Default 10000 (100.00 MXN). */
74
+ unitAmountMinor?: number;
75
+ }
76
+ declare function createMemorySlots(places: SlotPlaces, options?: MemorySlotsOptions): HoldingLineSource;
77
+ //#endregion
78
+ //#region src/testing/line-hold-conformance.d.ts
79
+ interface LineHoldConformanceOptions {
80
+ /** The context for a given clock. Default {@link testContext}; a source that keeps its places in D1 passes one with the project's `env.DB`. */
81
+ context?: (now: number) => PortContext | Promise<PortContext>;
82
+ }
83
+ declare function runLineHoldConformance(make: (places: SlotPlaces) => LineSource | Promise<LineSource>, tools: TestTools, options?: LineHoldConformanceOptions): void;
84
+ //#endregion
85
+ //#region src/testing/line-source.d.ts
86
+ interface KnownRef {
87
+ ref: string;
88
+ /** What the source must charge for one. Leave out to check only that it is a valid price. */
89
+ unitAmountMinor?: number;
90
+ currency?: string;
91
+ /** Options to resolve this ref with (a size, a colour), for a source that has them. */
92
+ options?: Readonly<Record<string, string>>;
93
+ }
94
+ /**
95
+ * A source whose price the buyer legitimately chooses inside bounds the server sets (a donation, a tip, a deposit of the buyer's size). The
96
+ * amount travels in `options[option]`, in minor units, as a string of digits. The harness then checks that the bounds hold and that nothing
97
+ * but a whole number inside them is ever priced; every other option name is still a price the buyer may not set.
98
+ */
99
+ interface BuyerPrice {
100
+ /** A ref in `known` whose `options` carry an amount (`{ amount: "5000" }`): the ref the amount is chosen on. */
101
+ ref: string;
102
+ /** The option the buyer puts the amount in. */
103
+ option: string;
104
+ /** The least and the most the source accepts, in minor units. Each must be accepted, and one either side refused. */
105
+ min: number;
106
+ max: number;
107
+ }
108
+ interface LineSourceFixtures {
109
+ /** The context the source runs in. Default {@link testContext}: a source that reads D1 passes its own, with the project's `env.DB`. */
110
+ ctx?: PortContext;
111
+ /** Refs that exist and can be bought. At least one. */
112
+ known: readonly KnownRef[];
113
+ /** Refs that exist but cannot be bought, with the availability the source must give them. */
114
+ unavailable?: readonly {
115
+ ref: string;
116
+ availability: Exclude<LineAvailability, "available" | "not_found">;
117
+ }[];
118
+ /** A ref that exists nowhere. Default `no-such-thing-here`. */
119
+ missingRef?: string;
120
+ /** For a source that lets the buyer pick the amount inside bounds (`donation.amount`). */
121
+ buyerPrice?: BuyerPrice;
122
+ /** More option names to try as a hostile price, beyond {@link PRICE_OPTION_NAMES}: the ones your source reads (`pledge`, `tip`). */
123
+ extraPriceOptions?: readonly string[];
124
+ }
125
+ declare const HARNESS_CHECKS: readonly ["empty", "shape", "order", "unknown", "unavailable", "server-prices", "no-mutation", "repeatable", "duplicates", "buyer-price", "holds"];
126
+ type HarnessCheck = (typeof HARNESS_CHECKS)[number];
127
+ interface HarnessFinding {
128
+ check: HarnessCheck;
129
+ message: string;
130
+ problems?: readonly CommerceProblem[];
131
+ }
132
+ /** Refs a hostile buyer sends. A source answers each with a `not_found` line, whatever it does with a ref. */
133
+ declare const HOSTILE_REFS: readonly string[];
134
+ /**
135
+ * The option names the harness tries as a browser's own price. A source may not read a price from any of them (except the one `buyerPrice`
136
+ * declares); add the names your source reads for other things with `extraPriceOptions`.
137
+ */
138
+ declare const PRICE_OPTION_NAMES: readonly ["price", "amount", "unitAmountMinor", "unit_price", "total", "currency", "discount"];
139
+ /** Runs the checks and returns what failed; an empty list is a source a checkout can rely on. */
140
+ declare function checkLineSource(source: LineSource, fixtures: LineSourceFixtures, only?: readonly HarnessCheck[]): Promise<HarnessFinding[]>;
141
+ /** The checks as a test suite: one `it` for each, failing with the findings. Run it in the feature's own tests, in workerd for a source that reads D1. */
142
+ declare function runLineSourceConformance(source: LineSource, fixtures: LineSourceFixtures, tools: TestTools): void;
143
+ //#endregion
144
+ //#region src/testing/payments.d.ts
145
+ type Failure = Extract<StartPaymentResult, {
146
+ ok: false;
147
+ }>;
148
+ interface FakePayments extends PaymentsPort {
149
+ /** Every distinct request that was accepted, in order. */
150
+ readonly started: readonly StartPaymentInput[];
151
+ /** Every reference whose payment was cancelled, in order, once each. */
152
+ readonly cancelled: readonly string[];
153
+ /** The next `start` answers with this failure, once. */
154
+ failNext(failure: Failure): void;
155
+ /** The payment of `reference` was paid, as a provider's event would say: it can no longer be cancelled or started again. */
156
+ markPaid(reference: string): void;
157
+ cancel: NonNullable<PaymentsPort["cancel"]>;
158
+ }
159
+ /**
160
+ * A payments port for tests: it checks each request the way a real one must (`checkStartPayment`), answers a payment id and a redirect URL,
161
+ * and is idempotent by `reference` (the same request again is the same payment; a different one under the same reference is refused). It
162
+ * cancels a payment that is not paid, once, and then refuses to start its reference again; `markPaid` stands in for the provider's event.
163
+ */
164
+ declare function createFakePayments(): FakePayments;
165
+ //#endregion
166
+ //#region src/testing/payments-conformance.d.ts
167
+ interface PaymentsConformanceOptions {
168
+ /** The context for a given clock. Default {@link testContext}; a provider that keeps payments in D1 passes one with the project's `env.DB`. */
169
+ context?: (now: number) => PortContext | Promise<PortContext>;
170
+ /**
171
+ * Leaves out the cases of `cancel`, for a provider that does not have that optional method. Without it, a provider with no `cancel` fails
172
+ * those cases and says why.
173
+ */
174
+ skipCancel?: boolean;
175
+ /** The start of every reference the suite makes (`<prefix>-<n>`), for a provider whose payments outlive one test. Default `conformance`. */
176
+ referencePrefix?: string;
177
+ }
178
+ declare function runPaymentsConformance(make: () => PaymentsPort | Promise<PaymentsPort>, tools: TestTools, options?: PaymentsConformanceOptions): void;
179
+ //#endregion
180
+ //#region src/testing/stock.d.ts
181
+ /** How one subject is stocked. A subject that is not seeded is `none`: always available. */
182
+ type StockSeedItem = {
183
+ tracking: "none";
184
+ } | {
185
+ tracking: "toggle";
186
+ out?: boolean;
187
+ outUntil?: number | null;
188
+ } | {
189
+ tracking: "count";
190
+ onHand: number;
191
+ allowOversell?: boolean;
192
+ };
193
+ /** Seeds by `subjectKey` (`catalog.variant:var_1`). */
194
+ type StockSeed = Readonly<Record<string, StockSeedItem>>;
195
+ declare const subjectKey: (subject: StockSubject) => string;
196
+ interface MemoryStock extends StockPort {
197
+ fulfil: NonNullable<StockPort["fulfil"]>;
198
+ uncommit: NonNullable<StockPort["uncommit"]>;
199
+ /** The counts of every `count` subject: for a test to read what the port did. */
200
+ counts(): Record<string, {
201
+ onHand: number;
202
+ reserved: number;
203
+ committed: number;
204
+ available: number;
205
+ }>;
206
+ }
207
+ declare function createMemoryStock(seed?: StockSeed): MemoryStock;
208
+ //#endregion
209
+ //#region src/testing/stock-conformance.d.ts
210
+ interface StockConformanceOptions {
211
+ /** The context for a given clock. Default {@link testContext}; a D1 provider passes one with the project's `env.DB`. */
212
+ context?: (now: number) => PortContext | Promise<PortContext>;
213
+ /**
214
+ * Leaves out the cases of `fulfil`, for a provider that does not have that optional method (it tracks no units on hand). Without it, a
215
+ * provider with no `fulfil` fails those cases and says why.
216
+ */
217
+ skipFulfil?: boolean;
218
+ /**
219
+ * Leaves out the cases of `uncommit`, for a provider that does not have that optional method. Without it, a provider with no `uncommit`
220
+ * fails those cases and says why.
221
+ */
222
+ skipUncommit?: boolean;
223
+ }
224
+ declare function runStockConformance(make: (seed: StockSeed) => StockPort | Promise<StockPort>, tools: TestTools, options?: StockConformanceOptions): void;
225
+ //#endregion
226
+ //#region src/testing/tax-conformance.d.ts
227
+ interface TaxConformanceOptions {
228
+ /** The context for a given clock. Default {@link testContext}; a provider that reads D1 passes one with the project's `env.DB`. */
229
+ context?: (now: number) => PortContext | Promise<PortContext>;
230
+ /** A destination the provider can price; default none. The suite asks with and without. */
231
+ destination?: Destination;
232
+ /** The order's currency. Default `MXN`. */
233
+ currency?: string;
234
+ }
235
+ declare function runTaxConformance(make: () => TaxPort | Promise<TaxPort>, tools: TestTools, options?: TaxConformanceOptions): void;
236
+ //#endregion
237
+ export { type DiscountConformanceOptions, type FakePayments, type FlatDiscountOptions, type FlatTaxOptions, HARNESS_CHECKS, HOSTILE_REFS, type HarnessCheck, type HarnessFinding, type KnownRef, type LineHoldConformanceOptions, type LineSourceFixtures, type MemorySlotsOptions, type MemoryStock, PRICE_OPTION_NAMES, type PaymentsConformanceOptions, type SlotPlaces, type StockConformanceOptions, type StockSeed, type StockSeedItem, TEST_NOW, type TaxConformanceOptions, type TestExpect, type TestTools, checkLineSource, createFakePayments, createFlatDiscount, createFlatTax, createMemorySlots, createMemoryStock, runDiscountConformance, runLineHoldConformance, runLineSourceConformance, runPaymentsConformance, runStockConformance, runTaxConformance, subjectKey, testContext };