@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/api.d.ts +259 -327
- package/dist/api.js +108 -68
- package/dist/card.d.ts +127 -81
- package/dist/card.js +271 -66
- package/dist/envelope.d.ts +46 -0
- package/dist/index.d.ts +231 -203
- package/dist/index.js +21 -12
- package/dist/merchant.d.ts +21 -120
- package/dist/merchant.js +60 -185
- package/dist/order-status.d.ts +2 -1
- package/dist/order-status.js +13 -1
- package/dist/order.d.ts +17 -0
- package/dist/order.js +13 -0
- package/dist/primitives.d.ts +13 -0
- package/dist/primitives.js +14 -0
- package/dist/quote.d.ts +6 -0
- package/dist/quote.js +10 -0
- package/dist/receipt.d.ts +8 -5
- package/dist/receipt.js +13 -6
- package/dist/results.d.ts +19 -10
- package/dist/results.js +21 -11
- package/dist/seller-site.d.ts +30 -0
- package/dist/seller-site.js +43 -0
- package/dist/ship-to.d.ts +50 -0
- package/dist/ship-to.js +76 -0
- package/dist/shipment.d.ts +42 -0
- package/dist/shipment.js +112 -0
- package/package.json +1 -1
package/dist/card.js
CHANGED
|
@@ -25,21 +25,29 @@
|
|
|
25
25
|
* more shape to keep in step for no gain to anybody.
|
|
26
26
|
*/
|
|
27
27
|
import { z } from "zod";
|
|
28
|
-
import { ParamSpecSchema, paramSpecToValidator } from "./param-spec.js";
|
|
28
|
+
import { FieldSpecSchema, ParamNameSchema, ParamSpecSchema, paramSpecToValidator, } from "./param-spec.js";
|
|
29
29
|
import { notPlainTextIn } from "./plain-text.js";
|
|
30
|
-
import { IdentifierSchema, MoneySchema, TimestampSchema } from "./primitives.js";
|
|
30
|
+
import { IdentifierSchema, MoneySchema, OpenWordSchema, TimestampSchema } from "./primitives.js";
|
|
31
|
+
import { SellerSiteSchema } from "./seller-site.js";
|
|
31
32
|
import { SellingStateSchema } from "./selling.js";
|
|
33
|
+
import { ShipToSchema } from "./ship-to.js";
|
|
34
|
+
import { ShipmentSchema } from "./shipment.js";
|
|
32
35
|
/**
|
|
33
36
|
* When the product reaches the agent, and therefore when the money moves.
|
|
34
37
|
*
|
|
35
38
|
* `sync` — in the answer to the purchase, and the payment executes last, after
|
|
36
39
|
* the merchant has delivered. `async` — later, by a separate call, and the
|
|
37
40
|
* payment executes at the moment of purchase. `confirm` — the merchant is
|
|
38
|
-
* asked first, and the payment executes right after they say yes.
|
|
41
|
+
* asked first, and the payment executes right after they say yes. `ship` — a
|
|
42
|
+
* parcel the merchant hands to a carrier (ADR-0033): the payment executes at
|
|
43
|
+
* the moment of purchase, as in `async`, and the order carries the buyer's
|
|
44
|
+
* address until the merchant takes it on, or it ends without them.
|
|
39
45
|
*/
|
|
40
|
-
export const FulfillmentSchema = z.enum(["sync", "async", "confirm"]).meta({
|
|
41
|
-
description: 'When the product reaches the agent, and so when the money moves. "sync" — in the answer to the purchase, payment last. "async" — later, by a separate call, payment at the moment of purchase. "confirm" — the merchant is asked first and the payment follows their yes. A card cannot be published as "confirm" during the pilot: the confirmation request has no shape on the wire yet, so a handler could not tell one from a paid order.',
|
|
46
|
+
export const FulfillmentSchema = z.enum(["sync", "async", "confirm", "ship"]).meta({
|
|
47
|
+
description: 'When the product reaches the agent, and so when the money moves. "sync" — in the answer to the purchase, payment last. "async" — later, by a separate call, payment at the moment of purchase. "confirm" — the merchant is asked first and the payment follows their yes. "ship" — a parcel the merchant hands to a carrier, payment at the moment of purchase; the purchase carries the address it goes to. A card cannot be published as "confirm" during the pilot: the confirmation request has no shape on the wire yet, so a handler could not tell one from a paid order.',
|
|
42
48
|
});
|
|
49
|
+
/** The longest a parcel's card may give its merchant to hand it to a carrier: thirty days. */
|
|
50
|
+
const SHIP_WITHIN_AT_MOST_SECONDS = 2_592_000;
|
|
43
51
|
/**
|
|
44
52
|
* How the price and availability of this card are asked for, if they are.
|
|
45
53
|
*
|
|
@@ -118,8 +126,49 @@ const listedText = (what) => z
|
|
|
118
126
|
* holds it is the merchants table, so this schema is the rule alone, applied
|
|
119
127
|
* wherever a merchant's listing name is written down.
|
|
120
128
|
*/
|
|
121
|
-
export const ServiceNameSchema = listedText("service name")
|
|
122
|
-
|
|
129
|
+
export const ServiceNameSchema = listedText("service name")
|
|
130
|
+
.superRefine((name, ctx) => {
|
|
131
|
+
// Every agent reads the name on every card and order of the merchant's
|
|
132
|
+
// (ADR-0034), so the door holds it to the card's own plain-text rule
|
|
133
|
+
// (ADR-0017): markup and character references are refused and named,
|
|
134
|
+
// not cleaned into words the merchant never wrote.
|
|
135
|
+
for (const phrase of notPlainTextIn(name, "one line")) {
|
|
136
|
+
ctx.addIssue({
|
|
137
|
+
code: "custom",
|
|
138
|
+
message: `this service name carries ${phrase}, and a service name is plain text, which an agent reads exactly as it is written`,
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
})
|
|
142
|
+
.meta({
|
|
143
|
+
description: "The name a seller is listed under in a discovery catalog and shown to every agent beside their products. At most 32 characters of printable ASCII, because that is what the catalog carries; a name outside that is refused here rather than truncated there, where nobody would be told. It is plain text: HTML markup and character references such as & are refused, and an ampersand written as text passes.",
|
|
144
|
+
});
|
|
145
|
+
/**
|
|
146
|
+
* The name as it is stored and read back: every rule the door holds it to
|
|
147
|
+
* except that it is plain text.
|
|
148
|
+
*
|
|
149
|
+
* That rule belongs to the door and not to the reader, for the reason the
|
|
150
|
+
* card's own words give (ADR-0017): a name stored before the rule may carry
|
|
151
|
+
* markup, every answer is held to its contract on the way out, and one old row
|
|
152
|
+
* would fail every card and order of its merchant's instead of being put right
|
|
153
|
+
* the next time the merchant sets their name.
|
|
154
|
+
*/
|
|
155
|
+
const StoredServiceNameSchema = listedText("service name");
|
|
156
|
+
/**
|
|
157
|
+
* Who sells, as an agent reads it beside a product and on an order: the name
|
|
158
|
+
* the merchant sells under and the site of their shop (ADR-0034).
|
|
159
|
+
*
|
|
160
|
+
* Both are the merchant's own word and nothing here checked either, which the
|
|
161
|
+
* description says to the reader who acts on it — a name and a site can be
|
|
162
|
+
* anybody's. Null is "none given": a merchant who gave no site has none here,
|
|
163
|
+
* and a name is missing only from an order whose merchant has since lost it.
|
|
164
|
+
*/
|
|
165
|
+
export const SellerSchema = z
|
|
166
|
+
.strictObject({
|
|
167
|
+
name: StoredServiceNameSchema.nullable(),
|
|
168
|
+
site: SellerSiteSchema.nullable(),
|
|
169
|
+
})
|
|
170
|
+
.meta({
|
|
171
|
+
description: "Who sells: the name the merchant sells under and the https address of their shop's own site, both as the merchant gave them. Agentify did not check either, so a name and a site can be anybody's. The site is where to take what an order cannot answer — a parcel that did not arrive, a return, the shop's terms. Either is null where the merchant has given none.",
|
|
123
172
|
});
|
|
124
173
|
/**
|
|
125
174
|
* The words a merchant puts on one product so an agent searching a catalog can
|
|
@@ -220,19 +269,31 @@ const DescriptionSchema = z
|
|
|
220
269
|
* JSON Schema, so the same constraint goes into the metadata as
|
|
221
270
|
* `minProperties`, where a generator can still see it.
|
|
222
271
|
*
|
|
223
|
-
* One
|
|
272
|
+
* One rule, held by the published card and by the projection below, because
|
|
224
273
|
* the promise is the same one: what the agent reads before paying is what the
|
|
225
274
|
* merchant is held to afterwards. Two copies of a refinement would be two
|
|
226
|
-
* promises, and the export would carry whichever was edited last.
|
|
275
|
+
* promises, and the export would carry whichever was edited last. The two
|
|
276
|
+
* declarations it is put on differ only in what else a field may carry: the
|
|
277
|
+
* merchant's is closed, and the agent's takes what is added later
|
|
278
|
+
* (ADR-0006 §5).
|
|
227
279
|
*/
|
|
228
|
-
const
|
|
280
|
+
const declaringAResult = (declaration) => declaration
|
|
281
|
+
.refine(
|
|
229
282
|
// Not merely non-empty: at least one field that actually arrives. A
|
|
230
283
|
// declaration of one field marked `required: false` satisfies "at least
|
|
231
284
|
// one" and promises the agent exactly as much as an empty one does.
|
|
232
|
-
(spec) => Object.values(spec).some((field) => field.required !== false), "a card declares at least one field of what the agent receives, and at least one of them arrives every time")
|
|
285
|
+
(spec) => Object.values(spec).some((field) => field.required !== false), "a card declares at least one field of what the agent receives, and at least one of them arrives every time")
|
|
286
|
+
.meta({
|
|
233
287
|
description: "What the agent receives on delivery. At least one field, and at least one of the fields is not marked required: false — a result that might be entirely absent promises nothing.",
|
|
234
288
|
minProperties: 1,
|
|
235
289
|
});
|
|
290
|
+
const DeclaredResultSchema = declaringAResult(ParamSpecSchema);
|
|
291
|
+
/**
|
|
292
|
+
* A declaration as an agent reads it: the merchant's fields, each open to what
|
|
293
|
+
* is added to a field later (ADR-0006 §5), so a new attribute of one field
|
|
294
|
+
* leaves the card readable to an agent built before it.
|
|
295
|
+
*/
|
|
296
|
+
const ReadDeclarationSchema = z.record(ParamNameSchema, FieldSpecSchema.loose());
|
|
236
297
|
/**
|
|
237
298
|
* The short forms a card may be written in, and the one form they all become.
|
|
238
299
|
*
|
|
@@ -355,11 +416,15 @@ const CardFieldsSchema = z.strictObject({
|
|
|
355
416
|
* says so, or a generated client would first meet the rule as a refusal.
|
|
356
417
|
*/
|
|
357
418
|
price: CardPriceSchema.meta({
|
|
358
|
-
description: 'Publishing refuses a price that is zero, not in USD or USDC, or written with fewer than two or more than six digits after the dot ("5.00", "0.001"), so that a price the catalog shows is one a payment can be taken at.',
|
|
419
|
+
description: 'Publishing refuses a price that is zero, not in USD or USDC, or written with fewer than two or more than six digits after the dot ("5.00", "0.001"), so that a price the catalog shows is one a payment can be taken at. On a "ship" card it is the goods without shipping: the price a purchase goes through at is the merchant\'s price handler\'s answer, which includes shipping to the buyer\'s place.',
|
|
359
420
|
}),
|
|
360
421
|
/** What the agent has to supply to buy. Absent when the purchase needs no input. */
|
|
361
422
|
params: writtenShort(ParamSpecSchema).optional(),
|
|
362
|
-
|
|
423
|
+
/**
|
|
424
|
+
* What the agent receives. Every card declares it except a parcel's, whose
|
|
425
|
+
* mode fixes it: the record of the parcel's shipment (ADR-0033).
|
|
426
|
+
*/
|
|
427
|
+
result: writtenShort(DeclaredResultSchema).optional(),
|
|
363
428
|
/**
|
|
364
429
|
* Words for an agent searching a discovery catalog. Absent on a card whose
|
|
365
430
|
* merchant named none, and never invented for them.
|
|
@@ -389,6 +454,16 @@ const CardFieldsSchema = z.strictObject({
|
|
|
389
454
|
confirm_deadline_seconds: z.int().positive().optional(),
|
|
390
455
|
/** How long the merchant may take to deliver an order it has accepted. */
|
|
391
456
|
fulfill_deadline_seconds: z.int().positive().optional(),
|
|
457
|
+
/**
|
|
458
|
+
* On a parcel's card, how long the merchant may take to hand it to a carrier,
|
|
459
|
+
* counted from the charge (ADR-0033). A name of its own rather than the
|
|
460
|
+
* delivery deadline's, because on an asynchronous card that number is the
|
|
461
|
+
* time to deliver, and a number read under the wrong name tells a person
|
|
462
|
+
* their parcel arrives when it merely leaves. The ceiling is thirty days, the
|
|
463
|
+
* longest the marketplaces give a seller, and it bounds how long a buyer's
|
|
464
|
+
* money sits with a merchant before the order becomes a refund owed.
|
|
465
|
+
*/
|
|
466
|
+
ship_within_seconds: z.int().positive().max(SHIP_WITHIN_AT_MOST_SECONDS).optional(),
|
|
392
467
|
});
|
|
393
468
|
/**
|
|
394
469
|
* Both deadlines are shown to the agent before it pays, which is why a card
|
|
@@ -419,8 +494,8 @@ const cardRules = (card, ctx) => {
|
|
|
419
494
|
// card that has one problem, and lifting the gate later would uncover it.
|
|
420
495
|
return;
|
|
421
496
|
}
|
|
422
|
-
// Past the gate
|
|
423
|
-
//
|
|
497
|
+
// Past the gate no mode is ever asked to confirm — which is why this needs no
|
|
498
|
+
// test on the mode of its own.
|
|
424
499
|
if (card.confirm_deadline_seconds !== undefined) {
|
|
425
500
|
ctx.addIssue({
|
|
426
501
|
code: "custom",
|
|
@@ -428,6 +503,24 @@ const cardRules = (card, ctx) => {
|
|
|
428
503
|
message: `only a card with fulfillment "confirm" is asked to confirm; this one is "${card.fulfillment}"`,
|
|
429
504
|
});
|
|
430
505
|
}
|
|
506
|
+
if (card.fulfillment === "ship") {
|
|
507
|
+
parcelRules(card, ctx);
|
|
508
|
+
return;
|
|
509
|
+
}
|
|
510
|
+
if (card.ship_within_seconds !== undefined) {
|
|
511
|
+
ctx.addIssue({
|
|
512
|
+
code: "custom",
|
|
513
|
+
path: ["ship_within_seconds"],
|
|
514
|
+
message: `only a card with fulfillment "ship" hands its goods to a carrier and names a time to ship; this one is "${card.fulfillment}"`,
|
|
515
|
+
});
|
|
516
|
+
}
|
|
517
|
+
if (card.result === undefined) {
|
|
518
|
+
ctx.addIssue({
|
|
519
|
+
code: "custom",
|
|
520
|
+
path: ["result"],
|
|
521
|
+
message: 'result is required: a card declares what the agent receives, and only a parcel\'s, fulfillment "ship", leaves that to its mode',
|
|
522
|
+
});
|
|
523
|
+
}
|
|
431
524
|
if (card.fulfillment === "sync" && card.fulfill_deadline_seconds !== undefined) {
|
|
432
525
|
ctx.addIssue({
|
|
433
526
|
code: "custom",
|
|
@@ -436,12 +529,62 @@ const cardRules = (card, ctx) => {
|
|
|
436
529
|
});
|
|
437
530
|
}
|
|
438
531
|
};
|
|
532
|
+
/**
|
|
533
|
+
* What a parcel's card is held to (ADR-0033), beside what every card is.
|
|
534
|
+
*
|
|
535
|
+
* Each rule is about a word an agent or a merchant would otherwise read wrong.
|
|
536
|
+
* The time to ship is required because it is the one promise the agent is
|
|
537
|
+
* given about when the goods leave. A result is refused because the mode fixes
|
|
538
|
+
* it — the record of the shipment — and one a merchant declared would be a
|
|
539
|
+
* second promise beside it. A delivery deadline is refused because the number
|
|
540
|
+
* would read as the time the parcel arrives. The price is the merchant's
|
|
541
|
+
* handler's to answer, because shipping depends on where the parcel goes, and
|
|
542
|
+
* only the merchant knows what it costs to send it there. And the address is
|
|
543
|
+
* not one of the card's parameters, because it travels in its own block.
|
|
544
|
+
*/
|
|
545
|
+
const parcelRules = (card, ctx) => {
|
|
546
|
+
if (card.ship_within_seconds === undefined) {
|
|
547
|
+
ctx.addIssue({
|
|
548
|
+
code: "custom",
|
|
549
|
+
path: ["ship_within_seconds"],
|
|
550
|
+
message: `a parcel's card names ship_within_seconds, the time to hand it to a carrier counted from the charge, at most ${SHIP_WITHIN_AT_MOST_SECONDS} (thirty days)`,
|
|
551
|
+
});
|
|
552
|
+
}
|
|
553
|
+
if (card.result !== undefined) {
|
|
554
|
+
ctx.addIssue({
|
|
555
|
+
code: "custom",
|
|
556
|
+
path: ["result"],
|
|
557
|
+
message: "a parcel's card declares no result: its mode fixes what the agent receives, the record of the parcel's shipment",
|
|
558
|
+
});
|
|
559
|
+
}
|
|
560
|
+
if (card.fulfill_deadline_seconds !== undefined) {
|
|
561
|
+
ctx.addIssue({
|
|
562
|
+
code: "custom",
|
|
563
|
+
path: ["fulfill_deadline_seconds"],
|
|
564
|
+
message: "a parcel's card names the time to ship, ship_within_seconds, and no delivery deadline: under that name the number would read as the time the parcel arrives",
|
|
565
|
+
});
|
|
566
|
+
}
|
|
567
|
+
if (card.price_check !== "handler") {
|
|
568
|
+
ctx.addIssue({
|
|
569
|
+
code: "custom",
|
|
570
|
+
path: ["price_check"],
|
|
571
|
+
message: "a parcel's price is asked of the merchant's own price handler, price_check: \"handler\", whose answer is the whole price with shipping to the buyer's place",
|
|
572
|
+
});
|
|
573
|
+
}
|
|
574
|
+
if (card.params !== undefined && "ship_to" in card.params) {
|
|
575
|
+
ctx.addIssue({
|
|
576
|
+
code: "custom",
|
|
577
|
+
path: ["params", "ship_to"],
|
|
578
|
+
message: "a parcel's card asks for no ship_to among its parameters: the address travels in a block of its own beside them",
|
|
579
|
+
});
|
|
580
|
+
}
|
|
581
|
+
};
|
|
439
582
|
// JSON Schema has no way to say "this field only when that one has this
|
|
440
583
|
// value", and zod drops the rules above when it renders a document. Left at
|
|
441
584
|
// that, an engineer generating a client from the export would build one that
|
|
442
585
|
// sends deadlines a card cannot carry and only find out on the first publish.
|
|
443
586
|
// Saying it in words is weaker than checking it, and better than silence.
|
|
444
|
-
const CARD_RULES_IN_WORDS = 'A card cannot be published as fulfillment "confirm" during the pilot: the confirmation request has no shape on the wire yet, so a handler could not tell one from a paid order. confirm_deadline_seconds is only allowed when fulfillment is "confirm", and fulfill_deadline_seconds only when fulfillment is "async" or "confirm" — a synchronous card delivers inside the system-wide response budget and names no deadline of its own.';
|
|
587
|
+
const CARD_RULES_IN_WORDS = 'A card cannot be published as fulfillment "confirm" during the pilot: the confirmation request has no shape on the wire yet, so a handler could not tell one from a paid order. confirm_deadline_seconds is only allowed when fulfillment is "confirm", and fulfill_deadline_seconds only when fulfillment is "async" or "confirm" — a synchronous card delivers inside the system-wide response budget and names no deadline of its own. result is required on every card except one whose fulfillment is "ship". A "ship" card, a parcel, names ship_within_seconds and is the only card that may; it declares no result and no fulfill_deadline_seconds, its price_check is "handler", and it asks for no ship_to among its params, because the purchase carries the address in a block of its own.';
|
|
445
588
|
/**
|
|
446
589
|
* The words on a card that an agent reads: the title, the description, and
|
|
447
590
|
* the title of each field the card declares.
|
|
@@ -546,8 +689,12 @@ export const CardSchema = CardFieldsSchema.superRefine(cardRules)
|
|
|
546
689
|
* place that picks.
|
|
547
690
|
*/
|
|
548
691
|
export const purchaseCheckFor = (card) => paramSpecToValidator(card.params ?? {}, "purchase");
|
|
549
|
-
/**
|
|
550
|
-
|
|
692
|
+
/**
|
|
693
|
+
* The check this card's delivery is held to: the goods its `result` declared,
|
|
694
|
+
* or for a parcel, which is not delivered with goods at all, its shipment
|
|
695
|
+
* (ADR-0033).
|
|
696
|
+
*/
|
|
697
|
+
export const deliveryCheckFor = (card) => card.result === undefined ? ShipmentSchema : paramSpecToValidator(card.result, "delivery");
|
|
551
698
|
/**
|
|
552
699
|
* The fields of a card as an agent reads it in a catalog.
|
|
553
700
|
*
|
|
@@ -571,11 +718,16 @@ export const deliveryCheckFor = (card) => paramSpecToValidator(card.result, "del
|
|
|
571
718
|
* gateway's, and this document does not claim to know it.
|
|
572
719
|
*
|
|
573
720
|
* Both deadlines stay, because they are the merchant's promise to the agent
|
|
574
|
-
* about how long it may wait, and the agent is told them before it pays.
|
|
575
|
-
*
|
|
576
|
-
*
|
|
577
|
-
*
|
|
578
|
-
*
|
|
721
|
+
* about how long it may wait, and the agent is told them before it pays. The
|
|
722
|
+
* projection writes each only on a mode that has it, and the document says so
|
|
723
|
+
* in words rather than as structure: it takes fields added later (ADR-0006
|
|
724
|
+
* §5), so a field an agent does not expect is one it ignores, not one it can
|
|
725
|
+
* refuse.
|
|
726
|
+
*
|
|
727
|
+
* The mode is a word whose known values are listed beside it, for the same
|
|
728
|
+
* reason. The storefront has no version, so a mode added later reaches agents
|
|
729
|
+
* that still hold this contract, and to them it has to be a card to pass over
|
|
730
|
+
* rather than a catalog they cannot read.
|
|
579
731
|
*
|
|
580
732
|
* `as_of` is added: the moment the price shown here was published. A price
|
|
581
733
|
* with no moment behind it cannot be judged stale, and this is the only
|
|
@@ -588,27 +740,28 @@ export const deliveryCheckFor = (card) => paramSpecToValidator(card.result, "del
|
|
|
588
740
|
* page — so carrying them here would put a foreign catalog's constraint in
|
|
589
741
|
* front of a reader who has no use for it.
|
|
590
742
|
*
|
|
591
|
-
*
|
|
592
|
-
*
|
|
593
|
-
*
|
|
594
|
-
*
|
|
595
|
-
* is deliberately not this. That name exists to satisfy one channel's rules,
|
|
596
|
-
* a merchant may have none, and standing it in for a public identity would
|
|
597
|
-
* answer a question — who "we" are to the buyer, and who the merchant is —
|
|
598
|
-
* that is still open.
|
|
743
|
+
* Who sells is here as the merchant gave it, a name and the site of their
|
|
744
|
+
* shop (ADR-0034), and as nothing more: no profile, no contact of ours, and no
|
|
745
|
+
* claim that either was checked. Who "we" are to the buyer is a question this
|
|
746
|
+
* document still does not answer.
|
|
599
747
|
*/
|
|
600
|
-
const
|
|
748
|
+
export const PublicCardSchema = z
|
|
749
|
+
.looseObject({
|
|
601
750
|
/** Our catalog identifier, the one a purchase, a receipt and a status use. */
|
|
602
751
|
id: IdentifierSchema,
|
|
603
752
|
title: TitleSchema,
|
|
604
753
|
description: DescriptionSchema,
|
|
605
754
|
/** The price in the catalog: what an agent compares when it is choosing. */
|
|
606
|
-
price: MoneySchema,
|
|
755
|
+
price: MoneySchema.loose(),
|
|
607
756
|
/** When the price above was published. */
|
|
608
757
|
as_of: TimestampSchema,
|
|
609
758
|
/** What the agent has to supply to buy. Absent when the purchase needs no input. */
|
|
610
|
-
params:
|
|
611
|
-
|
|
759
|
+
params: ReadDeclarationSchema.optional(),
|
|
760
|
+
/**
|
|
761
|
+
* What the agent receives. Absent on a parcel, whose mode fixes it: the
|
|
762
|
+
* record of the parcel's shipment.
|
|
763
|
+
*/
|
|
764
|
+
result: declaringAResult(ReadDeclarationSchema).optional(),
|
|
612
765
|
/**
|
|
613
766
|
* Whether the merchant is asked for this product's price and availability at
|
|
614
767
|
* the moment of purchase, so the sale may go through at a price other than
|
|
@@ -619,30 +772,36 @@ const PublicCardFieldsSchema = z.strictObject({
|
|
|
619
772
|
* about to move, read as true it distrusts a price that never moves.
|
|
620
773
|
*/
|
|
621
774
|
price_checked_at_purchase: z.boolean(),
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
775
|
+
/**
|
|
776
|
+
* Who sells this product, in the merchant's own words and unchecked. It is
|
|
777
|
+
* read with the catalog rather than copied onto the card at publishing, so
|
|
778
|
+
* a merchant who changes their name or gives a site is found by it on every
|
|
779
|
+
* card they already sell.
|
|
780
|
+
*/
|
|
781
|
+
seller: SellerSchema.loose(),
|
|
782
|
+
/**
|
|
783
|
+
* How the product is sold: "sync", "async" or "confirm" today, and a word
|
|
784
|
+
* added later reaches this same document. A reader keeps a default arm,
|
|
785
|
+
* and a card whose mode it does not know is one to pass over.
|
|
786
|
+
*
|
|
787
|
+
* Two branches rather than a bare string, so the known values cross into
|
|
788
|
+
* the exported document as a list a client can switch over, beside the
|
|
789
|
+
* branch that reads any other word (`OpenWordSchema`). A declared field's
|
|
790
|
+
* type, inside params and result, stays a closed list: a card with a type
|
|
791
|
+
* a reader does not know is one it cannot fill in, and it is passed over
|
|
792
|
+
* like a card of an unknown mode.
|
|
793
|
+
*/
|
|
794
|
+
fulfillment: z.union([FulfillmentSchema, OpenWordSchema]),
|
|
795
|
+
/** On "async" and "confirm": how long the merchant has to deliver, in seconds. */
|
|
796
|
+
fulfill_deadline_seconds: z.int().positive().optional(),
|
|
797
|
+
/** On "confirm": how long the merchant has to say yes, in seconds. */
|
|
798
|
+
confirm_deadline_seconds: z.int().positive().optional(),
|
|
799
|
+
/**
|
|
800
|
+
* On "ship": how long the merchant has to hand the parcel to a carrier,
|
|
801
|
+
* counted from the charge, in seconds. When it leaves, not when it arrives.
|
|
802
|
+
*/
|
|
803
|
+
ship_within_seconds: z.int().positive().optional(),
|
|
804
|
+
})
|
|
646
805
|
.meta({
|
|
647
806
|
// Everything below is written in prose above as well, and it has to be
|
|
648
807
|
// written twice: the reader this matters most to is the one holding the
|
|
@@ -650,7 +809,7 @@ export const PublicCardSchema = z
|
|
|
650
809
|
// money on what this card claims. `as_of` in particular means something
|
|
651
810
|
// narrower here than the same name means elsewhere in this contract, and a
|
|
652
811
|
// reader who assumed otherwise would trust a stale number.
|
|
653
|
-
description: "A product an agent can buy, projected from the card its merchant published. as_of is when the price shown here was published, and nothing more: on a card whose price is checked at purchase it says nothing about how fresh that check will be — elsewhere in this contract the same name means the moment a live answer was true. price_checked_at_purchase says the merchant is asked for a price at the moment of purchase, not that they answer; what happens when they are silent depends on the mode and belongs to the gateway. The number above is what an agent compares when choosing and may not be what the sale goes through at.
|
|
812
|
+
description: "A product an agent can buy, projected from the card its merchant published. as_of is when the price shown here was published, and nothing more: on a card whose price is checked at purchase it says nothing about how fresh that check will be — elsewhere in this contract the same name means the moment a live answer was true. price_checked_at_purchase says the merchant is asked for a price at the moment of purchase, not that they answer; what happens when they are silent depends on the mode and belongs to the gateway. The number above is what an agent compares when choosing and may not be what the sale goes through at. Three rules hold beyond the shape: a synchronous product names no delivery deadline, because it is delivered inside a response budget that is the same for every product on the platform; only a product whose merchant is asked to confirm names a confirmation deadline; and a parcel, fulfillment \"ship\", names ship_within_seconds — the time to hand it to a carrier counted from the charge, not the time it arrives — and no result, because what the agent receives is the record of its shipment, while every other product names a result. On a parcel the price shown is the goods without shipping, and the purchase goes through at the merchant's answer for the whole, shipping to the buyer's place included. seller is who sells, as the merchant gave it: Agentify did not check the name or the site. fulfillment is a word whose known values are listed beside it, and more may be added: a reader keeps a default arm, and a card whose mode it does not know is one to pass over, not a reason to stop reading the catalog. This document and every part inside it may also gain fields; a reader ignores the ones it does not know. The type of a declared field in params and result is a closed list, and a card with a type a reader does not know is one to pass over too.",
|
|
654
813
|
});
|
|
655
814
|
/**
|
|
656
815
|
* The card as an agent reads it, built from the card the merchant published.
|
|
@@ -662,18 +821,20 @@ export const PublicCardSchema = z
|
|
|
662
821
|
* every agent by default, and the first anybody heard of it would be a
|
|
663
822
|
* merchant's pricing address in a public catalog.
|
|
664
823
|
*
|
|
665
|
-
* The
|
|
666
|
-
* issued when it was published,
|
|
824
|
+
* The three things the card cannot know are passed in: the catalog identifier
|
|
825
|
+
* we issued when it was published, the moment its price was published, and
|
|
826
|
+
* who sells it as their merchant stands now.
|
|
667
827
|
*/
|
|
668
828
|
export const publicCardOf = (card, issued) => {
|
|
669
829
|
const common = {
|
|
670
830
|
id: issued.id,
|
|
831
|
+
seller: issued.seller,
|
|
671
832
|
title: card.title,
|
|
672
833
|
description: card.description,
|
|
673
834
|
price: card.price,
|
|
674
835
|
as_of: issued.as_of,
|
|
675
836
|
...(card.params === undefined ? {} : { params: card.params }),
|
|
676
|
-
result: card.result,
|
|
837
|
+
...(card.result === undefined ? {} : { result: card.result }),
|
|
677
838
|
price_checked_at_purchase: card.price_check !== undefined,
|
|
678
839
|
};
|
|
679
840
|
switch (card.fulfillment) {
|
|
@@ -698,6 +859,14 @@ export const publicCardOf = (card, issued) => {
|
|
|
698
859
|
? {}
|
|
699
860
|
: { fulfill_deadline_seconds: card.fulfill_deadline_seconds }),
|
|
700
861
|
};
|
|
862
|
+
case "ship":
|
|
863
|
+
return {
|
|
864
|
+
...common,
|
|
865
|
+
fulfillment: "ship",
|
|
866
|
+
...(card.ship_within_seconds === undefined
|
|
867
|
+
? {}
|
|
868
|
+
: { ship_within_seconds: card.ship_within_seconds }),
|
|
869
|
+
};
|
|
701
870
|
}
|
|
702
871
|
};
|
|
703
872
|
/**
|
|
@@ -732,9 +901,40 @@ const exampleOf = (spec) => Object.fromEntries(Object.entries(spec).map(([name,
|
|
|
732
901
|
* inside another schema, so that one line is dropped here.
|
|
733
902
|
*/
|
|
734
903
|
const purchaseBodySchemaOf = (card) => {
|
|
735
|
-
const { $schema, ...body } = z.toJSONSchema(z.strictObject({
|
|
904
|
+
const { $schema, ...body } = z.toJSONSchema(z.strictObject({
|
|
905
|
+
params: purchaseCheckFor(card),
|
|
906
|
+
// A parcel's purchase carries the address it goes to beside its
|
|
907
|
+
// parameters, and is refused without one (ADR-0032).
|
|
908
|
+
...(card.fulfillment === "ship" ? { ship_to: ShipToSchema } : {}),
|
|
909
|
+
}));
|
|
736
910
|
return body;
|
|
737
911
|
};
|
|
912
|
+
/**
|
|
913
|
+
* Where a parcel goes, in a listing's example purchase: Agentify's own office
|
|
914
|
+
* (ADR-0033), with the number taken out of it, so that the example is a real
|
|
915
|
+
* place and nobody's home.
|
|
916
|
+
*/
|
|
917
|
+
const LISTED_SHIP_TO = {
|
|
918
|
+
name: "Agentify",
|
|
919
|
+
line_one: "Jl. Raya Kediri, Beraban",
|
|
920
|
+
line_two: "Nuanu Creative City",
|
|
921
|
+
city: "Tabanan",
|
|
922
|
+
state: "BA",
|
|
923
|
+
postal_code: "82121",
|
|
924
|
+
country: "ID",
|
|
925
|
+
phone_number: "+62 000 0000 0000",
|
|
926
|
+
};
|
|
927
|
+
/**
|
|
928
|
+
* A recorded shipment, in a listing's example output, written as every other
|
|
929
|
+
* example here is: each field standing for what goes there, and the instant
|
|
930
|
+
* at the start of the clock rather than a date that looks like one somebody
|
|
931
|
+
* shipped on.
|
|
932
|
+
*/
|
|
933
|
+
const LISTED_SHIPMENT = {
|
|
934
|
+
carrier: "string",
|
|
935
|
+
tracking_number: "string",
|
|
936
|
+
shipped_at: "1970-01-01T00:00:00Z",
|
|
937
|
+
};
|
|
738
938
|
/**
|
|
739
939
|
* The card as a discovery catalog reads it.
|
|
740
940
|
*
|
|
@@ -754,9 +954,14 @@ export const bazaarDeclarationOf = (card, listed) => ({
|
|
|
754
954
|
...(listed.serviceName === null ? {} : { serviceName: listed.serviceName }),
|
|
755
955
|
...(card.tags === undefined ? {} : { tags: card.tags }),
|
|
756
956
|
},
|
|
757
|
-
input: {
|
|
957
|
+
input: {
|
|
958
|
+
params: exampleOf(card.params ?? {}),
|
|
959
|
+
...(card.fulfillment === "ship" ? { ship_to: LISTED_SHIP_TO } : {}),
|
|
960
|
+
},
|
|
758
961
|
inputSchema: purchaseBodySchemaOf(card),
|
|
759
|
-
|
|
962
|
+
// What the agent is finally handed: the goods the card declared, or for a
|
|
963
|
+
// parcel the record of its shipment.
|
|
964
|
+
output: { example: card.result === undefined ? LISTED_SHIPMENT : exampleOf(card.result) },
|
|
760
965
|
});
|
|
761
966
|
/**
|
|
762
967
|
* One card as the merchant who published it reads it back.
|
package/dist/envelope.d.ts
CHANGED
|
@@ -73,12 +73,35 @@ export declare const WORKER_ENVELOPE_PAYLOADS: Readonly<{
|
|
|
73
73
|
as_of: z.ZodISODateTime;
|
|
74
74
|
}, z.core.$strict>;
|
|
75
75
|
price_id: z.ZodOptional<z.ZodString>;
|
|
76
|
+
ship_to: z.ZodOptional<z.ZodUnion<readonly [z.ZodObject<{
|
|
77
|
+
name: z.ZodString;
|
|
78
|
+
line_one: z.ZodString;
|
|
79
|
+
line_two: z.ZodOptional<z.ZodString>;
|
|
80
|
+
city: z.ZodString;
|
|
81
|
+
state: z.ZodOptional<z.ZodString>;
|
|
82
|
+
postal_code: z.ZodOptional<z.ZodString>;
|
|
83
|
+
country: z.ZodString;
|
|
84
|
+
phone_number: z.ZodString;
|
|
85
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
86
|
+
country: z.ZodString;
|
|
87
|
+
state: z.ZodOptional<z.ZodString>;
|
|
88
|
+
city: z.ZodString;
|
|
89
|
+
postal_code: z.ZodOptional<z.ZodString>;
|
|
90
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
91
|
+
erased_at: z.ZodISODateTime;
|
|
92
|
+
}, z.core.$strict>]>>;
|
|
76
93
|
test: z.ZodBoolean;
|
|
77
94
|
}, z.core.$strict>;
|
|
78
95
|
/** "How much is this and is it there", asked before a sale goes through. */
|
|
79
96
|
readonly quote_request: z.ZodObject<{
|
|
80
97
|
merchant_item_id: z.ZodString;
|
|
81
98
|
params: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
99
|
+
ship_to: z.ZodOptional<z.ZodObject<{
|
|
100
|
+
country: z.ZodString;
|
|
101
|
+
state: z.ZodOptional<z.ZodString>;
|
|
102
|
+
city: z.ZodString;
|
|
103
|
+
postal_code: z.ZodOptional<z.ZodString>;
|
|
104
|
+
}, z.core.$strict>>;
|
|
82
105
|
price_id: z.ZodString;
|
|
83
106
|
purpose: z.ZodEnum<{
|
|
84
107
|
purchase: "purchase";
|
|
@@ -128,6 +151,23 @@ export declare const WorkerEnvelopeSchema: z.ZodDiscriminatedUnion<[z.ZodObject<
|
|
|
128
151
|
as_of: z.ZodISODateTime;
|
|
129
152
|
}, z.core.$strict>;
|
|
130
153
|
price_id: z.ZodOptional<z.ZodString>;
|
|
154
|
+
ship_to: z.ZodOptional<z.ZodUnion<readonly [z.ZodObject<{
|
|
155
|
+
name: z.ZodString;
|
|
156
|
+
line_one: z.ZodString;
|
|
157
|
+
line_two: z.ZodOptional<z.ZodString>;
|
|
158
|
+
city: z.ZodString;
|
|
159
|
+
state: z.ZodOptional<z.ZodString>;
|
|
160
|
+
postal_code: z.ZodOptional<z.ZodString>;
|
|
161
|
+
country: z.ZodString;
|
|
162
|
+
phone_number: z.ZodString;
|
|
163
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
164
|
+
country: z.ZodString;
|
|
165
|
+
state: z.ZodOptional<z.ZodString>;
|
|
166
|
+
city: z.ZodString;
|
|
167
|
+
postal_code: z.ZodOptional<z.ZodString>;
|
|
168
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
169
|
+
erased_at: z.ZodISODateTime;
|
|
170
|
+
}, z.core.$strict>]>>;
|
|
131
171
|
test: z.ZodBoolean;
|
|
132
172
|
}, z.core.$strict>;
|
|
133
173
|
}, z.core.$strict>, z.ZodObject<{
|
|
@@ -137,6 +177,12 @@ export declare const WorkerEnvelopeSchema: z.ZodDiscriminatedUnion<[z.ZodObject<
|
|
|
137
177
|
payload: z.ZodObject<{
|
|
138
178
|
merchant_item_id: z.ZodString;
|
|
139
179
|
params: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
180
|
+
ship_to: z.ZodOptional<z.ZodObject<{
|
|
181
|
+
country: z.ZodString;
|
|
182
|
+
state: z.ZodOptional<z.ZodString>;
|
|
183
|
+
city: z.ZodString;
|
|
184
|
+
postal_code: z.ZodOptional<z.ZodString>;
|
|
185
|
+
}, z.core.$strict>>;
|
|
140
186
|
price_id: z.ZodString;
|
|
141
187
|
purpose: z.ZodEnum<{
|
|
142
188
|
purchase: "purchase";
|