@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.
- package/dist/adapters/express.cjs +106 -10
- package/dist/adapters/express.cjs.map +1 -1
- package/dist/adapters/express.d.cts +9 -7
- package/dist/adapters/express.d.ts +9 -7
- package/dist/adapters/express.mjs +109 -10
- package/dist/adapters/express.mjs.map +1 -1
- package/dist/adapters/hono.cjs +99 -7
- package/dist/adapters/hono.cjs.map +1 -1
- package/dist/adapters/hono.d.cts +4 -3
- package/dist/adapters/hono.d.ts +4 -3
- package/dist/adapters/hono.mjs +102 -7
- package/dist/adapters/hono.mjs.map +1 -1
- package/dist/adapters/nextjs.cjs +99 -7
- package/dist/adapters/nextjs.cjs.map +1 -1
- package/dist/adapters/nextjs.d.cts +4 -3
- package/dist/adapters/nextjs.d.ts +4 -3
- package/dist/adapters/nextjs.mjs +102 -7
- package/dist/adapters/nextjs.mjs.map +1 -1
- package/dist/bridge/index.cjs +60 -5
- package/dist/bridge/index.cjs.map +1 -1
- package/dist/bridge/index.d.cts +17 -5
- package/dist/bridge/index.d.ts +17 -5
- package/dist/bridge/index.mjs +60 -5
- package/dist/bridge/index.mjs.map +1 -1
- package/dist/client/index.cjs +33 -2
- package/dist/client/index.cjs.map +1 -1
- package/dist/client/index.d.cts +29 -1
- package/dist/client/index.d.ts +29 -1
- package/dist/client/index.mjs +33 -2
- package/dist/client/index.mjs.map +1 -1
- package/dist/index.cjs +179 -28
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -4
- package/dist/index.d.ts +7 -4
- package/dist/index.mjs +179 -28
- package/dist/index.mjs.map +1 -1
- package/dist/manifest/index.cjs +2 -17
- package/dist/manifest/index.cjs.map +1 -1
- package/dist/manifest/index.d.cts +10 -4
- package/dist/manifest/index.d.ts +10 -4
- package/dist/manifest/index.mjs +2 -17
- package/dist/manifest/index.mjs.map +1 -1
- package/dist/{types-DcmArIC2.d.ts → types-B8BAV362.d.cts} +24 -1
- package/dist/{types-DcmArIC2.d.cts → types-B8BAV362.d.ts} +24 -1
- package/dist/types-Bzee9Hvr.d.ts +25 -0
- package/dist/types-CDKGAQ3o.d.ts +155 -0
- package/dist/types-CPnSzOfX.d.cts +155 -0
- package/dist/types-CqyAhbXM.d.cts +25 -0
- package/dist/webhooks/index.cjs +83 -3
- package/dist/webhooks/index.cjs.map +1 -1
- package/dist/webhooks/index.d.cts +11 -4
- package/dist/webhooks/index.d.ts +11 -4
- package/dist/webhooks/index.mjs +83 -3
- package/dist/webhooks/index.mjs.map +1 -1
- package/package.json +4 -1
- package/dist/types-C9mg4aQg.d.ts +0 -19
- package/dist/types-DMuHSL_a.d.cts +0 -19
- package/dist/types-DTjA3FHe.d.ts +0 -68
- 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}
|
|
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}
|
|
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
|
-
|
|
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
|
|
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 =
|
|
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(
|
|
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.
|
|
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,
|