@percayso-community/cayso-contracts 0.23.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.
Files changed (41) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +114 -0
  3. package/dist/assertion.d.ts +867 -0
  4. package/dist/assertion.js +63 -0
  5. package/dist/assurance.d.ts +353 -0
  6. package/dist/assurance.js +551 -0
  7. package/dist/citizen-market.d.ts +468 -0
  8. package/dist/citizen-market.js +16 -0
  9. package/dist/citizenship.d.ts +215 -0
  10. package/dist/citizenship.js +26 -0
  11. package/dist/client.d.ts +288 -0
  12. package/dist/client.js +370 -0
  13. package/dist/commercial-payment.d.ts +243 -0
  14. package/dist/commercial-payment.js +16 -0
  15. package/dist/contract-schema.generated.d.ts +14 -0
  16. package/dist/contract-schema.generated.js +3107 -0
  17. package/dist/errors.d.ts +171 -0
  18. package/dist/errors.js +28 -0
  19. package/dist/index.d.ts +621 -0
  20. package/dist/index.js +624 -0
  21. package/dist/marketplace-receipt.d.ts +306 -0
  22. package/dist/marketplace-receipt.js +116 -0
  23. package/dist/marketplace-settlement.d.ts +298 -0
  24. package/dist/marketplace-settlement.js +16 -0
  25. package/dist/money.d.ts +84 -0
  26. package/dist/money.js +34 -0
  27. package/dist/organisation.d.ts +60 -0
  28. package/dist/organisation.js +16 -0
  29. package/dist/purchase.d.ts +531 -0
  30. package/dist/purchase.js +107 -0
  31. package/dist/restriction.d.ts +262 -0
  32. package/dist/restriction.js +316 -0
  33. package/dist/routes.d.ts +155 -0
  34. package/dist/routes.js +128 -0
  35. package/dist/schema-types.d.ts +101 -0
  36. package/dist/schema-types.js +16 -0
  37. package/dist/schema.d.ts +24 -0
  38. package/dist/schema.js +16 -0
  39. package/dist/wallet.d.ts +92 -0
  40. package/dist/wallet.js +59 -0
  41. package/package.json +41 -0
package/dist/index.js ADDED
@@ -0,0 +1,624 @@
1
+ /*
2
+ * Copyright 2026 Percayso Community
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ /**
17
+ * `@percayso-community/cayso-contracts` — the versioned capability contract surface through which
18
+ * anything outside this repository reads a wallet (`cayso.wallet`).
19
+ *
20
+ * This barrel is the *only* public surface of the package: the record and
21
+ * response types, the closed failure-reason union, the assertion claims and the
22
+ * route constants land here across slices 5–7 (the assertion claims arrived in
23
+ * slice 7), and the thin client ships from the separate `./client` entry point
24
+ * in slice 8. Importing this package must do
25
+ * nothing but hand back its exports — no server, no connection, no environment
26
+ * read (CLAUDE.md: packages have no side effects on import).
27
+ *
28
+ * The assurance profile (CAY-0029) joins them, and is the first contract here to
29
+ * carry runtime values as well as types — the evidence statements and the
30
+ * acceptance policy are data a consumer and an issuer both have to read, and a
31
+ * type is erased before either can. The trust envelope (CAY-0030) adds the second
32
+ * set: the assertion header and envelope types, and the three clock constants an
33
+ * issuer sizes its credentials against.
34
+ *
35
+ * What the envelope adds here is the PIPER-FACING half of CAY-0030 and no more.
36
+ * The claims, the header, the scope vocabulary and the rotation obligation are a
37
+ * consumer's business and are published. The issuer registry — who we trust, under
38
+ * which key ids, serving which environment — is Cayso's own configuration and is
39
+ * deliberately NOT here: publishing our trust configuration would be publishing a
40
+ * map of what to attack, and it lives in the private `@cayso/identity` instead.
41
+ *
42
+ * The issued-but-uncaptured purchase (CAY-0033) is the newest: the status a
43
+ * purchase takes when its cents landed and its capture did not, which is neither a
44
+ * success nor a failure and may still become either; the bound on how many times
45
+ * capture is attempted before only an operator can move it; and the closed reason a
46
+ * compensated purchase finally carries. Its one runtime value is that bound.
47
+ *
48
+ * Purchase replay and continuation (CAY-0032) is the record before it: what a repeat `POST`
49
+ * with the same idempotency key does — it REPLAYS the original authorisation, at
50
+ * the original price — which statuses are terminal, the cancel path available to a
51
+ * holder, and what expiry releases. It carries three runtime values: the terminal
52
+ * status list and its predicate, and the reservation window a consumer sizes its
53
+ * confirmation page against.
54
+ *
55
+ * Citizenship provisioning (CAY-0031) is the contract before it: an explicit,
56
+ * idempotent call that provisions a wallet and its sign-up grant as one unit, and
57
+ * a separate read by which a consumer can ask whether a citizen has been
58
+ * provisioned WITHOUT provisioning them. It carries one runtime value — the
59
+ * `not_provisioned` wire code — and no figures: the grant's amount and its
60
+ * restriction period are FIELDS a consumer reads at runtime, sourced from the
61
+ * canon PRD through configuration, never literals here.
62
+ *
63
+ * The restricted-Cayso capability policy (CAY-0035) is the newest, and it is the
64
+ * only contract here that is a POLICY rather than a shape: four capabilities
65
+ * against four kinds of holding, every one of the sixteen cells written out as
66
+ * permitted, refused or explicitly open. It settles what a restriction actually
67
+ * restricts — cash-out, not spending — and it publishes the one cell the canon has
68
+ * not decided AS undecided rather than guessing it. It is published because a
69
+ * consumer rendering the restricted/unrestricted split on a balance cannot say what
70
+ * that split MEANS for a holder without it, and each consumer inventing its own
71
+ * answer is how two surfaces end up telling a citizen different things about the
72
+ * same cents. It is compile-time data with no side effects, and it enforces
73
+ * nothing.
74
+ *
75
+ * This is the *Piper-facing surface only*. Peer types, admin types, holdings and
76
+ * carves are deliberately not exported here; they are not a consumer's business.
77
+ * And it carries **no numbers** — amounts, rates, tiers, schedules and thresholds
78
+ * live in the canon PRD and are read from one place, never restated here.
79
+ */
80
+ // --- Value exports -----------------------------------------------------------
81
+ /**
82
+ * The independent semantic version of this contract surface.
83
+ *
84
+ * It is declared here and must agree with the package's own `version` field —
85
+ * a test asserts the two never drift. This is deliberately *not* a repo-wide
86
+ * constant shared with anything else: independent versioning is precisely what
87
+ * this money surface gains that Piper's own contracts lack, since theirs share
88
+ * one global version bumped across all twenty-two together (CAY-0026).
89
+ *
90
+ * `0.22.0` → `0.23.0` publishes the two money-grade marketplace operations and
91
+ * CAY-0082 §7's closed refusal unions (CAY-0083 §3, #303), and it is BREAKING because
92
+ * three closed tables grew:
93
+ *
94
+ * - **`ContractOperation` gains `'settle-marketplace-order'` and
95
+ * `'settle-marketplace-refund'`**, so every total map over the vocabulary needs
96
+ * their entries.
97
+ * - **`ASSURANCE_POLICY` gains their two rows, both money-grade allowlists** at the
98
+ * purchase path's bar. `'dev-bypass'` is `'refused'` at both, and a future method
99
+ * is admissible at neither without a policy decision (CAY-0029).
100
+ * - **`CaysoApiErrorCode` gains {@link MarketplaceOrderRefusal} and
101
+ * {@link MarketplaceRefundRefusal} by reference**, and with them the codes they
102
+ * add.
103
+ *
104
+ * The shapes are additive. {@link MarketplaceOrderRequest} and
105
+ * {@link MarketplaceRefundRequest} each carry one {@link StoreSignedStatement}: the
106
+ * exact bytes Store Platform signed and the signature over them, with nothing beside
107
+ * them, so the idempotency key, the price and who is paid are never the caller's
108
+ * word. {@link MarketplaceOrderResponse} is a receipt narrowed to a sale's, or one
109
+ * refusal; {@link MarketplaceRefundResponse} is a receipt narrowed to a refund's, or
110
+ * one refusal. No route serves either operation yet.
111
+ *
112
+ * `0.21.0` → `0.22.0` publishes the marketplace status read (CAY-0083 §2, #302), and
113
+ * it is BREAKING because two closed tables grew:
114
+ *
115
+ * - **`ContractOperation` gains `'read-marketplace-receipt'`**, so every total map
116
+ * over the vocabulary — `ASSURANCE_POLICY` among them — needs its entry.
117
+ * - **`ASSURANCE_POLICY` gains its row, read-scope (`'not-required'`)**: the read
118
+ * moves nothing and writes no row of its own, and the bar was applied when the
119
+ * sale or refund it reports on was presented.
120
+ *
121
+ * The shapes are additive. {@link MarketplaceReceiptReadRequest} carries the
122
+ * idempotency key and nothing else, because the paying wallet is the verified
123
+ * subject's own. {@link MarketplaceReceiptReadResponse} is a receipt, "no movement
124
+ * for this key", or a refusal from {@link MarketplaceReceiptReadRefusal} — and
125
+ * never "pending", because a movement is written or it is not (CAY-0023). The
126
+ * refusal joins `CaysoApiErrorCode` by reference and adds no code. No route serves
127
+ * the read yet, and the two money-grade marketplace operations are not published
128
+ * here (#303).
129
+ *
130
+ * `0.20.0` → `0.21.0` publishes the marketplace receipt (CAY-0083 §1, #301), and it
131
+ * is BREAKING because one closed union grew:
132
+ *
133
+ * - **`CaysoApiErrorCode` gains `receipt_signing_not_configured`**: the deployment
134
+ * holds no key it may sign a receipt with, so it writes no marketplace sale or
135
+ * refund. Published before the checkout that answers it (#303).
136
+ *
137
+ * The rest is additive. {@link MarketplaceReceipt} is a statement and Cayso's
138
+ * signature over its encoding, and the statement is one of four shapes — a
139
+ * third-party sale, a house-publisher charge, and the refund of each — so a
140
+ * house-publisher statement has no publisher leg to fill. It names wallet ids and
141
+ * never a Percayso identity. Two values arrive with it:
142
+ * {@link MARKETPLACE_RECEIPT_SIGNATURE_ALGORITHM}, and
143
+ * {@link encodeMarketplaceReceiptStatement}, the one encoding the signer and Store
144
+ * Platform both compute the signature over. No key, key set or verifier is here;
145
+ * no route serves a receipt yet (#302, #303).
146
+ *
147
+ * `0.19.0` → `0.20.0` serves the Treasury's buy-back (CAY-0080 slice 10, #291), and it
148
+ * is BREAKING because three closed tables grew:
149
+ *
150
+ * - **`ROUTES` gains `requestBuyBack`**, `POST /api/buy-backs`.
151
+ * `OPERATION_FOR_ROUTE` maps it to `'request-buy-back'`, the operation `0.17.0`
152
+ * classified, and the client gains `requestBuyBack`.
153
+ * - **{@link BuyBackRefusal} gains `eligible_sterling_insufficient`**: the Treasury's
154
+ * eligible sterling cannot meet the request, which is refused whole and never
155
+ * rationed (§2.3), pending Simon James's answer to Open decision I. There is still
156
+ * no per-holder limit reason: figure 11 is his, and until he answers the buy-back
157
+ * is shut by configuration.
158
+ * - **`CaysoApiErrorCode` gains `buy_back_not_configured` and
159
+ * `sterling_not_observed`**. The first is the buy-back's closed door, on a
160
+ * deployment with no buy-back store or with one of its figures unset. The second
161
+ * is a deployment that has never observed sterling; the purchase path already
162
+ * answered it (#246), and the union now says so.
163
+ *
164
+ * The buy-back's request and answer shapes are the ones `0.17.0` published, unchanged.
165
+ * The payout stays behind the fake gateway (§3.4) and adds nothing here.
166
+ *
167
+ * `0.18.0` → `0.19.0` settles a match (CAY-0080 slice 9, #290), and it is BREAKING
168
+ * because two closed unions grew:
169
+ *
170
+ * - **{@link QuoteWithdrawalReason} gains `authorisation_refused`**: a bid that met
171
+ * an ask and whose holder's sterling could not be authorised for the match leaves
172
+ * the book with this reason, and no cents move (CAY-0080 §3.2, step 2). A
173
+ * consumer's exhaustive rendering of a withdrawn quote must place it.
174
+ * - **{@link QuotePlacementRefusal} gains `sterling_leg_unavailable`**: the quote met
175
+ * the book and the sterling leg could not be reached, so nothing was written and
176
+ * the placement may be retried under the same key.
177
+ *
178
+ * The match's settlement — its capture, its bounded retries and an operator's
179
+ * re-attempt or compensation — is an operator surface and adds nothing here.
180
+ *
181
+ * `0.17.0` → `0.18.0` serves the citizen market's book (CAY-0080 slice 8, #289), and
182
+ * it is BREAKING because three closed tables grew.
183
+ *
184
+ * - **`ROUTES` gains `citizenMarket`, `placeQuote` and `withdrawQuote`**:
185
+ * `GET /api/citizen-market`, `POST /api/quotes` and `POST /api/quote-withdrawals`.
186
+ * `OPERATION_FOR_ROUTE` maps the two writes to `'place-quote'` and
187
+ * `'withdraw-quote'`, and the client gains `getCitizenMarket`, `placeQuote` and
188
+ * `withdrawQuote`, one method for each route. The buy-back is not served yet.
189
+ * - **`ContractOperation` gains `'read-citizen-market'`**, the read beside the two
190
+ * writes, with no assurance bar, as `'read-own-wallet'` has none.
191
+ * - **`CaysoApiErrorCode` gains `citizen_market_not_configured`**, the market's
192
+ * closed door on a deployment with no store or an unset figure. It is none of the
193
+ * market's refusal unions' members.
194
+ *
195
+ * The book's read shapes are new and additive: {@link CitizenMarketResponse} and
196
+ * {@link CitizenMarketView} — the published value and its band, both bounds per
197
+ * quote unit, the best bid and ask as {@link BookLevel}s, and the caller's own
198
+ * quotes as {@link OwnQuote}s, a withdrawn one carrying its closed
199
+ * {@link QuoteWithdrawalReason}. No match price, no feed and no history (Open
200
+ * decision F). The refusal unions of `0.17.0` do not change.
201
+ *
202
+ * `0.16.0` → `0.17.0` is the citizen market's contract and acceptance policy
203
+ * (CAY-0080 slices 3 and 4, #286), and it is BREAKING because two closed unions
204
+ * grew. No route is added and no migration is behind it: the operations are
205
+ * classified before they are served, as the commercial payment's was.
206
+ *
207
+ * - **`ContractOperation` gains `'place-quote'`, `'withdraw-quote'` and
208
+ * `'request-buy-back'`**, each money-grade in `ASSURANCE_POLICY` — `'document'`
209
+ * and `'document-and-biometric'`, never `'dev-bypass'` (Open decision Q). A
210
+ * consumer's exhaustive handling of the operation vocabulary must place them.
211
+ * - **`CaysoApiErrorCode` gains the market's refusals by reference**:
212
+ * {@link QuotePlacementRefusal}, which is CAY-0080 §1.6's fixed set
213
+ * ({@link QuoteEntryRefusal}) beside the key-reuse refusal,
214
+ * {@link QuoteWithdrawalRefusal} and {@link BuyBackRefusal}. The buy-back names
215
+ * no eligible-sterling shortfall and no per-holder limit, because both are
216
+ * Simon James's (Open decision I, figure 11).
217
+ * - **The request and answer shapes are new and additive**: {@link QuoteRequest}
218
+ * and {@link QuoteResponse}, {@link QuoteWithdrawalRequest} and
219
+ * {@link QuoteWithdrawalResponse}, {@link BuyBackRequest} and
220
+ * {@link BuyBackResponse}, each discriminated by `outcome`. No request names a
221
+ * wallet: the holder is the verified subject.
222
+ *
223
+ * Under semver below `1.0.0` the minor is where a breaking change goes, so the minor
224
+ * moves and the patch does not.
225
+ *
226
+ * `0.15.0` → `0.16.0` serves the commercial payment's Authorised-User route (CAY-0079,
227
+ * #284), and it is BREAKING because a closed union SHRANK.
228
+ *
229
+ * - **`CaysoApiErrorCode` loses `payment_allowance_route_not_served`.** It answered
230
+ * `authority: 'payment-allowance'` until the Authorised-User route shipped, and
231
+ * that route is now served: a caller declaring it is held to the pair's payment
232
+ * allowance and the Signatory / Authorised-User threshold, and is answered in
233
+ * `CommercialPaymentResponse`. A consumer that rendered the retired code must
234
+ * drop the case; nothing produces it.
235
+ *
236
+ * `CommercialPaymentRefusal` does not change: the Authorised-User route's members were
237
+ * on it from `0.14.0`, and the route now produces them.
238
+ *
239
+ * `0.14.0` → `0.15.0` serves the commercial payment, on the mandate route (CAY-0079
240
+ * slice 6, #283), and it is BREAKING because two closed tables grew.
241
+ *
242
+ * - **`ROUTES` gains `commercialPayment`**, `POST /api/commercial-payments`, and
243
+ * `OPERATION_FOR_ROUTE` maps it to `'make-commercial-payment'`. The client
244
+ * gains `makeCommercialPayment`, one method for the one route.
245
+ * - **`CaysoApiErrorCode` gains two seam codes.**
246
+ * `commercial_payment_store_not_configured` is the route's closed door on a
247
+ * deployment not told enough to make a payment. `payment_allowance_route_not_served`
248
+ * is the answer to `authority: 'payment-allowance'` until the Authorised-User
249
+ * route ships second (Open decision H); nothing is checked against an allowance
250
+ * and the mandate route is never tried instead. Neither is a
251
+ * `CommercialPaymentRefusal`, because each describes the deployment and not the
252
+ * payment.
253
+ *
254
+ * `CommercialPaymentRefusal` itself does not change. The route answers its members,
255
+ * including `assurance_not_money_grade` from the money gate, in the
256
+ * `CommercialPaymentRefused` envelope.
257
+ *
258
+ * `0.13.0` → `0.14.0` is the commercial payment's contract (CAY-0079, #281), and it
259
+ * is BREAKING because two closed unions grew. No route is added: the operation is
260
+ * classified before it is served, as `'provision-citizenship'` was, and the route is
261
+ * CAY-0079's slice 6.
262
+ *
263
+ * - **`ContractOperation` gains `'make-commercial-payment'`**, an Organisation
264
+ * paying a Citizen. Its acceptance policy is money-grade — `'document'` and
265
+ * `'document-and-biometric'`, never `'dev-bypass'` — the purchase path's bar. A
266
+ * consumer's exhaustive handling of the operation vocabulary must place it.
267
+ * - **`CaysoApiErrorCode` gains {@link CommercialPaymentRefusal} by reference**:
268
+ * CAY-0079 §3's set, including the Authorised-User route's reasons, which
269
+ * nothing can produce until that route ships second (Open decision H). They are
270
+ * here from the first version so that they are never a later change to a closed
271
+ * union.
272
+ * - **The request and answer shapes are new and additive**:
273
+ * {@link CommercialPaymentRequest}, and {@link CommercialPaymentResponse}
274
+ * discriminated by `outcome` as `'paid'` or `'refused'`. There is no status,
275
+ * because a commercial payment is one movement or nothing.
276
+ *
277
+ * Under semver below `1.0.0` the minor is where a breaking change goes, so the minor
278
+ * moves and the patch does not.
279
+ *
280
+ * `0.12.0` → `0.13.0` is erasure resolving a holder's in-flight purchases (CAY-0085,
281
+ * H8-R2), and it is BREAKING because a closed union grew:
282
+ *
283
+ * - **`PurchaseFailureReason` gains `'holder_erased'`.** The union is closed and
284
+ * consumers switch on it exhaustively, so a new member is breaking by construction
285
+ * (CAY-0023) — which is the property that makes it safe to add. Erasing a holder's
286
+ * binding now first ends every purchase of theirs that was authorised and had
287
+ * issued nothing, with this reason, and a settlement delivery for a wallet with no
288
+ * binding is refused with it rather than issuing into a wallet bound to nobody. A
289
+ * consumer polling such a purchase sees it end `failed` with a member it can
290
+ * render.
291
+ *
292
+ * Under semver below `1.0.0` the minor is where a breaking change goes, so the minor
293
+ * moves and the patch does not.
294
+ *
295
+ * `0.11.0` → `0.12.0` is the founder claim's contract (CAY-0081, #252), and it is
296
+ * BREAKING because two closed unions grew. The operation was classified first and is
297
+ * served in the same version, so no release carries the operation without its route.
298
+ *
299
+ * - **`ROUTES` gains `citizenshipFounderClaim`**, `POST /api/citizenship/founder-claim`,
300
+ * and the client gains `claimFounderWallet()` beside it. Neither takes a
301
+ * parameter: the founder wallet is named by the reference inside the signed
302
+ * assertion, and the Citizen by its subject. It answers
303
+ * {@link CitizenshipFounderClaimed} alone, with no `terms`, because a founder is
304
+ * never offered a sign-up grant.
305
+ * - **`ContractOperation` gains `'claim-founder-wallet'`.** Its acceptance policy
306
+ * accepts `'document-and-biometric'` alone, stricter than any other operation,
307
+ * because a founder completes full identity proofing before claiming. An issuer
308
+ * minting it must also mint the new claim beside it.
309
+ * - **`AssertionClaims` gains `founderClaimReference`**, optional on the wire and
310
+ * bound to that operation in both directions. A credential scoped to
311
+ * `'claim-founder-wallet'` without it is refused, and so is a credential that
312
+ * carries it without that scope. No credential this surface accepted before is
313
+ * refused now, because until today neither the key nor the scope entry could
314
+ * appear on a credential that verified.
315
+ * - **`Citizenship` gains `'founder-claimed'`** ({@link CitizenshipFounderClaimed}),
316
+ * carrying the wallet and no sign-up grant. A consumer's exhaustive switch on
317
+ * `state` must handle it. The founder claim answers it, and so do both
318
+ * citizenship routes for a claimed founder. A consumer that treated it as
319
+ * `not-provisioned` would offer a claimed founder the provisioning call that
320
+ * must not reach them.
321
+ * - **`CaysoApiErrorCode` gains {@link FounderClaimRefusal} by reference**,
322
+ * including `founder_wallet_lapsed`, which nothing can produce until the lapse
323
+ * is built. It is here from the first version so that it is never a later
324
+ * change to a closed union. It also gains `founder_claim_store_not_configured`,
325
+ * the route's 503 for a wiring with no store, beside its siblings.
326
+ *
327
+ * Under semver below `1.0.0` the minor is where a breaking change goes, so the
328
+ * minor moves and the patch does not.
329
+ *
330
+ * `0.10.0` → `0.11.0` is the build, not the contract (#270). `0.10.0` shipped relative
331
+ * imports without an extension, which Node's ESM loader refuses, so a consumer running
332
+ * the package with no bundler in front of it failed at start-up (piper.platform#182).
333
+ * The package now builds under NodeNext and every emitted specifier names its `.js`
334
+ * file. No type, export, route or file changed, and nothing on the wire moved. By the
335
+ * convention below that is a patch; #270 set the minor, so the minor moves.
336
+ *
337
+ * `0.9.0` → `0.10.0` is the transfer of a restricted lot, decided (CAY-0074). No type
338
+ * changed and nothing on the wire moved. What changed is two cells of
339
+ * `CAPABILITY_POLICY`: `transfer-to-another-holder` for a promotional reward and for
340
+ * a founder allocation went from `open` to `refused`, because a carve does not move
341
+ * restriction and a transfer would shed it. `OPEN_CAPABILITIES` is now empty. The
342
+ * `'open'` standing stays in the union for the next undecided cell.
343
+ *
344
+ * A consumer that does nothing keeps compiling, which would make this a patch. The
345
+ * minor moves instead because the answer a consumer renders changed behind an
346
+ * unchanged shape. A page that showed a citizen "not decided" must now show "not
347
+ * permitted", and that is the case this file exists to make visible.
348
+ *
349
+ * `0.8.0` → `0.9.0` is the published refusal contract (CAY-0058 §5), and it is
350
+ * PURELY ADDITIVE. No existing type changed, no closed union gained a member, no
351
+ * route was added or altered, and no refusal this surface already answered is
352
+ * spelled differently today than it was yesterday. What arrives is the envelope
353
+ * those refusals always travelled in ({@link CaysoErrorResponse}) and the closed
354
+ * set of codes it may carry ({@link CaysoApiErrorCode}), written down at last, plus
355
+ * the one code the request-rate limits answer with.
356
+ *
357
+ * - **`REQUEST_RATE_LIMITED` is new, and so is the refusal behind it.** A request
358
+ * may now be refused because too many arrived too quickly — from one source
359
+ * address, or under one verified credential. A consumer that renders an
360
+ * unrecognised code as an outage would mislead somebody who simply needs to
361
+ * wait, so the code is published and a consumer should render it as a refusal
362
+ * to retry shortly. The refusal carries no header and no body field saying how
363
+ * long shortly is; that is the contract, not an omission.
364
+ * - **`CaysoApiErrorCode` includes `PurchaseFailureReason` and
365
+ * `PurchaseCancelRefusalReason` by reference.** They are not restated, so
366
+ * neither can grow a member the published code set does not carry.
367
+ *
368
+ * A consumer that does nothing keeps working, which under the convention stated
369
+ * below would make this a patch. The minor moves instead because the surface grew a
370
+ * contract a consumer may now depend on exhausting — and because a refusal code that
371
+ * did not exist can now arrive, which is a behaviour change behind unchanged shapes,
372
+ * the case this file exists to make visible.
373
+ *
374
+ * `0.7.0` → `0.8.0` is the sterling that cannot be priced into cents (pen-test
375
+ * C3-3, #148), and it is BREAKING for the same reason the bump below is — a closed
376
+ * union grew:
377
+ *
378
+ * - **`PurchaseFailureReason` gains `'amount_not_priceable'`.** The union is
379
+ * closed and consumers switch on it exhaustively, so a new member is breaking
380
+ * by construction (CAY-0023) — which is the property that makes it safe to
381
+ * add. `POST /api/purchases` accepted any positive whole number of pence and
382
+ * decided whether it could be priced into cents deeper in, where the answer
383
+ * had no way of reaching a consumer; sterling beyond what integer cents can
384
+ * hold at the published value in force is now refused with this member, before
385
+ * anything is authorised, reserved or charged. A consumer asking for ordinary
386
+ * amounts sees no difference; one that could previously be answered with a
387
+ * failure outside the union now gets a member it can render.
388
+ *
389
+ * The bound the refusal marks is arithmetic and not a figure: it is the largest
390
+ * sterling that still prices inside integer cents at the published value, so it
391
+ * rises as the published value ratchets (CAY-0002, CAY-0013) and no number about
392
+ * it appears anywhere on this surface.
393
+ *
394
+ * `0.6.1` → `0.7.0` is the amount-mismatched replay (#134), and it is BREAKING
395
+ * because a closed union grew:
396
+ *
397
+ * - **`PurchaseFailureReason` gains `'amount_mismatch'`.** The union is closed
398
+ * and consumers switch on it exhaustively, so a new member is breaking by
399
+ * construction (CAY-0023) — which is the property that makes it safe to add. A
400
+ * repeat `POST /api/purchases` under a key the same holder has already used at
401
+ * a DIFFERENT `sterlingPence` is now refused with it, where it used to be
402
+ * answered as a Replay at whichever amount the first request carried. Replay
403
+ * means "the same idempotency key again" and a different amount is not the
404
+ * same request; a consumer that resumes an interrupted purchase by repeating
405
+ * it unchanged sees no difference, and one that changed the amount now learns
406
+ * that it must use a new key instead of being quietly charged the old one.
407
+ *
408
+ * `ScopeKey = ContractOperation | InternalOperation` arrived on this same
409
+ * unreleased line and is additive: `ContractOperation` stays closed, so a contract
410
+ * consumer's mistyped operation is still a compile error.
411
+ *
412
+ * `0.6.0` → `0.6.1` is the restricted-Cayso capability policy (CAY-0035), and it
413
+ * is PURELY ADDITIVE. No existing type changed, no closed union gained a member, no
414
+ * route was added or altered, and nothing on the wire moved: `Balance` still reports
415
+ * the same restricted and unrestricted figures it always did. What arrives is a new
416
+ * compile-time table saying what those figures MEAN, which a consumer may read or
417
+ * ignore. A consumer that does nothing keeps working, so the patch moves and the
418
+ * minor does not — the same convention the breaking bumps below state from the other
419
+ * side.
420
+ *
421
+ * It is a version bump at all, rather than none, because the surface genuinely grew:
422
+ * a consumer can now depend on `CAPABILITY_POLICY` existing, and a published package
423
+ * whose exports change without its version changing cannot be depended on at all.
424
+ *
425
+ * `0.5.0` → `0.6.0` is the issued-but-uncaptured purchase (CAY-0033), and it is
426
+ * BREAKING in three places, bumped as one — the same reasoning as the bump below.
427
+ *
428
+ * - **`PurchaseStatus` gains `'issued_uncaptured'`.** The union is closed and
429
+ * consumers switch on it exhaustively, so a new member is breaking by
430
+ * construction (CAY-0023) — which is the property that makes it safe to add. It
431
+ * is NOT terminal: a consumer that treated an unknown status as an ending would
432
+ * stop polling one step before the answer, which is exactly why the new member
433
+ * has to be visible in the version rather than arrive quietly.
434
+ * - **`PurchaseAuthorisationResponse` gains an `'unresolved'` branch.** A repeat
435
+ * `POST` of a key whose purchase has issued but not captured is answered with
436
+ * it. A consumer's exhaustive switch on `outcome` must handle it; there is no
437
+ * live hold to confirm and nothing has ended, so neither existing branch could
438
+ * have carried the truth.
439
+ * - **`PurchaseFailureReason` gains `'capture_failed'`, and
440
+ * `PurchaseCancelRefusalReason` gains `'already_issued'`.** Both unions are
441
+ * closed and exhaustively switched on, so both are breaking additions.
442
+ *
443
+ * `MAX_CAPTURE_ATTEMPTS`, the `PurchaseUnresolved` type and the `LivePurchaseStatus`
444
+ * union are additive and would not have needed a breaking bump on their own. Under
445
+ * semver below `1.0.0` the minor is where a breaking change goes, so the minor moves
446
+ * and the patch does not.
447
+ *
448
+ * `0.4.0` → `0.5.0` is purchase replay and continuation (CAY-0032), and it is
449
+ * BREAKING in three places, bumped as one. It is stated as breaking rather than
450
+ * softened, for the reason the bump below was: a consumer reading this must change
451
+ * what it does.
452
+ *
453
+ * - **`PurchaseAuthorised` gains a required `outcome` discriminant.** The
454
+ * response to `POST /api/purchases` is now ONE declared union
455
+ * ({@link PurchaseAuthorisationResponse}) that a consumer switches on, rather
456
+ * than three shapes it told apart by which fields were present. A consumer
457
+ * that sniffed for `paymentClientSecret` still works by accident today and
458
+ * will not the next time a branch is added, so the discriminant is required
459
+ * and the version says so.
460
+ * - **`PurchaseStatus` gains `'cancelled'`.** The union is closed and consumers
461
+ * switch on it exhaustively, so a new member is breaking by construction
462
+ * (CAY-0023) — which is the property that makes it safe to add. A cancelled
463
+ * purchase is deliberately not a failed one: a failure happened TO somebody, a
464
+ * cancellation was CHOSEN, and rendering them alike tells a holder their
465
+ * payment failed when they changed their mind.
466
+ * - **`ContractOperation` gains `'cancel-purchase'`.** An issuer minting
467
+ * assertions must put it in `scope` for a holder to be able to cancel, and an
468
+ * empty or unchanged scope authorises nothing (CAY-0030). A consumer that does
469
+ * not mint it simply cannot cancel — which is a refusal, not a failure, but it
470
+ * is a change to what an issuer must do.
471
+ *
472
+ * The cancel route, the terminal-status statement, the reservation window and the
473
+ * cancel response types are additive and would not have needed a breaking bump on
474
+ * their own. Under semver below `1.0.0` the minor is where a breaking change goes,
475
+ * so the minor moves and the patch does not.
476
+ *
477
+ * `0.3.0` → `0.4.0` was citizenship provisioning (CAY-0031), and it was a BREAKING
478
+ * change in two places, bumped as one. Both are stated as breaking rather than
479
+ * softened: a consumer reading this must change what it does, and a version that
480
+ * implied otherwise would be the lie that costs it an outage.
481
+ *
482
+ * - **`GET /api/wallet` no longer provisions.** It used to create a wallet on
483
+ * the first authenticated read (CAY-0022); it now creates nothing and refuses
484
+ * an unprovisioned citizen with {@link NOT_PROVISIONED}. A consumer that
485
+ * relied on reading a wallet to bring one into being must call
486
+ * `ROUTES.citizenshipProvision` first. Nothing in a type changed, which is
487
+ * exactly why the version has to say so: a silent behaviour change behind an
488
+ * unchanged shape is the worst kind, and the only place a consumer can be
489
+ * warned is here.
490
+ * - **`PurchaseFailureReason` gains `'not_provisioned'`.** The union is closed
491
+ * and consumers switch on it exhaustively, so a new member is breaking by
492
+ * construction (CAY-0023) — which is the property that makes it safe to add.
493
+ *
494
+ * The new `citizenship` types and the two new routes are additive and would not
495
+ * have needed a breaking bump on their own. Under semver below `1.0.0` the minor
496
+ * is where a breaking change goes, so the minor moves and the patch does not.
497
+ */
498
+ export const CONTRACT_VERSION = '0.23.0';
499
+ /** The package's own name, so a consumer can name what it depends on. */
500
+ export const packageName = '@percayso-community/cayso-contracts';
501
+ /**
502
+ * The `cayso.wallet` capability name (slice 5). A value, not a type: a consumer
503
+ * names the capability it is reading, and `CaysoWallet.capability` is typed as
504
+ * `typeof WALLET_CAPABILITY` so the two can never drift apart.
505
+ */
506
+ export { WALLET_CAPABILITY } from './wallet.js';
507
+ /**
508
+ * The `cayso.purchase` capability name and the route table (slice 6). Both are
509
+ * values: a consumer names the capability it is exercising, and reads a method
510
+ * and path from `ROUTES` rather than hand-writing a URL. The closed
511
+ * failure-reason union that pairs with them is a type, exported below.
512
+ */
513
+ export { PURCHASE_CAPABILITY } from './purchase.js';
514
+ export { ROUTES } from './routes.js';
515
+ /**
516
+ * The purchase lifecycle's runtime half (CAY-0032): which statuses a purchase
517
+ * never leaves, the predicate over them, and the window an authorisation holds its
518
+ * reserved headroom for.
519
+ *
520
+ * Values rather than types, and for the same reason the credential's clock
521
+ * parameters are: a consumer has to be able to READ them. A poller deciding
522
+ * whether to stop needs the terminal set at runtime, and a confirmation page
523
+ * deciding how long to stay live needs the window — neither can be read from a
524
+ * type, and a consumer that maintains its own copy of either maintains the copy
525
+ * that goes stale. The window is a MECHANISM parameter of this contract, the
526
+ * documented exception to keeping numbers in the canon PRD; no economic figure is
527
+ * here.
528
+ */
529
+ export { TERMINAL_PURCHASE_STATUSES, isTerminalPurchaseStatus, PURCHASE_RESERVATION_WINDOW_SECONDS, } from './purchase.js';
530
+ /**
531
+ * How many capture attempts a purchase gets before only an operator can move it
532
+ * (CAY-0033). A value for the same reason the window beside it is one: a consumer
533
+ * watching a purchase sit in `'issued_uncaptured'` is entitled to know that the
534
+ * retrying is bounded and where the bound is, and cannot read either from a type.
535
+ * A MECHANISM parameter of this contract, not an economic figure.
536
+ */
537
+ export { MAX_CAPTURE_ATTEMPTS } from './purchase.js';
538
+ /**
539
+ * The `not_provisioned` wire code (CAY-0031). A value, not a type: a consumer
540
+ * comparing a refusal against the contract's own string is comparing against one
541
+ * source, where a consumer retyping our spelling has made a second.
542
+ */
543
+ export { NOT_PROVISIONED } from './citizenship.js';
544
+ /**
545
+ * The credential's clock and retention parameters (CAY-0030): the ceiling an
546
+ * `exp` is measured against, the skew two honest clocks are allowed, and the
547
+ * floor on how long a recorded use must be kept so replay is actually refused.
548
+ *
549
+ * Values rather than types because a consumer has to be able to READ them — an
550
+ * issuer sizing its lifetimes against our ceiling cannot do it from a type — and
551
+ * because the retention floor is DERIVED from the other two and must stay derived.
552
+ * They are security parameters of this credential, which is the documented
553
+ * exception to keeping numbers in the canon PRD; no economic figure is here.
554
+ */
555
+ export { MAX_ASSERTION_LIFETIME_SECONDS, CLOCK_SKEW_TOLERANCE_SECONDS, MINIMUM_ASSERTION_USE_RETENTION_SECONDS, } from './assertion.js';
556
+ /**
557
+ * The assurance profile (CAY-0029): what each `VerificationMethod` asserts, which
558
+ * methods each operation accepts, and the version a claim is minted under.
559
+ *
560
+ * Unlike the other contracts here, this one has a RUNTIME half and must: a
561
+ * statement of evidence that only existed as a type would be erased before any
562
+ * issuer could check its own claim against it, and an acceptance policy only a
563
+ * compiler can read is not a policy a consumer can read. The values are frozen
564
+ * data and pure functions — nothing runs on import.
565
+ */
566
+ export { ASSURANCE_PROFILE_VERSION, RECOGNISED_ASSURANCE_PROFILE_VERSIONS, EVIDENCE_STATEMENTS, VERIFICATION_METHODS, ASSURANCE_POLICY, CONTRACT_OPERATIONS, OPERATION_FOR_ROUTE, acceptedMethods, assessAssurance, evidenceSupports, methodForEvidence, } from './assurance.js';
567
+ /**
568
+ * The restricted-Cayso capability policy (CAY-0035): what each kind of holding may
569
+ * do, which kinds land restricted and what an expiry does for each, and where a
570
+ * lot of any kind stands once its restriction has lapsed.
571
+ *
572
+ * Values rather than types for the same reason the assurance policy is one — a
573
+ * table only a compiler can read is not a table a consumer can render. A wallet
574
+ * page showing a holder why part of their balance cannot be cashed out yet reads
575
+ * these; a page that hard-coded the answer would be a second copy of a policy that
576
+ * has one home. Frozen data and nothing else: there is deliberately no function
577
+ * here, because a predicate over a standing would have to fold an open cell into
578
+ * a yes or a no.
579
+ *
580
+ * `OPEN_CAPABILITIES` is exported so that "which cells has nobody decided" has a
581
+ * runtime answer. It is empty since CAY-0074 settled the two transfer cells; a
582
+ * consumer still renders any cell it lists as open, never as refused, which is the
583
+ * comfortable mistake.
584
+ */
585
+ export { CAPABILITY_POLICY, RESTRICTION_ON_ARRIVAL, ONCE_UNRESTRICTED, HOLDING_KINDS, HOLDING_CAPABILITIES, OPEN_CAPABILITIES, } from './restriction.js';
586
+ /**
587
+ * The money path's own cents type (CAY-0045): the constructor that is the only way
588
+ * to obtain a {@link PositiveCents}, the amount a caller may ask the economy to
589
+ * move.
590
+ *
591
+ * A value rather than a type, and it has to be: a brand is erased, so a type alone
592
+ * publishes a shape nobody can construct. It is the second layer CLAUDE.md requires
593
+ * beside the schema's `CHECK (cents > 0)`, and it is HERE rather than beside the
594
+ * carve because `packages/ledger` may not depend on an app — the module that moves
595
+ * cents could not otherwise reach the module that types them (pen-test C3-1).
596
+ *
597
+ * It changes no wire shape. `Cents` stays the permissive alias every request and
598
+ * response speaks in, the served contract schema is unchanged, and nothing on this
599
+ * surface newly refuses a figure a consumer could already send. `money.ts` says why
600
+ * the two types are separate on purpose.
601
+ */
602
+ export { positiveCents } from './money.js';
603
+ /**
604
+ * The refusal envelope's one published code (CAY-0058 §5): what a request refused
605
+ * by a request-rate limit answers with.
606
+ *
607
+ * A value rather than a type for the reason `NOT_PROVISIONED` is one — a consumer
608
+ * comparing a refusal against a string it retyped itself is a consumer whose
609
+ * rendering goes wrong silently. The envelope and the closed code union beside it
610
+ * are erased and appear in the type block below; this constant is the whole of the
611
+ * runtime surface the refusal contract adds.
612
+ */
613
+ export { REQUEST_RATE_LIMITED } from './errors.js';
614
+ /**
615
+ * The marketplace receipt's runtime half (CAY-0083 §1): the algorithm it is signed
616
+ * with, and the exact bytes the signature is over.
617
+ *
618
+ * Values rather than types because both sides must compute the same bytes: a
619
+ * verifier that wrote its own JSON for the statement would one day disagree with the
620
+ * signer by a space and refuse every receipt. The encoder is pure — JSON and a UTF-8
621
+ * encoder, no cryptographic dependency — and refuses a statement that is not exactly
622
+ * one of the four.
623
+ */
624
+ export { MARKETPLACE_RECEIPT_SIGNATURE_ALGORITHM, encodeMarketplaceReceiptStatement, } from './marketplace-receipt.js';