@kedaruma/revlm-client 1.0.46 → 1.0.49

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,10 +1,15 @@
1
+ var __getOwnPropNames = Object.getOwnPropertyNames;
1
2
  var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
2
3
  get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
3
4
  }) : x)(function(x) {
4
5
  if (typeof require !== "undefined") return require.apply(this, arguments);
5
6
  throw Error('Dynamic require of "' + x + '" is not supported');
6
7
  });
8
+ var __commonJS = (cb, mod) => function __require2() {
9
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
10
+ };
7
11
 
8
12
  export {
9
- __require
13
+ __require,
14
+ __commonJS
10
15
  };
package/dist/index.d.mts CHANGED
@@ -201,6 +201,7 @@ declare class Revlm {
201
201
  private autoSetToken;
202
202
  private autoRefreshOn401;
203
203
  private cookieCheckPromise?;
204
+ private logLevel;
204
205
  constructor(baseUrl: string, opts?: RevlmOptions);
205
206
  setToken(token: string): void;
206
207
  getToken(): string | undefined;
@@ -213,6 +214,8 @@ declare class Revlm {
213
214
  private request;
214
215
  private shouldSkipAuthRetry;
215
216
  private shouldSkipCookieCheck;
217
+ private decodeJwtPayload;
218
+ private logTokenTtl;
216
219
  private signIfNeeded;
217
220
  private requestWithRetry;
218
221
  login(authId: string, password: string): Promise<LoginResponse>;
package/dist/index.d.ts CHANGED
@@ -201,6 +201,7 @@ declare class Revlm {
201
201
  private autoSetToken;
202
202
  private autoRefreshOn401;
203
203
  private cookieCheckPromise?;
204
+ private logLevel;
204
205
  constructor(baseUrl: string, opts?: RevlmOptions);
205
206
  setToken(token: string): void;
206
207
  getToken(): string | undefined;
@@ -213,6 +214,8 @@ declare class Revlm {
213
214
  private request;
214
215
  private shouldSkipAuthRetry;
215
216
  private shouldSkipCookieCheck;
217
+ private decodeJwtPayload;
218
+ private logTokenTtl;
216
219
  private signIfNeeded;
217
220
  private requestWithRetry;
218
221
  login(authId: string, password: string): Promise<LoginResponse>;
package/dist/index.js CHANGED
@@ -5,6 +5,9 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
6
  var __getProtoOf = Object.getPrototypeOf;
7
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __commonJS = (cb, mod) => function __require() {
9
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
10
+ };
8
11
  var __export = (target, all) => {
9
12
  for (var name in all)
10
13
  __defProp(target, name, { get: all[name], enumerable: true });
@@ -27,6 +30,73 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
27
30
  ));
28
31
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
32
 
33
+ // package.json
34
+ var require_package = __commonJS({
35
+ "package.json"(exports2, module2) {
36
+ module2.exports = {
37
+ name: "@kedaruma/revlm-client",
38
+ version: "1.0.49",
39
+ private: false,
40
+ description: "TypeScript client SDK for talking to the Revlm server replacement for MongoDB Realm.",
41
+ keywords: [
42
+ "realm",
43
+ "realm-web",
44
+ "mongodb-realm",
45
+ "mongodb",
46
+ "realm-alternative",
47
+ "app-services",
48
+ "auth"
49
+ ],
50
+ main: "dist/index.js",
51
+ module: "dist/index.mjs",
52
+ types: "dist/index.d.ts",
53
+ exports: {
54
+ ".": {
55
+ import: {
56
+ types: "./dist/index.d.mts",
57
+ default: "./dist/index.mjs"
58
+ },
59
+ require: {
60
+ types: "./dist/index.d.ts",
61
+ default: "./dist/index.js"
62
+ }
63
+ },
64
+ "./rn-setup": {
65
+ import: {
66
+ types: "./dist/rn-setup.d.mts",
67
+ default: "./dist/rn-setup.mjs"
68
+ },
69
+ require: {
70
+ types: "./dist/rn-setup.d.ts",
71
+ default: "./dist/rn-setup.js"
72
+ }
73
+ }
74
+ },
75
+ sideEffects: false,
76
+ files: [
77
+ "dist/"
78
+ ],
79
+ license: "ISC",
80
+ publishConfig: {
81
+ access: "public"
82
+ },
83
+ scripts: {
84
+ build: "tsup src/index.ts src/rn-setup.ts --format cjs,esm --dts --tsconfig tsconfig.build.json",
85
+ clean: "rm -rf dist node_modules kedaruma-revlm-client-*.tgz",
86
+ test: "pnpm exec jest --config ../../jest.config.cjs packages/revlm-client/src/__tests__/ --runInBand --watchman=false --verbose"
87
+ },
88
+ dependencies: {
89
+ "@kedaruma/revlm-shared": "workspace:*",
90
+ bson: "^6.10.4",
91
+ dotenv: "^17.2.3"
92
+ },
93
+ devDependencies: {
94
+ tsup: "^8.5.1"
95
+ }
96
+ };
97
+ }
98
+ });
99
+
30
100
  // src/index.ts
31
101
  var index_exports = {};
32
102
  __export(index_exports, {
@@ -146,6 +216,35 @@ var RevlmDBDatabase = class {
146
216
  };
147
217
 
148
218
  // src/Revlm.ts
219
+ function normalizeLogLevel(value) {
220
+ if (!value) return "error";
221
+ const lowered = value.toLowerCase();
222
+ if (lowered === "true" || lowered === "1") return "debug";
223
+ if (lowered === "false" || lowered === "0") return "error";
224
+ if (lowered === "error" || lowered === "warn" || lowered === "info" || lowered === "debug") {
225
+ return lowered;
226
+ }
227
+ return "error";
228
+ }
229
+ function getClientLogLevel() {
230
+ const envValue = typeof process !== "undefined" && process.env ? process.env.LOG_LEVEL : void 0;
231
+ const globalValue = globalThis?.LOG_LEVEL;
232
+ const value = typeof envValue === "string" ? envValue : typeof globalValue === "string" ? globalValue : void 0;
233
+ return normalizeLogLevel(value);
234
+ }
235
+ function maskSecret(value) {
236
+ if (!value) return void 0;
237
+ return `<...:${value.length}>`;
238
+ }
239
+ function getRevlmClientVersion() {
240
+ try {
241
+ const pkg = require_package();
242
+ if (pkg && typeof pkg.version === "string") return pkg.version;
243
+ } catch {
244
+ }
245
+ const globalVersion = globalThis?.REVLM_CLIENT_VERSION;
246
+ return typeof globalVersion === "string" ? globalVersion : "unknown";
247
+ }
149
248
  var Revlm = class {
150
249
  baseUrl;
151
250
  fetchImpl;
@@ -157,6 +256,7 @@ var Revlm = class {
157
256
  autoSetToken;
158
257
  autoRefreshOn401;
159
258
  cookieCheckPromise;
259
+ logLevel;
160
260
  constructor(baseUrl, opts = {}) {
161
261
  if (!baseUrl) throw new Error("baseUrl is required");
162
262
  this.baseUrl = baseUrl.replace(/\/$/, "");
@@ -167,9 +267,24 @@ var Revlm = class {
167
267
  this.provisionalAuthDomain = opts.provisionalAuthDomain || "";
168
268
  this.autoSetToken = opts.autoSetToken ?? true;
169
269
  this.autoRefreshOn401 = opts.autoRefreshOn401 || false;
270
+ this.logLevel = getClientLogLevel();
170
271
  if (!this.fetchImpl) {
171
272
  throw new Error("No fetch implementation available. Provide fetchImpl in options or run in Node 18+ with global fetch.");
172
273
  }
274
+ if (this.logLevel === "debug") {
275
+ console.log("\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
+ }
173
288
  }
174
289
  setToken(token) {
175
290
  this._token = token;
@@ -240,6 +355,43 @@ var Revlm = class {
240
355
  const pathname = path.startsWith("http") ? new URL(path).pathname : path;
241
356
  return pathname.includes("/cookie-check");
242
357
  }
358
+ decodeJwtPayload(token) {
359
+ if (!token) return null;
360
+ const parts = token.split(".");
361
+ const payloadPart = parts[1];
362
+ if (!payloadPart) return null;
363
+ const raw = payloadPart.replace(/-/g, "+").replace(/_/g, "/");
364
+ const pad = raw.length % 4 ? "=".repeat(4 - raw.length % 4) : "";
365
+ const base64 = raw + pad;
366
+ let jsonText = null;
367
+ if (typeof atob === "function") {
368
+ jsonText = atob(base64);
369
+ } else if (typeof Buffer !== "undefined") {
370
+ jsonText = Buffer.from(base64, "base64").toString("utf8");
371
+ }
372
+ if (!jsonText) return null;
373
+ try {
374
+ const payload = JSON.parse(jsonText);
375
+ return { exp: payload?.exp, iat: payload?.iat };
376
+ } catch {
377
+ return null;
378
+ }
379
+ }
380
+ logTokenTtl(event, path, tokenOverride) {
381
+ const token = tokenOverride || this._token;
382
+ if (!token) return;
383
+ const payload = this.decodeJwtPayload(token);
384
+ if (!payload || typeof payload.exp !== "number") return;
385
+ const now = Math.floor(Date.now() / 1e3);
386
+ const ttlSec = payload.exp - now;
387
+ console.log("### token ttl", {
388
+ event,
389
+ path,
390
+ ttlSec,
391
+ exp: payload.exp,
392
+ iat: payload.iat
393
+ });
394
+ }
243
395
  async signIfNeeded(_url, _method, headers, _body) {
244
396
  return { signedUrl: _url, signedHeaders: headers };
245
397
  }
@@ -269,6 +421,7 @@ var Revlm = class {
269
421
  out.error = parsed?.reason || parsed?.message || "Unknown error";
270
422
  }
271
423
  if (allowAuthRetry && !retrying && res.status === 401 && !this.shouldSkipAuthRetry(path)) {
424
+ const beforePayload = this.decodeJwtPayload(this._token || "");
272
425
  const refreshRes = await this.refreshToken();
273
426
  if (!refreshRes.ok) {
274
427
  console.warn("### refresh failed:", {
@@ -283,9 +436,23 @@ var Revlm = class {
283
436
  }
284
437
  }
285
438
  if (refreshRes && refreshRes.ok && refreshRes.token) {
439
+ const afterPayload = this.decodeJwtPayload(refreshRes.token);
440
+ const now = Math.floor(Date.now() / 1e3);
441
+ const oldExp = beforePayload?.exp;
442
+ const newExp = afterPayload?.exp;
443
+ console.log("### refresh success", {
444
+ path,
445
+ oldExp,
446
+ newExp,
447
+ oldTtlSec: typeof oldExp === "number" ? oldExp - now : void 0,
448
+ newTtlSec: typeof newExp === "number" ? newExp - now : void 0
449
+ });
286
450
  return this.requestWithRetry(path, method, body, { allowAuthRetry: false, retrying: true });
287
451
  }
288
452
  }
453
+ if (out.ok && !this.shouldSkipCookieCheck(path)) {
454
+ this.logTokenTtl("request_ok", path);
455
+ }
289
456
  return out;
290
457
  } catch (err) {
291
458
  if (err && err.revlmReason === "no_refresh_secret") {
@@ -337,11 +504,13 @@ var Revlm = class {
337
504
  if (this.cookieCheckPromise) return this.cookieCheckPromise;
338
505
  this.cookieCheckPromise = (async () => {
339
506
  const first = await this.requestWithRetry("/cookie-check", "POST", void 0, { allowAuthRetry: false, retrying: false });
507
+ console.log("### cookie check", { step: "first", ok: first.ok, reason: first.reason, status: first.status });
340
508
  if (first.ok) return;
341
509
  if (first.reason !== "cookie_missing") {
342
510
  throw new Error(`Cookie check failed: ${first.reason || first.error || "unknown_error"}`);
343
511
  }
344
512
  const second = await this.requestWithRetry("/cookie-check", "POST", void 0, { allowAuthRetry: false, retrying: false });
513
+ console.log("### cookie check", { step: "second", ok: second.ok, reason: second.reason, status: second.status });
345
514
  if (!second.ok) {
346
515
  throw new Error("Cookie support missing. Provide a cookie-aware fetch implementation for Node/RN.");
347
516
  }
package/dist/index.mjs CHANGED
@@ -1,4 +1,73 @@
1
- import "./chunk-Y6FXYEAI.mjs";
1
+ import {
2
+ __commonJS
3
+ } from "./chunk-EBO3CZXG.mjs";
4
+
5
+ // package.json
6
+ var require_package = __commonJS({
7
+ "package.json"(exports, module) {
8
+ module.exports = {
9
+ name: "@kedaruma/revlm-client",
10
+ version: "1.0.49",
11
+ private: false,
12
+ description: "TypeScript client SDK for talking to the Revlm server replacement for MongoDB Realm.",
13
+ keywords: [
14
+ "realm",
15
+ "realm-web",
16
+ "mongodb-realm",
17
+ "mongodb",
18
+ "realm-alternative",
19
+ "app-services",
20
+ "auth"
21
+ ],
22
+ main: "dist/index.js",
23
+ module: "dist/index.mjs",
24
+ types: "dist/index.d.ts",
25
+ exports: {
26
+ ".": {
27
+ import: {
28
+ types: "./dist/index.d.mts",
29
+ default: "./dist/index.mjs"
30
+ },
31
+ require: {
32
+ types: "./dist/index.d.ts",
33
+ default: "./dist/index.js"
34
+ }
35
+ },
36
+ "./rn-setup": {
37
+ import: {
38
+ types: "./dist/rn-setup.d.mts",
39
+ default: "./dist/rn-setup.mjs"
40
+ },
41
+ require: {
42
+ types: "./dist/rn-setup.d.ts",
43
+ default: "./dist/rn-setup.js"
44
+ }
45
+ }
46
+ },
47
+ sideEffects: false,
48
+ files: [
49
+ "dist/"
50
+ ],
51
+ license: "ISC",
52
+ publishConfig: {
53
+ access: "public"
54
+ },
55
+ scripts: {
56
+ build: "tsup src/index.ts src/rn-setup.ts --format cjs,esm --dts --tsconfig tsconfig.build.json",
57
+ clean: "rm -rf dist node_modules kedaruma-revlm-client-*.tgz",
58
+ test: "pnpm exec jest --config ../../jest.config.cjs packages/revlm-client/src/__tests__/ --runInBand --watchman=false --verbose"
59
+ },
60
+ dependencies: {
61
+ "@kedaruma/revlm-shared": "workspace:*",
62
+ bson: "^6.10.4",
63
+ dotenv: "^17.2.3"
64
+ },
65
+ devDependencies: {
66
+ tsup: "^8.5.1"
67
+ }
68
+ };
69
+ }
70
+ });
2
71
 
3
72
  // src/Revlm.ts
4
73
  import { EJSON } from "bson";
@@ -103,6 +172,35 @@ var RevlmDBDatabase = class {
103
172
  };
104
173
 
105
174
  // src/Revlm.ts
175
+ function normalizeLogLevel(value) {
176
+ if (!value) return "error";
177
+ const lowered = value.toLowerCase();
178
+ if (lowered === "true" || lowered === "1") return "debug";
179
+ if (lowered === "false" || lowered === "0") return "error";
180
+ if (lowered === "error" || lowered === "warn" || lowered === "info" || lowered === "debug") {
181
+ return lowered;
182
+ }
183
+ return "error";
184
+ }
185
+ function getClientLogLevel() {
186
+ const envValue = typeof process !== "undefined" && process.env ? process.env.LOG_LEVEL : void 0;
187
+ const globalValue = globalThis?.LOG_LEVEL;
188
+ const value = typeof envValue === "string" ? envValue : typeof globalValue === "string" ? globalValue : void 0;
189
+ return normalizeLogLevel(value);
190
+ }
191
+ function maskSecret(value) {
192
+ if (!value) return void 0;
193
+ return `<...:${value.length}>`;
194
+ }
195
+ function getRevlmClientVersion() {
196
+ try {
197
+ const pkg = require_package();
198
+ if (pkg && typeof pkg.version === "string") return pkg.version;
199
+ } catch {
200
+ }
201
+ const globalVersion = globalThis?.REVLM_CLIENT_VERSION;
202
+ return typeof globalVersion === "string" ? globalVersion : "unknown";
203
+ }
106
204
  var Revlm = class {
107
205
  baseUrl;
108
206
  fetchImpl;
@@ -114,6 +212,7 @@ var Revlm = class {
114
212
  autoSetToken;
115
213
  autoRefreshOn401;
116
214
  cookieCheckPromise;
215
+ logLevel;
117
216
  constructor(baseUrl, opts = {}) {
118
217
  if (!baseUrl) throw new Error("baseUrl is required");
119
218
  this.baseUrl = baseUrl.replace(/\/$/, "");
@@ -124,9 +223,24 @@ var Revlm = class {
124
223
  this.provisionalAuthDomain = opts.provisionalAuthDomain || "";
125
224
  this.autoSetToken = opts.autoSetToken ?? true;
126
225
  this.autoRefreshOn401 = opts.autoRefreshOn401 || false;
226
+ this.logLevel = getClientLogLevel();
127
227
  if (!this.fetchImpl) {
128
228
  throw new Error("No fetch implementation available. Provide fetchImpl in options or run in Node 18+ with global fetch.");
129
229
  }
230
+ if (this.logLevel === "debug") {
231
+ console.log("\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
+ }
130
244
  }
131
245
  setToken(token) {
132
246
  this._token = token;
@@ -197,6 +311,43 @@ var Revlm = class {
197
311
  const pathname = path.startsWith("http") ? new URL(path).pathname : path;
198
312
  return pathname.includes("/cookie-check");
199
313
  }
314
+ decodeJwtPayload(token) {
315
+ if (!token) return null;
316
+ const parts = token.split(".");
317
+ const payloadPart = parts[1];
318
+ if (!payloadPart) return null;
319
+ const raw = payloadPart.replace(/-/g, "+").replace(/_/g, "/");
320
+ const pad = raw.length % 4 ? "=".repeat(4 - raw.length % 4) : "";
321
+ const base64 = raw + pad;
322
+ let jsonText = null;
323
+ if (typeof atob === "function") {
324
+ jsonText = atob(base64);
325
+ } else if (typeof Buffer !== "undefined") {
326
+ jsonText = Buffer.from(base64, "base64").toString("utf8");
327
+ }
328
+ if (!jsonText) return null;
329
+ try {
330
+ const payload = JSON.parse(jsonText);
331
+ return { exp: payload?.exp, iat: payload?.iat };
332
+ } catch {
333
+ return null;
334
+ }
335
+ }
336
+ logTokenTtl(event, path, tokenOverride) {
337
+ const token = tokenOverride || this._token;
338
+ if (!token) return;
339
+ const payload = this.decodeJwtPayload(token);
340
+ if (!payload || typeof payload.exp !== "number") return;
341
+ const now = Math.floor(Date.now() / 1e3);
342
+ const ttlSec = payload.exp - now;
343
+ console.log("### token ttl", {
344
+ event,
345
+ path,
346
+ ttlSec,
347
+ exp: payload.exp,
348
+ iat: payload.iat
349
+ });
350
+ }
200
351
  async signIfNeeded(_url, _method, headers, _body) {
201
352
  return { signedUrl: _url, signedHeaders: headers };
202
353
  }
@@ -226,6 +377,7 @@ var Revlm = class {
226
377
  out.error = parsed?.reason || parsed?.message || "Unknown error";
227
378
  }
228
379
  if (allowAuthRetry && !retrying && res.status === 401 && !this.shouldSkipAuthRetry(path)) {
380
+ const beforePayload = this.decodeJwtPayload(this._token || "");
229
381
  const refreshRes = await this.refreshToken();
230
382
  if (!refreshRes.ok) {
231
383
  console.warn("### refresh failed:", {
@@ -240,9 +392,23 @@ var Revlm = class {
240
392
  }
241
393
  }
242
394
  if (refreshRes && refreshRes.ok && refreshRes.token) {
395
+ const afterPayload = this.decodeJwtPayload(refreshRes.token);
396
+ const now = Math.floor(Date.now() / 1e3);
397
+ const oldExp = beforePayload?.exp;
398
+ const newExp = afterPayload?.exp;
399
+ console.log("### refresh success", {
400
+ path,
401
+ oldExp,
402
+ newExp,
403
+ oldTtlSec: typeof oldExp === "number" ? oldExp - now : void 0,
404
+ newTtlSec: typeof newExp === "number" ? newExp - now : void 0
405
+ });
243
406
  return this.requestWithRetry(path, method, body, { allowAuthRetry: false, retrying: true });
244
407
  }
245
408
  }
409
+ if (out.ok && !this.shouldSkipCookieCheck(path)) {
410
+ this.logTokenTtl("request_ok", path);
411
+ }
246
412
  return out;
247
413
  } catch (err) {
248
414
  if (err && err.revlmReason === "no_refresh_secret") {
@@ -294,11 +460,13 @@ var Revlm = class {
294
460
  if (this.cookieCheckPromise) return this.cookieCheckPromise;
295
461
  this.cookieCheckPromise = (async () => {
296
462
  const first = await this.requestWithRetry("/cookie-check", "POST", void 0, { allowAuthRetry: false, retrying: false });
463
+ console.log("### cookie check", { step: "first", ok: first.ok, reason: first.reason, status: first.status });
297
464
  if (first.ok) return;
298
465
  if (first.reason !== "cookie_missing") {
299
466
  throw new Error(`Cookie check failed: ${first.reason || first.error || "unknown_error"}`);
300
467
  }
301
468
  const second = await this.requestWithRetry("/cookie-check", "POST", void 0, { allowAuthRetry: false, retrying: false });
469
+ console.log("### cookie check", { step: "second", ok: second.ok, reason: second.reason, status: second.status });
302
470
  if (!second.ok) {
303
471
  throw new Error("Cookie support missing. Provide a cookie-aware fetch implementation for Node/RN.");
304
472
  }
package/dist/rn-setup.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  __require
3
- } from "./chunk-Y6FXYEAI.mjs";
3
+ } from "./chunk-EBO3CZXG.mjs";
4
4
 
5
5
  // src/rn-setup.ts
6
6
  var safeRequire = (id) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kedaruma/revlm-client",
3
- "version": "1.0.46",
3
+ "version": "1.0.49",
4
4
  "private": false,
5
5
  "description": "TypeScript client SDK for talking to the Revlm server replacement for MongoDB Realm.",
6
6
  "keywords": [