@flumens/models 0.5.3 → 0.6.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.
@@ -1,4 +1,4 @@
1
- import Deferred from '@flumens/utils/dist/deferred';
1
+ import { Deferred } from '@flumens/utils';
2
2
  import ModelClass from './Model';
3
3
  import Store from './Stores/Store';
4
4
  interface ObservableArrayI<T> extends Array<T> {
@@ -1 +1,108 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("tslib"),t=require("mobx"),r=require("@flumens/utils/dist/deferred"),i=require("@flumens/utils/dist/uuid"),n=require("./Model.js");function o(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}var s=o(r),u=o(i),a=function(t){function r(r){var i=r.id,o=r.cid,a=r.models,l=void 0===a?[]:a,d=r.store,c=r.Model,f=void 0===c?n.default:c,p=t.apply(this,l)||this;return p.ready=new s.default,p.fetch=function(){return e.__awaiter(p,void 0,void 0,(function(){var t,r,i,n=this;return e.__generator(this,(function(e){switch(e.label){case 0:return this.store&&this.Model?[4,this.store.findAll()]:(this.ready.resolve(!1),[2]);case 1:return t=e.sent(),r=function(e){return new n.Model(e)},i=t.map(r),this.push.apply(this,i),this.ready.resolve(!0),[2]}}))}))},p.reset=function(){return e.__awaiter(p,void 0,void 0,(function(){return e.__generator(this,(function(e){switch(e.label){case 0:return this.length?[4,this.pop().destroy()]:[3,2];case 1:return e.sent(),[3,0];case 2:return[2]}}))}))},p.id=p.id||i,p.cid=p.cid||o||i||u.default(),p.Model=f,p.store=p.store||d,p}return e.__extends(r,t),r.prototype.spliceWithArray=function(){for(var e,t=[],r=0;r<arguments.length;r++)t[r]=arguments[r];return(e=this).spliceWithArray.apply(e,t)},r.prototype.clear=function(){return this.clear()},r.prototype.replace=function(){for(var e,t=[],r=0;r<arguments.length;r++)t[r]=arguments[r];return(e=this).replace.apply(e,t)},r.prototype.remove=function(){for(var e,t=[],r=0;r<arguments.length;r++)t[r]=arguments[r];return(e=this).remove.apply(e,t)},r.prototype.toJSON=function(){return this.toJSON()},r}((function(){for(var e=[],r=0;r<arguments.length;r++)e[r]=arguments[r];return t.observable(e)}));exports.default=a;
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var tslib = require('tslib');
6
+ var mobx = require('mobx');
7
+ var utils = require('@flumens/utils');
8
+ var Model = require('./Model.js');
9
+
10
+ // Mobx doesn't have an observable array class so we use an old-style class definition
11
+ var ObservableArray = function () {
12
+ var models = [];
13
+ for (var _i = 0; _i < arguments.length; _i++) {
14
+ models[_i] = arguments[_i];
15
+ }
16
+ return mobx.observable(models);
17
+ };
18
+ // Class functions need to be properties and not methods - don't know why yet
19
+ var Collection = /** @class */ (function (_super) {
20
+ tslib.__extends(Collection, _super);
21
+ function Collection(_a) {
22
+ var id = _a.id, cid = _a.cid, _b = _a.models, models = _b === void 0 ? [] : _b, store = _a.store, _c = _a.Model, Model$1 = _c === void 0 ? Model["default"] : _c;
23
+ var _this = _super.apply(this, models) || this;
24
+ /**
25
+ * A promise to flag if all the models were initialised from the store.
26
+ */
27
+ _this.ready = new utils.Deferred();
28
+ _this.fetch = function () { return tslib.__awaiter(_this, void 0, void 0, function () {
29
+ var modelsJSON, getModel, models;
30
+ var _this = this;
31
+ return tslib.__generator(this, function (_a) {
32
+ switch (_a.label) {
33
+ case 0:
34
+ if (!this.store || !this.Model) {
35
+ this.ready.resolve(false);
36
+ return [2 /*return*/];
37
+ }
38
+ return [4 /*yield*/, this.store.findAll()];
39
+ case 1:
40
+ modelsJSON = _a.sent();
41
+ getModel = function (modelJSON) { return new _this.Model(modelJSON); };
42
+ models = modelsJSON.map(getModel);
43
+ this.push.apply(this, models);
44
+ this.ready.resolve(true);
45
+ return [2 /*return*/];
46
+ }
47
+ });
48
+ }); };
49
+ _this.reset = function () { return tslib.__awaiter(_this, void 0, void 0, function () {
50
+ var model;
51
+ return tslib.__generator(this, function (_a) {
52
+ switch (_a.label) {
53
+ case 0:
54
+ if (!this.length) return [3 /*break*/, 2];
55
+ model = this.pop();
56
+ return [4 /*yield*/, model.destroy()];
57
+ case 1:
58
+ _a.sent(); // eslint-disable-line no-await-in-loop
59
+ return [3 /*break*/, 0];
60
+ case 2: return [2 /*return*/];
61
+ }
62
+ });
63
+ }); };
64
+ _this.id = _this.id || id;
65
+ _this.cid = _this.cid || cid || id || utils.UUIDv7();
66
+ _this.Model = Model$1;
67
+ _this.store = _this.store || store;
68
+ return _this;
69
+ }
70
+ // Mobx ObservableArray fn
71
+ Collection.prototype.spliceWithArray = function () {
72
+ var _a;
73
+ var args = [];
74
+ for (var _i = 0; _i < arguments.length; _i++) {
75
+ args[_i] = arguments[_i];
76
+ }
77
+ return (_a = this).spliceWithArray.apply(_a, args);
78
+ };
79
+ // Mobx ObservableArray fn
80
+ Collection.prototype.clear = function () {
81
+ return this.clear();
82
+ };
83
+ // Mobx ObservableArray fn
84
+ Collection.prototype.replace = function () {
85
+ var _a;
86
+ var args = [];
87
+ for (var _i = 0; _i < arguments.length; _i++) {
88
+ args[_i] = arguments[_i];
89
+ }
90
+ return (_a = this).replace.apply(_a, args);
91
+ };
92
+ // Mobx ObservableArray fn
93
+ Collection.prototype.remove = function () {
94
+ var _a;
95
+ var args = [];
96
+ for (var _i = 0; _i < arguments.length; _i++) {
97
+ args[_i] = arguments[_i];
98
+ }
99
+ return (_a = this).remove.apply(_a, args);
100
+ };
101
+ // Mobx ObservableArray fn
102
+ Collection.prototype.toJSON = function () {
103
+ return this.toJSON();
104
+ };
105
+ return Collection;
106
+ }(ObservableArray));
107
+
108
+ exports["default"] = Collection;
@@ -53,11 +53,11 @@ export default class DrupalUserModel<T extends Attrs = Attrs> extends Model<T> {
53
53
  id: z.ZodNumber;
54
54
  email: z.ZodString;
55
55
  }, "strip", z.ZodTypeAny, {
56
- id: number;
57
56
  email: string;
58
- }, {
59
57
  id: number;
58
+ }, {
60
59
  email: string;
60
+ id: number;
61
61
  }>;
62
62
  static resetSchema: z.ZodObject<{
63
63
  email: z.ZodString;
@@ -1 +1,433 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("tslib"),t=require("axios"),r=require("jwt-decode"),s=require("zod"),i=require("@flumens/utils/dist/errors"),n=require("../Model.js");function a(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}var o=a(t);function c(e,t){Object.keys(t).forEach((function(r){if(r.match(/^field_/)){var s=r.replace("field_","").replace(/_([a-z])/g,(function(e){return e[1].toUpperCase()}));if(!t[r])return;if(Array.isArray(t[r])&&t[r].length)return void(e[s]=t[r][0].value);e[s]=t[r]}}))}var u=function(e){var t;if(e.response&&e.response.data&&e.response.data.message){if(e.response.data.message.includes("is already taken"))throw new i.HandledError("This email is already taken.");if("The user credentials were incorrect."===e.response.data.message)throw new i.HandledError("Incorrect password or email");if("Unrecognized username or email address."===e.response.data.message)throw new i.HandledError("Unrecognized email address.");if("This account is already activated"===e.response.data.message)throw new i.HandledError("This account is already activated.");if(e.response.data.message.includes("not been activated"))throw new i.HandledError("The user has not been activated or is blocked.");throw new Error(e.response.data.message)}if(null===(t=e.message)||void 0===t?void 0:t.includes("timeout"))throw new i.HandledError("Timeout");throw e},h=6e4;var d={email:"",tokens:void 0,verified:!1,iss:void 0,indiciaUserId:void 0},l=function(t){function i(r){var s=this,i=r.config,n=e.__rest(r,["config"]);return(s=t.call(this,e.__assign(e.__assign({},n),{attrs:e.__assign(e.__assign({},d),n.attrs)}))||this).config=i,s}return e.__extends(i,t),i.prototype.logIn=function(t,r){return e.__awaiter(this,void 0,void 0,(function(){var s;return e.__generator(this,(function(e){switch(e.label){case 0:return[4,this._exchangePasswordToTokens(t,r)];case 1:return s=e.sent(),this.attrs.tokens=s,[4,this.refreshProfile()];case 2:return e.sent(),[2,this.save()]}}))}))},i.prototype.register=function(t,r,s){return e.__awaiter(this,void 0,void 0,(function(){var n,a,d,l;return e.__generator(this,(function(f){switch(f.label){case 0:return n=JSON.stringify(e.__assign({name:[{value:t}],pass:[{value:r}],mail:[{value:t}]},s)),a={method:"post",url:"".concat(this.config.url,"/user/register-with-password?_format=json"),headers:{"content-type":"application/json"},data:n,timeout:h},[4,o.default(a).catch(u)];case 1:if(d=f.sent().data,!!i.registerSchemaBackend.safeParse(d).error)throw new Error("Invalid backend response.");return[4,this._exchangePasswordToTokens(t,r)];case 2:return l=f.sent(),this.attrs.tokens=l,this.id=d.uid[0].value,this.attrs.email=t,c(this.attrs,d),[2,this.save()]}}))}))},i.prototype.reset=function(t){return e.__awaiter(this,void 0,void 0,(function(){var r,s,i;return e.__generator(this,(function(e){switch(e.label){case 0:r=JSON.stringify({mail:t}),s={method:"post",url:"".concat(this.config.url,"/user/password?_format=json"),headers:{"content-type":"application/json"},data:r},e.label=1;case 1:return e.trys.push([1,3,,6]),[4,o.default(s).catch(u)];case 2:return e.sent(),[3,6];case 3:return"The user has not been activated or is blocked."!==(i=e.sent()).message?[3,5]:[4,this._sendVerificationEmail(t)];case 4:return e.sent(),[2];case 5:return u(i),[3,6];case 6:return[2]}}))}))},i.prototype.delete=function(){return e.__awaiter(this,void 0,void 0,(function(){var t,r;return e.__generator(this,(function(e){switch(e.label){case 0:return[4,this.getAccessToken(!0)];case 1:return t=e.sent(),r={method:"delete",url:"".concat(this.config.url,"/user/").concat(this.id,"?_format=json"),headers:{Authorization:"Bearer ".concat(t)}},[4,o.default(r).catch(u)];case 2:return e.sent(),this.logOut(),[2]}}))}))},i.prototype.refreshProfile=function(){return e.__awaiter(this,void 0,void 0,(function(){var t=this;return e.__generator(this,(function(r){return this._refreshingProfilePromise||(this._refreshingProfilePromise=Promise.resolve().then((function(){return e.__awaiter(t,void 0,void 0,(function(){var t,r,s;return e.__generator(this,(function(e){switch(e.label){case 0:return[4,this.getAccessToken(!0)];case 1:return t=e.sent(),this.attrs.verified?(r={url:"".concat(this.config.url,"/user/").concat(this.id,"?_format=json"),headers:{Authorization:"Bearer ".concat(t)},timeout:h},[4,o.default(r).catch(u)]):[3,3];case 2:s=e.sent().data,this.attrs.email=s.mail[0].value,c(this.attrs,s),e.label=3;case 3:return[4,this.save()];case 4:return e.sent(),delete this._refreshingProfilePromise,[2]}}))}))})).catch((function(e){throw delete t._refreshingProfilePromise,e}))),[2,this._refreshingProfilePromise]}))}))},i.prototype.hasLogIn=function(){return console.warn("hasLogIn is deprecated, please use isLoggedIn instead."),this.isLoggedIn()},i.prototype.isLoggedIn=function(){return this.attrs.email,!!this.id},i.prototype.logOut=function(){return e.__awaiter(this,void 0,void 0,(function(){return e.__generator(this,(function(e){return[2,this.resetDefaults()]}))}))},i.prototype.resetDefaults=function(r){return t.prototype.resetDefaults.call(this,e.__assign(e.__assign({},d),r))},i.prototype.getAccessToken=function(t){var s;return e.__awaiter(this,void 0,void 0,(function(){var i,n,a,o,c;return e.__generator(this,(function(e){switch(e.label){case 0:if(!t&&!this.isLoggedIn())throw new Error("User is not logged in.");if(i=(this.attrs.tokens||{}).access_token,n=function(e){if(!e)return!0;var t=1e3*r.jwtDecode(e).exp;return Date.now()+12e4>t}(i),!(!i||n||t))return[3,6];e.label=1;case 1:return e.trys.push([1,3,,6]),[4,this._refreshAccessToken()];case 2:return e.sent(),[3,6];case 3:return a=e.sent(),console.error(a),o="The refresh token is invalid."===a.message,c="Token has no user email."===a.message,o||c?[4,this.logOut()]:[3,5];case 4:throw e.sent(),new Error("User re-login is required.");case 5:throw a;case 6:return[2,null===(s=this.attrs.tokens)||void 0===s?void 0:s.access_token]}}))}))},i.prototype._sendVerificationEmail=function(t){return e.__awaiter(this,void 0,void 0,(function(){var r,s;return e.__generator(this,(function(e){return r=JSON.stringify({mail:[{value:t||this.attrs.email}]}),s={method:"post",url:"".concat(this.config.url,"/user/register-with-password?_format=json&resendVerificationEmail=true"),headers:{"content-type":"application/json"},data:r,timeout:h},[2,o.default(s).catch(u)]}))}))},i.prototype._exchangePasswordToTokens=function(t,r){var s;return e.__awaiter(this,void 0,void 0,(function(){var i,n;return e.__generator(this,(function(e){switch(e.label){case 0:return(i=new FormData).append("grant_type","password"),i.append("username",t),i.append("password",r),i.append("client_id",this.config.clientId),this.config.clientPass&&i.append("client_secret",this.config.clientPass),(null===(s=this.config.scopes)||void 0===s?void 0:s.length)&&i.append("scope",this.config.scopes.join(" ")),n={method:"post",url:"".concat(this.config.url,"/oauth/token"),data:i},[4,o.default(n).catch(u)];case 1:return[2,e.sent().data]}}))}))},i.prototype._refreshAccessToken=function(){return e.__awaiter(this,void 0,void 0,(function(){var t=this;return e.__generator(this,(function(s){return this._refreshingTokenPromise||(this._refreshingTokenPromise=Promise.resolve().then((function(){return e.__awaiter(t,void 0,void 0,(function(){var t,s,i,n,a,d;return e.__generator(this,(function(l){switch(l.label){case 0:if(!(t=(this.attrs.tokens||{}).refresh_token))throw new Error("No user session refresh token was found");return(s=new FormData).append("grant_type","refresh_token"),s.append("refresh_token",t),s.append("client_id",this.config.clientId),this.config.clientPass&&s.append("client_secret",this.config.clientPass),i={method:"post",url:"".concat(this.config.url,"/oauth/token"),data:s,timeout:h},[4,o.default(i).catch(u)];case 1:if(n=l.sent().data,this.attrs.tokens=e.__assign(e.__assign({},this.attrs.tokens),n),a=r.jwtDecode(null===(d=this.attrs.tokens)||void 0===d?void 0:d.access_token),this.id=a.sub,this.attrs.email=a.email,!this.attrs.email)throw new Error("Token has no user email.");return this.attrs.verified=a.email_verified,this.attrs.iss=a.iss,this.attrs.indiciaUserId=a["http://indicia.org.uk/user:id"],a.scopes&&(this.attrs.roles=a.scopes),c(this.attrs,a),[4,this.save()];case 2:return l.sent(),delete this._refreshingTokenPromise,[2]}}))}))})).catch((function(e){throw delete t._refreshingTokenPromise,e}))),[2,this._refreshingTokenPromise]}))}))},i.loginSchema=s.object({email:s.z.string().email("Please fill in"),password:s.z.string().min(1,"Please fill in")}),i.loginSchemaBackend=s.object({id:s.z.number(),email:s.z.string().email()}),i.resetSchema=s.object({email:s.z.string().email("Please fill in")}),i.registerSchema=s.object({email:s.z.string().email("Please fill in"),password:s.z.string().min(1,"Please fill in")}),i.registerSchemaBackend=s.object({uid:s.z.array(s.object({value:s.z.number()}))}),i}(n.default);exports.default=l;
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var tslib = require('tslib');
6
+ var axios = require('axios');
7
+ var jwtDecode = require('jwt-decode');
8
+ var zod = require('zod');
9
+ var utils = require('@flumens/utils');
10
+ var Model = require('../Model.js');
11
+
12
+ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
13
+
14
+ var axios__default = /*#__PURE__*/_interopDefaultLegacy(axios);
15
+
16
+ /* eslint-disable camelcase */
17
+ function setUserFields(attrs, data) {
18
+ Object.keys(data).forEach(function (key) {
19
+ if (key.match(/^field_/)) {
20
+ var cammelCaseKey = key
21
+ .replace('field_', '')
22
+ .replace(/_([a-z])/g, function (g) { return g[1].toUpperCase(); });
23
+ if (!data[key]) {
24
+ return;
25
+ }
26
+ // use this for full drupal profile pull
27
+ if (Array.isArray(data[key]) && data[key].length) {
28
+ attrs[cammelCaseKey] = data[key][0].value; // eslint-disable-line
29
+ return;
30
+ }
31
+ attrs[cammelCaseKey] = data[key]; // eslint-disable-line
32
+ }
33
+ });
34
+ }
35
+ // axios wrapper to pass through server error messages
36
+ var parseServerError = function (e) {
37
+ var _a;
38
+ if (e.response && e.response.data && e.response.data.message) {
39
+ if (e.response.data.message.includes('is already taken')) {
40
+ throw new utils.HandledError('This email is already taken.');
41
+ }
42
+ if (e.response.data.message === 'The user credentials were incorrect.') {
43
+ throw new utils.HandledError('Incorrect password or email');
44
+ }
45
+ if (e.response.data.message === 'Unrecognized username or email address.') {
46
+ throw new utils.HandledError('Unrecognized email address.');
47
+ }
48
+ if (e.response.data.message === 'This account is already activated') {
49
+ throw new utils.HandledError('This account is already activated.');
50
+ }
51
+ // catches also one where email is embedded
52
+ if (e.response.data.message.includes('not been activated')) {
53
+ throw new utils.HandledError('The user has not been activated or is blocked.');
54
+ }
55
+ throw new Error(e.response.data.message);
56
+ }
57
+ if ((_a = e.message) === null || _a === void 0 ? void 0 : _a.includes('timeout')) {
58
+ throw new utils.HandledError('Timeout');
59
+ }
60
+ throw e;
61
+ };
62
+ var timeout = 60000; // default request timeout in ms
63
+ function hasTokenExpired(accessToken) {
64
+ var MAX_TIME_TO_ROUND_TRIP_REQUEST = 2 * 60 * 1000; // give extra 2min to upload large files etc
65
+ if (!accessToken)
66
+ return true;
67
+ var exp = jwtDecode.jwtDecode(accessToken).exp;
68
+ var expiryTime = exp * 1000; // UNIX timestamp
69
+ return Date.now() + MAX_TIME_TO_ROUND_TRIP_REQUEST > expiryTime;
70
+ }
71
+ var defaults = {
72
+ email: '',
73
+ tokens: undefined,
74
+ verified: false,
75
+ iss: undefined,
76
+ indiciaUserId: undefined,
77
+ };
78
+ var DrupalUserModel = /** @class */ (function (_super) {
79
+ tslib.__extends(DrupalUserModel, _super);
80
+ function DrupalUserModel(_a) {
81
+ var _this = this;
82
+ var config = _a.config, options = tslib.__rest(_a, ["config"]);
83
+ _this = _super.call(this, tslib.__assign(tslib.__assign({}, options), { attrs: tslib.__assign(tslib.__assign({}, defaults), options.attrs) })) || this;
84
+ _this.config = config;
85
+ return _this;
86
+ }
87
+ DrupalUserModel.prototype.logIn = function (email, password) {
88
+ return tslib.__awaiter(this, void 0, void 0, function () {
89
+ var tokens;
90
+ return tslib.__generator(this, function (_a) {
91
+ switch (_a.label) {
92
+ case 0: return [4 /*yield*/, this._exchangePasswordToTokens(email, password)];
93
+ case 1:
94
+ tokens = _a.sent();
95
+ this.attrs.tokens = tokens;
96
+ return [4 /*yield*/, this.refreshProfile()];
97
+ case 2:
98
+ _a.sent();
99
+ return [2 /*return*/, this.save()];
100
+ }
101
+ });
102
+ });
103
+ };
104
+ DrupalUserModel.prototype.register = function (email, password, otherFields) {
105
+ return tslib.__awaiter(this, void 0, void 0, function () {
106
+ var data, options, user, isValidResponse, tokens;
107
+ return tslib.__generator(this, function (_a) {
108
+ switch (_a.label) {
109
+ case 0:
110
+ data = JSON.stringify(tslib.__assign({ name: [{ value: email }], pass: [{ value: password }], mail: [{ value: email }] }, otherFields));
111
+ options = {
112
+ method: 'post',
113
+ url: "".concat(this.config.url, "/user/register-with-password?_format=json"),
114
+ headers: { 'content-type': 'application/json' },
115
+ data: data,
116
+ timeout: timeout,
117
+ };
118
+ return [4 /*yield*/, axios__default["default"](options).catch(parseServerError)];
119
+ case 1:
120
+ user = (_a.sent()).data;
121
+ isValidResponse = !DrupalUserModel.registerSchemaBackend.safeParse(user).error;
122
+ if (!isValidResponse) {
123
+ throw new Error('Invalid backend response.');
124
+ }
125
+ return [4 /*yield*/, this._exchangePasswordToTokens(email, password)];
126
+ case 2:
127
+ tokens = _a.sent();
128
+ this.attrs.tokens = tokens;
129
+ this.id = user.uid[0].value;
130
+ this.attrs.email = email;
131
+ setUserFields(this.attrs, user);
132
+ return [2 /*return*/, this.save()];
133
+ }
134
+ });
135
+ });
136
+ };
137
+ DrupalUserModel.prototype.reset = function (email) {
138
+ return tslib.__awaiter(this, void 0, void 0, function () {
139
+ var data, options, e_1;
140
+ return tslib.__generator(this, function (_a) {
141
+ switch (_a.label) {
142
+ case 0:
143
+ data = JSON.stringify({ mail: email });
144
+ options = {
145
+ method: 'post',
146
+ url: "".concat(this.config.url, "/user/password?_format=json"),
147
+ headers: { 'content-type': 'application/json' },
148
+ data: data,
149
+ };
150
+ _a.label = 1;
151
+ case 1:
152
+ _a.trys.push([1, 3, , 6]);
153
+ return [4 /*yield*/, axios__default["default"](options).catch(parseServerError)];
154
+ case 2:
155
+ _a.sent();
156
+ return [3 /*break*/, 6];
157
+ case 3:
158
+ e_1 = _a.sent();
159
+ if (!(e_1.message === 'The user has not been activated or is blocked.')) return [3 /*break*/, 5];
160
+ return [4 /*yield*/, this._sendVerificationEmail(email)];
161
+ case 4:
162
+ _a.sent();
163
+ return [2 /*return*/];
164
+ case 5:
165
+ parseServerError(e_1);
166
+ return [3 /*break*/, 6];
167
+ case 6: return [2 /*return*/];
168
+ }
169
+ });
170
+ });
171
+ };
172
+ DrupalUserModel.prototype.delete = function () {
173
+ return tslib.__awaiter(this, void 0, void 0, function () {
174
+ var token, options;
175
+ return tslib.__generator(this, function (_a) {
176
+ switch (_a.label) {
177
+ case 0: return [4 /*yield*/, this.getAccessToken(true)];
178
+ case 1:
179
+ token = _a.sent();
180
+ options = {
181
+ method: 'delete',
182
+ url: "".concat(this.config.url, "/user/").concat(this.id, "?_format=json"),
183
+ headers: { Authorization: "Bearer ".concat(token) },
184
+ };
185
+ return [4 /*yield*/, axios__default["default"](options).catch(parseServerError)];
186
+ case 2:
187
+ _a.sent();
188
+ this.logOut();
189
+ return [2 /*return*/];
190
+ }
191
+ });
192
+ });
193
+ };
194
+ /**
195
+ * Gets full user profile inc. fresh new tokens.
196
+ */
197
+ DrupalUserModel.prototype.refreshProfile = function () {
198
+ return tslib.__awaiter(this, void 0, void 0, function () {
199
+ var _this = this;
200
+ return tslib.__generator(this, function (_a) {
201
+ if (this._refreshingProfilePromise) {
202
+ return [2 /*return*/, this._refreshingProfilePromise];
203
+ }
204
+ this._refreshingProfilePromise = Promise.resolve()
205
+ .then(function () { return tslib.__awaiter(_this, void 0, void 0, function () {
206
+ var token, options, data;
207
+ return tslib.__generator(this, function (_a) {
208
+ switch (_a.label) {
209
+ case 0: return [4 /*yield*/, this.getAccessToken(true)];
210
+ case 1:
211
+ token = _a.sent();
212
+ if (!this.attrs.verified) return [3 /*break*/, 3];
213
+ options = {
214
+ url: "".concat(this.config.url, "/user/").concat(this.id, "?_format=json"),
215
+ headers: {
216
+ Authorization: "Bearer ".concat(token),
217
+ },
218
+ timeout: timeout,
219
+ };
220
+ return [4 /*yield*/, axios__default["default"](options).catch(parseServerError)];
221
+ case 2:
222
+ data = (_a.sent()).data;
223
+ this.attrs.email = data.mail[0].value;
224
+ setUserFields(this.attrs, data);
225
+ _a.label = 3;
226
+ case 3: return [4 /*yield*/, this.save()];
227
+ case 4:
228
+ _a.sent();
229
+ delete this._refreshingProfilePromise;
230
+ return [2 /*return*/];
231
+ }
232
+ });
233
+ }); })
234
+ .catch(function (e) {
235
+ delete _this._refreshingProfilePromise;
236
+ throw e;
237
+ });
238
+ return [2 /*return*/, this._refreshingProfilePromise];
239
+ });
240
+ });
241
+ };
242
+ /**
243
+ * @deprecated The method should not be used. Use isLoggedIn instead.
244
+ */
245
+ DrupalUserModel.prototype.hasLogIn = function () {
246
+ console.warn('hasLogIn is deprecated, please use isLoggedIn instead.');
247
+ return this.isLoggedIn();
248
+ };
249
+ DrupalUserModel.prototype.isLoggedIn = function () {
250
+ // eslint-disable-next-line no-unused-expressions
251
+ this.attrs.email; // force read the observable to make this function reactive
252
+ return !!this.id;
253
+ };
254
+ DrupalUserModel.prototype.logOut = function () {
255
+ return tslib.__awaiter(this, void 0, void 0, function () {
256
+ return tslib.__generator(this, function (_a) {
257
+ return [2 /*return*/, this.resetDefaults()];
258
+ });
259
+ });
260
+ };
261
+ DrupalUserModel.prototype.resetDefaults = function (defaultsToSet) {
262
+ return _super.prototype.resetDefaults.call(this, tslib.__assign(tslib.__assign({}, defaults), defaultsToSet));
263
+ };
264
+ DrupalUserModel.prototype.getAccessToken = function (forceRefresh) {
265
+ return tslib.__awaiter(this, void 0, void 0, function () {
266
+ var access_token, hasExpired, needRefresh, error_1, hasInvalidRefreshToken, userWasDeleted;
267
+ var _a;
268
+ return tslib.__generator(this, function (_b) {
269
+ switch (_b.label) {
270
+ case 0:
271
+ if (!forceRefresh && !this.isLoggedIn())
272
+ throw new Error('User is not logged in.');
273
+ access_token = (this.attrs.tokens || {}).access_token;
274
+ hasExpired = hasTokenExpired(access_token);
275
+ needRefresh = !access_token || hasExpired || forceRefresh;
276
+ if (!needRefresh) return [3 /*break*/, 6];
277
+ _b.label = 1;
278
+ case 1:
279
+ _b.trys.push([1, 3, , 6]);
280
+ return [4 /*yield*/, this._refreshAccessToken()];
281
+ case 2:
282
+ _b.sent();
283
+ return [3 /*break*/, 6];
284
+ case 3:
285
+ error_1 = _b.sent();
286
+ console.error(error_1);
287
+ hasInvalidRefreshToken = error_1.message === 'The refresh token is invalid.';
288
+ userWasDeleted = error_1.message === 'Token has no user email.';
289
+ if (!(hasInvalidRefreshToken || userWasDeleted)) return [3 /*break*/, 5];
290
+ return [4 /*yield*/, this.logOut()];
291
+ case 4:
292
+ _b.sent(); // force log out
293
+ throw new Error('User re-login is required.');
294
+ case 5: throw error_1;
295
+ case 6: return [2 /*return*/, (_a = this.attrs.tokens) === null || _a === void 0 ? void 0 : _a.access_token];
296
+ }
297
+ });
298
+ });
299
+ };
300
+ DrupalUserModel.prototype._sendVerificationEmail = function (email) {
301
+ return tslib.__awaiter(this, void 0, void 0, function () {
302
+ var data, options;
303
+ return tslib.__generator(this, function (_a) {
304
+ data = JSON.stringify({
305
+ mail: [{ value: email || this.attrs.email }],
306
+ });
307
+ options = {
308
+ method: 'post',
309
+ url: "".concat(this.config.url, "/user/register-with-password?_format=json&resendVerificationEmail=true"),
310
+ headers: { 'content-type': 'application/json' },
311
+ data: data,
312
+ timeout: timeout,
313
+ };
314
+ return [2 /*return*/, axios__default["default"](options).catch(parseServerError)];
315
+ });
316
+ });
317
+ };
318
+ DrupalUserModel.prototype._exchangePasswordToTokens = function (email, password) {
319
+ return tslib.__awaiter(this, void 0, void 0, function () {
320
+ var formdata, options, data;
321
+ var _a;
322
+ return tslib.__generator(this, function (_b) {
323
+ switch (_b.label) {
324
+ case 0:
325
+ formdata = new FormData();
326
+ formdata.append('grant_type', 'password');
327
+ formdata.append('username', email);
328
+ formdata.append('password', password);
329
+ formdata.append('client_id', this.config.clientId);
330
+ this.config.clientPass &&
331
+ formdata.append('client_secret', this.config.clientPass);
332
+ ((_a = this.config.scopes) === null || _a === void 0 ? void 0 : _a.length) &&
333
+ formdata.append('scope', this.config.scopes.join(' ')); // key name is singular
334
+ options = {
335
+ method: 'post',
336
+ url: "".concat(this.config.url, "/oauth/token"),
337
+ data: formdata,
338
+ };
339
+ return [4 /*yield*/, axios__default["default"](options).catch(parseServerError)];
340
+ case 1:
341
+ data = (_b.sent()).data;
342
+ return [2 /*return*/, data];
343
+ }
344
+ });
345
+ });
346
+ };
347
+ DrupalUserModel.prototype._refreshAccessToken = function () {
348
+ return tslib.__awaiter(this, void 0, void 0, function () {
349
+ var _this = this;
350
+ return tslib.__generator(this, function (_a) {
351
+ if (this._refreshingTokenPromise) {
352
+ return [2 /*return*/, this._refreshingTokenPromise];
353
+ }
354
+ this._refreshingTokenPromise = Promise.resolve()
355
+ .then(function () { return tslib.__awaiter(_this, void 0, void 0, function () {
356
+ var refresh_token, formdata, options, newTokens, decodedAccessToken;
357
+ var _a;
358
+ return tslib.__generator(this, function (_b) {
359
+ switch (_b.label) {
360
+ case 0:
361
+ refresh_token = (this.attrs.tokens || {}).refresh_token;
362
+ if (!refresh_token) {
363
+ throw new Error('No user session refresh token was found');
364
+ }
365
+ formdata = new FormData();
366
+ formdata.append('grant_type', 'refresh_token');
367
+ formdata.append('refresh_token', refresh_token);
368
+ formdata.append('client_id', this.config.clientId);
369
+ this.config.clientPass &&
370
+ formdata.append('client_secret', this.config.clientPass);
371
+ options = {
372
+ method: 'post',
373
+ url: "".concat(this.config.url, "/oauth/token"),
374
+ data: formdata,
375
+ timeout: timeout,
376
+ };
377
+ return [4 /*yield*/, axios__default["default"](options).catch(parseServerError)];
378
+ case 1:
379
+ newTokens = (_b.sent()).data;
380
+ this.attrs.tokens = tslib.__assign(tslib.__assign({}, this.attrs.tokens), newTokens);
381
+ decodedAccessToken = jwtDecode.jwtDecode((_a = this.attrs.tokens) === null || _a === void 0 ? void 0 : _a.access_token);
382
+ this.id = decodedAccessToken.sub;
383
+ this.attrs.email = decodedAccessToken.email;
384
+ if (!this.attrs.email) {
385
+ // can happen if user account was deleted and token refreshed
386
+ throw new Error('Token has no user email.');
387
+ }
388
+ this.attrs.verified = decodedAccessToken.email_verified;
389
+ this.attrs.iss = decodedAccessToken.iss;
390
+ this.attrs.indiciaUserId =
391
+ decodedAccessToken['http://indicia.org.uk/user:id'];
392
+ if (decodedAccessToken.scopes) {
393
+ this.attrs.roles = decodedAccessToken.scopes;
394
+ }
395
+ setUserFields(this.attrs, decodedAccessToken);
396
+ return [4 /*yield*/, this.save()];
397
+ case 2:
398
+ _b.sent();
399
+ delete this._refreshingTokenPromise;
400
+ return [2 /*return*/];
401
+ }
402
+ });
403
+ }); })
404
+ .catch(function (e) {
405
+ delete _this._refreshingTokenPromise;
406
+ throw e;
407
+ });
408
+ return [2 /*return*/, this._refreshingTokenPromise];
409
+ });
410
+ });
411
+ };
412
+ DrupalUserModel.loginSchema = zod.object({
413
+ email: zod.z.string().email('Please fill in'),
414
+ password: zod.z.string().min(1, 'Please fill in'),
415
+ });
416
+ DrupalUserModel.loginSchemaBackend = zod.object({
417
+ id: zod.z.number(),
418
+ email: zod.z.string().email(),
419
+ });
420
+ DrupalUserModel.resetSchema = zod.object({
421
+ email: zod.z.string().email('Please fill in'),
422
+ });
423
+ DrupalUserModel.registerSchema = zod.object({
424
+ email: zod.z.string().email('Please fill in'),
425
+ password: zod.z.string().min(1, 'Please fill in'),
426
+ });
427
+ DrupalUserModel.registerSchemaBackend = zod.object({
428
+ uid: zod.z.array(zod.object({ value: zod.z.number() })),
429
+ });
430
+ return DrupalUserModel;
431
+ }(Model["default"]));
432
+
433
+ exports["default"] = DrupalUserModel;