1 | "use strict";
|
2 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
3 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
4 | return new (P || (P = Promise))(function (resolve, reject) {
|
5 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
6 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
7 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
8 | step((generator = generator.apply(thisArg, _arguments || [])).next());
|
9 | });
|
10 | };
|
11 | var __importStar = (this && this.__importStar) || function (mod) {
|
12 | if (mod && mod.__esModule) return mod;
|
13 | var result = {};
|
14 | if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
|
15 | result["default"] = mod;
|
16 | return result;
|
17 | };
|
18 | Object.defineProperty(exports, "__esModule", { value: true });
|
19 | const openid_client_1 = require("openid-client");
|
20 | const xero = __importStar(require("./gen/api"));
|
21 | const request = require("request");
|
22 | class XeroClient {
|
23 | constructor(config) {
|
24 | this.config = config;
|
25 | this.tokenSet = new openid_client_1.TokenSet;
|
26 | this._tenants = [];
|
27 | this.accountingApi = new xero.AccountingApi();
|
28 | this.assetApi = new xero.AssetApi();
|
29 | this.projectApi = new xero.ProjectApi();
|
30 | }
|
31 | get tenants() {
|
32 | return this._tenants;
|
33 | }
|
34 | initialize() {
|
35 | return __awaiter(this, void 0, void 0, function* () {
|
36 | if (this.config) {
|
37 | const issuer = yield openid_client_1.Issuer.discover('https://identity.xero.com');
|
38 | this.openIdClient = new issuer.Client({
|
39 | client_id: this.config.clientId,
|
40 | client_secret: this.config.clientSecret,
|
41 | redirect_uris: this.config.redirectUris,
|
42 | });
|
43 | this.openIdClient[openid_client_1.custom.clock_tolerance] = 5;
|
44 | }
|
45 | return this;
|
46 | });
|
47 | }
|
48 | buildConsentUrl() {
|
49 | return __awaiter(this, void 0, void 0, function* () {
|
50 | yield this.initialize();
|
51 | let url;
|
52 | if (this.config) {
|
53 | url = this.openIdClient.authorizationUrl({
|
54 | redirect_uri: this.config.redirectUris[0],
|
55 | scope: this.config.scopes.join(' ') || 'openid email profile'
|
56 | });
|
57 | }
|
58 | return url;
|
59 | });
|
60 | }
|
61 | apiCallback(callbackUrl) {
|
62 | return __awaiter(this, void 0, void 0, function* () {
|
63 | const params = this.openIdClient.callbackParams(callbackUrl);
|
64 | const check = Object.assign({}, params);
|
65 | this.tokenSet = yield this.openIdClient.callback(this.config.redirectUris[0], params, check);
|
66 | this.setAccessToken();
|
67 | return this.tokenSet;
|
68 | });
|
69 | }
|
70 | disconnect(connectionId) {
|
71 | return __awaiter(this, void 0, void 0, function* () {
|
72 | yield this.queryApi('DELETE', `https://api.xero.com/connections/${connectionId}`);
|
73 | this.setAccessToken();
|
74 | return this.tokenSet;
|
75 | });
|
76 | }
|
77 | readIdTokenClaims() {
|
78 | return this.tokenSet.claims();
|
79 | }
|
80 | readTokenSet() {
|
81 | return this.tokenSet;
|
82 | }
|
83 | setTokenSet(tokenSet) {
|
84 | this.tokenSet = tokenSet;
|
85 | this.setAccessToken();
|
86 | }
|
87 | refreshToken() {
|
88 | return __awaiter(this, void 0, void 0, function* () {
|
89 | if (!this.tokenSet) {
|
90 | throw new Error('tokenSet is not defined');
|
91 | }
|
92 | const refreshedTokenSet = yield this.openIdClient.refresh(this.tokenSet.refresh_token);
|
93 | this.tokenSet = refreshedTokenSet;
|
94 | this.setAccessToken();
|
95 | return this.tokenSet;
|
96 | });
|
97 | }
|
98 | encodeBody(params) {
|
99 | var formBody = [];
|
100 | for (var property in params) {
|
101 | var encodedKey = encodeURIComponent(property);
|
102 | var encodedValue = encodeURIComponent(params[property]);
|
103 | formBody.push(encodedKey + "=" + encodedValue);
|
104 | }
|
105 | return formBody.join("&");
|
106 | }
|
107 | refreshWithRefreshToken(clientId, clientSecret, refreshToken) {
|
108 | return __awaiter(this, void 0, void 0, function* () {
|
109 | const result = yield this.postWithRefreshToken(clientId, clientSecret, refreshToken);
|
110 | const tokenSet = JSON.parse(result.body);
|
111 | this.tokenSet = tokenSet;
|
112 | this.setAccessToken();
|
113 | return this.tokenSet;
|
114 | });
|
115 | }
|
116 | postWithRefreshToken(clientId, clientSecret, refreshToken) {
|
117 | return __awaiter(this, void 0, void 0, function* () {
|
118 | const body = {
|
119 | grant_type: 'refresh_token',
|
120 | refresh_token: refreshToken
|
121 | };
|
122 | return new Promise((resolve, reject) => {
|
123 | request({
|
124 | method: 'POST',
|
125 | uri: 'https://identity.xero.com/connect/token',
|
126 | headers: {
|
127 | authorization: "Basic " + Buffer.from(clientId + ":" + clientSecret).toString('base64'),
|
128 | 'Content-Type': 'application/x-www-form-urlencoded'
|
129 | },
|
130 | body: this.encodeBody(body)
|
131 | }, (error, response, body) => {
|
132 | if (error) {
|
133 | reject(error);
|
134 | }
|
135 | else {
|
136 | if (response.statusCode && response.statusCode >= 200 && response.statusCode <= 299) {
|
137 | resolve({ response: response, body: body });
|
138 | }
|
139 | else {
|
140 | reject({ response: response, body: body });
|
141 | }
|
142 | }
|
143 | });
|
144 | });
|
145 | });
|
146 | }
|
147 | updateTenants() {
|
148 | return __awaiter(this, void 0, void 0, function* () {
|
149 | const result = yield this.queryApi('GET', 'https://api.xero.com/connections');
|
150 | let tenants = result.body.map(connection => connection);
|
151 | const getOrgsForAll = tenants.map((tenant) => __awaiter(this, void 0, void 0, function* () {
|
152 | const result = yield this.accountingApi.getOrganisations(tenant.tenantId);
|
153 | return result.body.organisations[0];
|
154 | }));
|
155 | const orgData = yield Promise.all(getOrgsForAll);
|
156 | tenants.map((tenant) => {
|
157 | tenant.orgData = orgData.filter((el) => el.organisationID == tenant.tenantId)[0];
|
158 | });
|
159 |
|
160 | tenants.sort((a, b) => new Date(b.updatedDateUtc) - new Date(a.updatedDateUtc));
|
161 | this._tenants = tenants;
|
162 | return tenants;
|
163 | });
|
164 | }
|
165 | queryApi(method, uri) {
|
166 | return __awaiter(this, void 0, void 0, function* () {
|
167 | return new Promise((resolve, reject) => {
|
168 | request({
|
169 | method,
|
170 | uri,
|
171 | auth: {
|
172 | bearer: this.tokenSet.access_token
|
173 | },
|
174 | json: true
|
175 | }, (error, response, body) => {
|
176 | if (error) {
|
177 | reject(error);
|
178 | }
|
179 | else {
|
180 | if (response.statusCode && response.statusCode >= 200 && response.statusCode <= 299) {
|
181 | resolve({ response: response, body: body });
|
182 | }
|
183 | else {
|
184 | reject({ response: response, body: body });
|
185 | }
|
186 | }
|
187 | });
|
188 | });
|
189 | });
|
190 | }
|
191 | setAccessToken() {
|
192 | const accessToken = this.tokenSet.access_token;
|
193 | if (typeof accessToken === 'undefined') {
|
194 | throw new Error('Access token is undefined!');
|
195 | }
|
196 | this.accountingApi.accessToken = accessToken;
|
197 | this.assetApi.accessToken = accessToken;
|
198 | this.projectApi.accessToken = accessToken;
|
199 |
|
200 | }
|
201 | }
|
202 | exports.XeroClient = XeroClient;
|
203 |
|
\ | No newline at end of file |