@relume_io/partner-node 2.0.1 → 2.2.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.cjs CHANGED
@@ -419,7 +419,7 @@ function isHttpsUrl(value) {
419
419
 
420
420
  // src/api.ts
421
421
  var DEFAULT_API_BASE_URL = "https://apis.relume.io/nova/partner/v1";
422
- var SDK_VERSION = "2.0.1";
422
+ var SDK_VERSION = "2.2.0";
423
423
  var USER_AGENT = `relume-partner-node/${SDK_VERSION}`;
424
424
  var DEFAULT_API_TIMEOUT_MS = 15e3;
425
425
  var DEFAULT_MAX_RETRIES = 2;
@@ -577,6 +577,11 @@ var CALL_TYPES = [
577
577
  "credits.charge",
578
578
  "credits.reverse"
579
579
  ];
580
+ function keyEnvironment(secretKey) {
581
+ if (secretKey.startsWith("sk_test_")) return "test";
582
+ if (secretKey.startsWith("sk_live_")) return "live";
583
+ return null;
584
+ }
580
585
  var InvalidCallbackResultError = class extends Error {
581
586
  constructor(message) {
582
587
  super(message);
@@ -589,10 +594,19 @@ function optionalString(value, max) {
589
594
  }
590
595
  return isString(value, 1, max) ? { ok: true, value } : { ok: false };
591
596
  }
597
+ function optionalStrings(value, max, maxItems) {
598
+ if (value === void 0 || value === null) {
599
+ return { ok: true, value: void 0 };
600
+ }
601
+ if (!Array.isArray(value) || value.length === 0 || value.length > maxItems || !value.every((item) => isString(item, 1, max))) {
602
+ return { ok: false };
603
+ }
604
+ return { ok: true, value: [...value] };
605
+ }
592
606
  function isCallType(value) {
593
607
  return CALL_TYPES.some((type) => type === value);
594
608
  }
595
- function parseCall(body) {
609
+ function parseCall(body, environment) {
596
610
  if (!isRecord(body)) {
597
611
  return {
598
612
  ok: false,
@@ -614,6 +628,17 @@ function parseCall(body) {
614
628
  message: `Invalid ${field} for ${type}.`,
615
629
  type
616
630
  });
631
+ if (body.environment !== void 0 && body.environment !== "test" && body.environment !== "live") {
632
+ return invalid("environment");
633
+ }
634
+ if (body.environment !== void 0 && body.environment !== environment) {
635
+ return {
636
+ ok: false,
637
+ code: "environment_mismatch",
638
+ message: `This ${type} is for ${body.environment}, but this server's secret key is for ${environment}.`,
639
+ type
640
+ };
641
+ }
617
642
  const { userId } = body;
618
643
  if (!isString(userId, 1, 128)) return invalid("userId");
619
644
  switch (type) {
@@ -631,6 +656,8 @@ function parseCall(body) {
631
656
  if (!siteId.ok) return invalid("siteId");
632
657
  const pageId = optionalString(body.pageId, 200);
633
658
  if (!pageId.ok) return invalid("pageId");
659
+ const pageIds = optionalStrings(body.pageIds, 200, 1e3);
660
+ if (!pageIds.ok) return invalid("pageIds");
634
661
  const charge = {
635
662
  userId,
636
663
  chargeId,
@@ -641,6 +668,7 @@ function parseCall(body) {
641
668
  };
642
669
  if (siteId.value !== void 0) charge.siteId = siteId.value;
643
670
  if (pageId.value !== void 0) charge.pageId = pageId.value;
671
+ if (pageIds.value !== void 0) charge.pageIds = pageIds.value;
644
672
  return { ok: true, call: { type, charge } };
645
673
  }
646
674
  case "credits.reverse": {
@@ -799,8 +827,9 @@ var isLedgerEntryDetail = hasStrings(
799
827
  "type",
800
828
  "status"
801
829
  );
830
+ var isCreditUnit = hasStrings("singular", "plural");
802
831
  function isPriceList(value) {
803
- return isRecord(value) && Array.isArray(value.data);
832
+ return isRecord(value) && Array.isArray(value.data) && isCreditUnit(value.creditUnit);
804
833
  }
805
834
  function segment(name, value) {
806
835
  if (typeof value !== "string" || value === "") {
@@ -879,7 +908,8 @@ function partnerApi(config) {
879
908
  })
880
909
  },
881
910
  prices: {
882
- list: async () => (await get("/prices", isPriceList)).data
911
+ list: async () => (await get("/prices", isPriceList)).data,
912
+ get: () => get("/prices", isPriceList)
883
913
  }
884
914
  };
885
915
  }
@@ -974,6 +1004,7 @@ var Relume = class _Relume {
974
1004
  */
975
1005
  fetchHandler;
976
1006
  #secretKey;
1007
+ #environment;
977
1008
  #api;
978
1009
  #callbacks = {};
979
1010
  #onHandlerError;
@@ -993,6 +1024,12 @@ var Relume = class _Relume {
993
1024
  "Relume.init: that is a publishable key. Pass the secret key (sk_\u2026); the publishable key goes to the embed."
994
1025
  );
995
1026
  }
1027
+ const environment = keyEnvironment(secretKey);
1028
+ if (environment === null) {
1029
+ throw new TypeError(
1030
+ "Relume.init: secretKey must start with sk_test_ or sk_live_."
1031
+ );
1032
+ }
996
1033
  const maxRetries = options.maxRetries ?? DEFAULT_MAX_RETRIES;
997
1034
  if (!Number.isSafeInteger(maxRetries) || maxRetries < 0) {
998
1035
  throw new TypeError(
@@ -1000,6 +1037,7 @@ var Relume = class _Relume {
1000
1037
  );
1001
1038
  }
1002
1039
  this.#secretKey = secretKey;
1040
+ this.#environment = environment;
1003
1041
  this.#now = options.now ?? Date.now;
1004
1042
  this.#api = {
1005
1043
  secretKey,
@@ -1075,8 +1113,9 @@ var Relume = class _Relume {
1075
1113
  }
1076
1114
  /**
1077
1115
  * `POST /relume/calls`, framework-agnostic: verifies the signature and the
1078
- * 5-minute window, routes by `type`, runs your callback and validates what
1079
- * it returns. Pass the raw body exactly as received.
1116
+ * 5-minute window, refuses a call for another environment than the secret
1117
+ * key's (`400 environment_mismatch`), routes by `type`, runs your callback
1118
+ * and validates what it returns. Pass the raw body exactly as received.
1080
1119
  */
1081
1120
  async handleCall(input) {
1082
1121
  const requestId = input.requestId ?? null;
@@ -1100,10 +1139,14 @@ var Relume = class _Relume {
1100
1139
  "The body is not valid JSON."
1101
1140
  );
1102
1141
  }
1103
- const parsed = parseCall(body);
1142
+ const parsed = parseCall(body, this.#environment);
1104
1143
  if (!parsed.ok) return errorResponse(400, parsed.code, parsed.message);
1105
1144
  const { call } = parsed;
1106
- const context = { type: call.type, requestId };
1145
+ const context = {
1146
+ type: call.type,
1147
+ environment: this.#environment,
1148
+ requestId
1149
+ };
1107
1150
  const callbackName = CALLBACK_FOR[call.type];
1108
1151
  if (!this.#callbacks[callbackName]) {
1109
1152
  this.#onHandlerError(