@rebilly/instruments 3.1.2-beta.0 → 3.2.0-beta.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rebilly/instruments",
3
- "version": "3.1.2-beta.0",
3
+ "version": "3.2.0-beta.0",
4
4
  "author": "Rebilly",
5
5
  "main": "dist/index.js",
6
6
  "unpkg": "dist/index.min.js",
@@ -18,6 +18,7 @@
18
18
  "@rebilly/risk-data-collector": "^2.0.1",
19
19
  "autoprefixer": "^10.3.4",
20
20
  "css": "^3.0.0",
21
+ "jwt-decode": "^3.1.2",
21
22
  "lodash.camelcase": "^4.3.0",
22
23
  "lodash.isequal": "^4.5.0",
23
24
  "lodash.kebabcase": "^4.1.1",
@@ -142,9 +142,19 @@ export async function fetchData({
142
142
  state.options.items ? fetchSummary({ data: summaryPayload, state }) : null
143
143
  ]);
144
144
 
145
- const plans = await fetchPlans({ state });
146
- state.data.plans = plans;
147
- const products = await fetchProducts({ state });
145
+ let plans = null;
146
+ let products = null;
147
+ try {
148
+ plans = await fetchPlans({ state });
149
+ state.data.plans = plans;
150
+ } catch(e) {
151
+ plans = [];
152
+ }
153
+ try {
154
+ products = await fetchProducts({ state });
155
+ } catch (e) {
156
+ products = [];
157
+ }
148
158
 
149
159
  return new DataInstance({
150
160
  state,
@@ -92,15 +92,22 @@ export async function mount({
92
92
  state.loader.startLoading({ id: 'initForm' });
93
93
 
94
94
  // Setup state
95
- state.storefront = setupStorefront({ options });
96
95
  state.options = setupOptions({ options });
96
+ state.storefront = setupStorefront({ options });
97
97
  state.mainStyle = await setupStyles({ options });
98
98
  state.data = await fetchData({ state });
99
+
99
100
  state.options.themeFramepay = await setupFramepayTheme({ state, options });
100
101
  state.i18n = setupI18n({ state });
101
102
 
102
103
  setupFramepay({ state });
103
104
 
105
+ // Update state options from data
106
+ if ((!state.options.websiteId) && state.data.transaction?.websiteId) {
107
+ state.options.websiteId = state.data.transaction.websiteId;
108
+ } else if ((!state.options.websiteId) && state.data.invoice?.websiteId) {
109
+ state.options.websiteId = state.data.invoice.websiteId;
110
+ }
104
111
  if (state.data.transaction && state.data.transaction?.type === 'setup') {
105
112
  state.options.transactionType = 'setup';
106
113
  }
@@ -69,4 +69,24 @@ describe('RebillyInstruments instance', () => {
69
69
  );
70
70
  expect(FRAMEPAY_STYLE.href).toEqual(framePayStyleUrl);
71
71
  });
72
+
73
+ it('should mount with JWT pruchase data', async () => {
74
+ // Use https://www.jwt.io to help encode and decode JWT
75
+ const jwt = `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJkMGYzNWEzYy03N2M0LTQ0NDItOWFhNC03ODA5NDA2NzBjN2IiLCJleHAiOjE2NzM2NDk0ODcsImlhdCI6MTY0MjExMDczOS4zMjYyNDQsImFjbCI6W3sic2NvcGUiOnsib3JnYW5pemF0aW9uSWQiOlsidGVzdC1vcmdhbml6YXRpb24tZCJdLCJ0cmFuc2FjdGlvbklkIjpbInRlc3QtdHJhbnNhY3Rpb24taWQiXX0sInBlcm1pc3Npb25zIjpbMV19XSwiY2xhaW1zIjp7InRyYW5zYWN0aW9uSWQiOiJ0ZXN0LXRyYW5zYWN0aW9uLWlkIn0sIm1lcmNoYW50IjoidGVzdC1vcmdhbml6YXRpb24taWQiLCJjdXN0b21lciI6eyJpZCI6InRlc3QtY3VzdG9tZXItaWQiLCJuYW1lIjoiVGVzdGVyIFRlc3RlcnNvbiIsImNyZWF0ZWRUaW1lIjoiMjAyMi0wMS0xNFQwMDowMDowMCswMDowMCJ9fQ.h4voW-UvXzXRm1JlxkN8cNHhQ_IIPSWWN9BANfBWEHQ`;
76
+
77
+ const options = {
78
+ form: '.form-selector',
79
+ summary: '.summary-selector',
80
+ jwt,
81
+ };
82
+
83
+ const instance = await RenderMockRebillyInstruments(options);
84
+
85
+ expect(instance.state.options).toEqual(
86
+ expect.objectContaining({
87
+ transactionId: 'test-transaction-id',
88
+ organizationId: 'test-organization-id'
89
+ })
90
+ );
91
+ });
72
92
  });
@@ -1,4 +1,5 @@
1
1
  import merge from 'lodash.merge';
2
+ import decodeJwt from 'jwt-decode';
2
3
 
3
4
  export const defaults = {
4
5
  countryCode: 'US',
@@ -46,6 +47,7 @@ export const defaults = {
46
47
  export function validateOptions(options) {
47
48
  // TODO: validate more options
48
49
  const purchaseData = [
50
+ options.jwt,
49
51
  options.items,
50
52
  options.invoiceId,
51
53
  options.money,
@@ -73,9 +75,6 @@ export default ({
73
75
  };
74
76
 
75
77
  const combinedOptions = merge({...defaults}, {
76
- organizationId: options.organizationId,
77
- publishableKey: options.publishableKey,
78
- websiteId: options.websiteId,
79
78
  apiMode: options.apiMode,
80
79
  i18n: options.i18n,
81
80
  theme: options.theme,
@@ -88,6 +87,35 @@ export default ({
88
87
  _computed
89
88
  });
90
89
 
90
+ if (options.publishableKey) {
91
+ Object.entries({
92
+ organizationId: options.organizationId,
93
+ publishableKey: options.publishableKey,
94
+ websiteId: options.websiteId,
95
+ }).forEach(([key, value]) => {
96
+ combinedOptions[key] = value;
97
+ });
98
+ } else if (options.jwt) {
99
+ combinedOptions.jwt = options.jwt;
100
+ const {
101
+ merchant: organizationId,
102
+ claims: {
103
+ transactionId,
104
+ invoiceId,
105
+ }
106
+ } = decodeJwt(combinedOptions.jwt);
107
+
108
+ combinedOptions.organizationId = organizationId;
109
+
110
+ if (transactionId) {
111
+ combinedOptions.transactionId = transactionId;
112
+ }
113
+
114
+ if (invoiceId) {
115
+ combinedOptions.invoiceId = invoiceId;
116
+ }
117
+ }
118
+
91
119
  // Add optional key's
92
120
  [
93
121
  'items',
@@ -9,11 +9,14 @@ export default ({
9
9
  }
10
10
  }) => {
11
11
  const storefront = {
12
- publishableKey,
13
12
  orgnizationId,
14
13
  mode: apiMode || 'live'
15
14
  };
16
15
 
16
+ if (publishableKey) {
17
+ storefront.publishableKey = publishableKey;
18
+ }
19
+
17
20
  if (_dev) {
18
21
  storefront.liveUrl = _dev.liveUrl || 'https://api.rebilly.com';
19
22
  storefront.sandboxUrl =
@@ -31,6 +31,7 @@ export async function Endpoint({
31
31
  export class StorefrontInstance {
32
32
  constructor({
33
33
  publishableKey = null,
34
+ jwt = null,
34
35
  organizationId = null,
35
36
  mode = 'live',
36
37
  timeout = 10000,
@@ -51,7 +52,12 @@ export class StorefrontInstance {
51
52
  urls
52
53
  });
53
54
 
54
- api.setPublishableKey(publishableKey);
55
+ if (publishableKey) {
56
+ api.setPublishableKey(publishableKey);
57
+ }
58
+ if (jwt) {
59
+ api.setSessionToken(jwt);
60
+ }
55
61
 
56
62
  this.api = api;
57
63
  return this.api;
@@ -3,7 +3,7 @@ import { Endpoint } from './index';
3
3
 
4
4
  export async function fetchInvoice({ data = null, state = null }) {
5
5
  return Endpoint({state}, async () => {
6
- state.storefront.setSessionToken(state.options.customerJwt);
6
+ state.storefront.setSessionToken(state.options.customerJwt || state.options.jwt);
7
7
  const {fields} = await state.storefront.invoices.get(data);
8
8
 
9
9
  return new InvoiceModel(fields);
@@ -3,11 +3,13 @@ import { Endpoint } from './index';
3
3
 
4
4
  export async function fetchProducts({ state }) {
5
5
  return Endpoint({state}, async () => {
6
- if (state.data.plans === null) {
7
- return null;
6
+ let plansData = [];
7
+ if (state.data.plans) {
8
+ plansData = state.data.plans;
9
+ }
10
+ if (state.data.invoice?.items) {
11
+ plansData = state.data.invoice.items;
8
12
  }
9
-
10
- const plansData = state.data.plans || [];
11
13
  const filterByProductId = {
12
14
  filter: ''
13
15
  };
@@ -8,13 +8,21 @@ export async function fetchReadyToPay({ state, riskMetadata = null }) {
8
8
  const { riskMetadata: data } = await collectData();
9
9
  riskMetadata = data;
10
10
  }
11
- const websiteId = state.options?.websiteId || null;
12
-
11
+
13
12
  const data = {
14
- websiteId,
15
13
  riskMetadata
16
14
  };
17
-
15
+
16
+ let websiteId = state.options?.websiteId || null;
17
+ if (!websiteId) {
18
+ if (state.data.transaction?.websiteId) {
19
+ websiteId = state.data.transaction.websiteId
20
+ } else if (state.data.invoice?.websiteId) {
21
+ websiteId = state.data.invoice.websiteId;
22
+ }
23
+ }
24
+ data.websiteId = websiteId;
25
+
18
26
  if (state.options?.items) {
19
27
  data.items = state.options.items;
20
28
  }
@@ -3,7 +3,7 @@ import { Endpoint } from './index';
3
3
 
4
4
  export async function fetchTransaction({ data = null, state = null }) {
5
5
  return Endpoint({state}, async () => {
6
- state.storefront.setSessionToken(state.options.customerJwt);
6
+ state.storefront.setSessionToken(state.options.customerJwt || state.options.jwt);
7
7
  const {fields} = await state.storefront.transactions.get(data);
8
8
 
9
9
  return new TransactionModel(fields);
@@ -57,6 +57,7 @@ export const button = () => `
57
57
 
58
58
  .rebilly-instruments-button.rebilly-instruments-button-secondary:not([disabled]):hover,
59
59
  .rebilly-instruments-button.rebilly-instruments-button-secondary:not([disabled]):active {
60
+ color: var(--rebilly-buttonColorBackground);
60
61
  background: var(--rebilly-colorBackground);
61
62
  }
62
63
 
@@ -45,7 +45,7 @@ export function generateDigitalWallet({ state, EXPRESS_METHODS }) {
45
45
  applePayDisplayOptions: paymentInstruments.applePay.displayOptions
46
46
  }
47
47
  }
48
- })
48
+ });
49
49
 
50
50
  return output;
51
51
  }
@@ -23,7 +23,7 @@ export function getPaymentMethods({ state }) {
23
23
  METHODS: []
24
24
  };
25
25
 
26
- state.data.readyToPay.forEach((method) => {
26
+ state.data.readyToPay?.forEach((method) => {
27
27
  if (isExpressMethod(method)) {
28
28
  const { METHOD_TYPE } = getMethodData(method);
29
29
  // Add loader entry per express method
@@ -87,7 +87,8 @@ export async function RenderMockRebillyInstruments(options = {}) {
87
87
  'items',
88
88
  'invoiceId',
89
89
  'transactionId',
90
- 'money'
90
+ 'money',
91
+ 'jwt'
91
92
  ].some(key => Object.keys(options).includes(key))
92
93
  if(!hasPurchaseData) {
93
94
  defaultOptions.items = [