@kedaruma/revlm-client 1.0.50 → 1.0.53

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/dist/index.d.mts CHANGED
@@ -204,12 +204,19 @@ declare class Revlm {
204
204
  private autoRefreshOn401;
205
205
  private cookieCheckPromise?;
206
206
  private logLevel;
207
+ private refreshPromise;
207
208
  constructor(baseUrl: string, opts?: RevlmOptions);
209
+ private canLog;
210
+ logError(...args: any[]): void;
211
+ logWarn(...args: any[]): void;
212
+ logInfo(...args: any[]): void;
213
+ logDebug(...args: any[]): void;
208
214
  setToken(token: string): void;
209
215
  getToken(): string | undefined;
210
216
  clearToken(): void;
211
217
  logout(): void;
212
218
  refreshToken(): Promise<RevlmResponse>;
219
+ private refreshTokenSingleFlight;
213
220
  verifyToken(): Promise<RevlmResponse>;
214
221
  private makeHeaders;
215
222
  private parseResponse;
package/dist/index.d.ts CHANGED
@@ -204,12 +204,19 @@ declare class Revlm {
204
204
  private autoRefreshOn401;
205
205
  private cookieCheckPromise?;
206
206
  private logLevel;
207
+ private refreshPromise;
207
208
  constructor(baseUrl: string, opts?: RevlmOptions);
209
+ private canLog;
210
+ logError(...args: any[]): void;
211
+ logWarn(...args: any[]): void;
212
+ logInfo(...args: any[]): void;
213
+ logDebug(...args: any[]): void;
208
214
  setToken(token: string): void;
209
215
  getToken(): string | undefined;
210
216
  clearToken(): void;
211
217
  logout(): void;
212
218
  refreshToken(): Promise<RevlmResponse>;
219
+ private refreshTokenSingleFlight;
213
220
  verifyToken(): Promise<RevlmResponse>;
214
221
  private makeHeaders;
215
222
  private parseResponse;
package/dist/index.js CHANGED
@@ -35,7 +35,7 @@ var require_package = __commonJS({
35
35
  "package.json"(exports2, module2) {
36
36
  module2.exports = {
37
37
  name: "@kedaruma/revlm-client",
38
- version: "1.0.50",
38
+ version: "1.0.53",
39
39
  private: false,
40
40
  description: "TypeScript client SDK for talking to the Revlm server replacement for MongoDB Realm.",
41
41
  keywords: [
@@ -216,6 +216,12 @@ var RevlmDBDatabase = class {
216
216
  };
217
217
 
218
218
  // src/Revlm.ts
219
+ var LOG_LEVEL_RANK = {
220
+ error: 0,
221
+ warn: 1,
222
+ info: 2,
223
+ debug: 3
224
+ };
219
225
  function normalizeLogLevel(value) {
220
226
  if (!value) return "info";
221
227
  const lowered = value.toLowerCase();
@@ -251,6 +257,7 @@ var Revlm = class {
251
257
  autoRefreshOn401;
252
258
  cookieCheckPromise;
253
259
  logLevel;
260
+ refreshPromise;
254
261
  constructor(baseUrl, opts = {}) {
255
262
  if (!baseUrl) throw new Error("baseUrl is required");
256
263
  this.baseUrl = baseUrl.replace(/\/$/, "");
@@ -265,20 +272,33 @@ var Revlm = class {
265
272
  if (!this.fetchImpl) {
266
273
  throw new Error("No fetch implementation available. Provide fetchImpl in options or run in Node 18+ with global fetch.");
267
274
  }
268
- if (this.logLevel === "debug" || this.logLevel === "info") {
269
- console.log("\u{1F680} Revlm Client Init", {
270
- version: getRevlmClientVersion(),
271
- baseUrl: this.baseUrl,
272
- autoSetToken: this.autoSetToken,
273
- autoRefreshOn401: this.autoRefreshOn401,
274
- provisionalEnabled: this.provisionalEnabled,
275
- provisionalAuthDomain: this.provisionalAuthDomain || void 0,
276
- provisionalAuthSecretMaster: maskSecret(this.provisionalAuthSecretMaster),
277
- defaultHeaders: Object.keys(this.defaultHeaders || {}),
278
- fetchImplProvided: !!opts.fetchImpl,
279
- logLevel: this.logLevel
280
- });
281
- }
275
+ this.logInfo("\u{1F680} Revlm Client Init", {
276
+ version: getRevlmClientVersion(),
277
+ baseUrl: this.baseUrl,
278
+ autoSetToken: this.autoSetToken,
279
+ autoRefreshOn401: this.autoRefreshOn401,
280
+ provisionalEnabled: this.provisionalEnabled,
281
+ provisionalAuthDomain: this.provisionalAuthDomain || void 0,
282
+ provisionalAuthSecretMaster: maskSecret(this.provisionalAuthSecretMaster),
283
+ defaultHeaders: Object.keys(this.defaultHeaders || {}),
284
+ fetchImplProvided: !!opts.fetchImpl,
285
+ logLevel: this.logLevel
286
+ });
287
+ }
288
+ canLog(level) {
289
+ return LOG_LEVEL_RANK[this.logLevel] >= LOG_LEVEL_RANK[level];
290
+ }
291
+ logError(...args) {
292
+ if (this.canLog("error")) console.error(...args);
293
+ }
294
+ logWarn(...args) {
295
+ if (this.canLog("warn")) console.warn(...args);
296
+ }
297
+ logInfo(...args) {
298
+ if (this.canLog("info")) console.log(...args);
299
+ }
300
+ logDebug(...args) {
301
+ if (this.canLog("debug")) console.log(...args);
282
302
  }
283
303
  setToken(token) {
284
304
  this._token = token;
@@ -303,6 +323,18 @@ var Revlm = class {
303
323
  }
304
324
  return res;
305
325
  }
326
+ async refreshTokenSingleFlight() {
327
+ if (!this.refreshPromise) {
328
+ this.refreshPromise = (async () => {
329
+ try {
330
+ return await this.refreshToken();
331
+ } finally {
332
+ this.refreshPromise = void 0;
333
+ }
334
+ })();
335
+ }
336
+ return this.refreshPromise;
337
+ }
306
338
  // Verify current token with server. If invalid/expired, clear local token.
307
339
  async verifyToken() {
308
340
  if (!this._token) return { ok: false, error: "No token set" };
@@ -378,7 +410,7 @@ var Revlm = class {
378
410
  if (!payload || typeof payload.exp !== "number") return;
379
411
  const now = Math.floor(Date.now() / 1e3);
380
412
  const ttlSec = payload.exp - now;
381
- console.log("### token ttl", {
413
+ this.logDebug("### token ttl", {
382
414
  event,
383
415
  path,
384
416
  ttlSec,
@@ -416,9 +448,12 @@ var Revlm = class {
416
448
  }
417
449
  if (allowAuthRetry && !retrying && res.status === 401 && !this.shouldSkipAuthRetry(path)) {
418
450
  const beforePayload = this.decodeJwtPayload(this._token || "");
419
- const refreshRes = await this.refreshToken();
451
+ const refreshRes = await this.refreshTokenSingleFlight();
420
452
  if (!refreshRes.ok) {
421
- console.warn("### refresh failed:", {
453
+ if (refreshRes.reason === "not_expired") {
454
+ return this.requestWithRetry(path, method, body, { allowAuthRetry: false, retrying: true });
455
+ }
456
+ this.logDebug("### refresh failed:", {
422
457
  reason: refreshRes.reason,
423
458
  status: refreshRes.status,
424
459
  error: refreshRes.error
@@ -434,7 +469,7 @@ var Revlm = class {
434
469
  const now = Math.floor(Date.now() / 1e3);
435
470
  const oldExp = beforePayload?.exp;
436
471
  const newExp = afterPayload?.exp;
437
- console.log("### refresh success", {
472
+ this.logDebug("### refresh success", {
438
473
  path,
439
474
  oldExp,
440
475
  newExp,
@@ -498,13 +533,13 @@ var Revlm = class {
498
533
  if (this.cookieCheckPromise) return this.cookieCheckPromise;
499
534
  this.cookieCheckPromise = (async () => {
500
535
  const first = await this.requestWithRetry("/cookie-check", "POST", void 0, { allowAuthRetry: false, retrying: false });
501
- console.log("### cookie check", { step: "first", ok: first.ok, reason: first.reason, status: first.status });
536
+ this.logDebug("### cookie check", { step: "first", ok: first.ok, reason: first.reason, status: first.status });
502
537
  if (first.ok) return;
503
538
  if (first.reason !== "cookie_missing") {
504
539
  throw new Error(`Cookie check failed: ${first.reason || first.error || "unknown_error"}`);
505
540
  }
506
541
  const second = await this.requestWithRetry("/cookie-check", "POST", void 0, { allowAuthRetry: false, retrying: false });
507
- console.log("### cookie check", { step: "second", ok: second.ok, reason: second.reason, status: second.status });
542
+ this.logDebug("### cookie check", { step: "second", ok: second.ok, reason: second.reason, status: second.status });
508
543
  if (!second.ok) {
509
544
  throw new Error("Cookie support missing. Provide a cookie-aware fetch implementation for Node/RN.");
510
545
  }
@@ -588,7 +623,7 @@ var App = class {
588
623
  throw new Error("Unsupported credentials type");
589
624
  }
590
625
  const res = await this.revlm.login(cred.email, cred.password);
591
- console.log("### App:login res:", res);
626
+ this.revlm.logInfo("### App:login res:", res);
592
627
  if (!res || !res.ok || !res.token) {
593
628
  const errMsg = res && !res.ok ? res.error : "login failed";
594
629
  const err = new Error(errMsg);
package/dist/index.mjs CHANGED
@@ -7,7 +7,7 @@ var require_package = __commonJS({
7
7
  "package.json"(exports, module) {
8
8
  module.exports = {
9
9
  name: "@kedaruma/revlm-client",
10
- version: "1.0.50",
10
+ version: "1.0.53",
11
11
  private: false,
12
12
  description: "TypeScript client SDK for talking to the Revlm server replacement for MongoDB Realm.",
13
13
  keywords: [
@@ -172,6 +172,12 @@ var RevlmDBDatabase = class {
172
172
  };
173
173
 
174
174
  // src/Revlm.ts
175
+ var LOG_LEVEL_RANK = {
176
+ error: 0,
177
+ warn: 1,
178
+ info: 2,
179
+ debug: 3
180
+ };
175
181
  function normalizeLogLevel(value) {
176
182
  if (!value) return "info";
177
183
  const lowered = value.toLowerCase();
@@ -207,6 +213,7 @@ var Revlm = class {
207
213
  autoRefreshOn401;
208
214
  cookieCheckPromise;
209
215
  logLevel;
216
+ refreshPromise;
210
217
  constructor(baseUrl, opts = {}) {
211
218
  if (!baseUrl) throw new Error("baseUrl is required");
212
219
  this.baseUrl = baseUrl.replace(/\/$/, "");
@@ -221,20 +228,33 @@ var Revlm = class {
221
228
  if (!this.fetchImpl) {
222
229
  throw new Error("No fetch implementation available. Provide fetchImpl in options or run in Node 18+ with global fetch.");
223
230
  }
224
- if (this.logLevel === "debug" || this.logLevel === "info") {
225
- console.log("\u{1F680} Revlm Client Init", {
226
- version: getRevlmClientVersion(),
227
- baseUrl: this.baseUrl,
228
- autoSetToken: this.autoSetToken,
229
- autoRefreshOn401: this.autoRefreshOn401,
230
- provisionalEnabled: this.provisionalEnabled,
231
- provisionalAuthDomain: this.provisionalAuthDomain || void 0,
232
- provisionalAuthSecretMaster: maskSecret(this.provisionalAuthSecretMaster),
233
- defaultHeaders: Object.keys(this.defaultHeaders || {}),
234
- fetchImplProvided: !!opts.fetchImpl,
235
- logLevel: this.logLevel
236
- });
237
- }
231
+ this.logInfo("\u{1F680} Revlm Client Init", {
232
+ version: getRevlmClientVersion(),
233
+ baseUrl: this.baseUrl,
234
+ autoSetToken: this.autoSetToken,
235
+ autoRefreshOn401: this.autoRefreshOn401,
236
+ provisionalEnabled: this.provisionalEnabled,
237
+ provisionalAuthDomain: this.provisionalAuthDomain || void 0,
238
+ provisionalAuthSecretMaster: maskSecret(this.provisionalAuthSecretMaster),
239
+ defaultHeaders: Object.keys(this.defaultHeaders || {}),
240
+ fetchImplProvided: !!opts.fetchImpl,
241
+ logLevel: this.logLevel
242
+ });
243
+ }
244
+ canLog(level) {
245
+ return LOG_LEVEL_RANK[this.logLevel] >= LOG_LEVEL_RANK[level];
246
+ }
247
+ logError(...args) {
248
+ if (this.canLog("error")) console.error(...args);
249
+ }
250
+ logWarn(...args) {
251
+ if (this.canLog("warn")) console.warn(...args);
252
+ }
253
+ logInfo(...args) {
254
+ if (this.canLog("info")) console.log(...args);
255
+ }
256
+ logDebug(...args) {
257
+ if (this.canLog("debug")) console.log(...args);
238
258
  }
239
259
  setToken(token) {
240
260
  this._token = token;
@@ -259,6 +279,18 @@ var Revlm = class {
259
279
  }
260
280
  return res;
261
281
  }
282
+ async refreshTokenSingleFlight() {
283
+ if (!this.refreshPromise) {
284
+ this.refreshPromise = (async () => {
285
+ try {
286
+ return await this.refreshToken();
287
+ } finally {
288
+ this.refreshPromise = void 0;
289
+ }
290
+ })();
291
+ }
292
+ return this.refreshPromise;
293
+ }
262
294
  // Verify current token with server. If invalid/expired, clear local token.
263
295
  async verifyToken() {
264
296
  if (!this._token) return { ok: false, error: "No token set" };
@@ -334,7 +366,7 @@ var Revlm = class {
334
366
  if (!payload || typeof payload.exp !== "number") return;
335
367
  const now = Math.floor(Date.now() / 1e3);
336
368
  const ttlSec = payload.exp - now;
337
- console.log("### token ttl", {
369
+ this.logDebug("### token ttl", {
338
370
  event,
339
371
  path,
340
372
  ttlSec,
@@ -372,9 +404,12 @@ var Revlm = class {
372
404
  }
373
405
  if (allowAuthRetry && !retrying && res.status === 401 && !this.shouldSkipAuthRetry(path)) {
374
406
  const beforePayload = this.decodeJwtPayload(this._token || "");
375
- const refreshRes = await this.refreshToken();
407
+ const refreshRes = await this.refreshTokenSingleFlight();
376
408
  if (!refreshRes.ok) {
377
- console.warn("### refresh failed:", {
409
+ if (refreshRes.reason === "not_expired") {
410
+ return this.requestWithRetry(path, method, body, { allowAuthRetry: false, retrying: true });
411
+ }
412
+ this.logDebug("### refresh failed:", {
378
413
  reason: refreshRes.reason,
379
414
  status: refreshRes.status,
380
415
  error: refreshRes.error
@@ -390,7 +425,7 @@ var Revlm = class {
390
425
  const now = Math.floor(Date.now() / 1e3);
391
426
  const oldExp = beforePayload?.exp;
392
427
  const newExp = afterPayload?.exp;
393
- console.log("### refresh success", {
428
+ this.logDebug("### refresh success", {
394
429
  path,
395
430
  oldExp,
396
431
  newExp,
@@ -454,13 +489,13 @@ var Revlm = class {
454
489
  if (this.cookieCheckPromise) return this.cookieCheckPromise;
455
490
  this.cookieCheckPromise = (async () => {
456
491
  const first = await this.requestWithRetry("/cookie-check", "POST", void 0, { allowAuthRetry: false, retrying: false });
457
- console.log("### cookie check", { step: "first", ok: first.ok, reason: first.reason, status: first.status });
492
+ this.logDebug("### cookie check", { step: "first", ok: first.ok, reason: first.reason, status: first.status });
458
493
  if (first.ok) return;
459
494
  if (first.reason !== "cookie_missing") {
460
495
  throw new Error(`Cookie check failed: ${first.reason || first.error || "unknown_error"}`);
461
496
  }
462
497
  const second = await this.requestWithRetry("/cookie-check", "POST", void 0, { allowAuthRetry: false, retrying: false });
463
- console.log("### cookie check", { step: "second", ok: second.ok, reason: second.reason, status: second.status });
498
+ this.logDebug("### cookie check", { step: "second", ok: second.ok, reason: second.reason, status: second.status });
464
499
  if (!second.ok) {
465
500
  throw new Error("Cookie support missing. Provide a cookie-aware fetch implementation for Node/RN.");
466
501
  }
@@ -544,7 +579,7 @@ var App = class {
544
579
  throw new Error("Unsupported credentials type");
545
580
  }
546
581
  const res = await this.revlm.login(cred.email, cred.password);
547
- console.log("### App:login res:", res);
582
+ this.revlm.logInfo("### App:login res:", res);
548
583
  if (!res || !res.ok || !res.token) {
549
584
  const errMsg = res && !res.ok ? res.error : "login failed";
550
585
  const err = new Error(errMsg);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kedaruma/revlm-client",
3
- "version": "1.0.50",
3
+ "version": "1.0.53",
4
4
  "private": false,
5
5
  "description": "TypeScript client SDK for talking to the Revlm server replacement for MongoDB Realm.",
6
6
  "keywords": [