macbid-ts-api 0.1.5 → 1.0.0-beta.2

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/MacBid.d.ts CHANGED
@@ -3,7 +3,11 @@ export interface AuthInfo {
3
3
  email?: string;
4
4
  password?: string;
5
5
  token?: string;
6
+ token_expiration?: Date;
6
7
  user_id?: string;
8
+ refresh_token?: string;
9
+ refresh_token_expiration?: Date;
10
+ validation_code?: string;
7
11
  }
8
12
  export interface WatchlistFull {
9
13
  auction_lot_id: number;
@@ -60,7 +64,8 @@ export declare class MacBid {
60
64
  API_ROOT: string;
61
65
  private macbid_session_headers;
62
66
  private auth_info;
63
- constructor(auth_info: AuthInfo);
67
+ private tokenFilePath?;
68
+ constructor(auth_info: AuthInfo, tokenFilePath?: string);
64
69
  authenticate: () => Promise<void>;
65
70
  get: (path: string) => Promise<MacBidApiResponse>;
66
71
  post: (path: string, options?: RequestInit) => Promise<MacBidApiResponse>;
@@ -70,12 +75,40 @@ export declare class MacBid {
70
75
  private check_auth;
71
76
  /**
72
77
  * Do the login request
78
+ * @param email - User email
79
+ * @param password - User password
80
+ * @param validation_code - Optional validation code. If not provided, will check auth_info.validation_code
73
81
  */
74
- login: (email: string, password: string) => Promise<boolean>;
82
+ login: (email: string, password: string, validation_code?: string) => Promise<boolean>;
83
+ get_refresh_token_expiration: () => Date;
84
+ /**
85
+ * Check if the access token is expired or about to expire (within 5 minutes)
86
+ */
87
+ private isTokenExpired;
88
+ /**
89
+ * Check if the refresh token is expired
90
+ */
91
+ private isRefreshTokenExpired;
92
+ /**
93
+ * Refresh the access token using the refresh token
94
+ */
95
+ refreshToken: () => Promise<boolean>;
96
+ /**
97
+ * Ensure the access token is valid, refreshing if necessary
98
+ */
99
+ private ensureValidToken;
75
100
  /**
76
101
  * Returns the logged in user's favorites, and all of their (visible) attributes.
77
102
  */
78
103
  get_watchlist: () => Promise<WatchlistFull[]>;
104
+ /**
105
+ * Save tokens to file for persistence across restarts
106
+ */
107
+ private saveTokens;
108
+ /**
109
+ * Load tokens from file
110
+ */
111
+ static loadTokens: (tokenFilePath: string) => Promise<Partial<AuthInfo> | null>;
79
112
  }
80
113
  export default MacBid;
81
114
  //# sourceMappingURL=MacBid.d.ts.map
package/MacBid.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"MacBid.d.ts","sourceRoot":"","sources":["MacBid.ts"],"names":[],"mappings":"AAAA,OAAc,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE7C,MAAM,WAAW,QAAQ;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,aAAa;IAC5B,cAAc,EAAE,MAAM,CAAC;IACvB,sBAAsB,EAAE,IAAI,CAAC;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,IAAI,CAAC;IAClB,qBAAqB,EAAE,MAAM,GAAG,IAAI,CAAC;IACrC,mBAAmB,EAAE,IAAI,CAAC;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,IAAI,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,IAAI,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,gBAAgB,EAAE,MAAM,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,mBAAmB,EAAE,IAAI,CAAC;IAC1B,cAAc,EAAE,IAAI,CAAC;IACrB,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,aAAa,CAAC;IAC9B,QAAQ,EAAE,IAAI,GAAG,MAAM,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,WAAW,CAAC;CAC3B;AAED,oBAAY,WAAW;IACrB,MAAM,WAAW;IACjB,QAAQ,aAAa;CACtB;AAED,oBAAY,aAAa;IACvB,OAAO,YAAY;IACnB,OAAO,aAAa;IACpB,OAAO,aAAa;CACrB;AAED,MAAM,WAAW,iBAAkB,SAAQ,QAAQ;IACjD,IAAI,EAAE,MAAM,OAAO,CAAC;QAClB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;KACxB,CAAC,CAAC;CACJ;AAED,qBAAa,MAAM;IACV,cAAc,SAAyB;IACvC,QAAQ,SAAiC;IAEhD,OAAO,CAAC,sBAAsB,CAE5B;IACF,OAAO,CAAC,SAAS,CAAW;gBAEhB,SAAS,EAAE,QAAQ;IAKxB,YAAY,sBAajB;IAEK,GAAG,SAAgB,MAAM,KAAG,QAAQ,iBAAiB,CAAC,CAGlC;IAEpB,IAAI,SACH,MAAM,YACF,WAAW,KACpB,QAAQ,iBAAiB,CAAC,CAOF;IAE3B;;OAEG;IACH,OAAO,CAAC,UAAU,CAKhB;IAEF;;OAEG;IACI,KAAK,UAAiB,MAAM,YAAY,MAAM,KAAG,QAAQ,OAAO,CAAC,CAuBtE;IAEF;;OAEG;IACI,aAAa,QAAa,QAAQ,aAAa,EAAE,CAAC,CAOvD;CACH;AAED,eAAe,MAAM,CAAC"}
1
+ {"version":3,"file":"MacBid.d.ts","sourceRoot":"","sources":["MacBid.ts"],"names":[],"mappings":"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"}
package/MacBid.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import fetch from "node-fetch";
2
+ import { promises as fs } from "node:fs";
2
3
  export var AuctionType;
3
4
  (function (AuctionType) {
4
5
  AuctionType["Pallet"] = "pallet";
@@ -17,36 +18,60 @@ export class MacBid {
17
18
  "Content-Type": "application/json",
18
19
  };
19
20
  auth_info;
20
- constructor(auth_info) {
21
+ tokenFilePath;
22
+ constructor(auth_info, tokenFilePath) {
21
23
  this.auth_info = auth_info;
24
+ this.tokenFilePath = tokenFilePath;
22
25
  this.authenticate();
23
26
  }
24
27
  authenticate = async () => {
25
28
  if (this.auth_info) {
29
+ // If we have a token, check if it's still valid
26
30
  if (this.auth_info.token) {
27
31
  this.macbid_session_headers["Authorization"] = this.auth_info
28
32
  .token;
33
+ // Token will be auto-refreshed by ensureValidToken if needed
34
+ return;
29
35
  }
30
- else {
31
- if (this.auth_info.email && this.auth_info.password) {
32
- await this.login(this.auth_info.email, this.auth_info.password);
36
+ // If we have a refresh token but no access token, try to refresh first
37
+ if (this.auth_info.refresh_token && !this.isRefreshTokenExpired()) {
38
+ try {
39
+ await this.refreshToken();
40
+ return;
33
41
  }
34
- else {
35
- throw new Error("Invalid auth_info");
42
+ catch (error) {
43
+ // If refresh fails, fall through to login
44
+ console.warn("Failed to refresh token, attempting login:", error);
36
45
  }
37
46
  }
47
+ // No valid tokens, need to login
48
+ if (this.auth_info.email && this.auth_info.password) {
49
+ await this.login(this.auth_info.email, this.auth_info.password);
50
+ }
51
+ else {
52
+ throw new Error("Invalid auth_info");
53
+ }
54
+ }
55
+ };
56
+ get = async (path) => {
57
+ await this.ensureValidToken();
58
+ return (await fetch(this.API_ROOT + path, {
59
+ headers: this.macbid_session_headers,
60
+ }));
61
+ };
62
+ post = async (path, options) => {
63
+ // Don't refresh token for auth endpoints
64
+ if (!path.includes("/auth/")) {
65
+ await this.ensureValidToken();
38
66
  }
67
+ return (await fetch(this.API_ROOT + path, {
68
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
69
+ // @ts-ignore
70
+ headers: this.macbid_session_headers,
71
+ method: "POST",
72
+ ...options,
73
+ }));
39
74
  };
40
- get = async (path) => (await fetch(this.API_ROOT + path, {
41
- headers: this.macbid_session_headers,
42
- }));
43
- post = async (path, options) => (await fetch(this.API_ROOT + path, {
44
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
45
- // @ts-ignore
46
- headers: this.macbid_session_headers,
47
- method: "POST",
48
- ...options,
49
- }));
50
75
  /**
51
76
  * Raise an exception if an endpoint requiring login is called without valid auth
52
77
  */
@@ -58,26 +83,149 @@ export class MacBid {
58
83
  };
59
84
  /**
60
85
  * Do the login request
86
+ * @param email - User email
87
+ * @param password - User password
88
+ * @param validation_code - Optional validation code. If not provided, will check auth_info.validation_code
61
89
  */
62
- login = async (email, password) => {
90
+ login = async (email, password, validation_code) => {
63
91
  const login_params = {
92
+ device_id: crypto.randomUUID(),
64
93
  email: email,
65
94
  password: password,
95
+ ref_code: null,
96
+ ref_r: null,
97
+ remember_me: true,
98
+ utm_campaign: null,
99
+ utm_medium: null,
100
+ utm_source: null,
66
101
  };
67
- const res = await this.post("/token", {
102
+ // https://api.macdiscount.com/auth/auth-validation
103
+ const res = await this.post("/auth/auth-validation", {
68
104
  body: JSON.stringify(login_params),
69
105
  });
70
106
  const resJson = await res.json();
71
- const token = resJson["token"];
72
- const user_id = resJson["user_id"];
73
- if (token) {
74
- this.auth_info.token = token;
75
- this.auth_info.user_id = user_id;
107
+ if (resJson["message"] === "Login validation code sent") {
108
+ // Get validation code from parameter, auth_info, or throw error
109
+ const code = validation_code ||
110
+ this.auth_info.validation_code ||
111
+ process.env.MACBID_VALIDATION_CODE;
112
+ if (!code) {
113
+ throw new Error("Validation code required. Provide it via:\n" +
114
+ " 1. login() method parameter: login(email, password, validation_code)\n" +
115
+ " 2. AuthInfo.validation_code when creating MacBid instance\n" +
116
+ " 3. MACBID_VALIDATION_CODE environment variable");
117
+ }
118
+ const validation_params = {
119
+ code: code,
120
+ device_id: login_params.device_id,
121
+ new_password: "",
122
+ remember_me: true,
123
+ };
124
+ const validation_res = await this.post("/auth/validate-access-code", {
125
+ body: JSON.stringify(validation_params),
126
+ });
127
+ const validation_resJson = await validation_res.json();
128
+ const access_token = validation_resJson["access_token"];
129
+ const refresh_token = validation_resJson["refresh_token"];
130
+ const user_id = validation_resJson["user_id"];
131
+ const expires = validation_resJson["expires"];
132
+ const expiration_refresh = validation_resJson["expiration_refresh"];
133
+ if (access_token) {
134
+ this.auth_info.token = access_token;
135
+ this.auth_info.user_id = user_id;
136
+ this.macbid_session_headers["Authorization"] = this.auth_info.token;
137
+ this.auth_info.token_expiration = new Date(expires * 1000);
138
+ this.auth_info.refresh_token = refresh_token;
139
+ this.auth_info.refresh_token_expiration = new Date(expiration_refresh * 1000);
140
+ await this.saveTokens();
141
+ return true;
142
+ }
143
+ }
144
+ console.error(JSON.stringify(resJson, null, 2));
145
+ throw new Error("Login failed");
146
+ };
147
+ get_refresh_token_expiration = () => {
148
+ if (this.auth_info.refresh_token_expiration) {
149
+ return this.auth_info.refresh_token_expiration;
150
+ }
151
+ else {
152
+ throw new Error("Refresh token expiration not set, make sure to login first.");
153
+ }
154
+ };
155
+ /**
156
+ * Check if the access token is expired or about to expire (within 5 minutes)
157
+ */
158
+ isTokenExpired = () => {
159
+ if (!this.auth_info.token_expiration) {
160
+ return true;
161
+ }
162
+ // Refresh if token expires within 5 minutes
163
+ const bufferTime = 5 * 60 * 1000; // 5 minutes in milliseconds
164
+ return Date.now() >= this.auth_info.token_expiration.getTime() - bufferTime;
165
+ };
166
+ /**
167
+ * Check if the refresh token is expired
168
+ */
169
+ isRefreshTokenExpired = () => {
170
+ if (!this.auth_info.refresh_token_expiration) {
171
+ return true;
172
+ }
173
+ return Date.now() >= this.auth_info.refresh_token_expiration.getTime();
174
+ };
175
+ /**
176
+ * Refresh the access token using the refresh token
177
+ */
178
+ refreshToken = async () => {
179
+ if (!this.auth_info.refresh_token) {
180
+ throw new Error("No refresh token available. Please login again.");
181
+ }
182
+ if (this.isRefreshTokenExpired()) {
183
+ throw new Error("Refresh token has expired. Please login again.");
184
+ }
185
+ const refresh_params = {
186
+ refresh_token: this.auth_info.refresh_token,
187
+ };
188
+ // Use fetch directly to avoid triggering ensureValidToken and use PUT method
189
+ const res = await fetch(this.API_ROOT + "/auth/refresh-token", {
190
+ method: "PUT",
191
+ body: JSON.stringify(refresh_params),
192
+ headers: {
193
+ "Content-Type": "application/json",
194
+ },
195
+ });
196
+ const resJson = (await res.json());
197
+ // Check for error response
198
+ if (resJson["error"]) {
199
+ throw new Error(`Failed to refresh token: ${resJson["error"]}`);
200
+ }
201
+ const access_token = resJson["access_token"];
202
+ const refresh_token = resJson["refresh_token"];
203
+ const expires = resJson["expires"];
204
+ const expiration_refresh = resJson["expiration_refresh"];
205
+ if (access_token) {
206
+ this.auth_info.token = access_token;
76
207
  this.macbid_session_headers["Authorization"] = this.auth_info.token;
208
+ this.auth_info.token_expiration = new Date(expires * 1000);
209
+ // Update refresh token if a new one is provided
210
+ if (refresh_token) {
211
+ this.auth_info.refresh_token = refresh_token;
212
+ }
213
+ if (expiration_refresh) {
214
+ this.auth_info.refresh_token_expiration = new Date(expiration_refresh * 1000);
215
+ }
216
+ await this.saveTokens();
77
217
  return true;
78
218
  }
79
219
  else {
80
- throw new Error("Login failed");
220
+ throw new Error("Failed to refresh token: no access token in response");
221
+ }
222
+ };
223
+ /**
224
+ * Ensure the access token is valid, refreshing if necessary
225
+ */
226
+ ensureValidToken = async () => {
227
+ if (this.isTokenExpired()) {
228
+ await this.refreshToken();
81
229
  }
82
230
  };
83
231
  /**
@@ -88,6 +236,47 @@ export class MacBid {
88
236
  const res = await this.get(`/auctions/customer/${this.auth_info["user_id"]}/active-auctions`);
89
237
  return (await res.json())["watchlist_full"];
90
238
  };
239
+ /**
240
+ * Save tokens to file for persistence across restarts
241
+ */
242
+ saveTokens = async () => {
243
+ if (!this.tokenFilePath) {
244
+ return;
245
+ }
246
+ try {
247
+ const tokenData = {
248
+ token: this.auth_info.token,
249
+ refresh_token: this.auth_info.refresh_token,
250
+ token_expiration: this.auth_info.token_expiration?.toISOString(),
251
+ refresh_token_expiration: this.auth_info.refresh_token_expiration?.toISOString(),
252
+ user_id: this.auth_info.user_id,
253
+ };
254
+ await fs.writeFile(this.tokenFilePath, JSON.stringify(tokenData, null, 2), "utf-8");
255
+ }
256
+ catch (error) {
257
+ console.warn("Failed to save tokens:", error);
258
+ }
259
+ };
260
+ /**
261
+ * Load tokens from file
262
+ */
263
+ static loadTokens = async (tokenFilePath) => {
264
+ try {
265
+ const data = await fs.readFile(tokenFilePath, "utf-8");
266
+ const tokenData = JSON.parse(data);
267
+ return {
268
+ token: tokenData.token,
269
+ refresh_token: tokenData.refresh_token,
270
+ token_expiration: tokenData.token_expiration ? new Date(tokenData.token_expiration) : undefined,
271
+ refresh_token_expiration: tokenData.refresh_token_expiration ? new Date(tokenData.refresh_token_expiration) : undefined,
272
+ user_id: tokenData.user_id,
273
+ };
274
+ }
275
+ catch (error) {
276
+ // File doesn't exist or is invalid, return null
277
+ return null;
278
+ }
279
+ };
91
280
  }
92
281
  export default MacBid;
93
282
  //# sourceMappingURL=MacBid.js.map
package/MacBid.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"MacBid.js","sourceRoot":"","sources":["MacBid.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"MacBid.js","sourceRoot":"","sources":["MacBid.ts"],"names":[],"mappings":"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"}
package/MacBid.ts CHANGED
@@ -1,10 +1,15 @@
1
1
  import fetch, { Response } from "node-fetch";
2
+ import { promises as fs } from "node:fs";
2
3
 
3
4
  export interface AuthInfo {
4
5
  email?: string;
5
6
  password?: string;
6
7
  token?: string;
8
+ token_expiration?: Date;
7
9
  user_id?: string;
10
+ refresh_token?: string;
11
+ refresh_token_expiration?: Date;
12
+ validation_code?: string;
8
13
  }
9
14
 
10
15
  export interface WatchlistFull {
@@ -69,43 +74,67 @@ export class MacBid {
69
74
  "Content-Type": "application/json",
70
75
  };
71
76
  private auth_info: AuthInfo;
77
+ private tokenFilePath?: string;
72
78
 
73
- constructor(auth_info: AuthInfo) {
79
+ constructor(auth_info: AuthInfo, tokenFilePath?: string) {
74
80
  this.auth_info = auth_info;
81
+ this.tokenFilePath = tokenFilePath;
75
82
  this.authenticate();
76
83
  }
77
84
 
78
85
  public authenticate = async () => {
79
86
  if (this.auth_info) {
87
+ // If we have a token, check if it's still valid
80
88
  if (this.auth_info.token) {
81
89
  this.macbid_session_headers["Authorization"] = this.auth_info
82
90
  .token as string;
83
- } else {
84
- if (this.auth_info.email && this.auth_info.password) {
85
- await this.login(this.auth_info.email, this.auth_info.password);
86
- } else {
87
- throw new Error("Invalid auth_info");
91
+ // Token will be auto-refreshed by ensureValidToken if needed
92
+ return;
93
+ }
94
+
95
+ // If we have a refresh token but no access token, try to refresh first
96
+ if (this.auth_info.refresh_token && !this.isRefreshTokenExpired()) {
97
+ try {
98
+ await this.refreshToken();
99
+ return;
100
+ } catch (error) {
101
+ // If refresh fails, fall through to login
102
+ console.warn("Failed to refresh token, attempting login:", error);
88
103
  }
89
104
  }
105
+
106
+ // No valid tokens, need to login
107
+ if (this.auth_info.email && this.auth_info.password) {
108
+ await this.login(this.auth_info.email, this.auth_info.password);
109
+ } else {
110
+ throw new Error("Invalid auth_info");
111
+ }
90
112
  }
91
113
  };
92
114
 
93
- public get = async (path: string): Promise<MacBidApiResponse> =>
94
- (await fetch(this.API_ROOT + path, {
115
+ public get = async (path: string): Promise<MacBidApiResponse> => {
116
+ await this.ensureValidToken();
117
+ return (await fetch(this.API_ROOT + path, {
95
118
  headers: this.macbid_session_headers,
96
119
  })) as MacBidApiResponse;
120
+ };
97
121
 
98
122
  public post = async (
99
123
  path: string,
100
124
  options?: RequestInit
101
- ): Promise<MacBidApiResponse> =>
102
- (await fetch(this.API_ROOT + path, {
125
+ ): Promise<MacBidApiResponse> => {
126
+ // Don't refresh token for auth endpoints
127
+ if (!path.includes("/auth/")) {
128
+ await this.ensureValidToken();
129
+ }
130
+ return (await fetch(this.API_ROOT + path, {
103
131
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
104
132
  // @ts-ignore
105
133
  headers: this.macbid_session_headers,
106
134
  method: "POST",
107
135
  ...options,
108
136
  })) as MacBidApiResponse;
137
+ };
109
138
 
110
139
  /**
111
140
  * Raise an exception if an endpoint requiring login is called without valid auth
@@ -119,31 +148,184 @@ export class MacBid {
119
148
 
120
149
  /**
121
150
  * Do the login request
151
+ * @param email - User email
152
+ * @param password - User password
153
+ * @param validation_code - Optional validation code. If not provided, will check auth_info.validation_code
122
154
  */
123
- public login = async (email: string, password: string): Promise<boolean> => {
155
+ public login = async (
156
+ email: string,
157
+ password: string,
158
+ validation_code?: string
159
+ ): Promise<boolean> => {
124
160
  const login_params = {
161
+ device_id: crypto.randomUUID(), // TODO: keep this the same to persist sms validation?
125
162
  email: email,
126
163
  password: password,
164
+ ref_code: null,
165
+ ref_r: null,
166
+ remember_me: true,
167
+ utm_campaign: null,
168
+ utm_medium: null,
169
+ utm_source: null,
127
170
  };
128
-
129
- const res = await this.post("/token", {
171
+ // https://api.macdiscount.com/auth/auth-validation
172
+ const res = await this.post("/auth/auth-validation", {
130
173
  body: JSON.stringify(login_params),
131
174
  });
132
175
 
133
176
  const resJson = await res.json();
134
- const token = resJson["token"];
135
- const user_id = resJson["user_id"];
136
177
 
137
- if (token) {
138
- this.auth_info.token = token as string;
139
- this.auth_info.user_id = user_id as string;
178
+ if (resJson["message"] === "Login validation code sent") {
179
+ // Get validation code from parameter, auth_info, or throw error
180
+ const code =
181
+ validation_code ||
182
+ this.auth_info.validation_code ||
183
+ process.env.MACBID_VALIDATION_CODE;
184
+
185
+ if (!code) {
186
+ throw new Error(
187
+ "Validation code required. Provide it via:\n" +
188
+ " 1. login() method parameter: login(email, password, validation_code)\n" +
189
+ " 2. AuthInfo.validation_code when creating MacBid instance\n" +
190
+ " 3. MACBID_VALIDATION_CODE environment variable"
191
+ );
192
+ }
193
+
194
+ const validation_params = {
195
+ code: code,
196
+ device_id: login_params.device_id,
197
+ new_password: "",
198
+ remember_me: true,
199
+ };
200
+
201
+ const validation_res = await this.post("/auth/validate-access-code", {
202
+ body: JSON.stringify(validation_params),
203
+ });
204
+
205
+ const validation_resJson = await validation_res.json();
206
+
207
+ const access_token = validation_resJson["access_token"] as string;
208
+ const refresh_token = validation_resJson["refresh_token"] as string;
209
+ const user_id = validation_resJson["user_id"] as string;
210
+ const expires = validation_resJson["expires"] as number;
211
+ const expiration_refresh = validation_resJson["expiration_refresh"] as number;
212
+
213
+ if (access_token) {
214
+ this.auth_info.token = access_token as string;
215
+ this.auth_info.user_id = user_id as string;
216
+ this.macbid_session_headers["Authorization"] = this.auth_info.token;
217
+ this.auth_info.token_expiration = new Date(expires * 1000);
218
+ this.auth_info.refresh_token = refresh_token;
219
+ this.auth_info.refresh_token_expiration = new Date(expiration_refresh * 1000);
220
+ await this.saveTokens();
221
+ return true;
222
+ }
223
+ }
224
+ console.error(JSON.stringify(resJson, null, 2));
225
+ throw new Error("Login failed");
226
+ };
227
+
228
+ public get_refresh_token_expiration = (): Date => {
229
+ if (this.auth_info.refresh_token_expiration) {
230
+ return this.auth_info.refresh_token_expiration;
231
+ } else {
232
+ throw new Error("Refresh token expiration not set, make sure to login first.");
233
+ }
234
+ }
235
+
236
+ /**
237
+ * Check if the access token is expired or about to expire (within 5 minutes)
238
+ */
239
+ private isTokenExpired = (): boolean => {
240
+ if (!this.auth_info.token_expiration) {
241
+ return true;
242
+ }
243
+ // Refresh if token expires within 5 minutes
244
+ const bufferTime = 5 * 60 * 1000; // 5 minutes in milliseconds
245
+ return Date.now() >= this.auth_info.token_expiration.getTime() - bufferTime;
246
+ }
247
+
248
+ /**
249
+ * Check if the refresh token is expired
250
+ */
251
+ private isRefreshTokenExpired = (): boolean => {
252
+ if (!this.auth_info.refresh_token_expiration) {
253
+ return true;
254
+ }
255
+ return Date.now() >= this.auth_info.refresh_token_expiration.getTime();
256
+ }
257
+
258
+ /**
259
+ * Refresh the access token using the refresh token
260
+ */
261
+ public refreshToken = async (): Promise<boolean> => {
262
+ if (!this.auth_info.refresh_token) {
263
+ throw new Error("No refresh token available. Please login again.");
264
+ }
265
+
266
+ if (this.isRefreshTokenExpired()) {
267
+ throw new Error("Refresh token has expired. Please login again.");
268
+ }
269
+
270
+ const refresh_params = {
271
+ refresh_token: this.auth_info.refresh_token,
272
+ };
273
+
274
+ // Use fetch directly to avoid triggering ensureValidToken and use PUT method
275
+ const res = await fetch(this.API_ROOT + "/auth/refresh-token", {
276
+ method: "PUT",
277
+ body: JSON.stringify(refresh_params),
278
+ headers: {
279
+ "Content-Type": "application/json",
280
+ },
281
+ });
282
+
283
+ const resJson = (await res.json()) as {
284
+ error?: string;
285
+ access_token?: string;
286
+ refresh_token?: string;
287
+ expires?: number;
288
+ expiration_refresh?: number;
289
+ };
290
+
291
+ // Check for error response
292
+ if (resJson["error"]) {
293
+ throw new Error(`Failed to refresh token: ${resJson["error"]}`);
294
+ }
295
+
296
+ const access_token = resJson["access_token"] as string;
297
+ const refresh_token = resJson["refresh_token"] as string | undefined;
298
+ const expires = resJson["expires"] as number;
299
+ const expiration_refresh = resJson["expiration_refresh"] as number | undefined;
300
+
301
+ if (access_token) {
302
+ this.auth_info.token = access_token;
140
303
  this.macbid_session_headers["Authorization"] = this.auth_info.token;
304
+ this.auth_info.token_expiration = new Date(expires * 1000);
141
305
 
306
+ // Update refresh token if a new one is provided
307
+ if (refresh_token) {
308
+ this.auth_info.refresh_token = refresh_token;
309
+ }
310
+ if (expiration_refresh) {
311
+ this.auth_info.refresh_token_expiration = new Date(expiration_refresh * 1000);
312
+ }
313
+
314
+ await this.saveTokens();
142
315
  return true;
143
316
  } else {
144
- throw new Error("Login failed");
317
+ throw new Error("Failed to refresh token: no access token in response");
145
318
  }
146
- };
319
+ }
320
+
321
+ /**
322
+ * Ensure the access token is valid, refreshing if necessary
323
+ */
324
+ private ensureValidToken = async (): Promise<void> => {
325
+ if (this.isTokenExpired()) {
326
+ await this.refreshToken();
327
+ }
328
+ }
147
329
 
148
330
  /**
149
331
  * Returns the logged in user's favorites, and all of their (visible) attributes.
@@ -156,6 +338,56 @@ export class MacBid {
156
338
 
157
339
  return (await res.json())["watchlist_full"] as WatchlistFull[];
158
340
  };
341
+
342
+ /**
343
+ * Save tokens to file for persistence across restarts
344
+ */
345
+ private saveTokens = async (): Promise<void> => {
346
+ if (!this.tokenFilePath) {
347
+ return;
348
+ }
349
+
350
+ try {
351
+ const tokenData = {
352
+ token: this.auth_info.token,
353
+ refresh_token: this.auth_info.refresh_token,
354
+ token_expiration: this.auth_info.token_expiration?.toISOString(),
355
+ refresh_token_expiration: this.auth_info.refresh_token_expiration?.toISOString(),
356
+ user_id: this.auth_info.user_id,
357
+ };
358
+
359
+ await fs.writeFile(this.tokenFilePath, JSON.stringify(tokenData, null, 2), "utf-8");
360
+ } catch (error) {
361
+ console.warn("Failed to save tokens:", error);
362
+ }
363
+ };
364
+
365
+ /**
366
+ * Load tokens from file
367
+ */
368
+ public static loadTokens = async (tokenFilePath: string): Promise<Partial<AuthInfo> | null> => {
369
+ try {
370
+ const data = await fs.readFile(tokenFilePath, "utf-8");
371
+ const tokenData = JSON.parse(data) as {
372
+ token?: string;
373
+ refresh_token?: string;
374
+ token_expiration?: string;
375
+ refresh_token_expiration?: string;
376
+ user_id?: string;
377
+ };
378
+
379
+ return {
380
+ token: tokenData.token,
381
+ refresh_token: tokenData.refresh_token,
382
+ token_expiration: tokenData.token_expiration ? new Date(tokenData.token_expiration) : undefined,
383
+ refresh_token_expiration: tokenData.refresh_token_expiration ? new Date(tokenData.refresh_token_expiration) : undefined,
384
+ user_id: tokenData.user_id,
385
+ };
386
+ } catch (error) {
387
+ // File doesn't exist or is invalid, return null
388
+ return null;
389
+ }
390
+ };
159
391
  }
160
392
 
161
393
  export default MacBid;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "macbid-ts-api",
3
- "version": "0.1.5",
3
+ "version": "1.0.0-beta.2",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/pkmnct/macbid-ts-api.git"