powr-sdk-web 5.8.0 → 5.8.1

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.
@@ -53,7 +53,8 @@ var PowrLogin = function PowrLogin(_ref) {
53
53
  _ref$international = _ref.international,
54
54
  international = _ref$international === void 0 ? false : _ref$international,
55
55
  _ref$allowedCountries = _ref.allowedCountries,
56
- allowedCountries = _ref$allowedCountries === void 0 ? null : _ref$allowedCountries;
56
+ allowedCountries = _ref$allowedCountries === void 0 ? null : _ref$allowedCountries,
57
+ onSessionExpired = _ref.onSessionExpired;
57
58
  var resolvedDefaultCountry = (0, _phone.resolveCountry)(defaultCountry, defaultCountryCode);
58
59
  var _useState = (0, _react.useState)(function () {
59
60
  switch (mode) {
@@ -496,7 +497,15 @@ var PowrLogin = function PowrLogin(_ref) {
496
497
  }
497
498
  setPendingAuth({
498
499
  user: data.user,
499
- token: data.token
500
+ token: data.token,
501
+ refreshToken: data.refreshToken,
502
+ onTokenRefreshed: function onTokenRefreshed(newToken) {
503
+ setPendingAuth(function (prev) {
504
+ return prev ? _objectSpread(_objectSpread({}, prev), {}, {
505
+ token: newToken
506
+ }) : prev;
507
+ });
508
+ }
500
509
  });
501
510
  setAuthView('add-phone');
502
511
  setLoading(false);
@@ -583,12 +592,14 @@ var PowrLogin = function PowrLogin(_ref) {
583
592
  fullName: ''
584
593
  });
585
594
  };
586
- var handleAddPhoneComplete = function handleAddPhoneComplete(updatedUser) {
595
+ var handleAddPhoneComplete = function handleAddPhoneComplete(updatedUser, sessionToken) {
587
596
  if (!pendingAuth) return;
597
+ var token = sessionToken || pendingAuth.token;
588
598
  var payload = {
589
599
  success: true,
590
600
  user: updatedUser,
591
- token: pendingAuth.token
601
+ token: token,
602
+ refreshToken: pendingAuth.refreshToken
592
603
  };
593
604
  setAuthView('form');
594
605
  setPendingAuth(null);
@@ -602,6 +613,17 @@ var PowrLogin = function PowrLogin(_ref) {
602
613
  setError('');
603
614
  setSuccess('');
604
615
  };
616
+ var handleAddPhoneSessionExpired = function handleAddPhoneSessionExpired() {
617
+ setAuthView('form');
618
+ setPendingAuth(null);
619
+ setError('');
620
+ setSuccess('');
621
+ if (typeof onSessionExpired === 'function') {
622
+ onSessionExpired();
623
+ return;
624
+ }
625
+ setError('Your session timed out. Sign in again to add your phone number.');
626
+ };
605
627
  var handleGetOtp = /*#__PURE__*/function () {
606
628
  var _ref7 = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee5() {
607
629
  var _yield$apiCall2, data, ok, _t6;
@@ -693,6 +715,8 @@ var PowrLogin = function PowrLogin(_ref) {
693
715
  appName: appName,
694
716
  onComplete: handleAddPhoneComplete,
695
717
  onBack: handleAddPhoneBack,
718
+ onSessionExpired: handleAddPhoneSessionExpired,
719
+ refreshToken: pendingAuth.refreshToken,
696
720
  requirePhoneVerification: requirePhoneVerification,
697
721
  defaultCountry: resolvedDefaultCountry,
698
722
  defaultCountryCode: defaultCountryCode,
package/dist/index.js CHANGED
@@ -165,6 +165,12 @@ Object.defineProperty(exports, "PowrTable", {
165
165
  return _table["default"];
166
166
  }
167
167
  });
168
+ Object.defineProperty(exports, "SESSION_MESSAGES", {
169
+ enumerable: true,
170
+ get: function get() {
171
+ return _sessionMessages.SESSION_MESSAGES;
172
+ }
173
+ });
168
174
  Object.defineProperty(exports, "addPhoneStep", {
169
175
  enumerable: true,
170
176
  get: function get() {
@@ -207,6 +213,12 @@ Object.defineProperty(exports, "getCountryOptions", {
207
213
  return _phone.getCountryOptions;
208
214
  }
209
215
  });
216
+ Object.defineProperty(exports, "getFriendlyAuthError", {
217
+ enumerable: true,
218
+ get: function get() {
219
+ return _sessionMessages.getFriendlyAuthError;
220
+ }
221
+ });
210
222
  Object.defineProperty(exports, "getLocalPhoneNumber", {
211
223
  enumerable: true,
212
224
  get: function get() {
@@ -231,6 +243,18 @@ Object.defineProperty(exports, "hasValidPhone", {
231
243
  return _onboarding.hasValidPhone;
232
244
  }
233
245
  });
246
+ Object.defineProperty(exports, "isAuthSessionError", {
247
+ enumerable: true,
248
+ get: function get() {
249
+ return _jwt.isAuthSessionError;
250
+ }
251
+ });
252
+ Object.defineProperty(exports, "isJwtExpired", {
253
+ enumerable: true,
254
+ get: function get() {
255
+ return _jwt.isJwtExpired;
256
+ }
257
+ });
234
258
  Object.defineProperty(exports, "isValidPhone", {
235
259
  enumerable: true,
236
260
  get: function get() {
@@ -302,4 +326,6 @@ var _powrVerify = _interopRequireDefault(require("./powrVerify"));
302
326
  var _PhoneInput = _interopRequireDefault(require("./components/PhoneInput"));
303
327
  var _onboarding = require("./onboarding");
304
328
  var _phone = require("./utils/phone");
329
+ var _jwt = require("./utils/jwt");
330
+ var _sessionMessages = require("./utils/sessionMessages");
305
331
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
@@ -9,7 +9,10 @@ var _react = _interopRequireWildcard(require("react"));
9
9
  var _firebase = require("../utils/firebase");
10
10
  var _utils = require("./utils");
11
11
  var _phone = require("../utils/phone");
12
+ var _jwt = require("../utils/jwt");
13
+ var _sessionMessages = require("../utils/sessionMessages");
12
14
  var _PhoneInput = _interopRequireDefault(require("../components/PhoneInput"));
15
+ var _SessionExpiredPanel = _interopRequireDefault(require("./SessionExpiredPanel"));
13
16
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
14
17
  function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, "default": e }; if (null === e || "object" != _typeof(e) && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t6 in e) "default" !== _t6 && {}.hasOwnProperty.call(e, _t6) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t6)) && (i.get || i.set) ? o(f, _t6, i) : f[_t6] = e[_t6]); return f; })(e, t); }
15
18
  function _regenerator() { /*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/babel/babel/blob/main/packages/babel-helpers/LICENSE */ var e, t, r = "function" == typeof Symbol ? Symbol : {}, n = r.iterator || "@@iterator", o = r.toStringTag || "@@toStringTag"; function i(r, n, o, i) { var c = n && n.prototype instanceof Generator ? n : Generator, u = Object.create(c.prototype); return _regeneratorDefine2(u, "_invoke", function (r, n, o) { var i, c, u, f = 0, p = o || [], y = !1, G = { p: 0, n: 0, v: e, a: d, f: d.bind(e, 4), d: function d(t, r) { return i = t, c = 0, u = e, G.n = r, a; } }; function d(r, n) { for (c = r, u = n, t = 0; !y && f && !o && t < p.length; t++) { var o, i = p[t], d = G.p, l = i[2]; r > 3 ? (o = l === n) && (u = i[(c = i[4]) ? 5 : (c = 3, 3)], i[4] = i[5] = e) : i[0] <= d && ((o = r < 2 && d < i[1]) ? (c = 0, G.v = n, G.n = i[1]) : d < l && (o = r < 3 || i[0] > n || n > l) && (i[4] = r, i[5] = n, G.n = l, c = 0)); } if (o || r > 1) return a; throw y = !0, n; } return function (o, p, l) { if (f > 1) throw TypeError("Generator is already running"); for (y && 1 === p && d(p, l), c = p, u = l; (t = c < 2 ? e : u) || !y;) { i || (c ? c < 3 ? (c > 1 && (G.n = -1), d(c, u)) : G.n = u : G.v = u); try { if (f = 2, i) { if (c || (o = "next"), t = i[o]) { if (!(t = t.call(i, u))) throw TypeError("iterator result is not an object"); if (!t.done) return t; u = t.value, c < 2 && (c = 0); } else 1 === c && (t = i["return"]) && t.call(i), c < 2 && (u = TypeError("The iterator does not provide a '" + o + "' method"), c = 1); i = e; } else if ((t = (y = G.n < 0) ? u : r.call(n, G)) !== a) break; } catch (t) { i = e, c = 1, u = t; } finally { f = 1; } } return { value: t, done: y }; }; }(r, o, i), !0), u; } var a = {}; function Generator() {} function GeneratorFunction() {} function GeneratorFunctionPrototype() {} t = Object.getPrototypeOf; var c = [][n] ? t(t([][n]())) : (_regeneratorDefine2(t = {}, n, function () { return this; }), t), u = GeneratorFunctionPrototype.prototype = Generator.prototype = Object.create(c); function f(e) { return Object.setPrototypeOf ? Object.setPrototypeOf(e, GeneratorFunctionPrototype) : (e.__proto__ = GeneratorFunctionPrototype, _regeneratorDefine2(e, o, "GeneratorFunction")), e.prototype = Object.create(u), e; } return GeneratorFunction.prototype = GeneratorFunctionPrototype, _regeneratorDefine2(u, "constructor", GeneratorFunctionPrototype), _regeneratorDefine2(GeneratorFunctionPrototype, "constructor", GeneratorFunction), GeneratorFunction.displayName = "GeneratorFunction", _regeneratorDefine2(GeneratorFunctionPrototype, o, "GeneratorFunction"), _regeneratorDefine2(u), _regeneratorDefine2(u, o, "Generator"), _regeneratorDefine2(u, n, function () { return this; }), _regeneratorDefine2(u, "toString", function () { return "[object Generator]"; }), (_regenerator = function _regenerator() { return { w: i, m: f }; })(); }
@@ -35,6 +38,8 @@ var AddPhonePanel = function AddPhonePanel(_ref) {
35
38
  appName = _ref.appName,
36
39
  onComplete = _ref.onComplete,
37
40
  onBack = _ref.onBack,
41
+ onSessionExpired = _ref.onSessionExpired,
42
+ refreshToken = _ref.refreshToken,
38
43
  _ref$requirePhoneVeri = _ref.requirePhoneVerification,
39
44
  requirePhoneVerification = _ref$requirePhoneVeri === void 0 ? false : _ref$requirePhoneVeri,
40
45
  defaultCountry = _ref.defaultCountry,
@@ -88,6 +93,15 @@ var AddPhonePanel = function AddPhonePanel(_ref) {
88
93
  _useState20 = _slicedToArray(_useState19, 2),
89
94
  resendTimer = _useState20[0],
90
95
  setResendTimer = _useState20[1];
96
+ var _useState21 = (0, _react.useState)(false),
97
+ _useState22 = _slicedToArray(_useState21, 2),
98
+ sessionExpired = _useState22[0],
99
+ setSessionExpired = _useState22[1];
100
+ _react["default"].useEffect(function () {
101
+ if (pendingAuth !== null && pendingAuth !== void 0 && pendingAuth.token && (0, _jwt.isJwtExpired)(pendingAuth.token)) {
102
+ setSessionExpired(true);
103
+ }
104
+ }, [pendingAuth === null || pendingAuth === void 0 ? void 0 : pendingAuth.token]);
91
105
  _react["default"].useEffect(function () {
92
106
  if (resendTimer <= 0) return undefined;
93
107
  var id = setInterval(function () {
@@ -124,49 +138,86 @@ var AddPhonePanel = function AddPhonePanel(_ref) {
124
138
  setE164(formatted);
125
139
  setPhoneValid(isValid);
126
140
  };
141
+ var handleSignInAgain = function handleSignInAgain() {
142
+ if (typeof onSessionExpired === 'function') {
143
+ onSessionExpired();
144
+ return;
145
+ }
146
+ if (typeof onBack === 'function') {
147
+ onBack();
148
+ }
149
+ };
150
+ var markSessionExpired = function markSessionExpired() {
151
+ setSessionExpired(true);
152
+ setError('');
153
+ setSuccess('');
154
+ };
127
155
  var savePhone = /*#__PURE__*/function () {
128
156
  var _ref3 = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee(formattedPhone) {
129
- var userId, existing, email, _yield$updatePowrUser, ok, data;
157
+ var userId, sessionToken, sessionRefreshToken, existing, email, _yield$updatePowrUser, ok, data, activeToken;
130
158
  return _regenerator().w(function (_context) {
131
159
  while (1) switch (_context.n) {
132
160
  case 0:
133
161
  userId = (0, _utils.getUserId)(pendingAuth === null || pendingAuth === void 0 ? void 0 : pendingAuth.user);
134
- if (!(!userId || !(pendingAuth !== null && pendingAuth !== void 0 && pendingAuth.token))) {
162
+ sessionToken = pendingAuth === null || pendingAuth === void 0 ? void 0 : pendingAuth.token;
163
+ sessionRefreshToken = refreshToken || (pendingAuth === null || pendingAuth === void 0 ? void 0 : pendingAuth.refreshToken);
164
+ if (!(!userId || !sessionToken)) {
135
165
  _context.n = 1;
136
166
  break;
137
167
  }
138
- throw new Error('Missing user session. Please sign in again.');
168
+ markSessionExpired();
169
+ return _context.a(2, null);
139
170
  case 1:
171
+ if (!(0, _jwt.isJwtExpired)(sessionToken)) {
172
+ _context.n = 2;
173
+ break;
174
+ }
175
+ markSessionExpired();
176
+ return _context.a(2, null);
177
+ case 2:
140
178
  existing = pendingAuth.user || {};
141
179
  email = existing.email && existing.email.includes('@') && existing.email || existing.phoneNumber && existing.phoneNumber.includes('@') && existing.phoneNumber || existing.email || '';
142
- _context.n = 2;
180
+ _context.n = 3;
143
181
  return (0, _utils.updatePowrUser)({
144
182
  apiUrl: apiUrl,
145
183
  projectId: projectId,
146
184
  userId: userId,
147
- token: pendingAuth.token,
185
+ token: sessionToken,
186
+ refreshToken: sessionRefreshToken,
148
187
  body: {
149
188
  phoneNumber: formattedPhone,
150
189
  email: email,
151
190
  fullName: existing.fullName
152
- }
191
+ },
192
+ onTokenRefreshed: pendingAuth === null || pendingAuth === void 0 ? void 0 : pendingAuth.onTokenRefreshed
153
193
  });
154
- case 2:
194
+ case 3:
155
195
  _yield$updatePowrUser = _context.v;
156
196
  ok = _yield$updatePowrUser.ok;
157
197
  data = _yield$updatePowrUser.data;
198
+ activeToken = _yield$updatePowrUser.token;
158
199
  if (ok) {
159
- _context.n = 3;
200
+ _context.n = 5;
160
201
  break;
161
202
  }
162
- throw new Error((data === null || data === void 0 ? void 0 : data.message) || 'Failed to save phone number');
163
- case 3:
164
- return _context.a(2, _objectSpread(_objectSpread({}, existing), {}, {
165
- phoneNumber: formattedPhone,
166
- email: email || existing.email,
167
- powrId: existing.powrId || userId,
168
- _id: existing._id || userId
169
- }));
203
+ if (!(0, _jwt.isAuthSessionError)(data === null || data === void 0 ? void 0 : data.message)) {
204
+ _context.n = 4;
205
+ break;
206
+ }
207
+ markSessionExpired();
208
+ return _context.a(2, null);
209
+ case 4:
210
+ throw new Error((0, _sessionMessages.getFriendlyAuthError)(data === null || data === void 0 ? void 0 : data.message) || _sessionMessages.SESSION_MESSAGES.saveFailed);
211
+ case 5:
212
+ return _context.a(2, {
213
+ user: _objectSpread(_objectSpread({}, existing), {}, {
214
+ phoneNumber: formattedPhone,
215
+ email: email || existing.email,
216
+ powrId: existing.powrId || userId,
217
+ _id: existing._id || userId
218
+ }),
219
+ token: activeToken
220
+ });
170
221
  }
171
222
  }, _callee);
172
223
  }));
@@ -176,7 +227,7 @@ var AddPhonePanel = function AddPhonePanel(_ref) {
176
227
  }();
177
228
  var handleSaveWithoutOtp = /*#__PURE__*/function () {
178
229
  var _ref4 = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee2() {
179
- var formattedPhone, updatedUser, _t;
230
+ var formattedPhone, result, _t;
180
231
  return _regenerator().w(function (_context2) {
181
232
  while (1) switch (_context2.p = _context2.n) {
182
233
  case 0:
@@ -189,31 +240,38 @@ var AddPhonePanel = function AddPhonePanel(_ref) {
189
240
  _context2.n = 2;
190
241
  break;
191
242
  }
192
- setError('Please enter a valid phone number');
243
+ setError(_sessionMessages.SESSION_MESSAGES.invalidPhone);
193
244
  setLoading(false);
194
245
  return _context2.a(2);
195
246
  case 2:
196
247
  _context2.n = 3;
197
248
  return savePhone(formattedPhone);
198
249
  case 3:
199
- updatedUser = _context2.v;
250
+ result = _context2.v;
251
+ if (result) {
252
+ _context2.n = 4;
253
+ break;
254
+ }
255
+ setLoading(false);
256
+ return _context2.a(2);
257
+ case 4:
200
258
  setSuccess('Phone number saved!');
201
- onComplete(updatedUser);
202
- _context2.n = 5;
259
+ onComplete(result.user, result.token);
260
+ _context2.n = 6;
203
261
  break;
204
- case 4:
205
- _context2.p = 4;
206
- _t = _context2.v;
207
- console.error('add-phone save error', _t);
208
- setError((_t === null || _t === void 0 ? void 0 : _t.message) || 'Failed to save phone number');
209
262
  case 5:
210
263
  _context2.p = 5;
211
- setLoading(false);
212
- return _context2.f(5);
264
+ _t = _context2.v;
265
+ console.error('add-phone save error', _t);
266
+ setError((_t === null || _t === void 0 ? void 0 : _t.message) || _sessionMessages.SESSION_MESSAGES.saveFailed);
213
267
  case 6:
268
+ _context2.p = 6;
269
+ setLoading(false);
270
+ return _context2.f(6);
271
+ case 7:
214
272
  return _context2.a(2);
215
273
  }
216
- }, _callee2, null, [[1, 4, 5, 6]]);
274
+ }, _callee2, null, [[1, 5, 6, 7]]);
217
275
  }));
218
276
  return function handleSaveWithoutOtp() {
219
277
  return _ref4.apply(this, arguments);
@@ -234,7 +292,7 @@ var AddPhonePanel = function AddPhonePanel(_ref) {
234
292
  _context3.n = 2;
235
293
  break;
236
294
  }
237
- setError('Please enter a valid phone number');
295
+ setError(_sessionMessages.SESSION_MESSAGES.invalidPhone);
238
296
  setLoading(false);
239
297
  return _context3.a(2);
240
298
  case 2:
@@ -267,7 +325,7 @@ var AddPhonePanel = function AddPhonePanel(_ref) {
267
325
  _context3.p = 8;
268
326
  _t3 = _context3.v;
269
327
  console.error('add-phone sendOtp error', _t3);
270
- setError((_t3 === null || _t3 === void 0 ? void 0 : _t3.message) || 'Failed to send OTP.');
328
+ setError((_t3 === null || _t3 === void 0 ? void 0 : _t3.message) || 'Failed to send OTP. Please try again.');
271
329
  clearRecaptcha();
272
330
  case 9:
273
331
  _context3.p = 9;
@@ -284,7 +342,7 @@ var AddPhonePanel = function AddPhonePanel(_ref) {
284
342
  }();
285
343
  var verifyOtp = /*#__PURE__*/function () {
286
344
  var _ref6 = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee4() {
287
- var formattedPhone, updatedUser, _t4, _t5;
345
+ var formattedPhone, result, _t4, _t5;
288
346
  return _regenerator().w(function (_context4) {
289
347
  while (1) switch (_context4.p = _context4.n) {
290
348
  case 0:
@@ -317,30 +375,43 @@ var AddPhonePanel = function AddPhonePanel(_ref) {
317
375
  _context4.n = 7;
318
376
  return savePhone(formattedPhone);
319
377
  case 7:
320
- updatedUser = _context4.v;
378
+ result = _context4.v;
379
+ if (result) {
380
+ _context4.n = 8;
381
+ break;
382
+ }
383
+ setLoading(false);
384
+ return _context4.a(2);
385
+ case 8:
321
386
  clearRecaptcha();
322
387
  setSuccess('Phone number saved!');
323
- onComplete(updatedUser);
324
- _context4.n = 9;
388
+ onComplete(result.user, result.token);
389
+ _context4.n = 10;
325
390
  break;
326
- case 8:
327
- _context4.p = 8;
391
+ case 9:
392
+ _context4.p = 9;
328
393
  _t5 = _context4.v;
329
394
  console.error('add-phone verifyOtp error', _t5);
330
395
  setError((_t5 === null || _t5 === void 0 ? void 0 : _t5.message) || 'Invalid OTP. Please try again.');
331
- case 9:
332
- _context4.p = 9;
333
- setLoading(false);
334
- return _context4.f(9);
335
396
  case 10:
397
+ _context4.p = 10;
398
+ setLoading(false);
399
+ return _context4.f(10);
400
+ case 11:
336
401
  return _context4.a(2);
337
402
  }
338
- }, _callee4, null, [[3, 5], [1, 8, 9, 10]]);
403
+ }, _callee4, null, [[3, 5], [1, 9, 10, 11]]);
339
404
  }));
340
405
  return function verifyOtp() {
341
406
  return _ref6.apply(this, arguments);
342
407
  };
343
408
  }();
409
+ if (sessionExpired) {
410
+ return /*#__PURE__*/_react["default"].createElement(_SessionExpiredPanel["default"], {
411
+ onSignIn: handleSignInAgain,
412
+ loading: loading
413
+ });
414
+ }
344
415
  var subtitle = requirePhoneVerification ? "".concat(appName, " uses your phone for sign-in. Verify your number to continue.") : "".concat(appName, " uses your phone for sign-in. Add your number to continue.");
345
416
  return /*#__PURE__*/_react["default"].createElement("div", {
346
417
  style: panelStyles.wrapper
@@ -7,8 +7,10 @@ Object.defineProperty(exports, "__esModule", {
7
7
  exports["default"] = void 0;
8
8
  var _react = _interopRequireWildcard(require("react"));
9
9
  var _OnboardingShell = _interopRequireDefault(require("./OnboardingShell"));
10
+ var _SessionExpiredPanel = _interopRequireDefault(require("./SessionExpiredPanel"));
10
11
  var _utils = require("./utils");
11
12
  var _phone = require("../utils/phone");
13
+ var _jwt = require("../utils/jwt");
12
14
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
13
15
  function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, "default": e }; if (null === e || "object" != _typeof(e) && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t in e) "default" !== _t && {}.hasOwnProperty.call(e, _t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t)) && (i.get || i.set) ? o(f, _t, i) : f[_t] = e[_t]); return f; })(e, t); }
14
16
  function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
@@ -55,7 +57,10 @@ var PowrOnboardingProvider = function PowrOnboardingProvider(_ref) {
55
57
  international = _ref$international === void 0 ? false : _ref$international,
56
58
  _ref$allowedCountries = _ref.allowedCountries,
57
59
  allowedCountries = _ref$allowedCountries === void 0 ? null : _ref$allowedCountries,
60
+ refreshToken = _ref.refreshToken,
58
61
  onUserUpdate = _ref.onUserUpdate,
62
+ onSessionExpired = _ref.onSessionExpired,
63
+ onTokenRefreshed = _ref.onTokenRefreshed,
59
64
  onAllComplete = _ref.onAllComplete,
60
65
  children = _ref.children;
61
66
  var resolvedDefaultCountry = (0, _phone.resolveCountry)(defaultCountry, defaultCountryCode);
@@ -89,9 +94,12 @@ var PowrOnboardingProvider = function PowrOnboardingProvider(_ref) {
89
94
  defaultCountry: resolvedDefaultCountry,
90
95
  defaultCountryCode: defaultCountryCode,
91
96
  international: international,
92
- allowedCountries: allowedCountries
97
+ allowedCountries: allowedCountries,
98
+ refreshToken: refreshToken,
99
+ onSessionExpired: onSessionExpired,
100
+ onTokenRefreshed: onTokenRefreshed
93
101
  };
94
- }, [localUser, token, apiUrl, projectId, appName, requirePhoneVerification, resolvedDefaultCountry, defaultCountryCode, international, allowedCountries]);
102
+ }, [localUser, token, apiUrl, projectId, appName, requirePhoneVerification, resolvedDefaultCountry, defaultCountryCode, international, allowedCountries, refreshToken, onSessionExpired, onTokenRefreshed]);
95
103
  var runEvaluation = (0, _react.useCallback)(/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee() {
96
104
  var pending;
97
105
  return _regenerator().w(function (_context) {
@@ -128,6 +136,7 @@ var PowrOnboardingProvider = function PowrOnboardingProvider(_ref) {
128
136
  (0, _react.useEffect)(function () {
129
137
  runEvaluation();
130
138
  }, [runEvaluation]);
139
+ var sessionTimedOut = !skip && isHydrated && !!localUser && !!token && (0, _jwt.isJwtExpired)(token);
131
140
  var handleStepComplete = /*#__PURE__*/function () {
132
141
  var _ref3 = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee2(patch) {
133
142
  var updatedUser, pending;
@@ -181,6 +190,17 @@ var PowrOnboardingProvider = function PowrOnboardingProvider(_ref) {
181
190
  if (skip || !isHydrated || !localUser || !token) {
182
191
  return children;
183
192
  }
193
+ if (sessionTimedOut) {
194
+ return /*#__PURE__*/_react["default"].createElement(_OnboardingShell["default"], {
195
+ appName: appName,
196
+ appLogo: appLogo,
197
+ currentStep: 1,
198
+ totalSteps: 1,
199
+ stepTitle: "Sign in"
200
+ }, /*#__PURE__*/_react["default"].createElement(_SessionExpiredPanel["default"], {
201
+ onSignIn: onSessionExpired
202
+ }));
203
+ }
184
204
  if (evaluating) {
185
205
  return /*#__PURE__*/_react["default"].createElement("div", {
186
206
  style: loadingStyles.page
@@ -0,0 +1,71 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports["default"] = void 0;
7
+ var _react = _interopRequireDefault(require("react"));
8
+ var _sessionMessages = require("../utils/sessionMessages");
9
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
10
+ var SessionExpiredPanel = function SessionExpiredPanel(_ref) {
11
+ var _ref$title = _ref.title,
12
+ title = _ref$title === void 0 ? _sessionMessages.SESSION_MESSAGES.expiredTitle : _ref$title,
13
+ _ref$body = _ref.body,
14
+ body = _ref$body === void 0 ? _sessionMessages.SESSION_MESSAGES.expiredBody : _ref$body,
15
+ _ref$actionLabel = _ref.actionLabel,
16
+ actionLabel = _ref$actionLabel === void 0 ? _sessionMessages.SESSION_MESSAGES.signInAgain : _ref$actionLabel,
17
+ onSignIn = _ref.onSignIn,
18
+ _ref$loading = _ref.loading,
19
+ loading = _ref$loading === void 0 ? false : _ref$loading;
20
+ return /*#__PURE__*/_react["default"].createElement("div", {
21
+ style: styles.wrapper
22
+ }, /*#__PURE__*/_react["default"].createElement("div", {
23
+ style: styles.icon,
24
+ "aria-hidden": "true"
25
+ }, "\u23F1"), /*#__PURE__*/_react["default"].createElement("h2", {
26
+ style: styles.title
27
+ }, title), /*#__PURE__*/_react["default"].createElement("p", {
28
+ style: styles.body
29
+ }, body), /*#__PURE__*/_react["default"].createElement("button", {
30
+ type: "button",
31
+ onClick: onSignIn,
32
+ disabled: loading || typeof onSignIn !== 'function',
33
+ style: styles.primaryButton
34
+ }, loading ? 'Please wait...' : actionLabel));
35
+ };
36
+ var styles = {
37
+ wrapper: {
38
+ width: '100%',
39
+ textAlign: 'center',
40
+ padding: '8px 0 4px'
41
+ },
42
+ icon: {
43
+ fontSize: 32,
44
+ lineHeight: 1,
45
+ marginBottom: 12
46
+ },
47
+ title: {
48
+ margin: '0 0 10px',
49
+ fontSize: 22,
50
+ fontWeight: 700,
51
+ color: '#111827'
52
+ },
53
+ body: {
54
+ margin: '0 0 20px',
55
+ fontSize: 14,
56
+ color: '#6b7280',
57
+ lineHeight: 1.6
58
+ },
59
+ primaryButton: {
60
+ width: '100%',
61
+ padding: 12,
62
+ background: '#ff6b35',
63
+ color: 'white',
64
+ border: 'none',
65
+ borderRadius: 8,
66
+ cursor: 'pointer',
67
+ fontWeight: 700,
68
+ fontSize: 15
69
+ }
70
+ };
71
+ var _default = exports["default"] = SessionExpiredPanel;
@@ -14,17 +14,24 @@ var AddPhoneStepView = function AddPhoneStepView(_ref) {
14
14
  onBack = _ref.onBack;
15
15
  var pendingAuth = {
16
16
  user: ctx.user,
17
- token: ctx.token
17
+ token: ctx.token,
18
+ refreshToken: ctx.refreshToken,
19
+ onTokenRefreshed: ctx.onTokenRefreshed
18
20
  };
19
21
  return /*#__PURE__*/_react["default"].createElement(_AddPhonePanel["default"], {
20
22
  apiUrl: ctx.apiUrl,
21
23
  projectId: ctx.projectId,
22
24
  pendingAuth: pendingAuth,
25
+ refreshToken: ctx.refreshToken,
23
26
  appName: ctx.appName || 'App',
24
- onComplete: function onComplete(updatedUser) {
25
- return _onComplete(updatedUser);
27
+ onComplete: function onComplete(updatedUser, sessionToken) {
28
+ if (sessionToken && typeof ctx.onTokenRefreshed === 'function') {
29
+ ctx.onTokenRefreshed(sessionToken);
30
+ }
31
+ _onComplete(updatedUser);
26
32
  },
27
33
  onBack: onBack,
34
+ onSessionExpired: ctx.onSessionExpired,
28
35
  requirePhoneVerification: ctx.requirePhoneVerification === true,
29
36
  defaultCountry: ctx.defaultCountry,
30
37
  defaultCountryCode: ctx.defaultCountryCode,
@@ -83,6 +83,7 @@ Object.defineProperty(exports, "parsePhone", {
83
83
  return _phone.parsePhone;
84
84
  }
85
85
  });
86
+ exports.refreshAccessToken = refreshAccessToken;
86
87
  Object.defineProperty(exports, "resolveCountry", {
87
88
  enumerable: true,
88
89
  get: function get() {
@@ -245,41 +246,146 @@ function _needsOnboarding() {
245
246
  }));
246
247
  return _needsOnboarding.apply(this, arguments);
247
248
  }
248
- function updatePowrUser(_x4) {
249
- return _updatePowrUser.apply(this, arguments);
249
+ function refreshAccessToken(_x4) {
250
+ return _refreshAccessToken.apply(this, arguments);
250
251
  }
251
- function _updatePowrUser() {
252
- _updatePowrUser = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee3(_ref) {
253
- var apiUrl, projectId, userId, token, body, separator, url, response, data;
252
+ function _refreshAccessToken() {
253
+ _refreshAccessToken = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee3(_ref) {
254
+ var apiUrl, projectId, refreshToken, url, response, data;
254
255
  return _regenerator().w(function (_context3) {
255
256
  while (1) switch (_context3.n) {
256
257
  case 0:
257
- apiUrl = _ref.apiUrl, projectId = _ref.projectId, userId = _ref.userId, token = _ref.token, body = _ref.body;
258
- separator = '?';
259
- url = "".concat(apiUrl, "/users/").concat(userId).concat(separator, "projectId=").concat(projectId);
260
- _context3.n = 1;
258
+ apiUrl = _ref.apiUrl, projectId = _ref.projectId, refreshToken = _ref.refreshToken;
259
+ if (refreshToken) {
260
+ _context3.n = 1;
261
+ break;
262
+ }
263
+ return _context3.a(2, {
264
+ ok: false,
265
+ data: {
266
+ message: 'No refresh token'
267
+ }
268
+ });
269
+ case 1:
270
+ url = "".concat(apiUrl, "/auth/refresh-token?projectId=").concat(projectId);
271
+ _context3.n = 2;
261
272
  return fetch(url, {
262
- method: 'PUT',
273
+ method: 'POST',
263
274
  headers: {
264
- 'Content-Type': 'application/json',
265
- Authorization: "Bearer ".concat(token)
275
+ 'Content-Type': 'application/json'
266
276
  },
267
- body: JSON.stringify(body)
277
+ body: JSON.stringify({
278
+ refreshToken: refreshToken
279
+ })
268
280
  });
269
- case 1:
281
+ case 2:
270
282
  response = _context3.v;
271
- _context3.n = 2;
283
+ _context3.n = 3;
272
284
  return response.json()["catch"](function () {
273
285
  return {};
274
286
  });
275
- case 2:
287
+ case 3:
276
288
  data = _context3.v;
289
+ if (response.ok) {
290
+ _context3.n = 4;
291
+ break;
292
+ }
277
293
  return _context3.a(2, {
278
- ok: response.ok,
294
+ ok: false,
295
+ data: data
296
+ });
297
+ case 4:
298
+ return _context3.a(2, {
299
+ ok: true,
300
+ token: data.token,
279
301
  data: data
280
302
  });
281
303
  }
282
304
  }, _callee3);
283
305
  }));
306
+ return _refreshAccessToken.apply(this, arguments);
307
+ }
308
+ function updatePowrUser(_x5) {
309
+ return _updatePowrUser.apply(this, arguments);
310
+ }
311
+ function _updatePowrUser() {
312
+ _updatePowrUser = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee5(_ref2) {
313
+ var apiUrl, projectId, userId, token, refreshToken, body, onTokenRefreshed, activeToken, putUser, response, data, refreshed;
314
+ return _regenerator().w(function (_context5) {
315
+ while (1) switch (_context5.n) {
316
+ case 0:
317
+ apiUrl = _ref2.apiUrl, projectId = _ref2.projectId, userId = _ref2.userId, token = _ref2.token, refreshToken = _ref2.refreshToken, body = _ref2.body, onTokenRefreshed = _ref2.onTokenRefreshed;
318
+ activeToken = token;
319
+ putUser = /*#__PURE__*/function () {
320
+ var _ref3 = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee4() {
321
+ var url;
322
+ return _regenerator().w(function (_context4) {
323
+ while (1) switch (_context4.n) {
324
+ case 0:
325
+ url = "".concat(apiUrl, "/users/").concat(userId, "?projectId=").concat(projectId);
326
+ return _context4.a(2, fetch(url, {
327
+ method: 'PUT',
328
+ headers: {
329
+ 'Content-Type': 'application/json',
330
+ Authorization: "Bearer ".concat(activeToken)
331
+ },
332
+ body: JSON.stringify(body)
333
+ }));
334
+ }
335
+ }, _callee4);
336
+ }));
337
+ return function putUser() {
338
+ return _ref3.apply(this, arguments);
339
+ };
340
+ }();
341
+ _context5.n = 1;
342
+ return putUser();
343
+ case 1:
344
+ response = _context5.v;
345
+ _context5.n = 2;
346
+ return response.json()["catch"](function () {
347
+ return {};
348
+ });
349
+ case 2:
350
+ data = _context5.v;
351
+ if (!(response.status === 401 && refreshToken)) {
352
+ _context5.n = 6;
353
+ break;
354
+ }
355
+ _context5.n = 3;
356
+ return refreshAccessToken({
357
+ apiUrl: apiUrl,
358
+ projectId: projectId,
359
+ refreshToken: refreshToken
360
+ });
361
+ case 3:
362
+ refreshed = _context5.v;
363
+ if (!(refreshed.ok && refreshed.token)) {
364
+ _context5.n = 6;
365
+ break;
366
+ }
367
+ activeToken = refreshed.token;
368
+ if (typeof onTokenRefreshed === 'function') {
369
+ onTokenRefreshed(activeToken);
370
+ }
371
+ _context5.n = 4;
372
+ return putUser();
373
+ case 4:
374
+ response = _context5.v;
375
+ _context5.n = 5;
376
+ return response.json()["catch"](function () {
377
+ return {};
378
+ });
379
+ case 5:
380
+ data = _context5.v;
381
+ case 6:
382
+ return _context5.a(2, {
383
+ ok: response.ok,
384
+ data: data,
385
+ token: activeToken
386
+ });
387
+ }
388
+ }, _callee5);
389
+ }));
284
390
  return _updatePowrUser.apply(this, arguments);
285
391
  }
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.decodeJwtPayload = decodeJwtPayload;
7
+ exports.isAuthSessionError = isAuthSessionError;
8
+ exports.isJwtExpired = isJwtExpired;
9
+ function decodeJwtPayload(token) {
10
+ if (!token || typeof token !== 'string') return null;
11
+ try {
12
+ var parts = token.split('.');
13
+ if (parts.length < 2) return null;
14
+ var base64 = parts[1].replace(/-/g, '+').replace(/_/g, '/');
15
+ var padded = base64.padEnd(base64.length + (4 - base64.length % 4) % 4, '=');
16
+ var json = atob(padded);
17
+ return JSON.parse(json);
18
+ } catch (_unused) {
19
+ return null;
20
+ }
21
+ }
22
+ function isJwtExpired(token) {
23
+ var leewaySeconds = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 30;
24
+ var payload = decodeJwtPayload(token);
25
+ if (!(payload !== null && payload !== void 0 && payload.exp)) return false;
26
+ var now = Math.floor(Date.now() / 1000);
27
+ return payload.exp <= now + leewaySeconds;
28
+ }
29
+ function isAuthSessionError(message) {
30
+ if (!message || typeof message !== 'string') return false;
31
+ var lower = message.toLowerCase();
32
+ return lower.includes('jwt expired') || lower.includes('invalid token') || lower.includes('no authorization token') || lower.includes('no token provided');
33
+ }
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.SESSION_MESSAGES = void 0;
7
+ exports.getFriendlyAuthError = getFriendlyAuthError;
8
+ var SESSION_MESSAGES = exports.SESSION_MESSAGES = {
9
+ expiredTitle: 'Your session timed out',
10
+ expiredBody: 'For your security, sign-in sessions expire after a while. Sign in again to save your phone number and continue.',
11
+ signInAgain: 'Sign in again',
12
+ loginBannerTitle: 'Your session timed out',
13
+ loginBannerBody: 'Please sign in again to continue where you left off.',
14
+ saveFailed: 'We could not save your phone number. Please try again.',
15
+ invalidPhone: 'Please enter a valid phone number.'
16
+ };
17
+ function getFriendlyAuthError(message) {
18
+ if (!message || typeof message !== 'string') {
19
+ return SESSION_MESSAGES.saveFailed;
20
+ }
21
+ var lower = message.toLowerCase();
22
+ if (lower.includes('jwt expired') || lower.includes('invalid token') || lower.includes('no authorization token') || lower.includes('no token provided') || lower.includes('missing user session')) {
23
+ return null;
24
+ }
25
+ return message;
26
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "powr-sdk-web",
3
- "version": "5.8.0",
3
+ "version": "5.8.1",
4
4
  "main": "dist/index.js",
5
5
  "scripts": {
6
6
  "build": "babel src -d dist --copy-files",