@percayso-community/cayso-contracts 1.0.0 → 2.1.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
@@ -26,15 +26,27 @@ Cloud verifies Cayso's authorisation acknowledgement under a key it reads from
26
26
  `ACKNOWLEDGEMENT_KEYS_ROUTE`, an unauthenticated read of public keys, published
27
27
  apart from both.
28
28
 
29
- **Percayso BizID's authority assertion** (CAY-0100) is published ahead of the
30
- binding that accepts it. `AuthorityClaims` is its own type, under the identity
31
- assertion's `AssertionHeader`, with no verification or assurance fields. It travels
32
- in the `AUTHORITY_ASSERTION_HEADER` header, beside `Authorization`, and the thin
33
- client sends it only on an Organisation operation given a per-request provider for
34
- it. The binding's refusals are the closed `AuthorityBindingRefusal`.
35
- `AssertionClaims` declares `auth_time`, which Percayso ID mints and the binding
36
- compares. `organisationAuthority` and `mandateFor` are retired and still published,
37
- until the breaking step that removes them.
29
+ **Percayso BizID's authority assertion** (CAY-0100) is published, and from `2.0.0`
30
+ it is served: an act on an Organisation Wallet needs it. `AuthorityClaims` is its own
31
+ type, under the identity assertion's `AssertionHeader`, with no verification or
32
+ assurance fields. It travels in the `AUTHORITY_ASSERTION_HEADER` header, beside
33
+ `Authorization`, and the thin client sends it only on an Organisation operation given
34
+ a per-request provider for it. Cayso binds it to the identity assertion — the same
35
+ `sub`, the same `auth_time`, its `operation` in the identity assertion's `scope` and
36
+ equal to the route's, both current at once — on `provisionOrganisation`,
37
+ `makeCommercialPayment` on the `'mandate'` route, and `authorisePurchase` with any
38
+ `onBehalfOfWalletId`, which must then name the wallet the bound Organisation is bound
39
+ to, and refuses one that does not bind with a member of the closed
40
+ `AuthorityBindingRefusal`. The payment-allowance route and a Citizen's own purchase need
41
+ none. `AssertionClaims` declares `auth_time`, which
42
+ Percayso ID mints and the binding compares. `organisationAuthority` and `mandateFor`
43
+ are retired, authorise nothing, and are still published until the major that removes
44
+ them.
45
+
46
+ **`2.0.0` is a major, breaking on the wire from `1.0.0`** (CAY-0101): it lists
47
+ nothing older, so `GET /api/version` answers `2.0.0` alone, and a consumer on `1.0.0`
48
+ or on the `0.x` line that negotiates through it stops reading this Cayso until it
49
+ moves to `2.0.0`. See `CONTRACT_VERSION`'s docblock for what changed.
38
50
 
39
51
  **The operator read surface, on its own entry point** (CAY-0026, Amendments 4 and 5).
40
52
  Four reads an operator app's *server* calls — the movement list, the purchase list, the
@@ -124,8 +136,8 @@ consumer's handshake accepts a Cayso if `contractVersion` or any entry of
124
136
  same minor. Only a
125
137
  major breaks, and its first release lists nothing from an older major and says so in
126
138
  the bump's changelog. An earlier major is listed only during a declared transition:
127
- `1.0.0` keeps `0.32.0`, `0.31.0`, `0.30.0` and `0.29.0`, and the next major drops them
128
- ([CAY-0101](../../docs/architectural-decision-record/CAY-0101-the-contracts-follow-ordinary-semantic-versioning-from-1-0-0.md),
139
+ `1.0.0` kept `0.32.0`, `0.31.0`, `0.30.0` and `0.29.0`, and `2.0.0`, the next major,
140
+ dropped them ([CAY-0101](../../docs/architectural-decision-record/CAY-0101-the-contracts-follow-ordinary-semantic-versioning-from-1-0-0.md),
129
141
  amending CAY-0086).
130
142
 
131
143
  Alongside it, `GET /api/version/schema` serves the same machine-readable
@@ -394,8 +394,12 @@
394
394
  * is already bound to (CMTY-0018 §4, CAY-0095). Its own operation, because it decides
395
395
  * where a Node's earnings land and binds no key: a credential minted to delegate
396
396
  * spending must not thereby direct earnings, nor the reverse.
397
+ *
398
+ * `'bind-enrolled-node'` is the Citizen binding a Node the Registry enrolled under them
399
+ * to their own wallet (CMTY-0018 §4, CAY-0095 Amendment 1): the Citizen's own tap, no
400
+ * Instance key. Its own operation for the same reason as `'bind-node'`.
397
401
  */
398
- export type ContractOperation = 'read-own-wallet' | 'read-purchase-result' | 'authorise-purchase' | 'cancel-purchase' | 'provision-citizenship' | 'read-own-citizenship' | 'provision-organisation' | 'claim-founder-wallet' | 'make-commercial-payment' | 'make-citizen-transfer' | 'change-handle' | 'read-handle-change-receipt' | 'place-quote' | 'withdraw-quote' | 'request-buy-back' | 'read-citizen-market' | 'read-marketplace-receipt' | 'settle-marketplace-order' | 'settle-marketplace-refund' | 'present-standing-authorisation' | 'revoke-standing-authorisation' | 'bind-node';
402
+ export type ContractOperation = 'read-own-wallet' | 'read-purchase-result' | 'authorise-purchase' | 'cancel-purchase' | 'provision-citizenship' | 'read-own-citizenship' | 'provision-organisation' | 'claim-founder-wallet' | 'make-commercial-payment' | 'make-citizen-transfer' | 'change-handle' | 'read-handle-change-receipt' | 'place-quote' | 'withdraw-quote' | 'request-buy-back' | 'read-citizen-market' | 'read-marketplace-receipt' | 'settle-marketplace-order' | 'settle-marketplace-refund' | 'present-standing-authorisation' | 'revoke-standing-authorisation' | 'bind-node' | 'bind-enrolled-node';
399
403
  /**
400
404
  * An operation key belonging to a deployment's OWN surfaces rather than to this
401
405
  * contract — operator work, above all. Deliberately not enumerated: this package
package/dist/assurance.js CHANGED
@@ -553,6 +553,22 @@ export const ASSURANCE_POLICY = {
553
553
  'held to the bar of presenting a standing authorisation: anything but the development ' +
554
554
  'bypass.',
555
555
  },
556
+ // The Citizen binding a Node the Registry enrolled under them (CAY-0095 Amendment 1).
557
+ // The same bar as 'bind-node', for the same reason: where a Node's earnings land.
558
+ 'bind-enrolled-node': {
559
+ operation: 'bind-enrolled-node',
560
+ assurance: 'required',
561
+ decisions: {
562
+ // Asserts nothing; permanently refused wherever "identity-verified" is meant.
563
+ 'dev-bypass': 'refused',
564
+ document: 'accepted',
565
+ 'document-and-biometric': 'accepted',
566
+ },
567
+ rationale: "Binding an enrolled Node decides which wallet the Node's earnings are paid into at " +
568
+ 'every later settlement, without the holder present, and a binding is never ' +
569
+ 're-pointed, so it is held to the bar of presenting a standing authorisation: ' +
570
+ 'anything but the development bypass.',
571
+ },
556
572
  };
557
573
  /**
558
574
  * Every operation, as a value. Derived from {@link ASSURANCE_POLICY} for the same
@@ -596,6 +612,7 @@ export const OPERATION_FOR_ROUTE = {
596
612
  standingAuthorisation: 'present-standing-authorisation',
597
613
  revokeStandingAuthorisation: 'revoke-standing-authorisation',
598
614
  bindNode: 'bind-node',
615
+ bindEnrolledNode: 'bind-enrolled-node',
599
616
  version: null,
600
617
  };
601
618
  /**
@@ -9,11 +9,11 @@
9
9
  * mandate. It is not a second identity assertion and shares no type with
10
10
  * `AssertionClaims`.
11
11
  *
12
- * This file is the SHAPE ALONE, published so that Piper can build against it
13
- * before Cayso accepts it. Nothing here reads, verifies or binds a credential.
12
+ * This file is the SHAPE ALONE. Nothing here reads, verifies or binds a credential.
14
13
  * BizID's registration as an authority issuer, its verifier and the binding to
15
- * Percayso ID's assertion are later slices (#415–#417), and until they are served
16
- * an Organisation operation answers exactly as it did.
14
+ * Percayso ID's assertion are Cayso's (#415–#417), and from `2.0.0` the binding is
15
+ * served: an act on an Organisation Wallet without a binding authority assertion is
16
+ * refused with a member of {@link AuthorityBindingRefusal}.
17
17
  *
18
18
  * ## The envelope is the identity assertion's
19
19
  *
@@ -178,9 +178,9 @@ export interface AuthorityClaims {
178
178
  * Why the binding refused an Organisation operation: CAY-0100 §4's working shape,
179
179
  * closed and spelled here.
180
180
  *
181
- * Published before anything produces it, as `founder_wallet_lapsed` was, so a
182
- * consumer exhausting `CaysoApiErrorCode` renders it from the version that declared
183
- * it. A new reason is a new member and a contract version, never a free-text field.
181
+ * Published at `0.31.0`, before anything produced it, as `founder_wallet_lapsed` was,
182
+ * and produced from `2.0.0` on the Organisation operations (#417). A new reason is a
183
+ * new member and a contract version, never a free-text field.
184
184
  * Every member means the same thing: the operation did not happen.
185
185
  *
186
186
  * It is the BINDING's refusal, not the operation's. Each operation keeps its own
package/dist/client.d.ts CHANGED
@@ -86,7 +86,7 @@
86
86
  */
87
87
  import type { BuyBackMade, BuyBackRequest, CitizenMarketViewed, QuotePlaced, QuoteRequest, QuoteWithdrawalRequest, QuoteWithdrawn } from './citizen-market.js';
88
88
  import type { CitizenshipFounderClaimed, CitizenshipView } from './citizenship.js';
89
- import type { StandingAuthorisationAcknowledged, StandingAuthorisationRequest, StandingAuthorisationRevocationRequest, StandingAuthorisationRevoked, NodeBindingRequest, NodeBound } from './cloud-settlement.js';
89
+ import type { StandingAuthorisationAcknowledged, StandingAuthorisationRequest, StandingAuthorisationRevocationRequest, StandingAuthorisationRevoked, NodeBindingRequest, NodeBound, NodeEnrolmentBindingRequest } from './cloud-settlement.js';
90
90
  import type { CitizenTransferMade, CitizenTransferRequest } from './citizen-transfer.js';
91
91
  import type { CommercialPaymentMade, CommercialPaymentRequest } from './commercial-payment.js';
92
92
  import type { HandleChangeCharged, HandleChangeReceiptReadResponse } from './handle-change.js';
@@ -182,24 +182,22 @@ export interface CaysoClient {
182
182
  */
183
183
  claimFounderWallet(): Promise<CitizenshipFounderClaimed>;
184
184
  /**
185
- * Provision the ORGANISATION the caller's assertion attests authority for, and
186
- * answer its wallet (CAY-0059).
185
+ * Provision the ORGANISATION BizID's authority assertion names, and answer its
186
+ * wallet (CAY-0059, CAY-0100 §1).
187
187
  *
188
- * IT TAKES NO ARGUMENT, AND THAT IS THE DECISION RATHER THAN AN OVERSIGHT. The
189
- * Organisation ID is read from the organisation-authority claim on the verified
190
- * assertion and from nowhere else — so there is no value a caller could pass
191
- * that would reach the holder key, and a signature here naming an organisation
192
- * would be the wallet-creation oracle CAY-0057 describes.
188
+ * IT NAMES NO ORGANISATION, AND THAT IS THE DECISION RATHER THAN AN OVERSIGHT. The
189
+ * Organisation ID is read from the `organisationId` of BizID's authority assertion,
190
+ * bound to the verified identity assertion, and from nowhere else — so there is no
191
+ * value a caller could pass that would reach the holder key, and a signature here
192
+ * naming an organisation would be the wallet-creation oracle CAY-0057 describes.
193
193
  *
194
- * IDEMPOTENT on the attested Organisation ID, exactly as
195
- * {@link provisionCitizenship} is idempotent on the caller's own identity, so it
196
- * carries no idempotency key and a repeat is the same act rather than a second
197
- * one. A credential carrying no organisation authority is refused; absence
198
- * provisions nothing.
194
+ * IDEMPOTENT on the Organisation ID, exactly as {@link provisionCitizenship} is
195
+ * idempotent on the caller's own identity, so it carries no idempotency key and a
196
+ * repeat is the same act rather than a second one.
199
197
  *
200
198
  * `authority` supplies BizID's authority assertion for `provision-organisation`
201
- * (CAY-0100 §4). Optional, and sent only when given: no route reads it until the
202
- * binding is served, and from then an Organisation operation without it is refused.
199
+ * (CAY-0100 §4). From `2.0.0` it is required: without it the call is refused
200
+ * `authority_assertion_missing`, and nothing is provisioned.
203
201
  */
204
202
  provisionOrganisation(authority?: AuthorityAssertionProvider): Promise<OrganisationView>;
205
203
  /**
@@ -219,9 +217,9 @@ export interface CaysoClient {
219
217
  * repeat of it will keep answering `'terminal'` forever, and the remedy is a new
220
218
  * purchase under a NEW key.
221
219
  *
222
- * `authority` supplies BizID's authority assertion for a purchase on behalf of an
223
- * Organisation Wallet, when `onBehalfOfWalletId` names one (CAY-0100 §4a). A
224
- * Citizen's own purchase needs none and passes none.
220
+ * `authority` supplies BizID's authority assertion for a purchase on behalf of a wallet:
221
+ * every `onBehalfOfWalletId` needs one, naming the Organisation that wallet is bound to
222
+ * (CAY-0100 §4a). A Citizen's own purchase needs none and passes none.
225
223
  */
226
224
  authorisePurchase(req: PurchaseRequest, authority?: AuthorityAssertionProvider): Promise<PurchaseAuthorised | PurchaseTerminal>;
227
225
  getPurchase(purchaseId: string): Promise<PurchaseResult>;
@@ -370,6 +368,14 @@ export interface CaysoClient {
370
368
  * nothing was bound.
371
369
  */
372
370
  bindNode(req: NodeBindingRequest): Promise<NodeBound>;
371
+ /**
372
+ * Bind a Node the Registry enrolled under the caller to the caller's own wallet, under
373
+ * the caller's money-grade assertion (`bind-enrolled-node`, CAY-0095 Amendment 1).
374
+ * Safe to repeat: the same Node bound to the same wallet answers `bound` again and
375
+ * writes nothing. A refusal arrives as a thrown {@link CaysoApiError} whose `code` is a
376
+ * `NodeEnrolmentBindingRefusal` member, one of the gate's codes, or a seam code.
377
+ */
378
+ bindEnrolledNode(req: NodeEnrolmentBindingRequest): Promise<NodeBound>;
373
379
  getVersion(): Promise<CaysoVersion>;
374
380
  }
375
381
  /**
package/dist/client.js CHANGED
@@ -340,6 +340,15 @@ function buildClient(options, internals) {
340
340
  body: req,
341
341
  });
342
342
  },
343
+ async bindEnrolledNode(req) {
344
+ return requestJson({
345
+ method: ROUTES.bindEnrolledNode.method,
346
+ path: ROUTES.bindEnrolledNode.path,
347
+ // Safe to repeat: the same Node bound to the same wallet answers the same.
348
+ idempotent: true,
349
+ body: req,
350
+ });
351
+ },
343
352
  async getPurchase(purchaseId) {
344
353
  return requestJson({
345
354
  method: ROUTES.purchaseResult.method,
@@ -469,6 +469,61 @@ export type NodeBindingRefusal =
469
469
  | 'core_node_not_bound'
470
470
  /** The Node is already bound to a different wallet. A binding is never re-pointed. */
471
471
  | 'node_bound_to_another_wallet';
472
+ /**
473
+ * The Registry's statement that a Node is enrolled under a Citizen (CMTY-0018 §4, CMTY-0019,
474
+ * CAY-0095 Amendment 1): a CAY-0072 compact signed by a Registry key, whose header `kid`
475
+ * names that key. `iss` is the Registry's issuer, one fixed string per environment. `sub` is the Citizen's Percayso ID subject, which must be
476
+ * the verified assertion's.
477
+ */
478
+ export interface NodeEnrolmentClaims {
479
+ /** The Registry's issuer for this environment, e.g. `percayso-cloud-registry:dev`. Not the `kid`. */
480
+ readonly iss: string;
481
+ /** Exactly `'cayso'`, and checked, not merely present. */
482
+ readonly aud: 'cayso';
483
+ /** The Citizen the Node is enrolled under: their Percayso ID subject. */
484
+ readonly sub: string;
485
+ /** The Node enrolled. */
486
+ readonly node_id: NodeId;
487
+ /** Issued-at, in **seconds** since the Unix epoch. */
488
+ readonly iat: number;
489
+ /** Expiry, in **seconds** since the Unix epoch. */
490
+ readonly exp: number;
491
+ }
492
+ /**
493
+ * The Citizen binding an enrolled Node to their own wallet (`bind-enrolled-node`): the
494
+ * Registry-signed {@link NodeEnrolmentClaims} compact, and nothing else. No Instance key,
495
+ * no standing authorisation, no wallet.
496
+ */
497
+ export interface NodeEnrolmentBindingRequest {
498
+ readonly nodeEnrolment: string;
499
+ }
500
+ /** The enrolled-Node binding was refused, with one member of the closed union. Nothing was bound. */
501
+ export interface NodeEnrolmentBindingRefused {
502
+ readonly outcome: 'refused';
503
+ readonly error: NodeEnrolmentBindingRefusal;
504
+ }
505
+ /**
506
+ * Why binding an enrolled Node was refused. Closed. Every member means nothing was bound.
507
+ */
508
+ export type NodeEnrolmentBindingRefusal =
509
+ /** The verification method is outside the money-grade profile (`ASSURANCE_POLICY['bind-enrolled-node']`). */
510
+ 'assurance_not_money_grade'
511
+ /** Not a compact in CAY-0072's format, or its claims are not exactly {@link NodeEnrolmentClaims} with `aud` `'cayso'`. */
512
+ | 'node_enrolment_malformed'
513
+ /** `iss` is not this environment's Registry issuer, or the header's `kid` is no key of it. One member for both. */
514
+ | 'node_enrolment_issuer_not_recognised'
515
+ /** The signature does not verify over the bytes presented, or `alg` is not the key's. */
516
+ | 'node_enrolment_signature_invalid'
517
+ /** `exp` is at or before now, or `iat` is further ahead of now than the clock-skew tolerance. */
518
+ | 'node_enrolment_not_current'
519
+ /** `sub` is not the verified holder's subject: the Node is enrolled under somebody else. */
520
+ | 'node_enrolment_not_for_holder'
521
+ /** The verified holder has no Citizen Wallet bound now. */
522
+ | 'holder_has_no_wallet'
523
+ /** The Node is a Core Node. Its owner is the Operator, so it is bound to no Citizen Wallet. */
524
+ | 'core_node_not_bound'
525
+ /** The Node is already bound to a different wallet. A binding is never re-pointed. */
526
+ | 'node_bound_to_another_wallet';
472
527
  /**
473
528
  * The Contribution Store's question about one Node (CAY-0095): signed by a key of
474
529
  * the registered Store issuer, in CAY-0072's format, whose header `kid` names that
@@ -14,7 +14,7 @@
14
14
  * limitations under the License.
15
15
  */
16
16
  export const CONTRACT_SCHEMA = {
17
- "contractVersion": "1.0.0",
17
+ "contractVersion": "2.1.0",
18
18
  "packageName": "@percayso-community/cayso-contracts",
19
19
  "capabilities": {
20
20
  "wallet": "cayso.wallet",
@@ -101,6 +101,10 @@ export const CONTRACT_SCHEMA = {
101
101
  "method": "POST",
102
102
  "path": "/api/cloud/node-bindings"
103
103
  },
104
+ "bindEnrolledNode": {
105
+ "method": "POST",
106
+ "path": "/api/cloud/node-enrolment-bindings"
107
+ },
104
108
  "version": {
105
109
  "method": "GET",
106
110
  "path": "/api/version"
@@ -930,6 +934,9 @@ export const CONTRACT_SCHEMA = {
930
934
  {
931
935
  "literal": "core_node_ids_not_configured"
932
936
  },
937
+ {
938
+ "literal": "node_registry_not_configured"
939
+ },
933
940
  {
934
941
  "literal": "contribution_store_issuer_not_configured"
935
942
  },
@@ -1005,6 +1012,9 @@ export const CONTRACT_SCHEMA = {
1005
1012
  {
1006
1013
  "ref": "NodeBindingRefusal"
1007
1014
  },
1015
+ {
1016
+ "ref": "NodeEnrolmentBindingRefusal"
1017
+ },
1008
1018
  {
1009
1019
  "ref": "NodeBindingQueryRefusal"
1010
1020
  },
@@ -1824,6 +1834,9 @@ export const CONTRACT_SCHEMA = {
1824
1834
  },
1825
1835
  {
1826
1836
  "literal": "bind-node"
1837
+ },
1838
+ {
1839
+ "literal": "bind-enrolled-node"
1827
1840
  }
1828
1841
  ]
1829
1842
  }
@@ -3239,6 +3252,118 @@ export const CONTRACT_SCHEMA = {
3239
3252
  }
3240
3253
  }
3241
3254
  },
3255
+ "NodeEnrolmentBindingRefusal": {
3256
+ "kind": "alias",
3257
+ "of": {
3258
+ "union": [
3259
+ {
3260
+ "literal": "assurance_not_money_grade"
3261
+ },
3262
+ {
3263
+ "literal": "node_enrolment_malformed"
3264
+ },
3265
+ {
3266
+ "literal": "node_enrolment_issuer_not_recognised"
3267
+ },
3268
+ {
3269
+ "literal": "node_enrolment_signature_invalid"
3270
+ },
3271
+ {
3272
+ "literal": "node_enrolment_not_current"
3273
+ },
3274
+ {
3275
+ "literal": "node_enrolment_not_for_holder"
3276
+ },
3277
+ {
3278
+ "literal": "holder_has_no_wallet"
3279
+ },
3280
+ {
3281
+ "literal": "core_node_not_bound"
3282
+ },
3283
+ {
3284
+ "literal": "node_bound_to_another_wallet"
3285
+ }
3286
+ ]
3287
+ }
3288
+ },
3289
+ "NodeEnrolmentBindingRefused": {
3290
+ "kind": "object",
3291
+ "properties": {
3292
+ "outcome": {
3293
+ "type": {
3294
+ "literal": "refused"
3295
+ },
3296
+ "readonly": true,
3297
+ "optional": false
3298
+ },
3299
+ "error": {
3300
+ "type": {
3301
+ "ref": "NodeEnrolmentBindingRefusal"
3302
+ },
3303
+ "readonly": true,
3304
+ "optional": false
3305
+ }
3306
+ }
3307
+ },
3308
+ "NodeEnrolmentBindingRequest": {
3309
+ "kind": "object",
3310
+ "properties": {
3311
+ "nodeEnrolment": {
3312
+ "type": {
3313
+ "scalar": "string"
3314
+ },
3315
+ "readonly": true,
3316
+ "optional": false
3317
+ }
3318
+ }
3319
+ },
3320
+ "NodeEnrolmentClaims": {
3321
+ "kind": "object",
3322
+ "properties": {
3323
+ "iss": {
3324
+ "type": {
3325
+ "scalar": "string"
3326
+ },
3327
+ "readonly": true,
3328
+ "optional": false
3329
+ },
3330
+ "aud": {
3331
+ "type": {
3332
+ "literal": "cayso"
3333
+ },
3334
+ "readonly": true,
3335
+ "optional": false
3336
+ },
3337
+ "sub": {
3338
+ "type": {
3339
+ "scalar": "string"
3340
+ },
3341
+ "readonly": true,
3342
+ "optional": false
3343
+ },
3344
+ "node_id": {
3345
+ "type": {
3346
+ "ref": "NodeId"
3347
+ },
3348
+ "readonly": true,
3349
+ "optional": false
3350
+ },
3351
+ "iat": {
3352
+ "type": {
3353
+ "scalar": "number"
3354
+ },
3355
+ "readonly": true,
3356
+ "optional": false
3357
+ },
3358
+ "exp": {
3359
+ "type": {
3360
+ "scalar": "number"
3361
+ },
3362
+ "readonly": true,
3363
+ "optional": false
3364
+ }
3365
+ }
3366
+ },
3242
3367
  "NodeId": {
3243
3368
  "kind": "alias",
3244
3369
  "of": {
package/dist/errors.d.ts CHANGED
@@ -45,7 +45,7 @@
45
45
  import type { AuthorityBindingRefusal } from './authority.js';
46
46
  import type { FounderClaimRefusal } from './citizenship.js';
47
47
  import type { BuyBackRefusal, QuotePlacementRefusal, QuoteWithdrawalRefusal } from './citizen-market.js';
48
- import type { SettlementAssertionRefusal, StandingAuthorisationRefusal, StandingAuthorisationRevocationRefusal, NodeBindingQueryRefusal, NodeBindingRefusal } from './cloud-settlement.js';
48
+ import type { SettlementAssertionRefusal, StandingAuthorisationRefusal, StandingAuthorisationRevocationRefusal, NodeBindingQueryRefusal, NodeBindingRefusal, NodeEnrolmentBindingRefusal } from './cloud-settlement.js';
49
49
  import type { CitizenTransferRefusal } from './citizen-transfer.js';
50
50
  import type { HandleChangeReceiptReadRefusal, HandleChangeRefusal } from './handle-change.js';
51
51
  import type { CommercialPaymentRefusal } from './commercial-payment.js';
@@ -216,6 +216,8 @@ export type CaysoApiErrorCode =
216
216
  * Citizen Wallet. Told "none" is a configuration; untold is a closed door.
217
217
  */
218
218
  | 'core_node_ids_not_configured'
219
+ /** No Registry key is configured to verify a Node enrolment (CAY-0095, its first amendment). */
220
+ | 'node_registry_not_configured'
219
221
  /**
220
222
  * No Contribution Store issuer is registered on this deployment, so no statement
221
223
  * from the Store is verified and the Store's read of a Node's binding is not
@@ -227,8 +229,8 @@ export type CaysoApiErrorCode =
227
229
  * No authority issuer is registered on this deployment, so no authority assertion
228
230
  * from Percayso BizID is verified and no act that needs one is performed (CAY-0100).
229
231
  * A closed door, never a refusal of the assertion and never "act as the Citizen
230
- * alone". Declared before any route answers it: the binding to the identity
231
- * assertion is the first to serve it. Not `authority_assertion_invalid`, which says
232
+ * alone". Declared before any route answered it, and now answered, as a closed door, by the
233
+ * binding to the identity assertion. Not `authority_assertion_invalid`, which says
232
234
  * the assertion was presented and refused.
233
235
  */
234
236
  | 'authority_issuer_not_configured'
@@ -265,7 +267,7 @@ export type CaysoApiErrorCode =
265
267
  /** There is no such purchase under this caller's wallet. */
266
268
  | 'not_found'
267
269
  /** Something failed on the way and the refusal discloses nothing further. */
268
- | 'internal_error' | PurchaseFailureReason | PurchaseCancelRefusalReason | FounderClaimRefusal | CommercialPaymentRefusal | CitizenTransferRefusal | HandleChangeRefusal | HandleChangeReceiptReadRefusal | QuotePlacementRefusal | QuoteWithdrawalRefusal | BuyBackRefusal | MarketplaceReceiptReadRefusal | MarketplaceOrderRefusal | MarketplaceRefundRefusal | StandingAuthorisationRefusal | StandingAuthorisationRevocationRefusal | NodeBindingRefusal | NodeBindingQueryRefusal | SettlementAssertionRefusal | AuthorityBindingRefusal;
270
+ | 'internal_error' | PurchaseFailureReason | PurchaseCancelRefusalReason | FounderClaimRefusal | CommercialPaymentRefusal | CitizenTransferRefusal | HandleChangeRefusal | HandleChangeReceiptReadRefusal | QuotePlacementRefusal | QuoteWithdrawalRefusal | BuyBackRefusal | MarketplaceReceiptReadRefusal | MarketplaceOrderRefusal | MarketplaceRefundRefusal | StandingAuthorisationRefusal | StandingAuthorisationRevocationRefusal | NodeBindingRefusal | NodeEnrolmentBindingRefusal | NodeBindingQueryRefusal | SettlementAssertionRefusal | AuthorityBindingRefusal;
269
271
  /**
270
272
  * The body of every refusal on this surface: one code, and nothing beside it.
271
273
  *
package/dist/index.d.ts CHANGED
@@ -84,6 +84,29 @@
84
84
  * `supportedContractVersions` is on its own line: from `1.0.0` the same major, below
85
85
  * it the same minor.
86
86
  *
87
+ * `1.0.0` → `2.0.0` SERVES the two-signer binding (CAY-0100 §4, §4a, #417), and it is
88
+ * a MAJOR, BREAKING ON THE WIRE, declared so under CAY-0101. It lists nothing older: a
89
+ * deployment of it serves `2.0.0` alone, so `1.0.0` and the `0.x` transition major 1
90
+ * carried are no longer served. No type in this package changed shape; the behaviour
91
+ * behind three routes a `1.0.0` consumer already calls did:
92
+ *
93
+ * - **`ROUTES.organisationProvision`** reads the Organisation ID from BizID's
94
+ * {@link AuthorityClaims}, sent in {@link AUTHORITY_ASSERTION_HEADER} and bound to
95
+ * the identity assertion, and no longer from `organisationAuthority`. Without the
96
+ * header it answers `401 authority_assertion_missing`, where it used to provision
97
+ * or answer `403 no_organisation_authority`.
98
+ * - **`ROUTES.commercialPayment` on the `'mandate'` route** is authorised by the bound
99
+ * `AuthorityClaims`, not by `mandateFor`. The payment-allowance route is unchanged.
100
+ * - **`ROUTES.purchaseAuthorise` with any `onBehalfOfWalletId`** is authorised the
101
+ * same way, and the wallet named must be the one the bound Organisation is bound to;
102
+ * `mandateFor` authorises no delegated purchase, into any wallet. A Citizen's own
103
+ * purchase is unchanged.
104
+ *
105
+ * On those three acts the members of {@link AuthorityBindingRefusal} and
106
+ * `authority_issuer_not_configured` now reach the wire, which `0.31.0` declared and no
107
+ * route produced up to `1.0.0`. `organisationAuthority` and `mandateFor` stay declared,
108
+ * and are removed by a later major (#419).
109
+ *
87
110
  * `0.32.0` → `1.0.0` changes nothing but the version. Its content is exactly
88
111
  * `0.32.0`'s, and a deployment of it keeps serving `0.32.0`, `0.31.0`, `0.30.0` and
89
112
  * `0.29.0` as a declared transition from the `0.x` line, which the next major ends. The
@@ -652,7 +675,7 @@
652
675
  * have needed a breaking bump on their own. Under semver below `1.0.0` the minor
653
676
  * is where a breaking change goes, so the minor moves and the patch does not.
654
677
  */
655
- export declare const CONTRACT_VERSION: "1.0.0";
678
+ export declare const CONTRACT_VERSION: "2.1.0";
656
679
  /** The package's own name, so a consumer can name what it depends on. */
657
680
  export declare const packageName = "@percayso-community/cayso-contracts";
658
681
  /**
@@ -825,7 +848,7 @@ export type { HandleChangeReceiptStatement, HandleChangeReceipt, HandleChangeCha
825
848
  export type { QuoteSide, QuoteRequest, Quote, QuotePlaced, QuoteRefused, QuoteResponse, QuoteEntryRefusal, QuotePlacementRefusal, QuoteWithdrawalRequest, QuoteWithdrawal, QuoteWithdrawn, QuoteWithdrawalRefused, QuoteWithdrawalResponse, QuoteWithdrawalRefusal, BuyBackRequest, BuyBack, BuyBackMade, BuyBackRefused, BuyBackResponse, BuyBackRefusal, BookLevel, QuoteStatus, QuoteWithdrawalReason, OwnQuote, OwnQuoteNotWithdrawn, OwnQuoteWithdrawn, CitizenMarketView, CitizenMarketViewed, CitizenMarketViewRefusal, CitizenMarketViewRefused, CitizenMarketResponse, } from './citizen-market.js';
826
849
  export type { MarketplaceReceiptSignatureAlgorithm, MarketplaceReceiptKeyId, MarketplaceSaleKind, MarketplaceReceiptLeg, MarketplaceSettlementReceiptStatement, HousePublisherChargeReceiptStatement, ThirdPartyRefundReceiptStatement, HousePublisherRefundReceiptStatement, MarketplaceReceiptStatement, MarketplaceReceipt, MarketplaceReceiptReadRequest, MarketplaceReceiptFound, MarketplaceNoMovement, MarketplaceReceiptReadRefusal, MarketplaceReceiptReadRefused, MarketplaceReceiptReadResponse, } from './marketplace-receipt.js';
827
850
  export type { StoreSignedStatement, MarketplaceOrderRequest, MarketplaceRefundRequest, MarketplaceOrderReceipt, MarketplaceRefundReceipt, MarketplaceOrderSettled, MarketplaceOrderRefused, MarketplaceOrderResponse, MarketplaceOrderRefusal, MarketplaceRefundSettled, MarketplaceRefundRefused, MarketplaceRefundResponse, MarketplaceRefundRefusal, } from './marketplace-settlement.js';
828
- export type { InstanceKeyId, SettlementPeriodRule, SettlementPeriodId, NodeId, ContributionStoreIssuer, PercaysoCloudAudience, StandingAuthorisationClaims, StandingAuthorisationRequest, AuthorisationAcknowledgementClaims, AcknowledgementKeyId, AcknowledgementPublicKey, AcknowledgementKeySet, StandingAuthorisationAcknowledged, StandingAuthorisationRefused, StandingAuthorisationResponse, StandingAuthorisationRefusal, StandingAuthorisationRevocationRequest, StandingAuthorisationRevoked, StandingAuthorisationRevocationRefused, StandingAuthorisationRevocationResponse, StandingAuthorisationRevocationRefusal, NodePresentationClaims, NodeBindingRequest, NodeBound, NodeBindingRefused, NodeBindingResponse, NodeBindingRefusal, NodeBindingQueryClaims, NodeBindingQueryRequest, NodeBindingStatus, NodeBindingQueryRefused, NodeBindingQueryRefusal, ContributionType, SettlementPeriod, ContributionWithheldReason, ContributionQualified, ContributionWithheld, ContributionQualification, ContributionRow, ConsumptionRow, SettlementTotals, SettlementAssertionClaims, SettlementAssertionRequest, SettlementAssertionSettled, SettlementAssertionRefused, ContributionRowRefused, ConsumptionRowRefused, SettlementAssertionResponse, SettlementAssertionLevelRefusal, ContributionRowRefusal, ConsumptionRowRefusal, SettlementAssertionRefusal, } from './cloud-settlement.js';
851
+ export type { InstanceKeyId, SettlementPeriodRule, SettlementPeriodId, NodeId, ContributionStoreIssuer, PercaysoCloudAudience, StandingAuthorisationClaims, StandingAuthorisationRequest, AuthorisationAcknowledgementClaims, AcknowledgementKeyId, AcknowledgementPublicKey, AcknowledgementKeySet, StandingAuthorisationAcknowledged, StandingAuthorisationRefused, StandingAuthorisationResponse, StandingAuthorisationRefusal, StandingAuthorisationRevocationRequest, StandingAuthorisationRevoked, StandingAuthorisationRevocationRefused, StandingAuthorisationRevocationResponse, StandingAuthorisationRevocationRefusal, NodePresentationClaims, NodeBindingRequest, NodeBound, NodeBindingRefused, NodeBindingResponse, NodeBindingRefusal, NodeEnrolmentClaims, NodeEnrolmentBindingRequest, NodeEnrolmentBindingRefused, NodeEnrolmentBindingRefusal, NodeBindingQueryClaims, NodeBindingQueryRequest, NodeBindingStatus, NodeBindingQueryRefused, NodeBindingQueryRefusal, ContributionType, SettlementPeriod, ContributionWithheldReason, ContributionQualified, ContributionWithheld, ContributionQualification, ContributionRow, ConsumptionRow, SettlementTotals, SettlementAssertionClaims, SettlementAssertionRequest, SettlementAssertionSettled, SettlementAssertionRefused, ContributionRowRefused, ConsumptionRowRefused, SettlementAssertionResponse, SettlementAssertionLevelRefusal, ContributionRowRefusal, ConsumptionRowRefusal, SettlementAssertionRefusal, } from './cloud-settlement.js';
829
852
  export type { PurchaseRequest, PurchaseAuthorised, PurchaseTerminal, PurchaseUnresolved, PurchaseRefused, PurchaseAuthorisationResponse, PurchaseFailureReason, PurchaseStatus, LivePurchaseStatus, TerminalPurchaseStatus, PurchaseCancelRefusalReason, PurchaseCancelled, PurchaseCancelRefused, PurchaseCancelResponse, PurchaseResult, } from './purchase.js';
830
853
  export type { VerificationMethod, VerificationStatus, SubjectPersonhood, AssertionClaims, AssertionHeader, AssertionEnvelope, ContractOperation, InternalOperation, ScopeKey, } from './assertion.js';
831
854
  export type { AuthorityClaims, AuthorityEnvelope, AuthorityBindingRefusal } from './authority.js';
package/dist/index.js CHANGED
@@ -100,6 +100,29 @@
100
100
  * `supportedContractVersions` is on its own line: from `1.0.0` the same major, below
101
101
  * it the same minor.
102
102
  *
103
+ * `1.0.0` → `2.0.0` SERVES the two-signer binding (CAY-0100 §4, §4a, #417), and it is
104
+ * a MAJOR, BREAKING ON THE WIRE, declared so under CAY-0101. It lists nothing older: a
105
+ * deployment of it serves `2.0.0` alone, so `1.0.0` and the `0.x` transition major 1
106
+ * carried are no longer served. No type in this package changed shape; the behaviour
107
+ * behind three routes a `1.0.0` consumer already calls did:
108
+ *
109
+ * - **`ROUTES.organisationProvision`** reads the Organisation ID from BizID's
110
+ * {@link AuthorityClaims}, sent in {@link AUTHORITY_ASSERTION_HEADER} and bound to
111
+ * the identity assertion, and no longer from `organisationAuthority`. Without the
112
+ * header it answers `401 authority_assertion_missing`, where it used to provision
113
+ * or answer `403 no_organisation_authority`.
114
+ * - **`ROUTES.commercialPayment` on the `'mandate'` route** is authorised by the bound
115
+ * `AuthorityClaims`, not by `mandateFor`. The payment-allowance route is unchanged.
116
+ * - **`ROUTES.purchaseAuthorise` with any `onBehalfOfWalletId`** is authorised the
117
+ * same way, and the wallet named must be the one the bound Organisation is bound to;
118
+ * `mandateFor` authorises no delegated purchase, into any wallet. A Citizen's own
119
+ * purchase is unchanged.
120
+ *
121
+ * On those three acts the members of {@link AuthorityBindingRefusal} and
122
+ * `authority_issuer_not_configured` now reach the wire, which `0.31.0` declared and no
123
+ * route produced up to `1.0.0`. `organisationAuthority` and `mandateFor` stay declared,
124
+ * and are removed by a later major (#419).
125
+ *
103
126
  * `0.32.0` → `1.0.0` changes nothing but the version. Its content is exactly
104
127
  * `0.32.0`'s, and a deployment of it keeps serving `0.32.0`, `0.31.0`, `0.30.0` and
105
128
  * `0.29.0` as a declared transition from the `0.x` line, which the next major ends. The
@@ -668,7 +691,7 @@
668
691
  * have needed a breaking bump on their own. Under semver below `1.0.0` the minor
669
692
  * is where a breaking change goes, so the minor moves and the patch does not.
670
693
  */
671
- export const CONTRACT_VERSION = '1.0.0';
694
+ export const CONTRACT_VERSION = '2.1.0';
672
695
  /** The package's own name, so a consumer can name what it depends on. */
673
696
  export const packageName = '@percayso-community/cayso-contracts';
674
697
  /**
package/dist/routes.d.ts CHANGED
@@ -127,6 +127,11 @@
127
127
  * the wallet; the revocation is a row of its own beside them. The body names the
128
128
  * authorisation's `jti` and no wallet.
129
129
  *
130
+ * `bindEnrolledNode` binds a Node the Registry enrolled under the verified Citizen to that
131
+ * Citizen's own wallet (`bind-enrolled-node`, CAY-0095 Amendment 1). The body carries the
132
+ * Registry-signed enrolment and nothing else: no Instance key and no wallet. A `POST` to a
133
+ * collection of its own, for `bindNode`'s reasons.
134
+ *
130
135
  * `bindNode` binds a Node to the wallet its presenting Instance key is already bound
131
136
  * to (`bind-node`, CAY-0095), under the owner's assertion. A person is behind it, so
132
137
  * it is classified by a person's assurance. The body carries the Node ID signed by the
@@ -229,6 +234,10 @@ export declare const ROUTES: {
229
234
  readonly method: "POST";
230
235
  readonly path: "/api/cloud/node-bindings";
231
236
  };
237
+ readonly bindEnrolledNode: {
238
+ readonly method: "POST";
239
+ readonly path: "/api/cloud/node-enrolment-bindings";
240
+ };
232
241
  readonly version: {
233
242
  readonly method: "GET";
234
243
  readonly path: "/api/version";
package/dist/routes.js CHANGED
@@ -142,6 +142,11 @@
142
142
  * the wallet; the revocation is a row of its own beside them. The body names the
143
143
  * authorisation's `jti` and no wallet.
144
144
  *
145
+ * `bindEnrolledNode` binds a Node the Registry enrolled under the verified Citizen to that
146
+ * Citizen's own wallet (`bind-enrolled-node`, CAY-0095 Amendment 1). The body carries the
147
+ * Registry-signed enrolment and nothing else: no Instance key and no wallet. A `POST` to a
148
+ * collection of its own, for `bindNode`'s reasons.
149
+ *
145
150
  * `bindNode` binds a Node to the wallet its presenting Instance key is already bound
146
151
  * to (`bind-node`, CAY-0095), under the owner's assertion. A person is behind it, so
147
152
  * it is classified by a person's assurance. The body carries the Node ID signed by the
@@ -187,6 +192,7 @@ export const ROUTES = {
187
192
  path: '/api/cloud/standing-authorisation-revocations',
188
193
  },
189
194
  bindNode: { method: 'POST', path: '/api/cloud/node-bindings' },
195
+ bindEnrolledNode: { method: 'POST', path: '/api/cloud/node-enrolment-bindings' },
190
196
  version: { method: 'GET', path: '/api/version' },
191
197
  };
192
198
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@percayso-community/cayso-contracts",
3
- "version": "1.0.0",
3
+ "version": "2.1.0",
4
4
  "description": "The versioned capability contract surface through which anything outside this repository reads a wallet. Published; keep it the surface of every consumer outside this tree, Piper and the Percayso Cloud, and nothing internal.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {