@nuanu-ai/agentify-contracts 0.6.0 → 0.8.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/dist/merchant.js CHANGED
@@ -1,19 +1,16 @@
1
1
  /**
2
- * How a merchant comes to exist, the name their products are sold under, the
3
- * wallet their sales are paid into, and the keys they open the door with.
2
+ * What a merchant says about themselves: the name their products are sold
3
+ * under, the wallet their sales are paid into, and the keys they open the door
4
+ * with.
4
5
  *
5
- * The first two belong together because registering is the act that produces
6
- * both: one call makes the merchant and the key its cabinet will call as them
7
- * with, and what comes back carries that key once. Split across two files, a
8
- * reader working out what registering leaves a merchant holding would have to
9
- * read both to find that it is a key of a kind no list here carries. The name is here for the same reason read the other way round — it is a
10
- * fact about the merchant and about none of their cards, and the one question a
11
- * reader arrives with is which of the two names a merchant has is which.
6
+ * The name is here rather than beside the card because it is a fact about the
7
+ * merchant and about none of their cards, and the one question a reader
8
+ * arrives with is which of the two names a merchant has is which.
12
9
  *
13
10
  * Two rules run through the file and are worth saying once.
14
11
  *
15
- * The secret appears in exactly three documents, and every one of them is the
16
- * answer to a call that has just made a key. Nothing that is ever drawn again —
12
+ * The secret appears in one document, the answer to the call that has just
13
+ * made a key. Nothing that is ever drawn again —
17
14
  * the list a merchant reads, the row that comes back from disabling one — can
18
15
  * carry it, and the shapes below refuse it rather than merely omit it. What is
19
16
  * kept on our side is a digest, so there is nothing to put in those documents
@@ -25,9 +22,10 @@
25
22
  * nothing, while a flag answers only half.
26
23
  */
27
24
  import { z } from "zod";
28
- import { ServiceNameSchema } from "./card.js";
25
+ import { SellerSchema, ServiceNameSchema } from "./card.js";
29
26
  import { EvmAddressSchema } from "./evm-address.js";
30
27
  import { IdentifierSchema, TimestampSchema } from "./primitives.js";
28
+ import { SellerSiteSchema } from "./seller-site.js";
31
29
  /**
32
30
  * What a merchant calls one of their keys, so one of several can be told from
33
31
  * the others.
@@ -94,18 +92,6 @@ const IssuedKeyLabelSchema = KeyLabelSchema.max(LONGEST_KEY_LABEL, `a label is a
94
92
  const KeySecretSchema = z
95
93
  .string()
96
94
  .regex(/^\S+$/, "a key travels as a bearer token, so it carries no whitespace and is not empty");
97
- /**
98
- * The code that stands in the door of registration.
99
- *
100
- * It is one value out of the gateway's configuration, handed to a person along
101
- * with the address of the site (ADR-0014 §3). All this shape asks is that
102
- * something was actually typed: a form submitted with an empty field is a
103
- * mistake at the keyboard rather than a wrong code, and the two are worth
104
- * telling apart before anything is compared.
105
- */
106
- const InvitationSchema = z
107
- .string()
108
- .regex(/\S/, "an invitation is the code handed over with the address of the site");
109
95
  /**
110
96
  * One key a merchant holds, as they read it.
111
97
  *
@@ -161,11 +147,8 @@ export const MerchantKeySchema = z
161
147
  * refuses, on the one page where being refused looks like the product being
162
148
  * broken.
163
149
  *
164
- * It is not always one of the keys beside it, and that is the thing a reader is
165
- * likeliest to assume and be wrong about. A cabinet calls with a key made for a
166
- * cabinet, and those are in nobody's list, so a client that looked this
167
- * identifier up among the rows would find nothing — which is an answer rather
168
- * than an error, and a screen has to be built for it.
150
+ * It is always one of the keys beside it: every key is one a merchant issued
151
+ * for their own code, and the dashboard calls with none (ADR-0030).
169
152
  *
170
153
  * An object rather than a bare array, for that reason before any other — an
171
154
  * array has nowhere to put it.
@@ -175,18 +158,13 @@ export const MerchantKeyListSchema = z
175
158
  /**
176
159
  * The keys this merchant made for their own code, the revoked ones among
177
160
  * them.
178
- *
179
- * The keys a cabinet holds are not here and never will be: the merchant did
180
- * not issue one and has nothing to do with one. A list is what somebody
181
- * acts on, and a row nobody has any business acting on is a row that only
182
- * raises the question of why it will not go away.
183
161
  */
184
162
  keys: z.array(MerchantKeySchema),
185
163
  /** The key the request carrying this answer was made with. */
186
164
  this_call: IdentifierSchema,
187
165
  })
188
166
  .meta({
189
- description: "The keys one merchant made for their own code, working and revoked together, and the identifier of the key this very call was made with. That last field is here because a merchant cannot disable the key they are holding: without it a screen would offer a button the gateway refuses. It is not always among the keys listed — a cabinet calls with a key of its own, and those are in no list here — so a client matching it against the rows has to be built for finding none. The keys a cabinet holds are left out entirely: they are not issued by the merchant and cannot be revoked by them. This document does not say whether it is the whole list either — paging is not designed, and the absence of a field about it is not a promise that there is no more.",
167
+ description: "The keys one merchant made for their own code, working and revoked together, and the identifier of the key this very call was made with. That last field is here because a merchant cannot disable the key they are holding: without it a screen would offer a button the gateway refuses. It is always one of the keys listed, since every key is one the merchant issued. This document does not say whether it is the whole list either — paging is not designed, and the absence of a field about it is not a promise that there is no more.",
190
168
  });
191
169
  /** What a merchant sends to have a key made. */
192
170
  export const IssueKeyRequestSchema = z
@@ -211,7 +189,7 @@ export const IssuedKeySchema = z
211
189
  secret: KeySecretSchema,
212
190
  })
213
191
  .meta({
214
- description: "A key as it comes back from being issued: the row a merchant will see in their list from now on, and the key itself. It carries the key once. Three answers in this contract carry one — this, what registering gives back, and the key a cabinet asks for — and nothing else does, because what is written down on our side is a digest. A key that is lost is replaced by a new one rather than read back.",
192
+ description: "A key as it comes back from being issued: the row a merchant will see in their list from now on, and the key itself. It carries the key once, and it is the one answer in this contract that carries one, because what is written down on our side is a digest. A key that is lost is replaced by a new one rather than read back.",
215
193
  });
216
194
  /**
217
195
  * A key that has been revoked, as it now stands.
@@ -227,44 +205,6 @@ export const DisabledKeySchema = z
227
205
  .meta({
228
206
  description: "The key that was just revoked, with the instant it stopped working on it, so a merchant reads back what happened rather than taking the call's word for it. Revoking a key that was already revoked answers this same way and keeps the first instant, because that is the true one and a retry after a dropped connection must not rewrite it.",
229
207
  });
230
- /**
231
- * A key made for a cabinet, which is the secret and nothing else.
232
- *
233
- * Every other answer that makes a key carries the row beside it, and this one
234
- * cannot. A key made for a cabinet is in no merchant's list — they did not
235
- * issue it and have no reason to know it exists — so an identifier here would
236
- * name a row that no screen of theirs draws and no call of theirs reaches: not
237
- * the list it is absent from, and not the revoking, which takes the keys a
238
- * merchant issued and refuses this kind by name. What the caller does with this
239
- * is put it on the row of whoever just signed in, and that is the whole of what
240
- * it needs.
241
- */
242
- export const CabinetKeySchema = z
243
- .strictObject({
244
- /** The only moment this is readable. Nothing on our side keeps it. */
245
- secret: KeySecretSchema,
246
- })
247
- .meta({
248
- description: "A key made for a cabinet to call as one merchant, carried once and readable nowhere afterwards. There is no row beside it and there is nothing to put one: a key made this way is in no merchant's list of keys, and the call that revokes a key refuses this kind by name — so an identifier for it would name something no answer shows and no call acts on. Whoever asked for this holds it until they ask for another.",
249
- });
250
- /**
251
- * That the key a call was made with is gone.
252
- *
253
- * A constant, and deliberately: the call has one outcome. It removes the key it
254
- * was made with and no other, so there is nothing to count — a number here
255
- * could only be about rows this call cannot reach — and nothing to name, since
256
- * the caller is holding the only key it names. What is left to say is that it
257
- * is done, and it is said in a field rather than left to a status code so that
258
- * a client reads one document and not two kinds of evidence.
259
- */
260
- export const ForgottenCabinetKeySchema = z
261
- .strictObject({
262
- /** The key this call was made with no longer exists. */
263
- forgotten: z.literal(true),
264
- })
265
- .meta({
266
- description: "That the key this call was made with has been removed, which is the only thing this call does. There is nothing to count and nothing to name: it reaches one key, the one in the caller's hand, and the caller already knows which that is.",
267
- });
268
208
  /**
269
209
  * What a merchant's products are sold under, as the merchant reads it back.
270
210
  *
@@ -284,11 +224,20 @@ export const ForgottenCabinetKeySchema = z
284
224
  */
285
225
  export const SellerNameSchema = z
286
226
  .strictObject({
287
- /** What buyers read beside this merchant's products, or nothing. */
288
- seller_name: ServiceNameSchema.nullable(),
227
+ /**
228
+ * What buyers read beside this merchant's products, or nothing — read back
229
+ * by the rule an agent's `seller` reads it by, which leaves the plain-text
230
+ * rule to the door that writes it.
231
+ */
232
+ seller_name: SellerSchema.shape.name,
233
+ /**
234
+ * The https address of the merchant's own shop, where an agent takes what
235
+ * an order cannot answer (ADR-0034), or nothing where none was given.
236
+ */
237
+ seller_site: SellerSiteSchema.nullable(),
289
238
  })
290
239
  .meta({
291
- description: "The name a merchant's products are sold under: what a discovery catalog lists them under and what a buyer's agent is shown beside the price. Null means nobody has chosen one, which is where every merchant starts. The field is always present rather than left out when there is no name: an absent field would be indistinguishable from a client that dropped it. What a name may be is the catalog's rule rather than ours — at most 32 characters of printable ASCII — because a name outside it is dropped there in silence, so it is refused here where somebody is told. A merchant with no name cannot publish a card: a card published without one reaches a buyer's agent inside a payment request that names no seller at all.",
240
+ description: "The name a merchant's products are sold under: what a discovery catalog lists them under and what a buyer's agent is shown beside the price. Null means nobody has chosen one, which is where every merchant starts. The field is always present rather than left out when there is no name: an absent field would be indistinguishable from a client that dropped it. What a name may be is the catalog's rule rather than ours — at most 32 characters of printable ASCII — because a name outside it is dropped there in silence, so it is refused here where somebody is told. A merchant with no name cannot publish a card: a card published without one reaches a buyer's agent inside a payment request that names no seller at all. seller_site is the https address of the merchant's own shop, which every agent reads beside the name on their cards and orders as where to take what an order cannot answer; null means none was given.",
292
241
  });
293
242
  /**
294
243
  * What a merchant sends to change what their products are sold under.
@@ -303,7 +252,7 @@ export const SellerNameSchema = z
303
252
  * which is this same call, or an end to selling, which is the pause — and the
304
253
  * pause leaves their cards where they can find them again.
305
254
  *
306
- * So it is two documents rather than one, and a cabinet still reads back the
255
+ * So it is two documents rather than one, and a dashboard still reads back the
307
256
  * shape it sent. The message on a null is written here rather than left to a
308
257
  * type error, because "expected string, received null" describes the shape and
309
258
  * says nothing about which act the sender was reaching for.
@@ -311,7 +260,8 @@ export const SellerNameSchema = z
311
260
  export const SellerNameRequestSchema = z
312
261
  .strictObject({
313
262
  /**
314
- * What buyers are to read beside this merchant's products.
263
+ * What buyers are to read beside this merchant's products, where it is
264
+ * changing.
315
265
  *
316
266
  * The rule lives once, in `ServiceNameSchema`, and this reaches it through
317
267
  * a string that carries its own words for "this is not a name at all". A
@@ -320,18 +270,36 @@ export const SellerNameRequestSchema = z
320
270
  */
321
271
  seller_name: z
322
272
  .string({
323
- // A field that is missing is a client with a bug and a field holding
324
- // null is a client with a misunderstanding. Only the second gets this
325
- // sentence; the first falls through to the ordinary words about a
326
- // field that is not there, which is what its author needs to read.
273
+ // A field holding null is a client with a misunderstanding, and only
274
+ // that gets this sentence.
327
275
  error: (issue) => issue.input === undefined
328
276
  ? undefined
329
277
  : "a seller name cannot be taken away, only changed: a merchant who wants to stop being listed pauses their selling, which leaves their cards where they can put them back on sale",
330
278
  })
331
- .pipe(ServiceNameSchema),
279
+ .pipe(ServiceNameSchema)
280
+ .optional(),
281
+ /**
282
+ * The https address of the merchant's own shop, where it is changing
283
+ * (ADR-0034). Like the name it is changed and never taken away: an agent
284
+ * holding an order that named a site has been told where to go, and a
285
+ * site that vanished from the same order would leave it nowhere.
286
+ */
287
+ seller_site: z
288
+ .string({
289
+ error: (issue) => issue.input === undefined
290
+ ? undefined
291
+ : "a seller's site cannot be taken away, only changed: send the address it has moved to",
292
+ })
293
+ .pipe(SellerSiteSchema)
294
+ .optional(),
295
+ })
296
+ .refine((asked) => asked.seller_name !== undefined || asked.seller_site !== undefined, {
297
+ // A client that dropped both fields has a bug, and is told what this call
298
+ // takes rather than anything about taking a name away.
299
+ message: "a request names seller_name, seller_site or both: one that names neither changes nothing",
332
300
  })
333
301
  .meta({
334
- description: "What a merchant sends to change the name their products are sold under. The same rule as the answer — at most 32 characters of printable ASCII, the catalog's rule rather than ours — and one difference: null is refused. A merchant goes from no name to a name and from one name to another, never back to none, because a payment request names the seller and there would be nobody to name: every card they have published would come off sale, which is an end to their selling arriving under the name of editing a setting. Somebody reaching for null wants one of two other things: a different name, which is this call with a different value, or an end to selling, which is the pause.",
302
+ description: "What a merchant sends to change the name their products are sold under, the address of their shop's own site, or both; a field left out stays as it was, and one of the two has to be there. The name is held to the catalog's rule rather than ours — at most 32 characters of printable ASCII — and is plain text. The site is an https origin and nothing after it, such as https://shop.example. Null is refused for either. A merchant goes from no name to a name and from one name to another, never back to none, because a payment request names the seller and there would be nobody to name: every card they have published would come off sale, which is an end to their selling arriving under the name of editing a setting. Somebody reaching for null wants one of two other things: a different name, which is this call with a different value, or an end to selling, which is the pause. A site is changed the same way and never taken away.",
335
303
  });
336
304
  /**
337
305
  * A change of the wallet that has been asked for, announced, and has not taken
@@ -339,10 +307,9 @@ export const SellerNameRequestSchema = z
339
307
  *
340
308
  * It exists because a replacement does not apply at once where the money is
341
309
  * real (ADR-0019). The address a merchant is paid at is the one setting whose
342
- * change redirects money, and any key of theirs reaches it — the cabinet's, or
343
- * one sitting in their own server's environment — so on the live deployment a
344
- * replacement is told to every account of the merchant first and takes effect
345
- * forty-eight hours after that. What this document says is the two facts a
310
+ * change redirects money, and a dashboard session that is not the owner's could
311
+ * ask for one, so on the live deployment a replacement is told to every account
312
+ * of the merchant first and takes effect forty-eight hours after that. What this document says is the two facts a
346
313
  * merchant needs in that window: what replaces the address, and from when.
347
314
  *
348
315
  * Both are required. An address with no moment says nothing about when the
@@ -390,9 +357,10 @@ export const PendingPayoutWalletSchema = z
390
357
  * without this they would ask again, or conclude the change was lost.
391
358
  *
392
359
  * It is carried without moving `CONTRACT_VERSION`, which is the one known
393
- * exception to the rule that a new required field moves it (ADR-0006 §2): no
394
- * worker of the SDK reads this route, so the version would stop every
395
- * installed worker for a field none of them sees. What that costs is that a
360
+ * exception to the rule that a new required field moves it once a merchant we
361
+ * do not control runs the SDK (ADR-0006 §2): no worker of the SDK reads this
362
+ * route, so the version would stop every installed worker for a field none of
363
+ * them sees. What that costs is that a
396
364
  * merchant's own code holding this schema from an older release of this
397
365
  * package refuses the answer until the package is upgraded.
398
366
  */
@@ -406,96 +374,3 @@ export const PayoutWalletSchema = z
406
374
  .meta({
407
375
  description: "The address a merchant's sales are paid into, and any change of it that is waiting. Payments are not held by anybody on the way: a buyer's agent pays payout_wallet directly, and it is the payTo of every payment request made for this merchant's products now. Null means nobody has set one, which is where every merchant starts; the field is always present rather than left out, because an absent field is indistinguishable from a client that dropped it. The address comes back in the mixed-case spelling a wallet shows, whichever of the two accepted spellings was sent — so what a merchant reads back on a screen is character for character what they copied out of their wallet. On a deployment that settles on a real chain a merchant with no wallet here cannot publish a card, because the money from that card's sales would have nowhere to go. pending is a replacement that has been asked for and has not taken effect: on the live deployment a merchant who already has a wallet and asks for a different one is told of it by message, and the new address takes effect forty-eight hours later, so until takes_effect_at this answer names the address still paid and the waiting one beside it. A caller reading its old address back beside a pending change has not failed to write; the change is waiting. Null means nothing is waiting, which is every answer on the test channel and in a sandbox, where a change applies at once.",
408
376
  });
409
- /**
410
- * What a merchant sends to change where their sales are paid.
411
- *
412
- * The same field held to the same rule, and one difference, which is the same
413
- * difference the seller name has and rests on something harder. There is no
414
- * null. A merchant goes from having no wallet to having one and from one wallet
415
- * to another, and not back: a merchant who took their address away would keep
416
- * every card they had already published on sale, and the payment request an
417
- * agent is answered with cannot be built at all without an address — so the
418
- * products would stop being buyable and nothing anywhere would say why. What
419
- * somebody reaching for null actually wants is one of two other acts: a
420
- * different address, which is this same call, or an end to selling, which is
421
- * the pause, and the pause leaves their cards where they can put them back.
422
- *
423
- * There is nowhere here to put a key, and a document carrying one is refused
424
- * rather than trimmed. This contract knows where a merchant is paid and has no
425
- * business knowing anything that could spend it.
426
- */
427
- export const PayoutWalletRequestSchema = z
428
- .strictObject({
429
- /**
430
- * Where this merchant's sales are to be paid.
431
- *
432
- * The rule lives once, in `EvmAddressSchema`, and this reaches it through a
433
- * string that carries its own words for "this is not an address at all".
434
- */
435
- payout_wallet: z
436
- .string({
437
- // A field that is missing is a client with a bug and a field holding
438
- // null is a client with a misunderstanding. Only the second gets this
439
- // sentence; the first falls through to the ordinary words about a
440
- // field that is not there.
441
- error: (issue) => issue.input === undefined
442
- ? undefined
443
- : "a payout wallet cannot be taken away, only changed: a merchant who wants to stop being paid pauses their selling, which leaves their cards where they can put them back on sale — a merchant with cards on sale and no wallet has products a payment request cannot even be written for",
444
- })
445
- .pipe(EvmAddressSchema),
446
- })
447
- .meta({
448
- description: "What a merchant sends to set or change the address their sales are paid into. The same rule as the answer — 0x and forty hexadecimal characters, in lower case or in the exact mixed-case spelling a wallet shows — and one difference: null is refused. A merchant goes from no wallet to a wallet and from one wallet to another, never back to none, because their published cards stay on sale and a payment request for one of them cannot be written without an address. Somebody reaching for null wants either a different address, which is this call with a different value, or an end to selling, which is the pause. Nothing here takes a private key or a seed phrase, and a document carrying one is refused rather than ignored: this contract knows where a merchant is paid and nothing that could spend it.",
449
- });
450
- /**
451
- * What somebody sends to become a merchant.
452
- *
453
- * One field, and what is not here is most of what is worth reading. The address
454
- * and the password belong to the account rather than to the merchant, and they
455
- * stay on the other side of the boundary (ADR-0014 §1) — a gateway that took
456
- * either would be holding a person's credentials on the money path, which is
457
- * what this route's whole shape is arranged to avoid.
458
- *
459
- * The name the seller's products are sold under is not here either, and that
460
- * omission is a decision rather than a simplification. It is a public answer,
461
- * and asking for it here asks for it at the one moment a merchant knows least:
462
- * no products, no catalogue seen, no idea what the name is for. It is asked for
463
- * on the screen after this one instead, where there is room to say why it
464
- * matters, and it can be changed afterwards from the merchant's own settings.
465
- *
466
- * The shape refuses a name rather than ignoring one, because a field quietly
467
- * dropped is a person believing they have chosen what buyers will read.
468
- */
469
- export const RegistrationRequestSchema = z
470
- .strictObject({
471
- /** The code handed over with the address of the site. */
472
- invitation: InvitationSchema,
473
- })
474
- .meta({
475
- description: "What somebody sends to become a merchant: the invitation code they were given, and nothing else. The name their products are sold under is deliberately not here — it is a public answer, and asked for on the way in it is answered by somebody with no products and no idea what the name is for; it is set afterwards, and changed afterwards, through the merchant's own call for it. Nothing about an account is here either: an address and a password belong to whatever signs the person in, and are never sent to the gateway. A document carrying either is refused rather than trimmed, because a field accepted and dropped is somebody believing they said something.",
476
- });
477
- /**
478
- * What registering answers with: a merchant and the key their cabinet will call
479
- * as them with.
480
- *
481
- * The key is made for a cabinet rather than for the merchant's own code, and
482
- * that is what the caller of this route is. So it is in no list: a merchant who
483
- * has just registered has no keys of their own at all, and the first one they
484
- * do have is one they ask for. No row travels beside the secret for the same
485
- * reason no row appears in the list — the merchant did not issue it and cannot
486
- * disable it, so an identifier for it would be a value with nothing to do.
487
- *
488
- * No name comes back either, because none was chosen. A merchant who has just
489
- * registered is listed under nothing at all, and a field here would either be a
490
- * name this call invented or a null that says the same thing at more length.
491
- */
492
- export const RegisteredMerchantSchema = z
493
- .strictObject({
494
- /** The merchant that now exists, which every key and card of theirs names. */
495
- merchant_id: IdentifierSchema,
496
- /** The key itself, shown once, exactly as issuing one shows it. */
497
- secret: KeySecretSchema,
498
- })
499
- .meta({
500
- description: "What registering produced: the merchant, and the key whoever registered them will call as them with. The key is readable here and nowhere afterwards, so whoever made this call is the only party that can keep it. It is a key made for a cabinet rather than one of the merchant's own: it appears in no list of their keys and the call that revokes a key refuses its kind by name, so no row for it comes back here either. A merchant who has just registered has no keys of their own until they ask for one. The merchant is listed under no name yet and this answer carries none — the name their products are sold under is chosen afterwards, and until it is, publishing a card is refused. What this answer does not carry either is any notion of an account or a session: registering makes a merchant and a key, and whatever signs a person in is on the other side of this call.",
501
- });
@@ -31,10 +31,11 @@
31
31
  * order is reading the wrong list.
32
32
  */
33
33
  import { z } from "zod";
34
- export declare const ORDER_STATUSES: readonly ["in_progress", "delivered", "rejected", "payment_unresolved", "declined", "expired", "cancelled", "refund_due", "refunded", "delivered_unpaid"];
34
+ export declare const ORDER_STATUSES: readonly ["in_progress", "delivered", "shipped", "rejected", "payment_unresolved", "declined", "expired", "cancelled", "refund_due", "refunded", "delivered_unpaid"];
35
35
  export declare const OrderStatusSchema: z.ZodEnum<{
36
36
  delivered: "delivered";
37
37
  in_progress: "in_progress";
38
+ shipped: "shipped";
38
39
  rejected: "rejected";
39
40
  payment_unresolved: "payment_unresolved";
40
41
  declined: "declined";
@@ -36,10 +36,22 @@ export const ORDER_STATUSES = Object.freeze([
36
36
  "in_progress",
37
37
  /** Success: the product is with the agent and the money with the merchant. */
38
38
  "delivered",
39
+ /**
40
+ * A parcel is with the carrier and the money with the merchant (ADR-0033):
41
+ * the merchant recorded its shipment, and the order carries it. This is the
42
+ * last word Agentify has about the parcel. Every protocol that uses the word
43
+ * goes on past it to arrival; this one does not, because nothing reports an
44
+ * arrival here, and whether the parcel arrives is between the buyer and the
45
+ * merchant — the seller's site is where to ask.
46
+ */
47
+ "shipped",
39
48
  /**
40
49
  * Closed and the buyer's money is known not to have moved — the product was
41
50
  * gone, the parameters did not fit, the payment failed its check, the charge
42
- * came back failed, or a synchronous handler refused.
51
+ * came back failed, or a synchronous handler refused. On a parcel, the
52
+ * product being gone is the merchant's price answer saying "not available",
53
+ * which there can also mean the merchant does not ship to that place or the
54
+ * address lacks what their carrier needs.
43
55
  *
44
56
  * The machine keeps a finer distinction behind this word: a purchase that
45
57
  * never reached the merchant and one the merchant refused are separate
package/dist/order.d.ts CHANGED
@@ -45,6 +45,23 @@ export declare const OrderSchema: z.ZodObject<{
45
45
  as_of: z.ZodISODateTime;
46
46
  }, z.core.$strict>;
47
47
  price_id: z.ZodOptional<z.ZodString>;
48
+ ship_to: z.ZodOptional<z.ZodUnion<readonly [z.ZodObject<{
49
+ name: z.ZodString;
50
+ line_one: z.ZodString;
51
+ line_two: z.ZodOptional<z.ZodString>;
52
+ city: z.ZodString;
53
+ state: z.ZodOptional<z.ZodString>;
54
+ postal_code: z.ZodOptional<z.ZodString>;
55
+ country: z.ZodString;
56
+ phone_number: z.ZodString;
57
+ }, z.core.$strict>, z.ZodObject<{
58
+ country: z.ZodString;
59
+ state: z.ZodOptional<z.ZodString>;
60
+ city: z.ZodString;
61
+ postal_code: z.ZodOptional<z.ZodString>;
62
+ }, z.core.$strict>, z.ZodObject<{
63
+ erased_at: z.ZodISODateTime;
64
+ }, z.core.$strict>]>>;
48
65
  test: z.ZodBoolean;
49
66
  }, z.core.$strict>;
50
67
  export type Order = z.infer<typeof OrderSchema>;
package/dist/order.js CHANGED
@@ -36,6 +36,7 @@
36
36
  import { z } from "zod";
37
37
  import { ParamNameSchema } from "./param-spec.js";
38
38
  import { IdentifierSchema, SalePriceSchema } from "./primitives.js";
39
+ import { ErasedShipToSchema, ShipToLocalitySchema, ShipToSchema } from "./ship-to.js";
39
40
  export const OrderSchema = z.strictObject({
40
41
  /**
41
42
  * The order's identifier, which is also its idempotency key: the same string
@@ -67,6 +68,18 @@ export const OrderSchema = z.strictObject({
67
68
  * identifier can release it here.
68
69
  */
69
70
  price_id: IdentifierSchema.optional(),
71
+ /**
72
+ * Where a parcel goes (ADR-0032), present on a parcel's order and never on
73
+ * any other, in one of three shapes as the order goes along. Before it is
74
+ * paid, the locality the price was asked for — the place and nothing about
75
+ * who. Once paid, the whole address, which the merchant stores before taking
76
+ * the order on. Once Agentify no longer needs it — the order taken on, its
77
+ * shipment recorded, or the order ended or owing a refund without being taken
78
+ * on — only when Agentify erased its copy. From then on the merchant has the
79
+ * address only as they stored it from the paid order, and the order is not
80
+ * handed to a handler again.
81
+ */
82
+ ship_to: z.union([ShipToSchema, ShipToLocalitySchema, ErasedShipToSchema]).optional(),
70
83
  /**
71
84
  * Whether this is a test order.
72
85
  *
@@ -67,6 +67,18 @@ export declare const MoneySchema: z.ZodObject<{
67
67
  */
68
68
  export declare const TimestampSchema: z.ZodISODateTime;
69
69
  export declare const IdentifierSchema: z.ZodString;
70
+ /**
71
+ * A word of a vocabulary that grows without a version (ADR-0006 §5): a mode
72
+ * on the card an agent reads, a status on its order.
73
+ *
74
+ * The storefront has no version, so a word added later reaches agents that
75
+ * still hold this contract, and they read it rather than refuse the document.
76
+ * Open is not anything at all, though: a word is read by a program and shown
77
+ * to a person, so it has the shape every word in those lists already has —
78
+ * lower-case letters, digits and underscores, starting with a letter — and
79
+ * markup, padding or a page of text is not one.
80
+ */
81
+ export declare const OpenWordSchema: z.ZodString;
70
82
  /**
71
83
  * The price a purchase actually went through at.
72
84
  *
@@ -100,4 +112,5 @@ export type CurrencyCode = z.infer<typeof CurrencyCodeSchema>;
100
112
  export type Money = z.infer<typeof MoneySchema>;
101
113
  export type Timestamp = z.infer<typeof TimestampSchema>;
102
114
  export type Identifier = z.infer<typeof IdentifierSchema>;
115
+ export type OpenWord = z.infer<typeof OpenWordSchema>;
103
116
  export type SalePrice = z.infer<typeof SalePriceSchema>;
@@ -100,6 +100,20 @@ export const IdentifierSchema = z.string().regex(
100
100
  // then anything printable, then a last character under the same rule as the
101
101
  // first. One character on its own is allowed; nothing at all is not.
102
102
  new RegExp(`^[^\\s${UNPRINTABLE}](?:[^${UNPRINTABLE}]*[^\\s${UNPRINTABLE}])?$`, "u"), "an identifier must not be empty, padded with whitespace, or carry characters that show nothing");
103
+ /**
104
+ * A word of a vocabulary that grows without a version (ADR-0006 §5): a mode
105
+ * on the card an agent reads, a status on its order.
106
+ *
107
+ * The storefront has no version, so a word added later reaches agents that
108
+ * still hold this contract, and they read it rather than refuse the document.
109
+ * Open is not anything at all, though: a word is read by a program and shown
110
+ * to a person, so it has the shape every word in those lists already has —
111
+ * lower-case letters, digits and underscores, starting with a letter — and
112
+ * markup, padding or a page of text is not one.
113
+ */
114
+ export const OpenWordSchema = z
115
+ .string()
116
+ .regex(/^[a-z][a-z0-9_]{0,63}$/, "a word of this vocabulary is lower-case letters, digits and underscores, starts with a letter and is at most sixty-four characters long");
103
117
  /**
104
118
  * The price a purchase actually went through at.
105
119
  *
package/dist/quote.d.ts CHANGED
@@ -38,6 +38,12 @@ export declare const QuotePurposeSchema: z.ZodEnum<{
38
38
  export declare const QuoteRequestSchema: z.ZodObject<{
39
39
  merchant_item_id: z.ZodString;
40
40
  params: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
41
+ ship_to: z.ZodOptional<z.ZodObject<{
42
+ country: z.ZodString;
43
+ state: z.ZodOptional<z.ZodString>;
44
+ city: z.ZodString;
45
+ postal_code: z.ZodOptional<z.ZodString>;
46
+ }, z.core.$strict>>;
41
47
  price_id: z.ZodString;
42
48
  purpose: z.ZodEnum<{
43
49
  purchase: "purchase";
package/dist/quote.js CHANGED
@@ -25,6 +25,7 @@
25
25
  import { z } from "zod";
26
26
  import { ParamNameSchema } from "./param-spec.js";
27
27
  import { IdentifierSchema, MoneySchema, TimestampSchema } from "./primitives.js";
28
+ import { ShipToLocalitySchema } from "./ship-to.js";
28
29
  /**
29
30
  * Why we are asking.
30
31
  *
@@ -44,6 +45,15 @@ export const QuoteRequestSchema = z.strictObject({
44
45
  // Same dropped key as everywhere this contract parses free-form names; see
45
46
  // `PROTOTYPE_KEY_IS_DROPPED` in `param-spec.ts`.
46
47
  params: z.record(ParamNameSchema, z.unknown()).optional(),
48
+ /**
49
+ * Where a parcel goes, as its price is asked (ADR-0032): the country, the
50
+ * state, the city and the postal code, and nothing about who receives it. A
51
+ * price question reaches a merchant for purchases never made, and a shipping
52
+ * rate needs the place alone. Present on a parcel's question only; the
53
+ * answer is the whole price, shipping to this place included, or not
54
+ * available where the merchant does not ship there.
55
+ */
56
+ ship_to: ShipToLocalitySchema.optional(),
47
57
  /**
48
58
  * The identifier of this question, which comes back attached to the order.
49
59
  *
package/dist/receipt.d.ts CHANGED
@@ -40,18 +40,20 @@ import { z } from "zod";
40
40
  * if it did not, there was never anything to record. That is the same promise
41
41
  * the portal makes to the buyer in words: we say so when we learn.
42
42
  *
43
- * That leaves four: paid and still running, paid and delivered, paid and owed
44
- * back, paid and paid back.
43
+ * That leaves five: paid and still running, paid and delivered, a paid parcel
44
+ * shipped (ADR-0033), paid and owed back, paid and paid back.
45
45
  *
46
46
  * What this list does not say is when a receipt is written at all, and a reader
47
47
  * should not infer it from here. That is the gateway's, and a gateway that
48
- * writes one only as goods are released will only ever produce `delivered` —
49
- * so a consumer must not read the presence of these four as a promise that a
50
- * receipt exists for every payment that executed.
48
+ * writes one only as goods are released or a parcel ships will only ever
49
+ * produce `delivered` and `shipped` — so a consumer must not read the presence
50
+ * of these five as a promise that a receipt exists for every payment that
51
+ * executed.
51
52
  */
52
53
  export declare const ReceiptOutcomeSchema: z.ZodEnum<{
53
54
  delivered: "delivered";
54
55
  in_progress: "in_progress";
56
+ shipped: "shipped";
55
57
  refund_due: "refund_due";
56
58
  refunded: "refunded";
57
59
  }>;
@@ -70,6 +72,7 @@ export declare const ReceiptSchema: z.ZodObject<{
70
72
  outcome: z.ZodEnum<{
71
73
  delivered: "delivered";
72
74
  in_progress: "in_progress";
75
+ shipped: "shipped";
73
76
  refund_due: "refund_due";
74
77
  refunded: "refunded";
75
78
  }>;
package/dist/receipt.js CHANGED
@@ -41,16 +41,23 @@ import { IdentifierSchema, SalePriceSchema, TimestampSchema } from "./primitives
41
41
  * if it did not, there was never anything to record. That is the same promise
42
42
  * the portal makes to the buyer in words: we say so when we learn.
43
43
  *
44
- * That leaves four: paid and still running, paid and delivered, paid and owed
45
- * back, paid and paid back.
44
+ * That leaves five: paid and still running, paid and delivered, a paid parcel
45
+ * shipped (ADR-0033), paid and owed back, paid and paid back.
46
46
  *
47
47
  * What this list does not say is when a receipt is written at all, and a reader
48
48
  * should not infer it from here. That is the gateway's, and a gateway that
49
- * writes one only as goods are released will only ever produce `delivered` —
50
- * so a consumer must not read the presence of these four as a promise that a
51
- * receipt exists for every payment that executed.
49
+ * writes one only as goods are released or a parcel ships will only ever
50
+ * produce `delivered` and `shipped` — so a consumer must not read the presence
51
+ * of these five as a promise that a receipt exists for every payment that
52
+ * executed.
52
53
  */
53
- export const ReceiptOutcomeSchema = z.enum(["in_progress", "delivered", "refund_due", "refunded"]);
54
+ export const ReceiptOutcomeSchema = z.enum([
55
+ "in_progress",
56
+ "delivered",
57
+ "shipped",
58
+ "refund_due",
59
+ "refunded",
60
+ ]);
54
61
  export const ReceiptSchema = z.strictObject({
55
62
  /**
56
63
  * The receipt's own identifier. In the modes where the payment goes first,