/ packages / schema / standin_order.ts
standin_order.ts
  1  import type { CodecKey, CodecValue } from "@massmarket/utils/codec";
  2  
  3  import { ChainAddress, Payee } from "./standin_manifest.ts";
  4  import {
  5    BaseClass,
  6    ensureDate,
  7    ensureNumber,
  8    ensureSomeNumberAsBigInt,
  9    ensureString,
 10    ensureStringArray,
 11    ensureUint8Array,
 12  } from "./utils.ts";
 13  
 14  export class Order extends BaseClass {
 15    ID: number;
 16    Items: OrderedItem[];
 17    State: OrderState;
 18    InvoiceAddress?: AddressDetails;
 19    ShippingAddress?: AddressDetails;
 20    CanceledAt?: Date;
 21    ChosenPayee?: Payee;
 22    ChosenCurrency?: ChainAddress;
 23    PaymentDetails?: PaymentDetails;
 24    TxDetails?: OrderPaid;
 25  
 26    constructor(
 27      id: number = 0,
 28      items: OrderedItem[] = [],
 29      state: OrderState = OrderState.Unspecified,
 30      invoiceAddress?: AddressDetails,
 31      shippingAddress?: AddressDetails,
 32      canceledAt?: Date,
 33      chosenPayee?: Payee,
 34      chosenCurrency?: ChainAddress,
 35      paymentDetails?: PaymentDetails,
 36      txDetails?: OrderPaid,
 37    ) {
 38      super();
 39      this.ID = id;
 40      this.Items = items;
 41      this.State = state;
 42      this.InvoiceAddress = invoiceAddress;
 43      this.ShippingAddress = shippingAddress;
 44      this.CanceledAt = canceledAt;
 45      this.ChosenPayee = chosenPayee;
 46      this.ChosenCurrency = chosenCurrency;
 47      this.PaymentDetails = paymentDetails;
 48      this.TxDetails = txDetails;
 49    }
 50  
 51    static fromCBOR(value: CodecValue): Order {
 52      if (!(value instanceof Map)) {
 53        throw new TypeError("Expected value to be a Map");
 54      }
 55      const input = value as Map<CodecKey, CodecValue>;
 56      const id = ensureNumber(input.get("ID"), "ID");
 57  
 58      const items: OrderedItem[] = [];
 59      const itemsData = input.get("Items");
 60      if (itemsData !== undefined) {
 61        if (!Array.isArray(itemsData)) {
 62          throw new TypeError("Expected Items to be an array");
 63        }
 64        items.push(...itemsData.map((item) => {
 65          if (!(item instanceof Map)) {
 66            throw new TypeError("Expected item to be a Map");
 67          }
 68          return OrderedItem.fromCBOR(item);
 69        }));
 70      }
 71  
 72      const stateNum = ensureNumber(input.get("State"), "State");
 73  
 74      let invoiceAddress: AddressDetails | undefined;
 75      const invoiceAddressData = input.get("InvoiceAddress");
 76      if (invoiceAddressData !== undefined) {
 77        if (!(invoiceAddressData instanceof Map)) {
 78          throw new TypeError("Expected InvoiceAddress to be a Map");
 79        }
 80        invoiceAddress = AddressDetails.fromCBOR(invoiceAddressData);
 81      }
 82  
 83      let shippingAddress: AddressDetails | undefined;
 84      const shippingAddressData = input.get("ShippingAddress");
 85      if (shippingAddressData !== undefined) {
 86        if (!(shippingAddressData instanceof Map)) {
 87          throw new TypeError("Expected ShippingAddress to be a Map");
 88        }
 89        shippingAddress = AddressDetails.fromCBOR(shippingAddressData);
 90      }
 91  
 92      let canceledAt: Date | undefined;
 93      const canceledAtData = input.get("CanceledAt");
 94      if (canceledAtData !== undefined) {
 95        canceledAt = ensureDate(canceledAtData, "CanceledAt");
 96      }
 97  
 98      let chosenPayee: Payee | undefined;
 99      const chosenPayeeData = input.get("ChosenPayee");
100      if (chosenPayeeData !== undefined) {
101        if (!(chosenPayeeData instanceof Map)) {
102          throw new TypeError("Expected ChosenPayee to be a Map");
103        }
104        chosenPayee = Payee.fromCBOR(chosenPayeeData);
105      }
106  
107      let chosenCurrency: ChainAddress | undefined;
108      const chosenCurrencyData = input.get("ChosenCurrency");
109      if (chosenCurrencyData !== undefined) {
110        if (!(chosenCurrencyData instanceof Map)) {
111          throw new TypeError("Expected ChosenCurrency to be a Map");
112        }
113        chosenCurrency = ChainAddress.fromCBOR(chosenCurrencyData);
114      }
115  
116      let paymentDetails: PaymentDetails | undefined;
117      const paymentDetailsData = input.get("PaymentDetails");
118      if (paymentDetailsData !== undefined) {
119        if (!(paymentDetailsData instanceof Map)) {
120          throw new TypeError("Expected PaymentDetails to be a Map");
121        }
122        paymentDetails = PaymentDetails.fromCBOR(paymentDetailsData);
123      }
124  
125      let txDetails: OrderPaid | undefined;
126      const txDetailsData = input.get("TxDetails");
127      if (txDetailsData !== undefined) {
128        if (!(txDetailsData instanceof Map)) {
129          throw new TypeError("Expected TxDetails to be a Map");
130        }
131        txDetails = OrderPaid.fromCBOR(txDetailsData);
132      }
133  
134      return new Order(
135        id,
136        items,
137        stateNum,
138        invoiceAddress,
139        shippingAddress,
140        canceledAt,
141        chosenPayee,
142        chosenCurrency,
143        paymentDetails,
144        txDetails,
145      );
146    }
147  }
148  
149  export class OrderedItem extends BaseClass {
150    ListingID: number;
151    VariationIDs?: string[];
152    Quantity: number;
153  
154    constructor(
155      listingID: number = 0,
156      quantity: number = 1,
157      variationIDs?: string[],
158    ) {
159      super();
160      this.ListingID = listingID;
161      this.Quantity = quantity;
162      this.VariationIDs = variationIDs;
163    }
164  
165    static fromCBOR(value: CodecValue): OrderedItem {
166      if (!(value instanceof Map)) {
167        throw new TypeError("Expected value to be a Map");
168      }
169      const input = value as Map<CodecKey, CodecValue>;
170      const listingID = ensureNumber(input.get("ListingID"), "ListingID");
171      const quantity = ensureNumber(input.get("Quantity"), "Quantity");
172  
173      let variationIDs: string[] | undefined;
174      const variationIDsData = input.get("VariationIDs");
175      if (variationIDsData !== undefined) {
176        variationIDs = ensureStringArray(variationIDsData, "VariationIDs");
177      }
178  
179      return new OrderedItem(listingID, quantity, variationIDs);
180    }
181  }
182  
183  export enum OrderState {
184    Unspecified = 0,
185    Open = 1,
186    Canceled = 2,
187    Committed = 3,
188    PaymentChosen = 4,
189    Unpaid = 5,
190    Paid = 6,
191  }
192  
193  export class AddressDetails extends BaseClass {
194    Name: string;
195    Address1: string;
196    Address2?: string;
197    City: string;
198    PostalCode: string;
199    Country: string;
200    EmailAddress: string;
201    PhoneNumber?: string;
202  
203    constructor(
204      name: string = "",
205      address1: string = "",
206      city: string = "",
207      postalCode: string = "",
208      country: string = "",
209      emailAddress: string = "",
210      address2?: string,
211      phoneNumber?: string,
212    ) {
213      super();
214      this.Name = name;
215      this.Address1 = address1;
216      this.Address2 = address2;
217      this.City = city;
218      this.PostalCode = postalCode;
219      this.Country = country;
220      this.EmailAddress = emailAddress;
221      this.PhoneNumber = phoneNumber;
222    }
223  
224    static fromCBOR(value: CodecValue): AddressDetails {
225      if (!(value instanceof Map)) {
226        throw new TypeError("Expected value to be a Map");
227      }
228      const input = value as Map<CodecKey, CodecValue>;
229      const name = ensureString(input.get("Name"), "Name");
230      const address1 = ensureString(input.get("Address1"), "Address1");
231      const city = ensureString(input.get("City"), "City");
232      const postalCode = ensureString(input.get("PostalCode"), "PostalCode");
233      const country = ensureString(input.get("Country"), "Country");
234      const emailAddress = ensureString(
235        input.get("EmailAddress"),
236        "EmailAddress",
237      );
238  
239      let address2: string | undefined;
240      const address2Data = input.get("Address2");
241      if (address2Data !== undefined) {
242        address2 = ensureString(address2Data, "Address2");
243      }
244  
245      let phoneNumber: string | undefined;
246      const phoneNumberData = input.get("PhoneNumber");
247      if (phoneNumberData !== undefined) {
248        phoneNumber = ensureString(phoneNumberData, "PhoneNumber");
249      }
250  
251      return new AddressDetails(
252        name,
253        address1,
254        city,
255        postalCode,
256        country,
257        emailAddress,
258        address2,
259        phoneNumber,
260      );
261    }
262  }
263  
264  export class PaymentDetails extends BaseClass {
265    PaymentID: Uint8Array;
266    Total: bigint | number;
267    ListingHashes: Uint8Array[];
268    TTL: number;
269    ShopSignature: Uint8Array;
270  
271    constructor(
272      paymentID: Uint8Array = new Uint8Array(32),
273      total: bigint | number = 0n,
274      ttl: number = 0,
275      shopSignature: Uint8Array = new Uint8Array(65),
276      listingHashes: Uint8Array[] = [],
277    ) {
278      super();
279      this.PaymentID = paymentID;
280      this.Total = total;
281      this.ListingHashes = listingHashes;
282      this.TTL = ttl;
283      this.ShopSignature = shopSignature;
284    }
285  
286    static fromCBOR(value: CodecValue): PaymentDetails {
287      if (!(value instanceof Map)) {
288        throw new TypeError("Expected value to be a Map");
289      }
290      const input = value as Map<CodecKey, CodecValue>;
291      const paymentID = ensureUint8Array(input.get("PaymentID"), "PaymentID", 32);
292      const total = ensureSomeNumberAsBigInt(input.get("Total"), "Total");
293      const ttl = ensureNumber(input.get("TTL"), "TTL");
294      const shopSignature = ensureUint8Array(
295        input.get("ShopSignature"),
296        "ShopSignature",
297        65,
298      );
299  
300      const listingHashes: Uint8Array[] = [];
301      const listingHashesData = input.get("ListingHashes");
302      if (listingHashesData !== undefined) {
303        if (!Array.isArray(listingHashesData)) {
304          throw new TypeError("Expected ListingHashes to be an array");
305        }
306        for (const [index, hash] of listingHashesData.entries()) {
307          if (!(hash instanceof Uint8Array)) {
308            throw new TypeError("Expected hash to be a Uint8Array");
309          }
310          listingHashes.push(ensureUint8Array(hash, `hash ${index}`, 32));
311        }
312      }
313  
314      return new PaymentDetails(
315        paymentID,
316        total,
317        ttl,
318        shopSignature,
319        listingHashes,
320      );
321    }
322  }
323  
324  export class OrderPaid extends BaseClass {
325    TxHash?: Uint8Array;
326    BlockHash: Uint8Array;
327  
328    constructor(blockHash: Uint8Array = new Uint8Array(32), txHash?: Uint8Array) {
329      super();
330      this.BlockHash = blockHash;
331      this.TxHash = txHash;
332    }
333  
334    static fromCBOR(value: CodecValue): OrderPaid {
335      if (!(value instanceof Map)) {
336        throw new TypeError("Expected value to be a Map");
337      }
338      const input = value as Map<CodecKey, CodecValue>;
339      const blockHash = ensureUint8Array(input.get("BlockHash"), "BlockHash", 32);
340  
341      let txHash: Uint8Array | undefined;
342      const txHashData = input.get("TxHash");
343      if (txHashData !== undefined) {
344        txHash = ensureUint8Array(txHashData, "TxHash", 32);
345      }
346  
347      return new OrderPaid(blockHash, txHash);
348    }
349  }