@letsbot/sdk 0.2.0 → 0.5.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.js CHANGED
@@ -74,6 +74,7 @@ var operations = {
74
74
  addGroupParticipant: { method: "POST", path: "/group/add/participant", params: "body", send: false },
75
75
  archiveChat: { method: "POST", path: "/chat/archive", params: "body", send: false },
76
76
  blockUser: { method: "POST", path: "/user/block", params: "body", send: false },
77
+ cancelOrder: { method: "POST", path: "/orders/{orderId}/cancel", params: "body", send: false },
77
78
  checkPhone: { method: "POST", path: "/check/phone", params: "body", send: false },
78
79
  createGroup: { method: "POST", path: "/group/create", params: "body", send: false },
79
80
  createProduct: { method: "POST", path: "/product/create", params: "body", send: false },
@@ -108,6 +109,7 @@ var operations = {
108
109
  qr: { method: "POST", path: "/qr", params: "none", send: false },
109
110
  queryBroadcast: { method: "POST", path: "/instance/query/broadcast", params: "body", send: false },
110
111
  readChat: { method: "POST", path: "/chat/read", params: "body", send: false },
112
+ recordOrder: { method: "POST", path: "/orders", params: "body", send: false },
111
113
  removeGroupParticipant: { method: "POST", path: "/group/remove/participant", params: "body", send: false },
112
114
  renameGroup: { method: "POST", path: "/group/rename", params: "body", send: false },
113
115
  revokeInviteCode: { method: "POST", path: "/invite/revoke/code", params: "body", send: false },
@@ -238,7 +240,7 @@ var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
238
240
 
239
241
  // src/client.ts
240
242
  var DEFAULT_BASE_URL = "https://letsbot.net/api/v1";
241
- var SDK_VERSION = "0.2.0";
243
+ var SDK_VERSION = "0.5.0";
242
244
  var IDEMPOTENT_METHODS = /* @__PURE__ */ new Set(["GET", "HEAD", "OPTIONS"]);
243
245
  var RETRYABLE_5XX = /* @__PURE__ */ new Set([500, 502, 503, 504]);
244
246
  var LetsBotClient = class {
@@ -520,6 +522,10 @@ var resourceMap = {
520
522
  collections: "getCollections",
521
523
  getOrder: "getOrder"
522
524
  },
525
+ orders: {
526
+ record: "recordOrder",
527
+ cancel: "cancelOrder"
528
+ },
523
529
  session: {
524
530
  qr: "qr",
525
531
  find: "findSession",
@@ -561,13 +567,16 @@ var crmOperations = {
561
567
  crmCompleteTask: { method: "POST", path: "/tasks/{id}/complete", body: false },
562
568
  crmContactsSchema: { method: "GET", path: "/contacts/schema", body: false },
563
569
  crmCreateActivity: { method: "POST", path: "/activities", body: true },
564
- crmCreateCompany: { method: "POST", path: "/companies", body: true },
565
- crmCreateContact: { method: "POST", path: "/contacts", body: true },
570
+ crmCreateCompany: { method: "POST", path: "/companies", body: true, query: ["allow_duplicate"] },
571
+ crmCreateContact: { method: "POST", path: "/contacts", body: true, query: ["allow_duplicate"] },
572
+ crmCreateCustomRecord: { method: "POST", path: "/objects/{key}/records", body: true },
566
573
  crmCreateDeal: { method: "POST", path: "/deals", body: true },
567
574
  crmCreateProduct: { method: "POST", path: "/products", body: true },
568
575
  crmCreateQuote: { method: "POST", path: "/quotes", body: true },
569
576
  crmCreateTask: { method: "POST", path: "/tasks", body: true },
577
+ crmCustomObjectSchema: { method: "GET", path: "/objects/{key}/schema", body: false },
570
578
  crmDeleteCompany: { method: "DELETE", path: "/companies/{id}", body: false },
579
+ crmDeleteCustomRecord: { method: "DELETE", path: "/objects/{key}/records/{id}", body: false },
571
580
  crmDeleteDeal: { method: "DELETE", path: "/deals/{id}", body: false },
572
581
  crmDeleteProduct: { method: "DELETE", path: "/products/{id}", body: false },
573
582
  crmDeleteQuote: { method: "DELETE", path: "/quotes/{id}", body: false },
@@ -575,6 +584,7 @@ var crmOperations = {
575
584
  crmGetActivity: { method: "GET", path: "/activities/{id}", body: false },
576
585
  crmGetCompany: { method: "GET", path: "/companies/{id}", body: false },
577
586
  crmGetContact: { method: "GET", path: "/contacts/{id}", body: false },
587
+ crmGetCustomRecord: { method: "GET", path: "/objects/{key}/records/{id}", body: false },
578
588
  crmGetDeal: { method: "GET", path: "/deals/{id}", body: false },
579
589
  crmGetProduct: { method: "GET", path: "/products/{id}", body: false },
580
590
  crmGetQuote: { method: "GET", path: "/quotes/{id}", body: false },
@@ -584,6 +594,8 @@ var crmOperations = {
584
594
  crmListActivities: { method: "GET", path: "/activities", body: false },
585
595
  crmListCompanies: { method: "GET", path: "/companies", body: false },
586
596
  crmListContacts: { method: "GET", path: "/contacts", body: false },
597
+ crmListCustomObjects: { method: "GET", path: "/objects", body: false },
598
+ crmListCustomRecords: { method: "GET", path: "/objects/{key}/records", body: false },
587
599
  crmListDeals: { method: "GET", path: "/deals", body: false },
588
600
  crmListHookEvents: { method: "GET", path: "/hooks/events", body: false },
589
601
  crmListHooks: { method: "GET", path: "/hooks", body: false },
@@ -599,12 +611,14 @@ var crmOperations = {
599
611
  crmQuotesSchema: { method: "GET", path: "/quotes/schema", body: false },
600
612
  crmSearchCompanies: { method: "GET", path: "/companies/search", body: false },
601
613
  crmSearchContacts: { method: "GET", path: "/contacts/search", body: false },
614
+ crmSearchCustomRecords: { method: "GET", path: "/objects/{key}/records/search", body: false },
602
615
  crmSearchDeals: { method: "GET", path: "/deals/search", body: false },
603
616
  crmSubscribeHook: { method: "POST", path: "/hooks", body: true },
604
617
  crmUnlinkCompanyContact: { method: "DELETE", path: "/companies/{id}/contacts/{contactId}", body: false },
605
618
  crmUnsubscribeHook: { method: "DELETE", path: "/hooks/{id}", body: false },
606
619
  crmUpdateCompany: { method: "PATCH", path: "/companies/{id}", body: true },
607
620
  crmUpdateContact: { method: "PATCH", path: "/contacts/{id}", body: true },
621
+ crmUpdateCustomRecord: { method: "PATCH", path: "/objects/{key}/records/{id}", body: true },
608
622
  crmUpdateDeal: { method: "PATCH", path: "/deals/{id}", body: true },
609
623
  crmUpdateProduct: { method: "PATCH", path: "/products/{id}", body: true },
610
624
  crmUpdateQuote: { method: "PATCH", path: "/quotes/{id}", body: true },
@@ -612,6 +626,40 @@ var crmOperations = {
612
626
  };
613
627
 
614
628
  // src/crm.ts
629
+ var CRM_WEBHOOK_EVENTS = [
630
+ "contact.created",
631
+ "contact.updated",
632
+ "contact.deleted",
633
+ "company.created",
634
+ "company.updated",
635
+ "company.deleted",
636
+ "deal.created",
637
+ "deal.updated",
638
+ "deal.deleted",
639
+ "deal.stage_changed",
640
+ "deal.won",
641
+ "deal.lost",
642
+ "deal.assigned",
643
+ "task.created",
644
+ "task.completed",
645
+ "ticket.created",
646
+ "quote.sent",
647
+ "quote.viewed",
648
+ "quote.accepted",
649
+ "quote.signed",
650
+ "quote.paid",
651
+ "invoice.created",
652
+ "form.submitted",
653
+ "health.at_risk"
654
+ ];
655
+ function crmPossibleDuplicate(error) {
656
+ const e = error;
657
+ if (!e || e.status !== 409 || e.code !== "possible_duplicate") return null;
658
+ const body = e.body ?? {};
659
+ const duplicates = Array.isArray(body.duplicates) ? body.duplicates : [];
660
+ const existingId = Number(body.existing_id ?? duplicates[0]?.id);
661
+ return Number.isFinite(existingId) ? { existingId, duplicates } : null;
662
+ }
615
663
  var CRM_DEFAULT_RATE_LIMIT = 120;
616
664
  var CRM_SIGNATURE_HEADER = "X-LetsBot-Signature";
617
665
  var crmResourceMap = {
@@ -679,6 +727,18 @@ var crmResourceMap = {
679
727
  update: "crmUpdateProduct",
680
728
  delete: "crmDeleteProduct"
681
729
  },
730
+ customObjects: {
731
+ list: "crmListCustomObjects",
732
+ schema: "crmCustomObjectSchema"
733
+ },
734
+ customRecords: {
735
+ list: "crmListCustomRecords",
736
+ search: "crmSearchCustomRecords",
737
+ get: "crmGetCustomRecord",
738
+ create: "crmCreateCustomRecord",
739
+ update: "crmUpdateCustomRecord",
740
+ delete: "crmDeleteCustomRecord"
741
+ },
682
742
  hooks: {
683
743
  list: "crmListHooks",
684
744
  events: "crmListHookEvents",
@@ -719,6 +779,10 @@ var LetsBotCrm = class {
719
779
  activities;
720
780
  quotes;
721
781
  products;
782
+ /** Custom objects (`/objects`): 404 until the workspace has custom objects switched on. */
783
+ customObjects;
784
+ /** Records of a custom object (`/objects/{key}/records`); pass the object `key`, e.g. `co_projects`. */
785
+ customRecords;
722
786
  hooks;
723
787
  transport;
724
788
  constructor(options) {
@@ -747,6 +811,8 @@ var LetsBotCrm = class {
747
811
  this.activities = bind(crmResourceMap.activities);
748
812
  this.quotes = bind(crmResourceMap.quotes);
749
813
  this.products = bind(crmResourceMap.products);
814
+ this.customObjects = bind(crmResourceMap.customObjects);
815
+ this.customRecords = bind(crmResourceMap.customRecords);
750
816
  this.hooks = bind(crmResourceMap.hooks);
751
817
  }
752
818
  /** The resolved base URL, e.g. `https://mystore.letsbot.net/api/v1/crm`. */
@@ -772,10 +838,19 @@ var LetsBotCrm = class {
772
838
  return encodeURIComponent(String(value));
773
839
  });
774
840
  const url = new URL(this.transport.root + path);
841
+ const append = (key, value) => {
842
+ if (value === void 0 || value === null) return;
843
+ url.searchParams.append(key, typeof value === "object" ? JSON.stringify(value) : String(value));
844
+ };
775
845
  if (!meta.body) {
776
- for (const [key, value] of Object.entries(rest)) {
777
- if (value === void 0 || value === null) continue;
778
- url.searchParams.append(key, typeof value === "object" ? JSON.stringify(value) : String(value));
846
+ for (const [key, value] of Object.entries(rest)) append(key, value);
847
+ } else if ("query" in meta) {
848
+ for (const key of meta.query) {
849
+ if (key in rest) {
850
+ const value = rest[key];
851
+ append(key, typeof value === "boolean" ? value ? 1 : 0 : value);
852
+ delete rest[key];
853
+ }
779
854
  }
780
855
  }
781
856
  return this.transport.request(operationId, meta.method, url, meta.body ? rest : void 0, options);
@@ -811,6 +886,240 @@ function verifyCrmWebhookSignature(rawBody, header, secret, options = {}) {
811
886
  const given = Buffer.from(v1, "hex");
812
887
  return given.length === expected.length && timingSafeEqual(given, expected);
813
888
  }
889
+
890
+ // src/generated/erp-operations.ts
891
+ var erpOperations = {
892
+ erpConfirmSalesOrder: { method: "POST", path: "/sales/orders/{id}/confirm", body: false, idempotent: false },
893
+ erpCreateCreditNote: { method: "POST", path: "/sales/invoices/{id}/credit-notes", body: true, idempotent: true },
894
+ erpCreateExpense: { method: "POST", path: "/expenses", body: true, idempotent: true },
895
+ erpCreateInvoice: { method: "POST", path: "/sales/invoices", body: true, idempotent: true },
896
+ erpCreatePurchaseOrder: { method: "POST", path: "/purchasing/purchase-orders", body: true, idempotent: true },
897
+ erpCreateSalesOrder: { method: "POST", path: "/sales/orders", body: true, idempotent: true },
898
+ erpCustomerStatement: { method: "GET", path: "/sales/customers/{id}/statement", body: false, idempotent: false },
899
+ erpGetBill: { method: "GET", path: "/purchasing/bills/{id}", body: false, idempotent: false },
900
+ erpGetCreditNote: { method: "GET", path: "/sales/credit-notes/{id}", body: false, idempotent: false },
901
+ erpGetCustomer: { method: "GET", path: "/sales/customers/{id}", body: false, idempotent: false },
902
+ erpGetExpense: { method: "GET", path: "/expenses/{id}", body: false, idempotent: false },
903
+ erpGetInvoice: { method: "GET", path: "/sales/invoices/{id}", body: false, idempotent: false },
904
+ erpGetItem: { method: "GET", path: "/inventory/items/{id}", body: false, idempotent: false },
905
+ erpGetJournalEntry: { method: "GET", path: "/accounting/journal-entries/{id}", body: false, idempotent: false },
906
+ erpGetPayment: { method: "GET", path: "/sales/payments/{id}", body: false, idempotent: false },
907
+ erpGetPurchaseOrder: { method: "GET", path: "/purchasing/purchase-orders/{id}", body: false, idempotent: false },
908
+ erpGetSalesOrder: { method: "GET", path: "/sales/orders/{id}", body: false, idempotent: false },
909
+ erpGetSupplier: { method: "GET", path: "/purchasing/suppliers/{id}", body: false, idempotent: false },
910
+ erpHookEvents: { method: "GET", path: "/hooks/events", body: false, idempotent: false },
911
+ erpHookSample: { method: "GET", path: "/hooks/sample", body: false, idempotent: false },
912
+ erpInvoicePdfLink: { method: "GET", path: "/sales/invoices/{id}/pdf", body: false, idempotent: false },
913
+ erpIssueCreditNote: { method: "POST", path: "/sales/credit-notes/{id}/issue", body: false, idempotent: false },
914
+ erpIssueInvoice: { method: "POST", path: "/sales/invoices/{id}/issue", body: false, idempotent: false },
915
+ erpListAccounts: { method: "GET", path: "/accounting/accounts", body: false, idempotent: false },
916
+ erpListBills: { method: "GET", path: "/purchasing/bills", body: false, idempotent: false },
917
+ erpListCreditNotes: { method: "GET", path: "/sales/credit-notes", body: false, idempotent: false },
918
+ erpListCustomers: { method: "GET", path: "/sales/customers", body: false, idempotent: false },
919
+ erpListExpenseCategories: { method: "GET", path: "/expenses/categories", body: false, idempotent: false },
920
+ erpListExpenses: { method: "GET", path: "/expenses", body: false, idempotent: false },
921
+ erpListHooks: { method: "GET", path: "/hooks", body: false, idempotent: false },
922
+ erpListInvoices: { method: "GET", path: "/sales/invoices", body: false, idempotent: false },
923
+ erpListItems: { method: "GET", path: "/inventory/items", body: false, idempotent: false },
924
+ erpListJournalEntries: { method: "GET", path: "/accounting/journal-entries", body: false, idempotent: false },
925
+ erpListPayments: { method: "GET", path: "/sales/payments", body: false, idempotent: false },
926
+ erpListPurchaseOrders: { method: "GET", path: "/purchasing/purchase-orders", body: false, idempotent: false },
927
+ erpListSalesOrders: { method: "GET", path: "/sales/orders", body: false, idempotent: false },
928
+ erpListStockLevels: { method: "GET", path: "/inventory/stock-levels", body: false, idempotent: false },
929
+ erpListStockMoves: { method: "GET", path: "/inventory/stock-moves", body: false, idempotent: false },
930
+ erpListSuppliers: { method: "GET", path: "/purchasing/suppliers", body: false, idempotent: false },
931
+ erpListVariants: { method: "GET", path: "/inventory/variants", body: false, idempotent: false },
932
+ erpListWarehouses: { method: "GET", path: "/inventory/warehouses", body: false, idempotent: false },
933
+ erpRecordPayment: { method: "POST", path: "/sales/payments", body: true, idempotent: true },
934
+ erpReportBalanceSheet: { method: "GET", path: "/accounting/reports/balance-sheet", body: false, idempotent: false },
935
+ erpReportProfitAndLoss: { method: "GET", path: "/accounting/reports/profit-and-loss", body: false, idempotent: false },
936
+ erpReportVat: { method: "GET", path: "/accounting/reports/vat", body: false, idempotent: false },
937
+ erpSubscribeHook: { method: "POST", path: "/hooks", body: true, idempotent: false },
938
+ erpUnsubscribeHook: { method: "DELETE", path: "/hooks/{id}", body: false, idempotent: false }
939
+ };
940
+
941
+ // src/erp.ts
942
+ var ERP_DEFAULT_RATE_LIMIT = 120;
943
+ var ERP_WEBHOOK_EVENTS = [
944
+ "invoice.issued",
945
+ "invoice.paid",
946
+ "invoice.cleared",
947
+ "invoice.rejected",
948
+ "credit_note.issued",
949
+ "payment.received",
950
+ "order.confirmed",
951
+ "stock.low",
952
+ "po.confirmed_by_supplier",
953
+ "expense.posted"
954
+ ];
955
+ var erpResourceMap = {
956
+ items: { list: "erpListItems", get: "erpGetItem" },
957
+ variants: { list: "erpListVariants" },
958
+ warehouses: { list: "erpListWarehouses" },
959
+ stock: { levels: "erpListStockLevels", moves: "erpListStockMoves" },
960
+ customers: { list: "erpListCustomers", get: "erpGetCustomer", statement: "erpCustomerStatement" },
961
+ salesOrders: { list: "erpListSalesOrders", get: "erpGetSalesOrder", create: "erpCreateSalesOrder", confirm: "erpConfirmSalesOrder" },
962
+ invoices: {
963
+ list: "erpListInvoices",
964
+ get: "erpGetInvoice",
965
+ create: "erpCreateInvoice",
966
+ issue: "erpIssueInvoice",
967
+ pdfLink: "erpInvoicePdfLink",
968
+ createCreditNote: "erpCreateCreditNote"
969
+ },
970
+ creditNotes: { list: "erpListCreditNotes", get: "erpGetCreditNote", issue: "erpIssueCreditNote" },
971
+ payments: { list: "erpListPayments", get: "erpGetPayment", record: "erpRecordPayment" },
972
+ suppliers: { list: "erpListSuppliers", get: "erpGetSupplier" },
973
+ purchaseOrders: { list: "erpListPurchaseOrders", get: "erpGetPurchaseOrder", create: "erpCreatePurchaseOrder" },
974
+ bills: { list: "erpListBills", get: "erpGetBill" },
975
+ expenses: { list: "erpListExpenses", get: "erpGetExpense", create: "erpCreateExpense", categories: "erpListExpenseCategories" },
976
+ accounting: {
977
+ accounts: "erpListAccounts",
978
+ journalEntries: "erpListJournalEntries",
979
+ journalEntry: "erpGetJournalEntry",
980
+ profitAndLoss: "erpReportProfitAndLoss",
981
+ balanceSheet: "erpReportBalanceSheet",
982
+ vat: "erpReportVat"
983
+ },
984
+ hooks: {
985
+ list: "erpListHooks",
986
+ events: "erpHookEvents",
987
+ sample: "erpHookSample",
988
+ subscribe: "erpSubscribeHook",
989
+ unsubscribe: "erpUnsubscribeHook"
990
+ }
991
+ };
992
+ var UNSAFE2 = /* @__PURE__ */ new Set(["POST", "PATCH", "PUT", "DELETE"]);
993
+ function erpBaseUrl(workspace) {
994
+ const raw = workspace.trim();
995
+ if (raw === "") throw new TypeError("LetsBotErp: `workspace` is empty");
996
+ const host = (/^https?:\/\//i.test(raw) ? new URL(raw).host : raw.split("/")[0]).toLowerCase();
997
+ return `https://${host.includes(".") ? host : `${host}.letsbot.net`}/api/v1/erp`;
998
+ }
999
+ var ErpTransport = class extends LetsBotClient {
1000
+ authHeaders(apiKey) {
1001
+ return { "X-Zapier-Api-Key": apiKey };
1002
+ }
1003
+ request(operationId, method, url, json, idempotent, options) {
1004
+ const headers = this.baseHeaders(options);
1005
+ let body;
1006
+ if (json !== void 0) {
1007
+ headers["Content-Type"] = "application/json";
1008
+ body = JSON.stringify(json);
1009
+ }
1010
+ let idempotencyKey;
1011
+ if (idempotent && options.idempotencyKey !== false) {
1012
+ idempotencyKey = options.idempotencyKey ?? this.newKey();
1013
+ headers["Idempotency-Key"] = idempotencyKey;
1014
+ }
1015
+ const unsafeRetryAllowed = !UNSAFE2.has(method) || idempotencyKey !== void 0;
1016
+ return this.perform(operationId, method, url, headers, body, { idempotencyKey, unsafeRetryAllowed }, options);
1017
+ }
1018
+ get root() {
1019
+ return this.baseUrl;
1020
+ }
1021
+ };
1022
+ var LetsBotErp = class {
1023
+ items;
1024
+ variants;
1025
+ warehouses;
1026
+ stock;
1027
+ customers;
1028
+ salesOrders;
1029
+ invoices;
1030
+ creditNotes;
1031
+ payments;
1032
+ suppliers;
1033
+ purchaseOrders;
1034
+ bills;
1035
+ expenses;
1036
+ accounting;
1037
+ hooks;
1038
+ transport;
1039
+ constructor(options) {
1040
+ if (!options?.baseUrl && !options?.workspace) {
1041
+ throw new TypeError("LetsBotErp: pass `workspace` (e.g. mystore.letsbot.net) or `baseUrl`");
1042
+ }
1043
+ this.transport = new ErpTransport(
1044
+ {
1045
+ ...options,
1046
+ baseUrl: options.baseUrl ?? erpBaseUrl(options.workspace),
1047
+ rateLimit: options.rateLimit === false ? false : { requestsPerMinute: options.rateLimit?.requestsPerMinute ?? ERP_DEFAULT_RATE_LIMIT }
1048
+ },
1049
+ "LetsBotErp: `apiKey` (a workspace API key with the erp scope)"
1050
+ );
1051
+ const bind = (map) => {
1052
+ const bound = {};
1053
+ for (const [name, id] of Object.entries(map)) {
1054
+ bound[name] = (params, options2) => this.call(id, ...[params, options2]);
1055
+ }
1056
+ return bound;
1057
+ };
1058
+ this.items = bind(erpResourceMap.items);
1059
+ this.variants = bind(erpResourceMap.variants);
1060
+ this.warehouses = bind(erpResourceMap.warehouses);
1061
+ this.stock = bind(erpResourceMap.stock);
1062
+ this.customers = bind(erpResourceMap.customers);
1063
+ this.salesOrders = bind(erpResourceMap.salesOrders);
1064
+ this.invoices = bind(erpResourceMap.invoices);
1065
+ this.creditNotes = bind(erpResourceMap.creditNotes);
1066
+ this.payments = bind(erpResourceMap.payments);
1067
+ this.suppliers = bind(erpResourceMap.suppliers);
1068
+ this.purchaseOrders = bind(erpResourceMap.purchaseOrders);
1069
+ this.bills = bind(erpResourceMap.bills);
1070
+ this.expenses = bind(erpResourceMap.expenses);
1071
+ this.accounting = bind(erpResourceMap.accounting);
1072
+ this.hooks = bind(erpResourceMap.hooks);
1073
+ }
1074
+ /** The resolved base URL, e.g. `https://mystore.letsbot.net/api/v1/erp`. */
1075
+ get baseUrl() {
1076
+ return this.transport.root;
1077
+ }
1078
+ /** Call any ERP operation by its operationId and get the body. */
1079
+ async call(operationId, ...args) {
1080
+ return (await this.callWithResponse(operationId, ...args)).data;
1081
+ }
1082
+ /** Call any ERP operation and get the body plus status, headers, Idempotency-Key and replay flag. */
1083
+ async callWithResponse(operationId, ...args) {
1084
+ const [params = {}, options = {}] = args;
1085
+ const meta = erpOperations[operationId];
1086
+ if (!meta) throw new TypeError(`Unknown LetsBot ERP operation: ${String(operationId)}`);
1087
+ const rest = { ...params };
1088
+ const path = meta.path.replace(/\{(\w+)\}/g, (_, name) => {
1089
+ const value = rest[name];
1090
+ if (value === void 0 || value === null || value === "") {
1091
+ throw new TypeError(`${operationId}: \`${name}\` is required`);
1092
+ }
1093
+ delete rest[name];
1094
+ return encodeURIComponent(String(value));
1095
+ });
1096
+ const url = new URL(this.transport.root + path);
1097
+ if (!meta.body) {
1098
+ for (const [key, value] of Object.entries(rest)) {
1099
+ if (value === void 0 || value === null) continue;
1100
+ url.searchParams.append(key, typeof value === "object" ? JSON.stringify(value) : String(value));
1101
+ }
1102
+ }
1103
+ return this.transport.request(operationId, meta.method, url, meta.body ? rest : void 0, meta.idempotent, options);
1104
+ }
1105
+ /**
1106
+ * Every row of a list, page by page (`meta.last_page`).
1107
+ *
1108
+ * ```ts
1109
+ * for await (const invoice of erp.iterate('erpListInvoices', { status: 'issued,partially_paid', overdue: true })) { … }
1110
+ * ```
1111
+ */
1112
+ async *iterate(operationId, params = {}, options) {
1113
+ for (let page = 1; ; page++) {
1114
+ const body = await this.call(operationId, ...[{ per_page: 100, ...params, page }, options]);
1115
+ yield* body.data;
1116
+ if (body.data.length === 0 || page >= (body.meta?.last_page ?? page)) return;
1117
+ }
1118
+ }
1119
+ };
1120
+ function verifyErpWebhookSignature(rawBody, header, secret, options = {}) {
1121
+ return verifyCrmWebhookSignature(rawBody, header, secret, options);
1122
+ }
814
1123
  var IDENTITY_MAX_SUB_LENGTH = 191;
815
1124
  var IDENTITY_MAX_TTL_SECONDS = 7 * 24 * 60 * 60;
816
1125
  var IDENTITY_DEFAULT_TTL = "24h";
@@ -887,6 +1196,8 @@ var LetsBot = class extends LetsBotClient {
887
1196
  user;
888
1197
  instance;
889
1198
  products;
1199
+ /** Store orders: record one (order journey + invoice) or stop its journey. */
1200
+ orders;
890
1201
  session;
891
1202
  archive;
892
1203
  constructor(options) {
@@ -902,6 +1213,7 @@ var LetsBot = class extends LetsBotClient {
902
1213
  this.user = bindResource(this, resourceMap.user);
903
1214
  this.instance = bindResource(this, resourceMap.instance);
904
1215
  this.products = bindResource(this, resourceMap.products);
1216
+ this.orders = bindResource(this, resourceMap.orders);
905
1217
  this.session = bindResource(this, resourceMap.session);
906
1218
  this.archive = {
907
1219
  ...bindResource(this, resourceMap.archive),
@@ -910,6 +1222,6 @@ var LetsBot = class extends LetsBotClient {
910
1222
  }
911
1223
  };
912
1224
 
913
- export { CRM_DEFAULT_RATE_LIMIT, CRM_SIGNATURE_HEADER, DEFAULT_BASE_URL, IDENTITY_DEFAULT_TTL, IDENTITY_MAX_SUB_LENGTH, IDENTITY_MAX_TTL_SECONDS, LEGACY_WEBHOOK_SECRET, LetsBot, LetsBotApiError, LetsBotClient, LetsBotConnectionError, LetsBotCrm, SDK_VERSION, TokenBucket, createIdentityToken, crmBaseUrl, crmOperations, crmResourceMap, experimental_verifyWebhookSignature, isLogicalFailure, operations, resourceMap, verifyCrmWebhookSignature };
1225
+ export { CRM_DEFAULT_RATE_LIMIT, CRM_SIGNATURE_HEADER, CRM_WEBHOOK_EVENTS, DEFAULT_BASE_URL, ERP_DEFAULT_RATE_LIMIT, ERP_WEBHOOK_EVENTS, IDENTITY_DEFAULT_TTL, IDENTITY_MAX_SUB_LENGTH, IDENTITY_MAX_TTL_SECONDS, LEGACY_WEBHOOK_SECRET, LetsBot, LetsBotApiError, LetsBotClient, LetsBotConnectionError, LetsBotCrm, LetsBotErp, SDK_VERSION, TokenBucket, createIdentityToken, crmBaseUrl, crmOperations, crmPossibleDuplicate, crmResourceMap, erpBaseUrl, erpOperations, erpResourceMap, experimental_verifyWebhookSignature, isLogicalFailure, operations, resourceMap, verifyCrmWebhookSignature, verifyErpWebhookSignature };
914
1226
  //# sourceMappingURL=index.js.map
915
1227
  //# sourceMappingURL=index.js.map