@nymbalhq/types 1.4.0 → 1.6.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/index.d.ts CHANGED
@@ -24,6 +24,7 @@ declare class ValidationError extends NymbalError {
24
24
  constructor(message: string, options?: {
25
25
  cause?: unknown;
26
26
  context?: ErrorContext;
27
+ code?: string;
27
28
  });
28
29
  }
29
30
  declare class NotFoundError extends NymbalError {
@@ -71,6 +72,19 @@ declare class CheckoutError extends NymbalError {
71
72
  context?: ErrorContext;
72
73
  });
73
74
  }
75
+ /** A cart command that would take a line above `max`; `onCart` is what the line held before it. */
76
+ declare class CartLimitError extends NymbalError {
77
+ constructor(variantId: string, max: number, onCart: number);
78
+ }
79
+ /** Why a review was not taken. `not_a_buyer` is reserved: any signed-in customer may review. */
80
+ type ReviewRefusal = 'submit_unsupported' | 'already_reviewed' | 'not_a_buyer' | 'rejected';
81
+ declare class ReviewRefusedError extends NymbalError {
82
+ readonly refusal: ReviewRefusal;
83
+ constructor(refusal: ReviewRefusal, message?: string, options?: {
84
+ cause?: unknown;
85
+ context?: ErrorContext;
86
+ });
87
+ }
74
88
  declare class StatusTransitionError extends NymbalError {
75
89
  constructor(entity: string, fromStatus: string, toStatus: string, options?: {
76
90
  cause?: unknown;
@@ -155,26 +169,6 @@ interface Category {
155
169
  createdAt: string;
156
170
  }
157
171
 
158
- interface CartItem {
159
- variantId: string;
160
- productId: string;
161
- productName: string;
162
- variantName: string;
163
- priceMinor: number;
164
- qty: number;
165
- imageUrl: string;
166
- }
167
- interface Cart {
168
- token: string;
169
- customerId: string | null;
170
- items: CartItem[];
171
- subtotalMinor: number;
172
- currency: string;
173
- expiresAt: string;
174
- createdAt: string;
175
- updatedAt: string;
176
- }
177
-
178
172
  type OrderStatus = 'pending' | 'confirmed' | 'processing' | 'shipped' | 'delivered' | 'cancelled' | 'refunded' | 'partially_refunded';
179
173
  declare const ORDER_STATUS_TRANSITIONS: Record<OrderStatus, readonly OrderStatus[]>;
180
174
  declare function canTransitionOrder(from: OrderStatus, to: OrderStatus): boolean;
@@ -204,6 +198,10 @@ interface OrderLineItem {
204
198
  lineTotalMinor: number;
205
199
  imageUrl: string;
206
200
  }
201
+ /** Where an order came from: the storefront, an import, or the shopping agent that opened its cart. */
202
+ type OrderSource = 'storefront' | 'import' | `agent:${string}`;
203
+ /** The source a cart or order opened by the named agent carries. */
204
+ declare function agentSource(name: string): `agent:${string}`;
207
205
  interface Order {
208
206
  id: string;
209
207
  orderNumber: string;
@@ -229,6 +227,7 @@ interface Order {
229
227
  /** Σ of the order's succeeded refunds (or, for an import or a pre-refund-table order, what was refunded then). */
230
228
  refundedMinor: number;
231
229
  captureMethod: CaptureMethod | null;
230
+ source: OrderSource;
232
231
  createdAt: string;
233
232
  updatedAt: string;
234
233
  }
@@ -237,6 +236,13 @@ interface Order {
237
236
  * the key stays out of access logs that record request URLs.
238
237
  */
239
238
  declare const ORDER_KEY_HEADER = "x-nymbal-order-key";
239
+ /** The request header that carries the order's email beside an expired order key. Never a query parameter either. */
240
+ declare const ORDER_EMAIL_HEADER = "x-nymbal-order-email";
241
+ /**
242
+ * The API's attestation of a shopper's address on a page request it forwards to the storefront. The storefront server
243
+ * echoes it on the API calls it makes for that shopper, so they count against the shopper's address, not its own.
244
+ */
245
+ declare const SHOPPER_ATTESTATION_HEADER = "x-nymbal-shopper";
240
246
  /** Who took the money: the payments provider, the merchant recording an offline payment, or an imported history. */
241
247
  type CaptureMethod = 'provider' | 'manual' | 'import';
242
248
  type OrderRefundStatus = 'pending' | 'succeeded' | 'failed';
@@ -275,6 +281,33 @@ interface OrderHistoryEntry {
275
281
  timestamp: string;
276
282
  }
277
283
 
284
+ /** The most of one variant a cart line holds. */
285
+ declare const CART_LINE_MAX_QTY = 99;
286
+ interface CartItem {
287
+ variantId: string;
288
+ productId: string;
289
+ /** The product page's slug; lines stored before lines carried one have none. */
290
+ productSlug?: string;
291
+ productName: string;
292
+ variantName: string;
293
+ priceMinor: number;
294
+ qty: number;
295
+ imageUrl: string;
296
+ }
297
+ /** Who opened a cart: the storefront or a shopping agent. An import opens none. */
298
+ type CartSource = Exclude<OrderSource, 'import'>;
299
+ interface Cart {
300
+ token: string;
301
+ customerId: string | null;
302
+ items: CartItem[];
303
+ subtotalMinor: number;
304
+ currency: string;
305
+ source: CartSource;
306
+ expiresAt: string;
307
+ createdAt: string;
308
+ updatedAt: string;
309
+ }
310
+
278
311
  /** The lifecycle events an order's timeline shows, each one from an `order_history` row. */
279
312
  declare const ORDER_TIMELINE_KINDS: readonly ["placed", "paid", "shipped", "delivered", "cancelled", "partially_refunded", "refunded"];
280
313
  type OrderTimelineKind = (typeof ORDER_TIMELINE_KINDS)[number];
@@ -283,8 +316,17 @@ interface OrderTimelineEntry {
283
316
  /** ISO 8601, UTC. */
284
317
  at: string;
285
318
  }
286
- /** An order as a storefront reads it; `timeline` is optional so an adapter that returns a plain `Order` still fits. */
287
- interface ShopperOrder extends Order {
319
+ /** A shipping address as an order's key holder reads it: no phone, no company. */
320
+ type ShopperAddress = Omit<Address, 'phone' | 'company'>;
321
+ /** What only the order's signed-in owner reads, or the store's own records, beside what its key holder reads. */
322
+ type OwnerOrStoreField = 'id' | 'email' | 'billingAddress' | 'customerId' | 'sequence' | 'capturedMinor' | 'capturedAt' | 'refundedMinor' | 'captureMethod' | 'notes' | 'metadata' | 'paymentIntentId' | 'source' | 'updatedAt';
323
+ /**
324
+ * An order as a storefront reads it. A key holder reads the confirmation page's fields; its owner's session adds the
325
+ * email, both full addresses and the order's id. Every other field is optional, so an adapter that returns a plain
326
+ * `Order` still fits.
327
+ */
328
+ interface ShopperOrder extends Omit<Order, OwnerOrStoreField | 'shippingAddress'>, Partial<Pick<Order, OwnerOrStoreField>> {
329
+ shippingAddress: ShopperAddress;
288
330
  timeline?: OrderTimelineEntry[];
289
331
  }
290
332
 
@@ -353,6 +395,25 @@ interface Review {
353
395
  moderatedAt: string | null;
354
396
  moderatedBy: string | null;
355
397
  }
398
+ /** A review as the public list publishes it: no customer or order id, only whether a purchase verified it. */
399
+ interface PublicReview {
400
+ id: string;
401
+ productId: string;
402
+ rating: number;
403
+ title: string;
404
+ body: string;
405
+ verified: boolean;
406
+ submittedAt: string;
407
+ }
408
+ interface PublicReviewsResult {
409
+ items: PublicReview[];
410
+ nextCursor: string | null;
411
+ }
412
+ /** A product's rating as the product routes serve it: the average to one decimal and the approved review count. */
413
+ interface ProductRating {
414
+ average: number;
415
+ count: number;
416
+ }
356
417
  interface AggregateRating {
357
418
  productId: string;
358
419
  average: number;
@@ -369,6 +430,11 @@ interface PaymentIntentParams {
369
430
  /** Where the provider sends its receipt (Stripe's `receipt_email`). */
370
431
  receiptEmail?: string;
371
432
  metadata?: Record<string, string>;
433
+ /**
434
+ * A payment credential an agent was granted for this charge (a Stripe Shared Payment Token): the intent is confirmed
435
+ * with it at creation. Only an adapter with the `delegated` capability takes one.
436
+ */
437
+ delegatedToken?: string;
372
438
  }
373
439
  interface PaymentIntent {
374
440
  id: string;
@@ -434,6 +500,8 @@ declare const EVT_ORDER_REFUNDED = "order.refunded.v1";
434
500
  declare const EVT_ORDER_PARTIALLY_REFUNDED = "order.partially_refunded.v1";
435
501
  declare const EVT_ORDER_STATUS_CHANGED = "order.status_changed.v1";
436
502
  declare const EVT_ORDER_CONFIRMATION_RESEND_REQUESTED = "order.confirmation_resend_requested.v1";
503
+ /** An imported order taken back out of the store, with every row it owned. */
504
+ declare const EVT_ORDER_DELETED = "order.deleted.v1";
437
505
  declare const EVT_INVENTORY_CHANGED = "inventory.changed.v1";
438
506
  declare const EVT_INVENTORY_RESERVED = "inventory.reserved.v1";
439
507
  declare const EVT_INVENTORY_RELEASED = "inventory.released.v1";
@@ -455,12 +523,23 @@ declare const EVT_PAYMENT_CAPTURED = "payment.captured.v1";
455
523
  declare const EVT_PAYMENT_FAILED = "payment.failed.v1";
456
524
  declare const EVT_PAYMENT_REFUNDED = "payment.refunded.v1";
457
525
  declare const EVT_ALERT_REQUESTED = "alert.requested.v1";
526
+ /** A subscribe for an alert already active: the subscription stands and nothing is sent. */
527
+ declare const EVT_ALERT_REPEATED = "alert.repeated.v1";
458
528
  declare const EVT_ALERT_CONFIRMED = "alert.confirmed.v1";
459
529
  declare const EVT_ALERT_UNSUBSCRIBED = "alert.unsubscribed.v1";
460
530
  declare const EVT_ALERT_SENT = "alert.sent.v1";
531
+ /** A pending subscription's confirmation was sent; another goes only once the confirmation interval has passed. */
532
+ declare const EVT_ALERT_CONFIRMATION_SENT = "alert.confirmation_sent.v1";
533
+ /** A review the reviews adapter took for the store; the kernel resolved its reviewer and the order it is verified by. */
534
+ declare const EVT_REVIEW_SUBMITTED = "review.submitted.v1";
535
+ declare const EVT_PROPOSAL_CREATED = "proposal.created.v1";
536
+ declare const EVT_PROPOSAL_APPROVED = "proposal.approved.v1";
537
+ declare const EVT_PROPOSAL_REJECTED = "proposal.rejected.v1";
538
+ declare const EVT_PROPOSAL_APPLIED = "proposal.applied.v1";
539
+ declare const EVT_PROPOSAL_FAILED = "proposal.failed.v1";
461
540
  declare const EVT_ADAPTER_ERROR = "adapter.error.v1";
462
541
  declare const EVT_SETTINGS_CHANGED = "settings.changed.v1";
463
- declare const STANDARD_EVENT_TYPES: readonly ["product.created.v1", "product.updated.v1", "product.deleted.v1", "product.published.v1", "product.unpublished.v1", "product.viewed.v1", "product.restocked.v1", "product.variant_price_changed.v1", "category.created.v1", "category.updated.v1", "category.deleted.v1", "order.placed.v1", "order.paid.v1", "order.fulfilled.v1", "order.shipped.v1", "order.delivered.v1", "order.cancelled.v1", "order.refunded.v1", "order.partially_refunded.v1", "order.status_changed.v1", "order.confirmation_resend_requested.v1", "inventory.changed.v1", "inventory.reserved.v1", "inventory.released.v1", "inventory.low_stock.v1", "inventory.out_of_stock.v1", "customer.created.v1", "customer.updated.v1", "customer.deleted.v1", "visitor.merged.v1", "cart.created.v1", "cart.item_added.v1", "cart.item_removed.v1", "cart.updated.v1", "cart.abandoned.v1", "cart.converted.v1", "payment.intent_created.v1", "payment.captured.v1", "payment.failed.v1", "payment.refunded.v1", "alert.requested.v1", "alert.confirmed.v1", "alert.unsubscribed.v1", "alert.sent.v1", "adapter.error.v1", "settings.changed.v1"];
542
+ declare const STANDARD_EVENT_TYPES: readonly ["product.created.v1", "product.updated.v1", "product.deleted.v1", "product.published.v1", "product.unpublished.v1", "product.viewed.v1", "product.restocked.v1", "product.variant_price_changed.v1", "category.created.v1", "category.updated.v1", "category.deleted.v1", "order.placed.v1", "order.paid.v1", "order.fulfilled.v1", "order.shipped.v1", "order.delivered.v1", "order.cancelled.v1", "order.refunded.v1", "order.partially_refunded.v1", "order.status_changed.v1", "order.confirmation_resend_requested.v1", "order.deleted.v1", "inventory.changed.v1", "inventory.reserved.v1", "inventory.released.v1", "inventory.low_stock.v1", "inventory.out_of_stock.v1", "customer.created.v1", "customer.updated.v1", "customer.deleted.v1", "visitor.merged.v1", "cart.created.v1", "cart.item_added.v1", "cart.item_removed.v1", "cart.updated.v1", "cart.abandoned.v1", "cart.converted.v1", "payment.intent_created.v1", "payment.captured.v1", "payment.failed.v1", "payment.refunded.v1", "alert.requested.v1", "alert.repeated.v1", "alert.confirmed.v1", "alert.unsubscribed.v1", "alert.sent.v1", "alert.confirmation_sent.v1", "review.submitted.v1", "proposal.created.v1", "proposal.approved.v1", "proposal.rejected.v1", "proposal.applied.v1", "proposal.failed.v1", "adapter.error.v1", "settings.changed.v1"];
464
543
 
465
544
  /** What a shopper asks to be told about a variant: that it is back in stock, or that its price dropped. */
466
545
  type AlertKind = 'back_in_stock' | 'price_drop';
@@ -470,6 +549,114 @@ type AlertKind = 'back_in_stock' | 'price_drop';
470
549
  */
471
550
  type AlertStatus = 'pending' | 'active' | 'fired' | 'unsubscribed';
472
551
 
552
+ /** Where an agent's write stands: waiting, decided, then run. */
553
+ type ProposalStatus = 'pending' | 'approved' | 'rejected' | 'applied' | 'failed';
554
+ /** Who decided a proposal: an admin, or a policy the store's config sets. */
555
+ type ProposalDecider = {
556
+ kind: 'admin';
557
+ id: string;
558
+ } | {
559
+ kind: 'policy';
560
+ rule: 'agents.mcp.writes' | 'agents.autoApprove';
561
+ };
562
+ /** One proposal as the admin reads it. A handle's value (a cart id) is never served: only its argument's name. */
563
+ interface ProposalView {
564
+ id: string;
565
+ tool: string;
566
+ title: string;
567
+ command: string;
568
+ /** The arguments the agent sent, less its idempotency key and its handles. */
569
+ args: Record<string, unknown>;
570
+ handles: string[];
571
+ idempotencyKey: string | null;
572
+ status: ProposalStatus;
573
+ proposer: {
574
+ userId: string | null;
575
+ agent: {
576
+ name: string;
577
+ version?: string;
578
+ };
579
+ };
580
+ correlationId: string;
581
+ createdAt: string;
582
+ decision?: {
583
+ by: ProposalDecider;
584
+ at: string;
585
+ reason?: string;
586
+ };
587
+ /** What the route answered when the proposal ran. */
588
+ outcome?: {
589
+ status: number;
590
+ code?: string;
591
+ message?: string;
592
+ };
593
+ /** What a pending write would change, read from the store when the proposal is read on its own. */
594
+ preview?: ProposalPreview;
595
+ }
596
+ /** The commands whose pending proposal, read on its own, carries a preview. */
597
+ declare const PREVIEWED_COMMANDS: readonly string[];
598
+ /** One value a pending write changes, as it is now beside what the write would make it. */
599
+ interface ProposalChange {
600
+ /** What changes, as the admin reads it: "Name", "Price of Large", "Stock", "Refunded", "Status", "Media". */
601
+ label: string;
602
+ /** `money`: minor units of `ProposalPreview.currency`; `collection`: item or key counts, with `changed`. */
603
+ kind: 'value' | 'money' | 'collection';
604
+ current: string | number | null;
605
+ proposed: string | number | null;
606
+ changed?: boolean;
607
+ }
608
+ /** What a pending write acts on and what it changes there. */
609
+ interface ProposalPreview {
610
+ /** What the write acts on, read from the store now; null when the id names nothing. */
611
+ target: {
612
+ kind: 'product' | 'variant' | 'order';
613
+ id: string;
614
+ label: string;
615
+ } | null;
616
+ changes: ProposalChange[];
617
+ currency: string;
618
+ }
619
+ interface ProposalPage {
620
+ items: ProposalView[];
621
+ nextCursor: string | null;
622
+ /** Every proposal still waiting for a decision, whatever the page holds. */
623
+ pending: number;
624
+ }
625
+
626
+ /** Where a Settings field's value comes from: the config block, its declared env, a saved value, or nowhere. */
627
+ type SettingSourceName = 'config' | 'env' | 'settings';
628
+ /** One declared field as `GET /api/admin/settings` lists it; a secret never carries its value. */
629
+ interface SettingFieldView {
630
+ path: string;
631
+ label: string;
632
+ secret: boolean;
633
+ state: 'unset' | 'set';
634
+ source: SettingSourceName | null;
635
+ updatedAt: string | null;
636
+ /** Non-secret fields only. */
637
+ value?: unknown;
638
+ }
639
+ /** A slot whose provider declares settings, with its fields. */
640
+ interface SettingsSlotView {
641
+ slot: string;
642
+ provider: string;
643
+ fields: SettingFieldView[];
644
+ }
645
+ interface SettingsListing {
646
+ slots: SettingsSlotView[];
647
+ }
648
+ /**
649
+ * What a `PUT` or `DELETE` of a field answers: the change applies at the next start. `source` is where the field
650
+ * comes from afterwards: a `DELETE` of a row the config or environment shadows leaves that source.
651
+ */
652
+ interface SettingWriteResult {
653
+ slot: string;
654
+ path: string;
655
+ state: 'unset' | 'set';
656
+ source: SettingSourceName | null;
657
+ restartRequired: true;
658
+ }
659
+
473
660
  interface ProductSnapshot extends Product {
474
661
  variants: Variant[];
475
662
  categoryIds: string[];
@@ -575,6 +762,13 @@ interface OrderStatusChangedV1Payload {
575
762
  interface OrderConfirmationResendRequestedV1Payload {
576
763
  orderId: string;
577
764
  }
765
+ /** An imported order taken back out. It carries what the order's documents are keyed by, as its row is gone. */
766
+ interface OrderDeletedV1Payload {
767
+ orderId: string;
768
+ orderNumber: string;
769
+ customerId: string | null;
770
+ createdAt: string;
771
+ }
578
772
  interface InventoryChangedV1Payload {
579
773
  variantId: string;
580
774
  previousQty: number;
@@ -615,6 +809,8 @@ interface CustomerCreatedV1Payload {
615
809
  customerId: string;
616
810
  email: string;
617
811
  customer?: CustomerSnapshot;
812
+ /** `'import'` for a customer an import brought over, who is not welcomed; absent for one who registered. */
813
+ origin?: 'import';
618
814
  }
619
815
  interface CustomerUpdatedV1Payload {
620
816
  customerId: string;
@@ -683,6 +879,7 @@ interface AlertRequestedV1Payload {
683
879
  variantId: string;
684
880
  productId: string;
685
881
  }
882
+ type AlertRepeatedV1Payload = AlertRequestedV1Payload;
686
883
  interface AlertConfirmedV1Payload {
687
884
  subscriptionId: string;
688
885
  }
@@ -698,6 +895,45 @@ interface AlertSentV1Payload {
698
895
  */
699
896
  triggerEventId: string;
700
897
  }
898
+ interface AlertConfirmationSentV1Payload {
899
+ subscriptionId: string;
900
+ kind: AlertKind;
901
+ /** The alert.requested.v1 the confirmation answered. */
902
+ requestEventId: string;
903
+ }
904
+ interface ReviewSubmittedV1Payload {
905
+ reviewId: string;
906
+ productId: string;
907
+ customerId: string;
908
+ /** The reviewer's paid order holding the product, which makes the review verified; null when there is none. */
909
+ orderId: string | null;
910
+ rating: number;
911
+ }
912
+ interface ProposalCreatedV1Payload {
913
+ proposalId: string;
914
+ tool: string;
915
+ command: string;
916
+ proposerId: string | null;
917
+ agentName: string;
918
+ }
919
+ interface ProposalApprovedV1Payload extends ProposalCreatedV1Payload {
920
+ decidedBy: ProposalDecider;
921
+ }
922
+ interface ProposalRejectedV1Payload extends ProposalApprovedV1Payload {
923
+ reason: string | null;
924
+ }
925
+ interface ProposalAppliedV1Payload extends ProposalCreatedV1Payload {
926
+ outcome: {
927
+ status: number;
928
+ };
929
+ }
930
+ interface ProposalFailedV1Payload extends ProposalCreatedV1Payload {
931
+ outcome: {
932
+ status: number;
933
+ code?: string;
934
+ message?: string;
935
+ };
936
+ }
701
937
  interface AdapterErrorV1Payload {
702
938
  adapterType: string;
703
939
  adapterName: string;
@@ -711,7 +947,7 @@ interface AdapterErrorV1Payload {
711
947
  interface SettingsChangedV1Payload {
712
948
  slot: string;
713
949
  path: string;
714
- source: 'settings' | null;
950
+ source: SettingSourceName | null;
715
951
  }
716
952
 
717
953
  interface NymbalEventMap {
@@ -736,6 +972,7 @@ interface NymbalEventMap {
736
972
  [EVT_ORDER_PARTIALLY_REFUNDED]: OrderPartiallyRefundedV1Payload;
737
973
  [EVT_ORDER_STATUS_CHANGED]: OrderStatusChangedV1Payload;
738
974
  [EVT_ORDER_CONFIRMATION_RESEND_REQUESTED]: OrderConfirmationResendRequestedV1Payload;
975
+ [EVT_ORDER_DELETED]: OrderDeletedV1Payload;
739
976
  [EVT_INVENTORY_CHANGED]: InventoryChangedV1Payload;
740
977
  [EVT_INVENTORY_RESERVED]: InventoryReservedV1Payload;
741
978
  [EVT_INVENTORY_RELEASED]: InventoryReleasedV1Payload;
@@ -756,9 +993,17 @@ interface NymbalEventMap {
756
993
  [EVT_PAYMENT_FAILED]: PaymentFailedV1Payload;
757
994
  [EVT_PAYMENT_REFUNDED]: PaymentRefundedV1Payload;
758
995
  [EVT_ALERT_REQUESTED]: AlertRequestedV1Payload;
996
+ [EVT_ALERT_REPEATED]: AlertRepeatedV1Payload;
759
997
  [EVT_ALERT_CONFIRMED]: AlertConfirmedV1Payload;
760
998
  [EVT_ALERT_UNSUBSCRIBED]: AlertUnsubscribedV1Payload;
761
999
  [EVT_ALERT_SENT]: AlertSentV1Payload;
1000
+ [EVT_ALERT_CONFIRMATION_SENT]: AlertConfirmationSentV1Payload;
1001
+ [EVT_REVIEW_SUBMITTED]: ReviewSubmittedV1Payload;
1002
+ [EVT_PROPOSAL_CREATED]: ProposalCreatedV1Payload;
1003
+ [EVT_PROPOSAL_APPROVED]: ProposalApprovedV1Payload;
1004
+ [EVT_PROPOSAL_REJECTED]: ProposalRejectedV1Payload;
1005
+ [EVT_PROPOSAL_APPLIED]: ProposalAppliedV1Payload;
1006
+ [EVT_PROPOSAL_FAILED]: ProposalFailedV1Payload;
762
1007
  [EVT_ADAPTER_ERROR]: AdapterErrorV1Payload;
763
1008
  [EVT_SETTINGS_CHANGED]: SettingsChangedV1Payload;
764
1009
  }
@@ -819,6 +1064,10 @@ interface RequestContext<TBody = unknown, TQuery = Record<string, string | strin
819
1064
  correlationId: string;
820
1065
  logger: Logger;
821
1066
  ip: string;
1067
+ /** The agent a tool call is made for. Only the tool invoker sets it; no HTTP adapter does, so no header can claim it. */
1068
+ agent?: {
1069
+ name: string;
1070
+ };
822
1071
  }
823
1072
  interface ResponseCookie {
824
1073
  name: string;
@@ -863,6 +1112,60 @@ interface HttpAdapter {
863
1112
  start(port: number, host?: string): Promise<void>;
864
1113
  stop(): Promise<void>;
865
1114
  }
1115
+ /** A JSON Schema whose root is an object, as an MCP tool's `inputSchema` must be. */
1116
+ interface JsonSchemaObject {
1117
+ type: 'object';
1118
+ properties?: Record<string, unknown>;
1119
+ required?: string[];
1120
+ [keyword: string]: unknown;
1121
+ }
1122
+ /** Who a tool runs for: the verified bearer's user (none for an anonymous agent) and the agent's client info. */
1123
+ interface Caller {
1124
+ auth?: RequestAuth;
1125
+ agent: {
1126
+ name: string;
1127
+ version?: string;
1128
+ };
1129
+ /** The address the agent's request came from, for the route's rate rule. */
1130
+ ip?: string;
1131
+ }
1132
+ /**
1133
+ * One route of the API as an agent tool. `scope` is the least caller the route's gate admits; `kind` is `read` for a
1134
+ * GET, `session` for a write that changes nothing audited (the cart), `command` for an audited command.
1135
+ */
1136
+ interface ToolDefinition {
1137
+ name: string;
1138
+ title: string;
1139
+ description: string;
1140
+ inputSchema: JsonSchemaObject;
1141
+ scope: 'public' | 'customer' | 'admin';
1142
+ kind: 'read' | 'session' | 'command';
1143
+ route: {
1144
+ method: HttpMethod;
1145
+ path: string;
1146
+ command: string | null | undefined;
1147
+ };
1148
+ }
1149
+ interface ToolResult {
1150
+ content: Array<{
1151
+ type: 'text';
1152
+ text: string;
1153
+ }>;
1154
+ structuredContent?: Record<string, unknown>;
1155
+ isError?: boolean;
1156
+ }
1157
+ /** What a caller of the tool surface may ask of one call beside its arguments. */
1158
+ interface ToolCallOptions {
1159
+ /** The correlation id the call's request, its proposal and its audit entries carry; a fresh one when absent. */
1160
+ correlationId?: string;
1161
+ /** Keep a command as a pending proposal whatever the policy says (`agents.autoApprove`, `agents.mcp.writes`). */
1162
+ proposeWrites?: boolean;
1163
+ }
1164
+ /** The tools a store serves to agents; the transports (HTTP, stdio) bind it. */
1165
+ interface ToolSurface {
1166
+ list(caller: Caller): ToolDefinition[];
1167
+ call(name: string, args: unknown, caller: Caller, options?: ToolCallOptions): Promise<ToolResult>;
1168
+ }
866
1169
 
867
1170
  type HealthStatus = 'healthy' | 'degraded' | 'down';
868
1171
  interface HealthReport {
@@ -919,8 +1222,9 @@ type CommerceSlot = 'payments' | 'email' | 'reviews' | 'search' | 'analytics' |
919
1222
  type Slot = CommerceSlot | 'documentStore' | 'eventBus' | 'media' | 'security';
920
1223
  /**
921
1224
  * What the kernel hands an adapter package's `createAdapter`. A package that serves more than one slot switches on
922
- * `slot`; `config` is a commerce slot's `config` block from nymbal.config.ts, a primitive's connection block, or for
923
- * `security` the block named after the adapter (`security.cloudflare`).
1225
+ * `slot`; `config` is a commerce slot's `config` block from nymbal.config.ts, a primitive's connection block (or a
1226
+ * third-party primitive's `config`), or for `security` the block named after the adapter (`security.cloudflare`) or a
1227
+ * third-party adapter's `security.config`.
924
1228
  */
925
1229
  interface AdapterContext {
926
1230
  slot: Slot;
@@ -946,11 +1250,25 @@ interface AdapterSetting {
946
1250
  */
947
1251
  optional?: boolean;
948
1252
  }
949
- /** What a provider package exports: `createAdapter`, and the fields it lets Settings fill. */
1253
+ /**
1254
+ * What a provider package exports: `createAdapter`, the slot and provider it serves (checked when it is loaded), and
1255
+ * the fields it lets Settings fill.
1256
+ */
950
1257
  interface ProviderPackageModule {
951
1258
  createAdapter(ctx: AdapterContext): unknown;
1259
+ slot: Slot;
1260
+ provider: string;
952
1261
  settings?: readonly AdapterSetting[];
953
1262
  }
1263
+ /**
1264
+ * How `nymbal.config.ts` names an infrastructure slot's adapter (`documentStore`, `eventBus`, `media`): the provider,
1265
+ * the npm package it comes from when not `@nymbalhq/<slot>-<provider>`, and a third-party adapter's `ctx.config`.
1266
+ */
1267
+ interface InfrastructureBlock {
1268
+ provider: string;
1269
+ package?: string;
1270
+ config?: Record<string, unknown>;
1271
+ }
954
1272
 
955
1273
  interface PutOptions {
956
1274
  ttl?: number;
@@ -1098,6 +1416,67 @@ interface MediaStorage {
1098
1416
  healthCheck?(): Promise<HealthReport>;
1099
1417
  }
1100
1418
 
1419
+ /** The origins a surface builds its absolute URLs from: never the request's `Host`. */
1420
+ interface AgentSurfaceUrls {
1421
+ /** The API's origin: the profile, the MCP endpoint and the handoff link live there. */
1422
+ api: string;
1423
+ /** The storefront's origin, when one is known; product and category links are made on it. */
1424
+ storefront: string | undefined;
1425
+ }
1426
+ /** What an agent can do through a surface; part of the operator's view of it. */
1427
+ interface AgentSurfaceCapabilities {
1428
+ search: boolean;
1429
+ lookup: boolean;
1430
+ /** `handoff`: the agent opens a checkout and the buyer pays on the store's page; `agentic`: the agent pays. */
1431
+ checkout: 'handoff' | 'agentic' | 'none';
1432
+ }
1433
+ /** What a surface's REST route is handed: the request as its transport received it. */
1434
+ interface AgentRouteRequest {
1435
+ params: Record<string, string>;
1436
+ query: Record<string, string | string[] | undefined>;
1437
+ /** Lower-cased names. */
1438
+ headers: Record<string, string | string[] | undefined>;
1439
+ body: unknown;
1440
+ ip: string;
1441
+ requestId: string;
1442
+ }
1443
+ /** A REST route of an agent surface, served server to server under the surface's own credential (no CSRF). */
1444
+ interface AgentRoute {
1445
+ method: 'GET' | 'POST';
1446
+ path: string;
1447
+ handle(request: AgentRouteRequest): Promise<ResponseEnvelope>;
1448
+ }
1449
+ /**
1450
+ * One agent protocol a store serves (UCP, ACP): a discovery document, a tool endpoint and REST routes, each optional.
1451
+ */
1452
+ interface AgentSurfaceAdapter {
1453
+ name: string;
1454
+ capabilities: AgentSurfaceCapabilities;
1455
+ wellKnown?: {
1456
+ path: string;
1457
+ document(urls: AgentSurfaceUrls): Record<string, unknown>;
1458
+ };
1459
+ endpoint?: {
1460
+ path: string;
1461
+ tools: ToolSurface;
1462
+ };
1463
+ routes?: AgentRoute[];
1464
+ }
1465
+ /** The agent surfaces a store serves and the crawl files beside them; built by `attachHttp`. */
1466
+ interface AgentSurfaces {
1467
+ surfaces: AgentSurfaceAdapter[];
1468
+ /** Where the surfaces' tools take their origins from; the mount that serves them sets it. */
1469
+ useUrls(urls: () => AgentSurfaceUrls): void;
1470
+ /** `robots.txt`, or null when it is off. */
1471
+ robots(urls: AgentSurfaceUrls): string | null;
1472
+ /** `llms.txt`, or null when it is off. */
1473
+ llms(urls: AgentSurfaceUrls): Promise<string | null>;
1474
+ /** One page of the product feed, or null when it is off. */
1475
+ feed(urls: AgentSurfaceUrls, cursor?: string): Promise<Record<string, unknown> | null>;
1476
+ /** Whether `token` names a live cart a browser may be handed. */
1477
+ handoff(token: string): Promise<boolean>;
1478
+ }
1479
+
1101
1480
  type RateLimitAction = 'block' | 'challenge' | 'throttle';
1102
1481
  interface RateLimitRule {
1103
1482
  requests: number;
@@ -1140,11 +1519,58 @@ interface SecurityState {
1140
1519
  rulesApplied: string[];
1141
1520
  lastValidatedAt: string;
1142
1521
  }
1522
+ /**
1523
+ * What a security adapter tells the HTTP layer about the network in front of the store. Each value counts only when the
1524
+ * store sets neither its variable nor its config key.
1525
+ */
1526
+ interface SecurityNetwork {
1527
+ /** The proxies whose `X-Forwarded-For` (and client-address header) the API believes: presets, addresses or CIDRs. */
1528
+ trustedProxies?: string[];
1529
+ /** One header a listed proxy sets to the client's address, such as `CF-Connecting-IP`. */
1530
+ clientIpHeader?: string;
1531
+ /** Whether `clientIpHeader` may be honoured only on a request the origin lock admitted. */
1532
+ clientIpRequiresLock?: boolean;
1533
+ }
1534
+ /** Where a resolved network value came from: the variable, the config key, the adapter's name, or `default`. */
1535
+ interface NetworkSource {
1536
+ kind: 'env' | 'config' | 'adapter' | 'default';
1537
+ name: string;
1538
+ }
1539
+ /** The network block the HTTP server is built from, resolved once at boot. */
1540
+ interface ResolvedNetwork {
1541
+ trustedProxies: string[];
1542
+ trustedProxiesSource: NetworkSource;
1543
+ clientIpHeader?: string;
1544
+ clientIpHeaderSource?: NetworkSource;
1545
+ clientIpRequiresLock: boolean;
1546
+ /** Present when `NYMBAL_ORIGIN_SECRET` is set: the header the CDN proves itself in, and the secrets it may send. */
1547
+ originLock?: ResolvedOriginLock;
1548
+ }
1549
+ /** The origin lock, resolved once at boot: every entry is accepted, so a secret can be rotated without downtime. */
1550
+ interface ResolvedOriginLock {
1551
+ header: string;
1552
+ secrets: readonly string[];
1553
+ }
1554
+ /**
1555
+ * Whether the CDN sends the origin secret: `missing` when it has no enabled rule; `present` with the header the rule
1556
+ * sets and `entry`, the 0-based index of the secret it sends, or null when it sends none of them.
1557
+ */
1558
+ type OriginLockRule = {
1559
+ state: 'missing';
1560
+ } | {
1561
+ state: 'present';
1562
+ header: string;
1563
+ entry: number | null;
1564
+ };
1143
1565
  interface SecurityAdapter extends AdapterBase {
1144
1566
  applyMiddleware(app: HttpAdapter, config: SecurityConfigLike): Promise<void>;
1145
1567
  validate(config: SecurityConfigLike): Promise<ValidationResult>;
1146
1568
  drift?(config: SecurityConfigLike): Promise<DriftReport>;
1147
1569
  inspect?(): Promise<SecurityState>;
1570
+ /** The adapter's network settings, offered at boot; synchronous and without I/O. */
1571
+ network?(): SecurityNetwork;
1572
+ /** Whether the CDN in front sends one of the lock's secrets, read from the CDN itself. */
1573
+ originLockRule?(lock: ResolvedOriginLock): Promise<OriginLockRule>;
1148
1574
  }
1149
1575
  /** The response headers every security adapter sets in process, from the config's `headers` block. */
1150
1576
  declare function buildSecurityHeaders(security: SecurityConfigLike): Record<string, string>;
@@ -1228,10 +1654,21 @@ interface ReviewsResult {
1228
1654
  items: Review[];
1229
1655
  nextCursor: string | null;
1230
1656
  }
1657
+ /** What a reviews adapter can do; `capabilities()` of a reviews adapter answers a subset. */
1658
+ type ReviewsCapability = 'submit' | 'moderate' | 'aggregate' | 'invite' | 'widget';
1659
+ /**
1660
+ * The kernel resolves `customerId`, `author` and `orderId` (the reviewer's paid order holding the product) before the
1661
+ * adapter sees a submission; an adapter never looks up customers or orders. An adapter without `submit` refuses it
1662
+ * with `ReviewRefusedError('submit_unsupported')`.
1663
+ */
1231
1664
  interface ReviewSubmission {
1232
1665
  productId: string;
1233
1666
  customerId: string | null;
1234
1667
  orderId: string | null;
1668
+ author: {
1669
+ name: string;
1670
+ email: string;
1671
+ } | null;
1235
1672
  rating: number;
1236
1673
  title: string;
1237
1674
  body: string;
@@ -1302,39 +1739,68 @@ interface AnalyticsAdapter extends CommerceAdapter {
1302
1739
  track(event: string, properties: Record<string, unknown>): Promise<void>;
1303
1740
  identify(userId: string, traits: Record<string, unknown>): Promise<void>;
1304
1741
  }
1305
- interface ShippingRateParams {
1306
- fromPostalCode: string;
1307
- toPostalCode: string;
1308
- toCountry: string;
1742
+ /** What a shipping adapter does; each word is declared exactly when the method it names is present. */
1743
+ declare const SHIPPING_CAPABILITIES: readonly ["rates", "labels", "tracking"];
1744
+ /** `rates` has `rate`, `labels` has `createLabel` (and needs `rates`), `tracking` has `startTracking` and `receiveWebhook`. */
1745
+ type ShippingCapability = (typeof SHIPPING_CAPABILITIES)[number];
1746
+ /** A parcel has all three dimensions or none. Grams and millimetres, each positive. */
1747
+ type Parcel = {
1309
1748
  weightGrams: number;
1310
- currency: string;
1749
+ lengthMm?: never;
1750
+ widthMm?: never;
1751
+ heightMm?: never;
1752
+ } | {
1753
+ weightGrams: number;
1754
+ lengthMm: number;
1755
+ widthMm: number;
1756
+ heightMm: number;
1757
+ };
1758
+ interface ShippingRateParams {
1759
+ from: Address;
1760
+ to: Address;
1761
+ parcel: Parcel;
1311
1762
  }
1312
1763
  interface ShippingRate {
1764
+ /** Opaque to the kernel: handed back unchanged as `ShippingLabelParams.rateId`. */
1765
+ id: string;
1313
1766
  carrier: string;
1314
1767
  service: string;
1315
1768
  amountMinor: number;
1316
1769
  currency: string;
1317
- estimatedDays: number;
1770
+ estimatedDays: number | null;
1318
1771
  }
1319
1772
  interface ShippingLabelParams {
1320
- orderId: string;
1321
- carrier: string;
1322
- service: string;
1773
+ rateId: string;
1323
1774
  }
1324
1775
  interface ShippingLabel {
1325
1776
  labelUrl: string;
1326
1777
  trackingNumber: string;
1327
1778
  carrier: string;
1779
+ service: string;
1780
+ amountMinor: number;
1781
+ currency: string;
1328
1782
  }
1329
- interface ShippingTracking {
1330
- status: string;
1331
- lastUpdateAt: string;
1783
+ interface StartTrackingParams {
1784
+ trackingNumber: string;
1785
+ /** As the merchant typed it; null leaves the carrier to the provider. */
1786
+ carrier: string | null;
1332
1787
  }
1788
+ /**
1789
+ * `tracking`: the provider holds the number, now or from before. `refused`: it never will (an invalid number, an
1790
+ * unknown carrier, a refused key). An outage rejects instead, so the caller may try again.
1791
+ */
1792
+ type StartTrackingResult = {
1793
+ status: 'tracking';
1794
+ } | {
1795
+ status: 'refused';
1796
+ reason: string;
1797
+ };
1333
1798
  interface ShippingAdapter extends CommerceAdapter {
1334
1799
  readonly kind: 'shipping';
1335
- rate(params: ShippingRateParams): Promise<ShippingRate[]>;
1336
- createLabel(params: ShippingLabelParams): Promise<ShippingLabel>;
1337
- track(trackingNumber: string): Promise<ShippingTracking>;
1800
+ capabilities(): readonly ShippingCapability[];
1801
+ rate?(params: ShippingRateParams): Promise<ShippingRate[]>;
1802
+ createLabel?(params: ShippingLabelParams): Promise<ShippingLabel>;
1803
+ startTracking?(params: StartTrackingParams): Promise<StartTrackingResult>;
1338
1804
  }
1339
1805
  interface TaxLine {
1340
1806
  amountMinor: number;
@@ -1356,12 +1822,89 @@ interface TaxAdapter extends CommerceAdapter {
1356
1822
  readonly kind: 'tax';
1357
1823
  calculate(params: TaxCalculationParams): Promise<TaxCalculationResult>;
1358
1824
  }
1825
+ /** A tool the model may call. Its name matches `^[A-Za-z0-9_-]{1,64}$` and is unique among the tools of one request. */
1826
+ interface ChatTool {
1827
+ name: string;
1828
+ description: string;
1829
+ inputSchema: JsonSchemaObject;
1830
+ }
1831
+ /** A call the model asked for, its arguments a JSON object. */
1832
+ interface ChatToolCall {
1833
+ id: string;
1834
+ name: string;
1835
+ args: Record<string, unknown>;
1836
+ }
1837
+ /**
1838
+ * One turn of a conversation. The first turn is the user's. An assistant turn's `content` may be empty only when it
1839
+ * has calls; each call is answered by one `tool` turn before the next user or assistant turn.
1840
+ */
1841
+ type ChatMessage = {
1842
+ role: 'user';
1843
+ content: string;
1844
+ } | {
1845
+ role: 'assistant';
1846
+ content: string;
1847
+ toolCalls?: readonly ChatToolCall[];
1848
+ } | {
1849
+ role: 'tool';
1850
+ toolCallId: string;
1851
+ content: string;
1852
+ isError?: boolean;
1853
+ };
1854
+ interface ChatOptions {
1855
+ /** Instructions for the whole conversation, sent in the provider's own system field. */
1856
+ system?: string;
1857
+ /** The most tokens the answer may take; 1024 when omitted. */
1858
+ maxTokens?: number;
1859
+ tools?: readonly ChatTool[];
1860
+ /** Aborting it closes the request and rejects `adapter.cancelled`. */
1861
+ signal?: AbortSignal;
1862
+ }
1863
+ /** Why the answer ended: complete, cut at `maxTokens`, waiting on its tool calls, or anything else reported. */
1864
+ type ChatStopReason = 'end' | 'max_tokens' | 'tool_use' | 'other';
1865
+ interface ChatResult {
1866
+ /** '' when the answer is calls only. */
1867
+ text: string;
1868
+ stopReason: ChatStopReason;
1869
+ /** 0 where the provider reports none. */
1870
+ usage: {
1871
+ inputTokens: number;
1872
+ outputTokens: number;
1873
+ };
1874
+ /** The model as the provider reports it. */
1875
+ model: string;
1876
+ /** The calls the model asked for, in its order; [] when none. */
1877
+ toolCalls: ChatToolCall[];
1878
+ }
1879
+ /** What `chatStream` yields: text as it arrives, each call once its arguments are complete, and one `done` last. */
1880
+ type ChatStreamEvent = {
1881
+ type: 'text';
1882
+ delta: string;
1883
+ } | {
1884
+ type: 'tool_call';
1885
+ call: ChatToolCall;
1886
+ } | {
1887
+ type: 'done';
1888
+ result: ChatResult;
1889
+ };
1359
1890
  interface AiAdapter extends CommerceAdapter {
1360
1891
  readonly kind: 'ai';
1361
1892
  embed(texts: string[]): Promise<number[][]>;
1893
+ /** The text `chat` answers to a single user turn. */
1362
1894
  complete(prompt: string, opts?: {
1363
1895
  maxTokens?: number;
1364
1896
  }): Promise<string>;
1897
+ /**
1898
+ * One request to the provider. Refused input, a provider failure and a timeout reject with an `AdapterError` whose
1899
+ * context is `{ provider, status? }` and which never carries the key.
1900
+ */
1901
+ chat(messages: readonly ChatMessage[], opts?: ChatOptions): Promise<ChatResult>;
1902
+ /**
1903
+ * `chat` as it is generated: the text deltas concatenate to the `done` result's text and the `tool_call` events are
1904
+ * its calls in order. A stream broken after it started rejects `adapter.unavailable`; the whole stream is bounded as
1905
+ * one `chat`.
1906
+ */
1907
+ chatStream?(messages: readonly ChatMessage[], opts?: ChatOptions): AsyncIterable<ChatStreamEvent>;
1365
1908
  }
1366
1909
  /** The adapter interface each commerce slot takes: what a project injects for a slot whose provider is `custom`. */
1367
1910
  interface CommerceSlotAdapters {
@@ -1387,6 +1930,58 @@ interface WebhookDeliveryProblem {
1387
1930
  */
1388
1931
  declare function webhookDeliveryProblem(providerName: string, producesEvents: readonly string[], delivery: WebhookDelivery): WebhookDeliveryProblem | null;
1389
1932
 
1933
+ /**
1934
+ * `<providerName>.bounced.v1`: a message to `recipient` bounced. `hard` is the provider's permanent failure, `soft`
1935
+ * its transient one; a classification the adapter cannot map is `soft`, so a doubtful bounce never suppresses.
1936
+ */
1937
+ interface EmailBouncedV1Payload {
1938
+ recipient: string;
1939
+ bounce: 'hard' | 'soft';
1940
+ /** The `EmailSendResult.messageId` the bounce answers, when the provider gives one. */
1941
+ messageId: string | null;
1942
+ /** ISO 8601. */
1943
+ occurredAt: string;
1944
+ }
1945
+ /** `<providerName>.complained.v1`: `recipient` marked a message as spam. */
1946
+ interface EmailComplainedV1Payload {
1947
+ recipient: string;
1948
+ messageId: string | null;
1949
+ /** ISO 8601. */
1950
+ occurredAt: string;
1951
+ }
1952
+ type EmailFeedbackKind = 'bounced' | 'complained';
1953
+ /** The event type an email adapter publishes a bounce or a complaint under. */
1954
+ declare function emailFeedbackType(providerName: string, what: EmailFeedbackKind): string;
1955
+ /**
1956
+ * The first bounce or complaint in a verified delivery from the email adapter `providerName` that the kernel cannot
1957
+ * act on, or null when there is none. The route refuses such a delivery whole, before claiming it, so the provider's
1958
+ * retry after the adapter is fixed is still received; the email feedback contract suite certifies the same rule.
1959
+ */
1960
+ declare function emailFeedbackProblem(providerName: string, delivery: WebhookDelivery): WebhookDeliveryProblem | null;
1961
+
1962
+ /** The statuses a shipping adapter maps its carrier's onto; one it cannot map is `unknown`. */
1963
+ declare const SHIPPING_TRACKING_STATUSES: readonly ["pre_transit", "in_transit", "out_for_delivery", "delivered", "exception", "returned", "unknown"];
1964
+ type ShippingTrackingStatus = (typeof SHIPPING_TRACKING_STATUSES)[number];
1965
+ /** `<providerName>.tracking.v1`: the carrier reported `status` for the parcel `trackingNumber`. */
1966
+ interface ShippingTrackingV1Payload {
1967
+ trackingNumber: string;
1968
+ /** The carrier's code as the adapter's provider gives it, which need not match the merchant's own. */
1969
+ carrier: string | null;
1970
+ status: ShippingTrackingStatus;
1971
+ /** ISO 8601. */
1972
+ occurredAt: string;
1973
+ }
1974
+ /** The event type a shipping adapter publishes a tracking update under. */
1975
+ declare function shippingTrackingType(providerName: string): string;
1976
+ /** A tracking number as stored and looked up: no whitespace, upper case, so a carrier's spelling finds the merchant's. */
1977
+ declare function normaliseTrackingNumber(value: string): string;
1978
+ /**
1979
+ * The first tracking update in a verified delivery from the shipping adapter `providerName` that the kernel cannot act
1980
+ * on, or null when there is none. The route refuses such a delivery whole, before claiming it, so the provider's retry
1981
+ * after the adapter is fixed is still received; the shipping tracking contract suite certifies the same rule.
1982
+ */
1983
+ declare function shippingTrackingProblem(providerName: string, delivery: WebhookDelivery): WebhookDeliveryProblem | null;
1984
+
1390
1985
  interface RenderedEmail {
1391
1986
  subject: string;
1392
1987
  text: string;
@@ -1415,6 +2010,14 @@ interface StoreCapabilities {
1415
2010
  email: {
1416
2011
  delivers: boolean;
1417
2012
  };
2013
+ /** What the reviews adapter can do: without `submit` the store takes no review on its own site. */
2014
+ reviews: {
2015
+ capabilities: string[];
2016
+ };
2017
+ /** What the shipping adapter can do (`rates`, `labels`, `tracking`); none on a store that only ships by hand. */
2018
+ shipping: {
2019
+ capabilities: string[];
2020
+ };
1418
2021
  }
1419
2022
 
1420
2023
  /**
@@ -1435,7 +2038,7 @@ interface Recipe {
1435
2038
  summary: string;
1436
2039
  /** npm packages to install, SDKs included; empty when the service is built in. */
1437
2040
  install: string[];
1438
- /** Config paths and the values they take, e.g. `infrastructure.documentStore` = `'redis'`. */
2041
+ /** Config paths and the values they take, e.g. `infrastructure.documentStore.provider` = `'redis'`. */
1439
2042
  set: Array<{
1440
2043
  path: string;
1441
2044
  value: RecipeValue;
@@ -1456,37 +2059,6 @@ type StockLevel = 'out' | 'low' | 'in';
1456
2059
  declare function stockLevel(stock: number): StockLevel;
1457
2060
  declare const STOCK_LABELS: Record<StockLevel, string>;
1458
2061
 
1459
- /** Where a Settings field's value comes from: the config block, its declared env, a saved value, or nowhere. */
1460
- type SettingSourceName = 'config' | 'env' | 'settings';
1461
- /** One declared field as `GET /api/admin/settings` lists it; a secret never carries its value. */
1462
- interface SettingFieldView {
1463
- path: string;
1464
- label: string;
1465
- secret: boolean;
1466
- state: 'unset' | 'set';
1467
- source: SettingSourceName | null;
1468
- updatedAt: string | null;
1469
- /** Non-secret fields only. */
1470
- value?: unknown;
1471
- }
1472
- /** A slot whose provider declares settings, with its fields. */
1473
- interface SettingsSlotView {
1474
- slot: string;
1475
- provider: string;
1476
- fields: SettingFieldView[];
1477
- }
1478
- interface SettingsListing {
1479
- slots: SettingsSlotView[];
1480
- }
1481
- /** What a `PUT` or `DELETE` of a field answers: the change applies at the next start. */
1482
- interface SettingWriteResult {
1483
- slot: string;
1484
- path: string;
1485
- state: 'unset' | 'set';
1486
- source: 'settings' | null;
1487
- restartRequired: true;
1488
- }
1489
-
1490
2062
  /** Who a command ran for. A guest is `guest:anonymous`: a cart's token is a bearer credential and is never an id. */
1491
2063
  interface AuditActor {
1492
2064
  kind: 'admin' | 'customer' | 'guest' | 'system' | 'import';
@@ -1555,5 +2127,47 @@ interface AsOfRead<T = Record<string, unknown>> {
1555
2127
  record: T;
1556
2128
  }
1557
2129
 
1558
- export { AdapterError, AuthError, CORRELATION_ID_HEADER, CheckoutError, ConfigError, DEFAULT_PRODUCT_SORT, DEFAULT_QUERY_LIMIT, EVT_ADAPTER_ERROR, EVT_ALERT_CONFIRMED, EVT_ALERT_REQUESTED, EVT_ALERT_SENT, EVT_ALERT_UNSUBSCRIBED, EVT_CART_ABANDONED, EVT_CART_CONVERTED, EVT_CART_CREATED, EVT_CART_ITEM_ADDED, EVT_CART_ITEM_REMOVED, EVT_CART_UPDATED, EVT_CATEGORY_CREATED, EVT_CATEGORY_DELETED, EVT_CATEGORY_UPDATED, EVT_CUSTOMER_CREATED, EVT_CUSTOMER_DELETED, EVT_CUSTOMER_REGISTERED, EVT_CUSTOMER_UPDATED, EVT_INVENTORY_CHANGED, EVT_INVENTORY_LOW_STOCK, EVT_INVENTORY_OUT_OF_STOCK, EVT_INVENTORY_RELEASED, EVT_INVENTORY_RESERVED, EVT_ORDER_CANCELLED, EVT_ORDER_CONFIRMATION_RESEND_REQUESTED, EVT_ORDER_DELIVERED, EVT_ORDER_FULFILLED, EVT_ORDER_PAID, EVT_ORDER_PARTIALLY_REFUNDED, EVT_ORDER_PLACED, EVT_ORDER_REFUNDED, EVT_ORDER_SHIPPED, EVT_ORDER_STATUS_CHANGED, EVT_PAYMENT_CAPTURED, EVT_PAYMENT_FAILED, EVT_PAYMENT_INTENT_CREATED, EVT_PAYMENT_REFUNDED, EVT_PRODUCT_CREATED, EVT_PRODUCT_DELETED, EVT_PRODUCT_PUBLISHED, EVT_PRODUCT_RESTOCKED, EVT_PRODUCT_UNPUBLISHED, EVT_PRODUCT_UPDATED, EVT_PRODUCT_VARIANT_PRICE_CHANGED, EVT_PRODUCT_VIEWED, EVT_SETTINGS_CHANGED, EVT_VISITOR_MERGED, HEALTH_CHECK_TIMEOUT_MS, HttpError, IDEMPOTENCY_KEY_HEADER, IDEMPOTENT_REPLAYED_HEADER, NotFoundError, NymbalError, ORDER_KEY_HEADER, ORDER_STATUS_TRANSITIONS, ORDER_TIMELINE_KINDS, OrderConflictError, PRODUCT_SORT_KEYS, PRODUCT_SORT_LABELS, PaymentError, SECRET_MIN_LENGTH, STANDARD_EVENT_TYPES, STOCK_LABELS, StatusTransitionError, ValidationError, add, allocate, assertMinorUnits, assertOrderTransition, boundedHealthCheck, buildSecurityHeaders, canTransitionOrder, compareDocumentValues, connectionSecrets, displayUrl, documentValueAt, errorText, handlerFailedError, isValidCorrelationId, isValidIdempotencyKey, matchesSortKey, money, mulBy, paymentState, queryDocuments, refundableMinor, renderEmailTemplate, stockLevel, sub, sumMoney, webhookDeliveryProblem };
1559
- export type { AdapterBase, AdapterContext, AdapterErrorV1Payload, AdapterSetting, Address, AggregateRating, AiAdapter, AlertConfirmedV1Payload, AlertKind, AlertRequestedV1Payload, AlertSentV1Payload, AlertStatus, AlertUnsubscribedV1Payload, AnalyticsAdapter, AsOfRead, AuditActor, AuditEntry, AuditOutcome, AuditSubject, BoundedHealthCheckOptions, CaptureMethod, Cart, CartAbandonedV1Payload, CartConvertedV1Payload, CartCreatedV1Payload, CartItem, CartItemAddedV1Payload, CartItemRemovedV1Payload, CartUpdatedV1Payload, Category, CategoryCreatedV1Payload, CategoryDeletedV1Payload, CategoryUpdatedV1Payload, CheckoutPayment, CommerceAdapter, CommerceSlot, CommerceSlotAdapters, Customer, CustomerAddress, CustomerCreatedV1Payload, CustomerDeletedV1Payload, CustomerProfile, CustomerSnapshot, CustomerUpdatedV1Payload, DocumentStoreAdapter, DriftReport, EmailAdapter, EmailSendResult, ErrorContext, EventBusAdapter, EventHandler, EventMetadata, Facet, FacetParams, HandlerFailure, HealthReport, HealthStatus, HistoryChange, HistoryEntry, HistoryKind, HistoryPage, HttpAdapter, HttpMethod, IndexResult, InventoryChangedV1Payload, InventoryLowStockV1Payload, InventoryOutOfStockV1Payload, InventoryReleasedV1Payload, InventoryReservation, InventoryReservedV1Payload, Logger, MediaStorage, MiddlewareHandler, Money, NymbalEnvironment, NymbalEvent, NymbalEventMap, NymbalEventType, Order, OrderCancelledV1Payload, OrderConfirmationResendRequestedV1Payload, OrderDeliveredV1Payload, OrderFulfilledV1Payload, OrderHistoryEntry, OrderLineItem, OrderPaidV1Payload, OrderPartiallyRefundedV1Payload, OrderPayment, OrderPlacedV1Payload, OrderRefund, OrderRefundStatus, OrderRefundedV1Payload, OrderShippedV1Payload, OrderStatus, OrderStatusChangedV1Payload, OrderTimelineEntry, OrderTimelineKind, PaginationParams, PayloadOf, PaymentCapture, PaymentCapturedV1Payload, PaymentClient, PaymentFailedV1Payload, PaymentIntent, PaymentIntentCreatedV1Payload, PaymentIntentParams, PaymentRefundedV1Payload, PaymentState, PaymentStatus, PaymentsAdapter, Product, ProductCreatedV1Payload, ProductDeletedV1Payload, ProductMedia, ProductPublishedV1Payload, ProductRestockedV1Payload, ProductSnapshot, ProductSortKey, ProductStatus, ProductType, ProductUnpublishedV1Payload, ProductUpdatedV1Payload, ProductVariantPriceChangedV1Payload, ProductViewedV1Payload, ProviderPackageModule, PutOptions, QueryParams, QueryResult, RateLimitAction, RateLimitDecision, RateLimitRule, RecentViewer, Recipe, RecipeValue, Refund, RefundOptions, RenderedEmail, RequestAuth, RequestContext, ResponseCookie, ResponseEnvelope, RetryPolicy, Review, ReviewModerationStatus, ReviewResult, ReviewSubmission, ReviewsAdapter, ReviewsResult, Role, RouteHandler, RouteOptions, SearchAdapter, SearchDocument, SearchParams, SearchResult, SecurityAdapter, SecurityConfigLike, SecurityState, SettingFieldView, SettingSourceName, SettingWriteResult, SettingsChangedV1Payload, SettingsListing, SettingsSlotView, ShippingAdapter, ShippingLabel, ShippingLabelParams, ShippingRate, ShippingRateParams, ShippingTracking, ShopperOrder, Slot, SortKeyCondition, SseEvent, StockAdjustment, StockAdjustmentReason, StockLevel, StockStatus, StoreCapabilities, StreamContext, StreamHandler, Subscription, SubscriptionConfig, TaxAdapter, TaxCalculationParams, TaxCalculationResult, TaxLine, TransactionalEmail, ValidationResult, Variant, VariantDimensions, VariantOption, VariantStatus, VisitorMergedV1Payload, WebhookDelivery, WebhookDeliveryProblem, WebhookEventDraft, WebhookHeaders, WebhookResult };
2130
+ /**
2131
+ * What the admin's assistant stream sends, frame by frame: the answer's text as it arrives, one `tool` frame per tool
2132
+ * the model called (or one `proposal` frame for a write kept for a person to approve), then `done` or `error`.
2133
+ */
2134
+ type AssistantFrame = {
2135
+ event: 'text';
2136
+ data: {
2137
+ delta: string;
2138
+ };
2139
+ } | {
2140
+ event: 'tool';
2141
+ data: {
2142
+ name: string;
2143
+ title: string;
2144
+ ok: boolean;
2145
+ code?: string;
2146
+ applied?: true;
2147
+ };
2148
+ } | {
2149
+ event: 'proposal';
2150
+ data: ProposalView;
2151
+ } | {
2152
+ event: 'done';
2153
+ data: {
2154
+ text: string;
2155
+ steps: number;
2156
+ proposals: string[];
2157
+ };
2158
+ } | {
2159
+ event: 'error';
2160
+ data: {
2161
+ code: string;
2162
+ message: string;
2163
+ };
2164
+ };
2165
+ /** `POST /api/admin/assistant/turns`: the turn's id and the one-time ticket that opens its stream. */
2166
+ interface AssistantTurnIssued {
2167
+ turnId: string;
2168
+ ticket: string;
2169
+ expiresIn: number;
2170
+ }
2171
+
2172
+ export { AdapterError, AuthError, CART_LINE_MAX_QTY, CORRELATION_ID_HEADER, CartLimitError, CheckoutError, ConfigError, DEFAULT_PRODUCT_SORT, DEFAULT_QUERY_LIMIT, EVT_ADAPTER_ERROR, EVT_ALERT_CONFIRMATION_SENT, EVT_ALERT_CONFIRMED, EVT_ALERT_REPEATED, EVT_ALERT_REQUESTED, EVT_ALERT_SENT, EVT_ALERT_UNSUBSCRIBED, EVT_CART_ABANDONED, EVT_CART_CONVERTED, EVT_CART_CREATED, EVT_CART_ITEM_ADDED, EVT_CART_ITEM_REMOVED, EVT_CART_UPDATED, EVT_CATEGORY_CREATED, EVT_CATEGORY_DELETED, EVT_CATEGORY_UPDATED, EVT_CUSTOMER_CREATED, EVT_CUSTOMER_DELETED, EVT_CUSTOMER_REGISTERED, EVT_CUSTOMER_UPDATED, EVT_INVENTORY_CHANGED, EVT_INVENTORY_LOW_STOCK, EVT_INVENTORY_OUT_OF_STOCK, EVT_INVENTORY_RELEASED, EVT_INVENTORY_RESERVED, EVT_ORDER_CANCELLED, EVT_ORDER_CONFIRMATION_RESEND_REQUESTED, EVT_ORDER_DELETED, EVT_ORDER_DELIVERED, EVT_ORDER_FULFILLED, EVT_ORDER_PAID, EVT_ORDER_PARTIALLY_REFUNDED, EVT_ORDER_PLACED, EVT_ORDER_REFUNDED, EVT_ORDER_SHIPPED, EVT_ORDER_STATUS_CHANGED, EVT_PAYMENT_CAPTURED, EVT_PAYMENT_FAILED, EVT_PAYMENT_INTENT_CREATED, EVT_PAYMENT_REFUNDED, EVT_PRODUCT_CREATED, EVT_PRODUCT_DELETED, EVT_PRODUCT_PUBLISHED, EVT_PRODUCT_RESTOCKED, EVT_PRODUCT_UNPUBLISHED, EVT_PRODUCT_UPDATED, EVT_PRODUCT_VARIANT_PRICE_CHANGED, EVT_PRODUCT_VIEWED, EVT_PROPOSAL_APPLIED, EVT_PROPOSAL_APPROVED, EVT_PROPOSAL_CREATED, EVT_PROPOSAL_FAILED, EVT_PROPOSAL_REJECTED, EVT_REVIEW_SUBMITTED, EVT_SETTINGS_CHANGED, EVT_VISITOR_MERGED, HEALTH_CHECK_TIMEOUT_MS, HttpError, IDEMPOTENCY_KEY_HEADER, IDEMPOTENT_REPLAYED_HEADER, NotFoundError, NymbalError, ORDER_EMAIL_HEADER, ORDER_KEY_HEADER, ORDER_STATUS_TRANSITIONS, ORDER_TIMELINE_KINDS, OrderConflictError, PREVIEWED_COMMANDS, PRODUCT_SORT_KEYS, PRODUCT_SORT_LABELS, PaymentError, ReviewRefusedError, SECRET_MIN_LENGTH, SHIPPING_CAPABILITIES, SHIPPING_TRACKING_STATUSES, SHOPPER_ATTESTATION_HEADER, STANDARD_EVENT_TYPES, STOCK_LABELS, StatusTransitionError, ValidationError, add, agentSource, allocate, assertMinorUnits, assertOrderTransition, boundedHealthCheck, buildSecurityHeaders, canTransitionOrder, compareDocumentValues, connectionSecrets, displayUrl, documentValueAt, emailFeedbackProblem, emailFeedbackType, errorText, handlerFailedError, isValidCorrelationId, isValidIdempotencyKey, matchesSortKey, money, mulBy, normaliseTrackingNumber, paymentState, queryDocuments, refundableMinor, renderEmailTemplate, shippingTrackingProblem, shippingTrackingType, stockLevel, sub, sumMoney, webhookDeliveryProblem };
2173
+ export type { AdapterBase, AdapterContext, AdapterErrorV1Payload, AdapterSetting, Address, AgentRoute, AgentRouteRequest, AgentSurfaceAdapter, AgentSurfaceCapabilities, AgentSurfaceUrls, AgentSurfaces, AggregateRating, AiAdapter, AlertConfirmationSentV1Payload, AlertConfirmedV1Payload, AlertKind, AlertRepeatedV1Payload, AlertRequestedV1Payload, AlertSentV1Payload, AlertStatus, AlertUnsubscribedV1Payload, AnalyticsAdapter, AsOfRead, AssistantFrame, AssistantTurnIssued, AuditActor, AuditEntry, AuditOutcome, AuditSubject, BoundedHealthCheckOptions, Caller, CaptureMethod, Cart, CartAbandonedV1Payload, CartConvertedV1Payload, CartCreatedV1Payload, CartItem, CartItemAddedV1Payload, CartItemRemovedV1Payload, CartSource, CartUpdatedV1Payload, Category, CategoryCreatedV1Payload, CategoryDeletedV1Payload, CategoryUpdatedV1Payload, ChatMessage, ChatOptions, ChatResult, ChatStopReason, ChatStreamEvent, ChatTool, ChatToolCall, CheckoutPayment, CommerceAdapter, CommerceSlot, CommerceSlotAdapters, Customer, CustomerAddress, CustomerCreatedV1Payload, CustomerDeletedV1Payload, CustomerProfile, CustomerSnapshot, CustomerUpdatedV1Payload, DocumentStoreAdapter, DriftReport, EmailAdapter, EmailBouncedV1Payload, EmailComplainedV1Payload, EmailFeedbackKind, EmailSendResult, ErrorContext, EventBusAdapter, EventHandler, EventMetadata, Facet, FacetParams, HandlerFailure, HealthReport, HealthStatus, HistoryChange, HistoryEntry, HistoryKind, HistoryPage, HttpAdapter, HttpMethod, IndexResult, InfrastructureBlock, InventoryChangedV1Payload, InventoryLowStockV1Payload, InventoryOutOfStockV1Payload, InventoryReleasedV1Payload, InventoryReservation, InventoryReservedV1Payload, JsonSchemaObject, Logger, MediaStorage, MiddlewareHandler, Money, NetworkSource, NymbalEnvironment, NymbalEvent, NymbalEventMap, NymbalEventType, Order, OrderCancelledV1Payload, OrderConfirmationResendRequestedV1Payload, OrderDeletedV1Payload, OrderDeliveredV1Payload, OrderFulfilledV1Payload, OrderHistoryEntry, OrderLineItem, OrderPaidV1Payload, OrderPartiallyRefundedV1Payload, OrderPayment, OrderPlacedV1Payload, OrderRefund, OrderRefundStatus, OrderRefundedV1Payload, OrderShippedV1Payload, OrderSource, OrderStatus, OrderStatusChangedV1Payload, OrderTimelineEntry, OrderTimelineKind, OriginLockRule, PaginationParams, Parcel, PayloadOf, PaymentCapture, PaymentCapturedV1Payload, PaymentClient, PaymentFailedV1Payload, PaymentIntent, PaymentIntentCreatedV1Payload, PaymentIntentParams, PaymentRefundedV1Payload, PaymentState, PaymentStatus, PaymentsAdapter, Product, ProductCreatedV1Payload, ProductDeletedV1Payload, ProductMedia, ProductPublishedV1Payload, ProductRating, ProductRestockedV1Payload, ProductSnapshot, ProductSortKey, ProductStatus, ProductType, ProductUnpublishedV1Payload, ProductUpdatedV1Payload, ProductVariantPriceChangedV1Payload, ProductViewedV1Payload, ProposalAppliedV1Payload, ProposalApprovedV1Payload, ProposalChange, ProposalCreatedV1Payload, ProposalDecider, ProposalFailedV1Payload, ProposalPage, ProposalPreview, ProposalRejectedV1Payload, ProposalStatus, ProposalView, ProviderPackageModule, PublicReview, PublicReviewsResult, PutOptions, QueryParams, QueryResult, RateLimitAction, RateLimitDecision, RateLimitRule, RecentViewer, Recipe, RecipeValue, Refund, RefundOptions, RenderedEmail, RequestAuth, RequestContext, ResolvedNetwork, ResolvedOriginLock, ResponseCookie, ResponseEnvelope, RetryPolicy, Review, ReviewModerationStatus, ReviewRefusal, ReviewResult, ReviewSubmission, ReviewSubmittedV1Payload, ReviewsAdapter, ReviewsCapability, ReviewsResult, Role, RouteHandler, RouteOptions, SearchAdapter, SearchDocument, SearchParams, SearchResult, SecurityAdapter, SecurityConfigLike, SecurityNetwork, SecurityState, SettingFieldView, SettingSourceName, SettingWriteResult, SettingsChangedV1Payload, SettingsListing, SettingsSlotView, ShippingAdapter, ShippingCapability, ShippingLabel, ShippingLabelParams, ShippingRate, ShippingRateParams, ShippingTrackingStatus, ShippingTrackingV1Payload, ShopperAddress, ShopperOrder, Slot, SortKeyCondition, SseEvent, StartTrackingParams, StartTrackingResult, StockAdjustment, StockAdjustmentReason, StockLevel, StockStatus, StoreCapabilities, StreamContext, StreamHandler, Subscription, SubscriptionConfig, TaxAdapter, TaxCalculationParams, TaxCalculationResult, TaxLine, ToolCallOptions, ToolDefinition, ToolResult, ToolSurface, TransactionalEmail, ValidationResult, Variant, VariantDimensions, VariantOption, VariantStatus, VisitorMergedV1Payload, WebhookDelivery, WebhookDeliveryProblem, WebhookEventDraft, WebhookHeaders, WebhookResult };