@whatalo/plugin-sdk 1.2.0 → 1.2.2

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.
Files changed (59) hide show
  1. package/dist/adapters/express.cjs +106 -10
  2. package/dist/adapters/express.cjs.map +1 -1
  3. package/dist/adapters/express.d.cts +9 -7
  4. package/dist/adapters/express.d.ts +9 -7
  5. package/dist/adapters/express.mjs +109 -10
  6. package/dist/adapters/express.mjs.map +1 -1
  7. package/dist/adapters/hono.cjs +99 -7
  8. package/dist/adapters/hono.cjs.map +1 -1
  9. package/dist/adapters/hono.d.cts +4 -3
  10. package/dist/adapters/hono.d.ts +4 -3
  11. package/dist/adapters/hono.mjs +102 -7
  12. package/dist/adapters/hono.mjs.map +1 -1
  13. package/dist/adapters/nextjs.cjs +99 -7
  14. package/dist/adapters/nextjs.cjs.map +1 -1
  15. package/dist/adapters/nextjs.d.cts +4 -3
  16. package/dist/adapters/nextjs.d.ts +4 -3
  17. package/dist/adapters/nextjs.mjs +102 -7
  18. package/dist/adapters/nextjs.mjs.map +1 -1
  19. package/dist/bridge/index.cjs +60 -5
  20. package/dist/bridge/index.cjs.map +1 -1
  21. package/dist/bridge/index.d.cts +17 -5
  22. package/dist/bridge/index.d.ts +17 -5
  23. package/dist/bridge/index.mjs +60 -5
  24. package/dist/bridge/index.mjs.map +1 -1
  25. package/dist/client/index.cjs +33 -2
  26. package/dist/client/index.cjs.map +1 -1
  27. package/dist/client/index.d.cts +29 -1
  28. package/dist/client/index.d.ts +29 -1
  29. package/dist/client/index.mjs +33 -2
  30. package/dist/client/index.mjs.map +1 -1
  31. package/dist/index.cjs +179 -28
  32. package/dist/index.cjs.map +1 -1
  33. package/dist/index.d.cts +7 -4
  34. package/dist/index.d.ts +7 -4
  35. package/dist/index.mjs +179 -28
  36. package/dist/index.mjs.map +1 -1
  37. package/dist/manifest/index.cjs +2 -17
  38. package/dist/manifest/index.cjs.map +1 -1
  39. package/dist/manifest/index.d.cts +10 -4
  40. package/dist/manifest/index.d.ts +10 -4
  41. package/dist/manifest/index.mjs +2 -17
  42. package/dist/manifest/index.mjs.map +1 -1
  43. package/dist/{types-DcmArIC2.d.ts → types-B8BAV362.d.cts} +24 -1
  44. package/dist/{types-DcmArIC2.d.cts → types-B8BAV362.d.ts} +24 -1
  45. package/dist/types-Bzee9Hvr.d.ts +25 -0
  46. package/dist/types-CDKGAQ3o.d.ts +155 -0
  47. package/dist/types-CPnSzOfX.d.cts +155 -0
  48. package/dist/types-CqyAhbXM.d.cts +25 -0
  49. package/dist/webhooks/index.cjs +83 -3
  50. package/dist/webhooks/index.cjs.map +1 -1
  51. package/dist/webhooks/index.d.cts +11 -4
  52. package/dist/webhooks/index.d.ts +11 -4
  53. package/dist/webhooks/index.mjs +83 -3
  54. package/dist/webhooks/index.mjs.map +1 -1
  55. package/package.json +4 -1
  56. package/dist/types-C9mg4aQg.d.ts +0 -19
  57. package/dist/types-DMuHSL_a.d.cts +0 -19
  58. package/dist/types-DTjA3FHe.d.ts +0 -68
  59. package/dist/types-tHUO9u-c.d.cts +0 -68
package/dist/index.mjs CHANGED
@@ -111,6 +111,8 @@ var WhataloClient = class {
111
111
  inventory;
112
112
  /** Webhook resource methods */
113
113
  webhooks;
114
+ /** Geo reference data methods */
115
+ geo;
114
116
  constructor(options) {
115
117
  if (typeof window !== "undefined" && typeof process === "undefined") {
116
118
  console.warn(
@@ -132,6 +134,7 @@ var WhataloClient = class {
132
134
  this.store = new StoreResource(this);
133
135
  this.inventory = new InventoryResource(this);
134
136
  this.webhooks = new WebhookResource(this);
137
+ this.geo = new GeoResource(this);
135
138
  }
136
139
  /**
137
140
  * Internal request method shared by all resource namespaces.
@@ -373,10 +376,10 @@ var InventoryResource = class {
373
376
  this.client = client;
374
377
  }
375
378
  async get(productId) {
376
- return this.client.request("GET", `/products/${productId}/inventory`);
379
+ return this.client.request("GET", `/inventory/products/${productId}`);
377
380
  }
378
381
  async adjust(productId, data) {
379
- return this.client.request("PATCH", `/products/${productId}/inventory`, {
382
+ return this.client.request("PATCH", `/inventory/products/${productId}`, {
380
383
  body: data
381
384
  });
382
385
  }
@@ -398,17 +401,57 @@ var WebhookResource = class {
398
401
  return this.client.request("DELETE", `/webhooks/${id}`);
399
402
  }
400
403
  };
404
+ var GeoResource = class {
405
+ constructor(client) {
406
+ this.client = client;
407
+ }
408
+ /**
409
+ * List countries.
410
+ * By default returns only supported countries (is_supported=true).
411
+ * Pass `{ all: true }` to retrieve all 250 countries.
412
+ */
413
+ async listCountries(params) {
414
+ return this.client.request("GET", "/geo/countries", {
415
+ params: params?.all !== void 0 ? { all: params.all } : void 0
416
+ });
417
+ }
418
+ /**
419
+ * Get a single country by ISO 3166-1 alpha-2 code.
420
+ */
421
+ async getCountry(iso2) {
422
+ return this.client.request("GET", `/geo/countries/${iso2.toUpperCase()}`);
423
+ }
424
+ /**
425
+ * List provinces (states, departments, regions) for a country.
426
+ * Returns an empty array for countries with no province data.
427
+ */
428
+ async listProvinces(countryIso2) {
429
+ return this.client.request("GET", `/geo/countries/${countryIso2.toUpperCase()}/provinces`);
430
+ }
431
+ };
401
432
 
402
433
  // src/webhooks/verify.ts
403
434
  import { createHmac, timingSafeEqual } from "crypto";
435
+ var DEFAULT_TOLERANCE_SECONDS = 300;
404
436
  function verifyWebhook({
405
437
  payload,
406
438
  signature,
407
- secret
439
+ timestamp,
440
+ secret,
441
+ toleranceSeconds = DEFAULT_TOLERANCE_SECONDS,
442
+ currentTime = Math.floor(Date.now() / 1e3)
408
443
  }) {
409
- if (!payload || !signature || !secret) return false;
410
- const expected = createHmac("sha256", secret).update(payload, "utf8").digest("hex");
444
+ if (!payload || !signature || !secret || timestamp === "") return false;
445
+ const timestampString = String(timestamp);
446
+ const timestampValue = typeof timestamp === "number" ? timestamp : Number(timestamp);
447
+ if (!Number.isInteger(timestampValue)) return false;
448
+ if (!Number.isFinite(toleranceSeconds) || toleranceSeconds < 0) return false;
449
+ if (!Number.isFinite(currentTime)) return false;
450
+ const ageSeconds = Math.abs(currentTime - timestampValue);
451
+ if (ageSeconds > toleranceSeconds) return false;
452
+ const expected = createHmac("sha256", secret).update(`${timestampString}.${payload}`, "utf8").digest("hex");
411
453
  if (expected.length !== signature.length) return false;
454
+ if (!/^[a-f0-9]+$/i.test(signature)) return false;
412
455
  try {
413
456
  return timingSafeEqual(
414
457
  Buffer.from(expected, "hex"),
@@ -419,7 +462,73 @@ function verifyWebhook({
419
462
  }
420
463
  }
421
464
 
465
+ // src/webhooks/types.ts
466
+ import {
467
+ PUBLIC_WEBHOOK_EVENTS,
468
+ isPublicWebhookEvent
469
+ } from "@whatalo/protocol/events";
470
+ var WEBHOOK_EVENTS = PUBLIC_WEBHOOK_EVENTS;
471
+ function isWebhookEvent(value) {
472
+ return isPublicWebhookEvent(value);
473
+ }
474
+ function isRecord(value) {
475
+ return typeof value === "object" && value !== null && !Array.isArray(value);
476
+ }
477
+ function hasStringId(value) {
478
+ return isRecord(value) && typeof value.id === "string";
479
+ }
480
+ function isOptionalString(value, key) {
481
+ return value[key] === void 0 || typeof value[key] === "string";
482
+ }
483
+ function isRuntimeWebhookStore(value) {
484
+ return isRecord(value) && typeof value.id === "string" && typeof value.timezone === "string" && (value.name === void 0 || typeof value.name === "string");
485
+ }
486
+ function hasValidBasePayloadFields(value) {
487
+ if (!isOptionalString(value, "event_id")) return false;
488
+ if (!isOptionalString(value, "occurred_at")) return false;
489
+ return isRuntimeWebhookStore(value.store);
490
+ }
491
+ function isRuntimeOrderWebhookPayload(value) {
492
+ return hasValidBasePayloadFields(value) && hasStringId(value.order) && (value.customer === void 0 || hasStringId(value.customer));
493
+ }
494
+ function isRuntimeProductWebhookPayload(value) {
495
+ return hasValidBasePayloadFields(value) && hasStringId(value.product);
496
+ }
497
+ function isRuntimeCustomerWebhookPayload(value) {
498
+ return hasValidBasePayloadFields(value) && hasStringId(value.customer);
499
+ }
500
+ function isRuntimeCheckoutCompletedWebhookPayload(value) {
501
+ return hasValidBasePayloadFields(value) && hasStringId(value.order) && hasStringId(value.customer) && isRuntimeWebhookStore(value.store);
502
+ }
503
+ function isRuntimeCheckoutAbandonedWebhookPayload(value) {
504
+ return hasValidBasePayloadFields(value) && hasStringId(value.checkout) && isRuntimeWebhookStore(value.store);
505
+ }
506
+ function isRuntimeWebhookPayload(value, event) {
507
+ if (!isRecord(value)) return false;
508
+ switch (event) {
509
+ case WEBHOOK_EVENTS.ORDER_CREATED:
510
+ case WEBHOOK_EVENTS.ORDER_UPDATED:
511
+ case WEBHOOK_EVENTS.ORDER_CANCELLED:
512
+ case WEBHOOK_EVENTS.ORDER_COMPLETED:
513
+ return isRuntimeOrderWebhookPayload(value);
514
+ case WEBHOOK_EVENTS.PRODUCT_CREATED:
515
+ case WEBHOOK_EVENTS.PRODUCT_UPDATED:
516
+ case WEBHOOK_EVENTS.PRODUCT_DELETED:
517
+ return isRuntimeProductWebhookPayload(value);
518
+ case WEBHOOK_EVENTS.CUSTOMER_CREATED:
519
+ case WEBHOOK_EVENTS.CUSTOMER_UPDATED:
520
+ return isRuntimeCustomerWebhookPayload(value);
521
+ case WEBHOOK_EVENTS.CHECKOUT_COMPLETED:
522
+ return isRuntimeCheckoutCompletedWebhookPayload(value);
523
+ case WEBHOOK_EVENTS.CHECKOUT_ABANDONED:
524
+ return isRuntimeCheckoutAbandonedWebhookPayload(value);
525
+ default:
526
+ return false;
527
+ }
528
+ }
529
+
422
530
  // src/manifest/validate.ts
531
+ import { SCOPE_LIST } from "@whatalo/protocol/scopes";
423
532
  var ManifestValidationError = class extends Error {
424
533
  errors;
425
534
  constructor(errors) {
@@ -432,23 +541,7 @@ var ManifestValidationError = class extends Error {
432
541
  var ID_REGEX = /^[a-z0-9][a-z0-9-]*[a-z0-9]$/;
433
542
  var SEMVER_REGEX = /^\d+\.\d+\.\d+$/;
434
543
  var EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
435
- var VALID_PERMISSIONS = /* @__PURE__ */ new Set([
436
- "read:products",
437
- "write:products",
438
- "read:orders",
439
- "write:orders",
440
- "read:customers",
441
- "write:customers",
442
- "read:inventory",
443
- "write:inventory",
444
- "read:store",
445
- "write:store",
446
- "read:webhooks",
447
- "write:webhooks",
448
- "read:discounts",
449
- "write:discounts",
450
- "read:analytics"
451
- ]);
544
+ var VALID_PERMISSIONS = new Set(SCOPE_LIST.map((s) => s.token));
452
545
  var VALID_CATEGORIES = /* @__PURE__ */ new Set([
453
546
  "analytics",
454
547
  "marketing",
@@ -543,8 +636,11 @@ var DATA_RESOURCE_SCOPE = {
543
636
  products: "read:products",
544
637
  orders: "read:orders",
545
638
  customers: "read:customers",
546
- categories: "read:products"
639
+ categories: "read:products",
547
640
  // categories share the products scope
641
+ store: "read:store",
642
+ geo: "read:store"
643
+ // geo is global reference data, scoped to read:store
548
644
  };
549
645
  var BILLING_OPERATION = {
550
646
  GET_PLANS: "getPlans",
@@ -728,6 +824,18 @@ function useWhataloAction() {
728
824
  return { sendAction, showToast, navigate, openModal, closeModal, resize, billing };
729
825
  }
730
826
 
827
+ // src/bridge/visual-readiness.ts
828
+ var readyEmission = null;
829
+ function createReadyPayload() {
830
+ return { visualReadiness: true };
831
+ }
832
+ function emitReadyOnce(getParentOrigin, postReady) {
833
+ readyEmission ??= getParentOrigin().then((origin) => {
834
+ postReady(origin, createReadyPayload());
835
+ });
836
+ return readyEmission;
837
+ }
838
+
731
839
  // src/bridge/use-whatalo-context.ts
732
840
  var DEFAULT_CONTEXT = {
733
841
  storeId: "",
@@ -750,20 +858,32 @@ function useWhataloContext() {
750
858
  if (!payload || typeof payload.storeId !== "string") return;
751
859
  setContext(payload);
752
860
  setIsReady(true);
753
- if (payload.theme) {
861
+ if (payload.theme === "light" || payload.theme === "dark") {
754
862
  document.documentElement.setAttribute("data-theme", payload.theme);
863
+ document.documentElement.style.colorScheme = payload.theme;
864
+ waitForParentOrigin().then((origin) => {
865
+ window.parent.postMessage(
866
+ {
867
+ type: "whatalo:action",
868
+ actionId: crypto.randomUUID(),
869
+ action: "visual-ready",
870
+ payload: {}
871
+ },
872
+ origin
873
+ );
874
+ });
755
875
  }
756
876
  }, []);
757
877
  useEffect2(() => {
758
878
  attachInitListener();
759
879
  window.addEventListener("message", handleMessage);
760
- waitForParentOrigin().then((origin) => {
880
+ emitReadyOnce(waitForParentOrigin, (origin, payload) => {
761
881
  window.parent.postMessage(
762
882
  {
763
883
  type: "whatalo:action",
764
884
  actionId: crypto.randomUUID(),
765
885
  action: "ready",
766
- payload: {}
886
+ payload
767
887
  },
768
888
  origin
769
889
  );
@@ -956,16 +1076,44 @@ function useWhataloData() {
956
1076
  },
957
1077
  [fetchResource]
958
1078
  );
1079
+ const storeGet = useCallback3(async () => {
1080
+ const ack = await fetchResource("store", "get");
1081
+ return extractAckData(ack);
1082
+ }, [fetchResource]);
1083
+ const geoCountries = useCallback3(
1084
+ async (params) => {
1085
+ const ack = await fetchResource(
1086
+ "geo",
1087
+ "list",
1088
+ { ...params, _sub: "countries" }
1089
+ );
1090
+ return extractAckData(ack);
1091
+ },
1092
+ [fetchResource]
1093
+ );
1094
+ const geoProvinces = useCallback3(
1095
+ async (countryIso2) => {
1096
+ const ack = await fetchResource(
1097
+ "geo",
1098
+ "list",
1099
+ { _sub: "provinces", country: countryIso2 }
1100
+ );
1101
+ return extractAckData(ack);
1102
+ },
1103
+ [fetchResource]
1104
+ );
959
1105
  return {
960
1106
  products: { list: productsList, get: productsGet },
961
1107
  orders: { list: ordersList, get: ordersGet },
962
1108
  customers: { list: customersList, get: customersGet },
963
- categories: { list: categoriesList, get: categoriesGet }
1109
+ categories: { list: categoriesList, get: categoriesGet },
1110
+ store: { get: storeGet },
1111
+ geo: { countries: geoCountries, provinces: geoProvinces }
964
1112
  };
965
1113
  }
966
1114
 
967
1115
  // src/index.ts
968
- var SDK_VERSION = "1.2.0";
1116
+ var SDK_VERSION = "1.2.2";
969
1117
  export {
970
1118
  AuthenticationError,
971
1119
  AuthorizationError,
@@ -977,10 +1125,13 @@ export {
977
1125
  RateLimitError,
978
1126
  SDK_VERSION,
979
1127
  ValidationError,
1128
+ WEBHOOK_EVENTS,
980
1129
  WhataloAPIError,
981
1130
  WhataloClient,
982
1131
  clearSessionTokenCache,
983
1132
  defineApp,
1133
+ isRuntimeWebhookPayload,
1134
+ isWebhookEvent,
984
1135
  sessionToken,
985
1136
  useAppBridge,
986
1137
  useWhataloAction,