@kedaruma/revlm-client 1.0.11 → 1.0.13

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
@@ -174,6 +174,11 @@ type RevlmOptions = {
174
174
  provisionalAuthDomain?: string;
175
175
  autoSetToken?: boolean;
176
176
  autoRefreshOn401?: boolean;
177
+ sigv4SecretKey?: string;
178
+ sigv4AccessKey?: string;
179
+ sigv4Region?: string;
180
+ sigv4Service?: string;
181
+ sigv4Enabled?: boolean;
177
182
  };
178
183
  type RevlmResponse<T = any> = {
179
184
  ok: boolean;
@@ -193,6 +198,7 @@ declare class Revlm {
193
198
  private provisionalAuthDomain;
194
199
  private autoSetToken;
195
200
  private autoRefreshOn401;
201
+ private sigv4Signer;
196
202
  constructor(baseUrl: string, opts?: RevlmOptions);
197
203
  setToken(token: string): void;
198
204
  getToken(): string | undefined;
@@ -204,6 +210,7 @@ declare class Revlm {
204
210
  private parseResponse;
205
211
  private request;
206
212
  private shouldSkipAuthRetry;
213
+ private signIfNeeded;
207
214
  private requestWithRetry;
208
215
  login(authId: string, password: string): Promise<LoginResponse>;
209
216
  provisionalLogin(authId: string): Promise<ProvisionalLoginResponse>;
package/dist/index.d.ts CHANGED
@@ -174,6 +174,11 @@ type RevlmOptions = {
174
174
  provisionalAuthDomain?: string;
175
175
  autoSetToken?: boolean;
176
176
  autoRefreshOn401?: boolean;
177
+ sigv4SecretKey?: string;
178
+ sigv4AccessKey?: string;
179
+ sigv4Region?: string;
180
+ sigv4Service?: string;
181
+ sigv4Enabled?: boolean;
177
182
  };
178
183
  type RevlmResponse<T = any> = {
179
184
  ok: boolean;
@@ -193,6 +198,7 @@ declare class Revlm {
193
198
  private provisionalAuthDomain;
194
199
  private autoSetToken;
195
200
  private autoRefreshOn401;
201
+ private sigv4Signer;
196
202
  constructor(baseUrl: string, opts?: RevlmOptions);
197
203
  setToken(token: string): void;
198
204
  getToken(): string | undefined;
@@ -204,6 +210,7 @@ declare class Revlm {
204
210
  private parseResponse;
205
211
  private request;
206
212
  private shouldSkipAuthRetry;
213
+ private signIfNeeded;
207
214
  private requestWithRetry;
208
215
  login(authId: string, password: string): Promise<LoginResponse>;
209
216
  provisionalLogin(authId: string): Promise<ProvisionalLoginResponse>;
package/dist/index.js CHANGED
@@ -46,6 +46,8 @@ module.exports = __toCommonJS(index_exports);
46
46
  // src/Revlm.ts
47
47
  var import_bson = require("bson");
48
48
  var import_revlm_shared = require("@kedaruma/revlm-shared");
49
+ var import_signature_v4 = require("@aws-sdk/signature-v4");
50
+ var import_sha256_js = require("@aws-crypto/sha256-js");
49
51
 
50
52
  // src/MdbCollection.ts
51
53
  var MdbCollection = class {
@@ -156,6 +158,7 @@ var Revlm = class {
156
158
  provisionalAuthDomain;
157
159
  autoSetToken;
158
160
  autoRefreshOn401;
161
+ sigv4Signer;
159
162
  constructor(baseUrl, opts = {}) {
160
163
  if (!baseUrl) throw new Error("baseUrl is required");
161
164
  this.baseUrl = baseUrl.replace(/\/$/, "");
@@ -166,6 +169,24 @@ var Revlm = class {
166
169
  this.provisionalAuthDomain = opts.provisionalAuthDomain || "";
167
170
  this.autoSetToken = opts.autoSetToken ?? true;
168
171
  this.autoRefreshOn401 = opts.autoRefreshOn401 || false;
172
+ const sigv4SecretKey = opts.sigv4SecretKey || process.env.REVLM_SIGV4_SECRET_KEY;
173
+ const sigv4AccessKey = opts.sigv4AccessKey || process.env.REVLM_SIGV4_ACCESS_KEY || "revlm-access";
174
+ const sigv4Region = opts.sigv4Region || process.env.REVLM_SIGV4_REGION || "revlm";
175
+ const sigv4Service = opts.sigv4Service || process.env.REVLM_SIGV4_SERVICE || "revlm";
176
+ const sigv4Enabled = opts.sigv4Enabled ?? true;
177
+ if (sigv4Enabled) {
178
+ if (!sigv4SecretKey) {
179
+ throw new Error("SigV4 is enabled but REVLM_SIGV4_SECRET_KEY or opts.sigv4SecretKey is not provided");
180
+ }
181
+ this.sigv4Signer = new import_signature_v4.SignatureV4({
182
+ credentials: { accessKeyId: sigv4AccessKey, secretAccessKey: sigv4SecretKey },
183
+ region: sigv4Region,
184
+ service: sigv4Service,
185
+ sha256: import_sha256_js.Sha256
186
+ });
187
+ } else {
188
+ this.sigv4Signer = null;
189
+ }
169
190
  if (!this.fetchImpl) {
170
191
  throw new Error("No fetch implementation available. Provide fetchImpl in options or run in Node 18+ with global fetch.");
171
192
  }
@@ -214,7 +235,7 @@ var Revlm = class {
214
235
  headers["Content-Type"] = "application/ejson";
215
236
  }
216
237
  if (this._token) {
217
- headers["Authorization"] = `Bearer ${this._token}`;
238
+ headers["X-Revlm-JWT"] = `Bearer ${this._token}`;
218
239
  }
219
240
  return headers;
220
241
  }
@@ -238,6 +259,33 @@ var Revlm = class {
238
259
  const pathname = path.startsWith("http") ? new URL(path).pathname : path;
239
260
  return pathname.includes("/login") || pathname.includes("/provisional-login") || pathname.includes("/refresh-token") || pathname.includes("/verify-token");
240
261
  }
262
+ async signIfNeeded(url, method, headers, body) {
263
+ if (!this.sigv4Signer) {
264
+ return { signedUrl: url, signedHeaders: headers };
265
+ }
266
+ const u = new URL(url);
267
+ const signingHeaders = {
268
+ host: u.host,
269
+ ...headers
270
+ };
271
+ const reqToSign = {
272
+ method,
273
+ protocol: u.protocol,
274
+ path: u.pathname + (u.search || ""),
275
+ hostname: u.hostname,
276
+ headers: signingHeaders,
277
+ body: body ?? ""
278
+ };
279
+ if (u.port) {
280
+ reqToSign.port = Number(u.port);
281
+ }
282
+ const signed = await this.sigv4Signer.sign(reqToSign);
283
+ const signedHeaders = {};
284
+ Object.entries(signed.headers || {}).forEach(([k, v]) => {
285
+ signedHeaders[k] = Array.isArray(v) ? v.join(",") : String(v);
286
+ });
287
+ return { signedUrl: url, signedHeaders };
288
+ }
241
289
  async requestWithRetry(path, method = "POST", body, opts = { allowAuthRetry: false, retrying: false }) {
242
290
  const { allowAuthRetry, retrying } = opts;
243
291
  const url = path.startsWith("http") ? path : `${this.baseUrl}${path.startsWith("/") ? "" : "/"}${path}`;
@@ -247,10 +295,11 @@ var Revlm = class {
247
295
  if (hasBody) {
248
296
  serializedBody = import_bson.EJSON.stringify(body);
249
297
  }
298
+ const { signedUrl, signedHeaders } = await this.signIfNeeded(url, method, headers, serializedBody);
250
299
  try {
251
- const res = await this.fetchImpl(url, {
300
+ const res = await this.fetchImpl(signedUrl, {
252
301
  method,
253
- headers,
302
+ headers: signedHeaders,
254
303
  body: serializedBody
255
304
  });
256
305
  const parsed = await this.parseResponse(res);
package/dist/index.mjs CHANGED
@@ -1,6 +1,8 @@
1
1
  // src/Revlm.ts
2
2
  import { EJSON } from "bson";
3
3
  import { AuthClient } from "@kedaruma/revlm-shared";
4
+ import { SignatureV4 } from "@aws-sdk/signature-v4";
5
+ import { Sha256 } from "@aws-crypto/sha256-js";
4
6
 
5
7
  // src/MdbCollection.ts
6
8
  var MdbCollection = class {
@@ -111,6 +113,7 @@ var Revlm = class {
111
113
  provisionalAuthDomain;
112
114
  autoSetToken;
113
115
  autoRefreshOn401;
116
+ sigv4Signer;
114
117
  constructor(baseUrl, opts = {}) {
115
118
  if (!baseUrl) throw new Error("baseUrl is required");
116
119
  this.baseUrl = baseUrl.replace(/\/$/, "");
@@ -121,6 +124,24 @@ var Revlm = class {
121
124
  this.provisionalAuthDomain = opts.provisionalAuthDomain || "";
122
125
  this.autoSetToken = opts.autoSetToken ?? true;
123
126
  this.autoRefreshOn401 = opts.autoRefreshOn401 || false;
127
+ const sigv4SecretKey = opts.sigv4SecretKey || process.env.REVLM_SIGV4_SECRET_KEY;
128
+ const sigv4AccessKey = opts.sigv4AccessKey || process.env.REVLM_SIGV4_ACCESS_KEY || "revlm-access";
129
+ const sigv4Region = opts.sigv4Region || process.env.REVLM_SIGV4_REGION || "revlm";
130
+ const sigv4Service = opts.sigv4Service || process.env.REVLM_SIGV4_SERVICE || "revlm";
131
+ const sigv4Enabled = opts.sigv4Enabled ?? true;
132
+ if (sigv4Enabled) {
133
+ if (!sigv4SecretKey) {
134
+ throw new Error("SigV4 is enabled but REVLM_SIGV4_SECRET_KEY or opts.sigv4SecretKey is not provided");
135
+ }
136
+ this.sigv4Signer = new SignatureV4({
137
+ credentials: { accessKeyId: sigv4AccessKey, secretAccessKey: sigv4SecretKey },
138
+ region: sigv4Region,
139
+ service: sigv4Service,
140
+ sha256: Sha256
141
+ });
142
+ } else {
143
+ this.sigv4Signer = null;
144
+ }
124
145
  if (!this.fetchImpl) {
125
146
  throw new Error("No fetch implementation available. Provide fetchImpl in options or run in Node 18+ with global fetch.");
126
147
  }
@@ -169,7 +190,7 @@ var Revlm = class {
169
190
  headers["Content-Type"] = "application/ejson";
170
191
  }
171
192
  if (this._token) {
172
- headers["Authorization"] = `Bearer ${this._token}`;
193
+ headers["X-Revlm-JWT"] = `Bearer ${this._token}`;
173
194
  }
174
195
  return headers;
175
196
  }
@@ -193,6 +214,33 @@ var Revlm = class {
193
214
  const pathname = path.startsWith("http") ? new URL(path).pathname : path;
194
215
  return pathname.includes("/login") || pathname.includes("/provisional-login") || pathname.includes("/refresh-token") || pathname.includes("/verify-token");
195
216
  }
217
+ async signIfNeeded(url, method, headers, body) {
218
+ if (!this.sigv4Signer) {
219
+ return { signedUrl: url, signedHeaders: headers };
220
+ }
221
+ const u = new URL(url);
222
+ const signingHeaders = {
223
+ host: u.host,
224
+ ...headers
225
+ };
226
+ const reqToSign = {
227
+ method,
228
+ protocol: u.protocol,
229
+ path: u.pathname + (u.search || ""),
230
+ hostname: u.hostname,
231
+ headers: signingHeaders,
232
+ body: body ?? ""
233
+ };
234
+ if (u.port) {
235
+ reqToSign.port = Number(u.port);
236
+ }
237
+ const signed = await this.sigv4Signer.sign(reqToSign);
238
+ const signedHeaders = {};
239
+ Object.entries(signed.headers || {}).forEach(([k, v]) => {
240
+ signedHeaders[k] = Array.isArray(v) ? v.join(",") : String(v);
241
+ });
242
+ return { signedUrl: url, signedHeaders };
243
+ }
196
244
  async requestWithRetry(path, method = "POST", body, opts = { allowAuthRetry: false, retrying: false }) {
197
245
  const { allowAuthRetry, retrying } = opts;
198
246
  const url = path.startsWith("http") ? path : `${this.baseUrl}${path.startsWith("/") ? "" : "/"}${path}`;
@@ -202,10 +250,11 @@ var Revlm = class {
202
250
  if (hasBody) {
203
251
  serializedBody = EJSON.stringify(body);
204
252
  }
253
+ const { signedUrl, signedHeaders } = await this.signIfNeeded(url, method, headers, serializedBody);
205
254
  try {
206
- const res = await this.fetchImpl(url, {
255
+ const res = await this.fetchImpl(signedUrl, {
207
256
  method,
208
- headers,
257
+ headers: signedHeaders,
209
258
  body: serializedBody
210
259
  });
211
260
  const parsed = await this.parseResponse(res);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kedaruma/revlm-client",
3
- "version": "1.0.11",
3
+ "version": "1.0.13",
4
4
  "private": false,
5
5
  "description": "TypeScript client SDK for talking to the Revlm server replacement for MongoDB Realm.",
6
6
  "keywords": [
@@ -36,9 +36,11 @@
36
36
  "access": "public"
37
37
  },
38
38
  "dependencies": {
39
+ "@aws-sdk/signature-v4": "^3.374.0",
40
+ "@aws-crypto/sha256-js": "^5.2.0",
39
41
  "bson": "^6.10.4",
40
42
  "dotenv": "^17.2.3",
41
- "@kedaruma/revlm-shared": "1.0.3"
43
+ "@kedaruma/revlm-shared": "1.0.4"
42
44
  },
43
45
  "devDependencies": {
44
46
  "tsup": "^8.5.1"