@glideidentity/glide-be-sdk-node 2.1.0 → 2.1.1

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,7 +1,9 @@
1
1
  /** Cookie name prefix for device binding codes. Append the session key for the full name. */
2
2
  export declare const BINDING_COOKIE_PREFIX = "_glide_bind_";
3
- /** Cookie max-age in seconds (10 minutes, matches session TTL). */
4
- export declare const BINDING_COOKIE_MAX_AGE = 600;
3
+ /** Cookie max-age in seconds. Set to 5 minutes sufficient for the carrier
4
+ * authentication round-trip (typically under 2 minutes). The cookie auto-expires
5
+ * after this period, so explicit clearing is optional. */
6
+ export declare const BINDING_COOKIE_MAX_AGE = 300;
5
7
  /**
6
8
  * Returns the full cookie name for a given session key.
7
9
  *
@@ -1 +1 @@
1
- {"version":3,"file":"device-binding.d.ts","sourceRoot":"","sources":["../src/device-binding.ts"],"names":[],"mappings":"AAMA,6FAA6F;AAC7F,eAAO,MAAM,qBAAqB,iBAAiB,CAAC;AAEpD,mEAAmE;AACnE,eAAO,MAAM,sBAAsB,MAAM,CAAC;AAE1C;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAK/D;AAMD;;;;;;;GAOG;AACH,eAAO,MAAM,MAAM,QAAsB,CAAC;AAE1C;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAItD;AAMD;;;GAGG;AACH,wBAAgB,cAAc,IAAI,MAAM,CAEvC;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAIpD;AAMD,MAAM,WAAW,oBAAoB;IACjC,oEAAoE;IACpE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,oCAAoC;IACpC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;;;OAKG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;CACpB;AAeD;;;;;;;GAOG;AACH,wBAAgB,2BAA2B,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,oBAAoB,GAAG,MAAM,CAoBtH;AAED;;;;;;GAMG;AACH,wBAAgB,6BAA6B,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,oBAAoB,GAAG,MAAM,CAoBxG;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CAAC,YAAY,EAAE,MAAM,GAAG,SAAS,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAU3G;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,wBAAwB,CAAC,YAAY,EAAE,MAAM,GAAG,SAAS,EAAE,OAAO,CAAC,EAAE,oBAAoB,GAAG,MAAM,EAAE,CAmBnH;AAMD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,qBAAqB,CAAC,gBAAgB,EAAE,MAAM,GAAG,MAAM,CAqGtE"}
1
+ {"version":3,"file":"device-binding.d.ts","sourceRoot":"","sources":["../src/device-binding.ts"],"names":[],"mappings":"AAMA,6FAA6F;AAC7F,eAAO,MAAM,qBAAqB,iBAAiB,CAAC;AAEpD;;2DAE2D;AAC3D,eAAO,MAAM,sBAAsB,MAAM,CAAC;AAE1C;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAK/D;AAMD;;;;;;;GAOG;AACH,eAAO,MAAM,MAAM,QAAsB,CAAC;AAE1C;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAItD;AAMD;;;GAGG;AACH,wBAAgB,cAAc,IAAI,MAAM,CAEvC;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAIpD;AAMD,MAAM,WAAW,oBAAoB;IACjC,oEAAoE;IACpE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,oCAAoC;IACpC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;;;OAKG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;CACpB;AAeD;;;;;;;GAOG;AACH,wBAAgB,2BAA2B,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,oBAAoB,GAAG,MAAM,CAoBtH;AAED;;;;;;GAMG;AACH,wBAAgB,6BAA6B,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,oBAAoB,GAAG,MAAM,CAoBxG;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CAAC,YAAY,EAAE,MAAM,GAAG,SAAS,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAU3G;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,wBAAwB,CAAC,YAAY,EAAE,MAAM,GAAG,SAAS,EAAE,OAAO,CAAC,EAAE,oBAAoB,GAAG,MAAM,EAAE,CAmBnH;AAMD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,qBAAqB,CAAC,gBAAgB,EAAE,MAAM,GAAG,MAAM,CAsJtE"}
@@ -16,8 +16,10 @@ const crypto_1 = require("crypto");
16
16
  // ---------------------------------------------------------------------------
17
17
  /** Cookie name prefix for device binding codes. Append the session key for the full name. */
18
18
  exports.BINDING_COOKIE_PREFIX = '_glide_bind_';
19
- /** Cookie max-age in seconds (10 minutes, matches session TTL). */
20
- exports.BINDING_COOKIE_MAX_AGE = 600;
19
+ /** Cookie max-age in seconds. Set to 5 minutes sufficient for the carrier
20
+ * authentication round-trip (typically under 2 minutes). The cookie auto-expires
21
+ * after this period, so explicit clearing is optional. */
22
+ exports.BINDING_COOKIE_MAX_AGE = 300;
21
23
  /**
22
24
  * Returns the full cookie name for a given session key.
23
25
  *
@@ -231,31 +233,65 @@ function getCompletionPageHtml(completeEndpoint) {
231
233
  <meta charset="utf-8">
232
234
  <meta name="viewport" content="width=device-width, initial-scale=1">
233
235
  <meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'unsafe-inline'; style-src 'unsafe-inline'; connect-src 'self'">
234
- <title>Completing verification...</title>
236
+ <title>Verifying</title>
235
237
  <style>
236
- body { font-family: system-ui, -apple-system, sans-serif; display: flex; justify-content: center; align-items: center; min-height: 100vh; margin: 0; background: #fafafa; color: #333; }
237
- .card { text-align: center; padding: 2rem; max-width: 400px; }
238
- .spinner { width: 40px; height: 40px; border: 3px solid #e0e0e0; border-top-color: #333; border-radius: 50%; animation: spin 0.8s linear infinite; margin: 0 auto 1rem; }
238
+ * { box-sizing: border-box; margin: 0; padding: 0; }
239
+ body { font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Text', system-ui, sans-serif; display: flex; justify-content: center; align-items: center; min-height: 100vh; min-height: 100dvh; background: #fff; color: #1a1a1a; -webkit-font-smoothing: antialiased; }
240
+ .spinner-wrap { text-align: center; }
241
+ .spinner { width: 44px; height: 44px; border: 3px solid transparent; border-top-color: #222; border-radius: 50%; animation: spin 0.7s linear infinite; margin: 0 auto; }
239
242
  @keyframes spin { to { transform: rotate(360deg); } }
240
243
  .hidden { display: none; }
241
- .error { color: #c62828; }
242
- .success { color: #2e7d32; }
243
- .close-hint { margin-top: 0.75rem; font-size: 0.875rem; color: #888; }
244
+ .hint { margin-top: 1.5rem; font-size: 0.875rem; color: #999; }
245
+ .err { display: none; text-align: center; padding: 2rem 1.5rem; max-width: 340px; }
246
+ .err h2 { font-size: 1.25rem; font-weight: 600; color: #1a1a1a; margin-bottom: 1rem; letter-spacing: -0.02em; line-height: 1.3; }
247
+ .err-points { text-align: left; margin: 0 auto 1.5rem; max-width: 280px; }
248
+ .err-points li { font-size: 0.875rem; line-height: 1.6; color: #555; margin-bottom: 0.375rem; padding-left: 0.25rem; }
249
+ .illust { margin: 0 auto 1.5rem; }
250
+ .illust svg { color: #94a3b8; }
251
+ .illust-browser { width: 140px; height: 90px; position: relative; }
252
+ .illust-browser .b { position: absolute; width: 52px; height: 40px; border: 2px solid #cbd5e1; border-radius: 6px; background: #f8fafc; }
253
+ .illust-browser .b .bar { height: 10px; border-bottom: 1.5px solid #e2e8f0; display: flex; align-items: center; padding: 0 4px; gap: 2px; }
254
+ .illust-browser .b .bar i { width: 3px; height: 3px; border-radius: 50%; background: #cbd5e1; }
255
+ .illust-browser .b1 { left: 10px; top: 16px; } .illust-browser .b2 { right: 10px; top: 16px; }
256
+ .illust-browser .aw { position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); }
257
+ .illust-browser .aw svg { width: 36px; height: 36px; animation: arrowSpin 2.5s ease-in-out infinite; }
258
+ @keyframes arrowSpin { 0%,100% { transform: rotate(0); } 50% { transform: rotate(180deg); } }
259
+ .illust-retry svg { width: 48px; height: 48px; animation: retryPulse 2s ease-in-out infinite; }
260
+ @keyframes retryPulse { 0%,100% { transform: scale(1); opacity: 0.7; } 50% { transform: scale(1.1); opacity: 1; } }
261
+ .illust-wifi svg { width: 48px; height: 48px; animation: wifiBlink 2s ease-in-out infinite; }
262
+ @keyframes wifiBlink { 0%,100% { opacity: 1; } 50% { opacity: 0.4; } }
263
+ .illust-link svg { width: 48px; height: 48px; animation: linkShake 2s ease-in-out infinite; }
264
+ @keyframes linkShake { 0%,100% { transform: rotate(0); } 25% { transform: rotate(-5deg); } 75% { transform: rotate(5deg); } }
265
+ .badge { display: inline-flex; align-items: center; background: #fff4e6; border: 1px solid #ffd8a8; border-radius: 100px; padding: 5px 14px; font-size: 0.6875rem; font-weight: 600; color: #e67700; text-transform: uppercase; letter-spacing: 0.06em; margin-top: 0.25rem; }
266
+ @keyframes fadeUp { from { opacity: 0; transform: translateY(12px); } to { opacity: 1; transform: translateY(0); } }
267
+ .err.show { display: block; animation: fadeUp 0.35s ease-out; }
244
268
  </style>
245
269
  </head>
246
270
  <body>
247
- <div class="card">
248
- <div id="loading" role="status" aria-live="polite">
249
- <div class="spinner"></div>
250
- <p>Completing verification&hellip;</p>
271
+ <div class="spinner-wrap" id="loading" role="status" aria-live="polite">
272
+ <div class="spinner"></div>
273
+ <p class="hint hidden" id="hint"></p>
274
+ </div>
275
+ <div class="err" id="error" role="alert" aria-live="assertive">
276
+ <h2 id="err-title"></h2>
277
+ <ol class="err-points" id="err-points"></ol>
278
+ <div class="illust illust-browser hidden" id="ill-browser">
279
+ <div class="illust-browser">
280
+ <div class="b b1"><div class="bar"><i></i><i></i><i></i></div></div>
281
+ <div class="b b2"><div class="bar"><i></i><i></i><i></i></div></div>
282
+ <div class="aw"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="23 4 23 10 17 10"/><polyline points="1 20 1 14 7 14"/><path d="M3.51 9a9 9 0 0114.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0020.49 15"/></svg></div>
283
+ </div>
284
+ </div>
285
+ <div class="illust illust-retry hidden" id="ill-retry">
286
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="23 4 23 10 17 10"/><path d="M20.49 15a9 9 0 11-2.12-9.36L23 10"/></svg>
251
287
  </div>
252
- <div id="success" class="hidden" role="status" aria-live="polite">
253
- <p class="success">Verification complete.</p>
254
- <p id="close-hint" class="close-hint hidden">You may now close this tab.</p>
288
+ <div class="illust illust-wifi hidden" id="ill-wifi">
289
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M1 1l22 22M16.72 11.06A10.94 10.94 0 0119 12.55M5 12.55a10.94 10.94 0 015.17-2.39M10.71 5.05A16 16 0 0122.56 9M1.42 9a15.91 15.91 0 014.7-2.88M8.53 16.11a6 6 0 016.95 0M12 20h.01"/></svg>
255
290
  </div>
256
- <div id="error" class="hidden" role="alert" aria-live="assertive">
257
- <p class="error" id="error-message">Verification failed.</p>
291
+ <div class="illust illust-link hidden" id="ill-link">
292
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M15 7h3a5 5 0 010 10h-3m-6 0H6a5 5 0 010-10h3"/><line x1="8" y1="12" x2="16" y2="12"/></svg>
258
293
  </div>
294
+ <div class="badge">Action required</div>
259
295
  </div>
260
296
  <script>
261
297
  (async function() {
@@ -266,7 +302,7 @@ function getCompletionPageHtml(completeEndpoint) {
266
302
  window.history.replaceState(null, '', window.location.pathname + window.location.search);
267
303
 
268
304
  if (!aggCode || !sessionKey) {
269
- show('error', 'Invalid completion link.');
305
+ showError('Invalid verification link', ['This verification link is not valid.', 'Please go back and try again.'], 'link');
270
306
  return;
271
307
  }
272
308
 
@@ -286,33 +322,48 @@ function getCompletionPageHtml(completeEndpoint) {
286
322
  try { localStorage.removeItem(signalKey); } catch(e) {}
287
323
  }, 5000);
288
324
  } catch(e) {}
289
-
290
- show('success');
291
- setTimeout(function() { tryClose(); }, 1500);
325
+ tryClose();
292
326
  } else {
293
- var errMsg = 'Verification failed. Please try again.';
294
- try {
295
- var data = await res.json();
296
- if (data && data.message) errMsg = data.message;
297
- } catch (_) {}
298
- show('error', errMsg);
327
+ var code = '';
328
+ try { var data = await res.json(); code = (data && (data.code || data.error)) || ''; } catch (_) {}
329
+ var err = friendlyError(code);
330
+ showError(err.title, err.points, err.illust);
299
331
  }
300
332
  } catch (e) {
301
- show('error', 'Network error. Please try again.');
333
+ showError('Connection issue', ['We could not reach the server.', 'Check your internet connection and try again.'], 'wifi');
334
+ }
335
+
336
+ function friendlyError(code) {
337
+ switch (code) {
338
+ case 'MISSING_BINDING_COOKIE':
339
+ case 'BROWSER_MISMATCH':
340
+ return { title: 'Open in your default browser', points: ['Carrier verification must be started from your default browser.', 'The redirect will always open in your default browser to complete.'], illust: 'browser' };
341
+ default:
342
+ return { title: 'Verification could not be completed', points: ['Something went wrong during verification.', 'Please go back and try again.'], illust: 'retry' };
343
+ }
302
344
  }
303
345
 
304
346
  function tryClose() {
347
+ document.querySelector('.spinner').classList.add('hidden');
305
348
  window.close();
306
349
  try { window.open('', '_self').close(); } catch(e) {}
307
350
  setTimeout(function() {
308
- document.getElementById('close-hint').classList.remove('hidden');
309
- }, 200);
351
+ document.getElementById('hint').textContent = 'You may close this tab.';
352
+ document.getElementById('hint').classList.remove('hidden');
353
+ }, 300);
310
354
  }
311
355
 
312
- function show(id, msg) {
356
+ function showError(title, points, illust) {
313
357
  document.getElementById('loading').classList.add('hidden');
314
- document.getElementById(id).classList.remove('hidden');
315
- if (msg) document.getElementById('error-message').textContent = msg;
358
+ document.getElementById('err-title').textContent = title;
359
+ var ol = document.getElementById('err-points');
360
+ ol.innerHTML = '';
361
+ (points || []).forEach(function(p) { var li = document.createElement('li'); li.textContent = p; ol.appendChild(li); });
362
+ var ids = ['ill-browser','ill-retry','ill-wifi','ill-link'];
363
+ ids.forEach(function(id) { document.getElementById(id).classList.add('hidden'); });
364
+ var el = document.getElementById('ill-' + (illust || 'retry'));
365
+ if (el) el.classList.remove('hidden');
366
+ document.getElementById('error').classList.add('show');
316
367
  }
317
368
  })();
318
369
  </script>
@@ -2,7 +2,6 @@ import { GlideSdkSettings, PrepareResult } from '../types';
2
2
  import { Logger } from '../logger';
3
3
  import { OAuthManager } from '../internal/oauth';
4
4
  import type { PrepareRequest, CompleteRequest, VerifyPhoneNumberRequest, VerifyPhoneNumberResponse, GetPhoneNumberRequest, GetPhoneNumberResponse, ReportInvocationRequest, ReportInvocationResponse, StatusResponse } from '@glideidentity/glide-be-sdk-node-core';
5
- /** Handles SIM-based phone authentication via the Glide API. */
6
5
  export declare class MagicalAuth {
7
6
  private settings;
8
7
  private oauthClient;
@@ -1 +1 @@
1
- {"version":3,"file":"magical-auth.d.ts","sourceRoot":"","sources":["../../src/services/magical-auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAC3D,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAEnC,OAAO,EAAE,YAAY,EAAc,MAAM,mBAAmB,CAAC;AAK7D,OAAO,KAAK,EACR,cAAc,EAEd,eAAe,EACf,wBAAwB,EACxB,yBAAyB,EACzB,qBAAqB,EACrB,sBAAsB,EACtB,uBAAuB,EACvB,wBAAwB,EACxB,cAAc,EACjB,MAAM,uCAAuC,CAAC;AAa/C,gEAAgE;AAChE,qBAAa,WAAW;IACpB,OAAO,CAAC,QAAQ,CAAmB;IACnC,OAAO,CAAC,WAAW,CAAe;IAClC,OAAO,CAAC,MAAM,CAAS;gBAEX,QAAQ,EAAE,gBAAgB,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM;IAMjF;;;;;;;OAOG;IACG,OAAO,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC;IAkG1D,kDAAkD;IAC5C,iBAAiB,CAAC,GAAG,EAAE,wBAAwB,GAAG,OAAO,CAAC,yBAAyB,CAAC;IA8C1F,kCAAkC;IAC5B,cAAc,CAAC,GAAG,EAAE,qBAAqB,GAAG,OAAO,CAAC,sBAAsB,CAAC;IA8CjF;;;;;;;;;;;OAWG;IACG,gBAAgB,CAAC,GAAG,EAAE,uBAAuB,GAAG,OAAO,CAAC,wBAAwB,CAAC;IAsCvF;;;;;;;;;;;OAWG;IACG,QAAQ,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IAiEnD;;;;;;;OAOG;IACG,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IAgC9D,OAAO,CAAC,WAAW;CAyCtB"}
1
+ {"version":3,"file":"magical-auth.d.ts","sourceRoot":"","sources":["../../src/services/magical-auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAC3D,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAEnC,OAAO,EAAE,YAAY,EAAc,MAAM,mBAAmB,CAAC;AAK7D,OAAO,KAAK,EACR,cAAc,EAEd,eAAe,EACf,wBAAwB,EACxB,yBAAyB,EACzB,qBAAqB,EACrB,sBAAsB,EACtB,uBAAuB,EACvB,wBAAwB,EACxB,cAAc,EACjB,MAAM,uCAAuC,CAAC;AA+B/C,qBAAa,WAAW;IACpB,OAAO,CAAC,QAAQ,CAAmB;IACnC,OAAO,CAAC,WAAW,CAAe;IAClC,OAAO,CAAC,MAAM,CAAS;gBAEX,QAAQ,EAAE,gBAAgB,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM;IAMjF;;;;;;;OAOG;IACG,OAAO,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC;IAkG1D,kDAAkD;IAC5C,iBAAiB,CAAC,GAAG,EAAE,wBAAwB,GAAG,OAAO,CAAC,yBAAyB,CAAC;IAkD1F,kCAAkC;IAC5B,cAAc,CAAC,GAAG,EAAE,qBAAqB,GAAG,OAAO,CAAC,sBAAsB,CAAC;IAgDjF;;;;;;;;;;;OAWG;IACG,gBAAgB,CAAC,GAAG,EAAE,uBAAuB,GAAG,OAAO,CAAC,wBAAwB,CAAC;IAsCvF;;;;;;;;;;;OAWG;IACG,QAAQ,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IAiEnD;;;;;;;OAOG;IACG,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IAgC9D,OAAO,CAAC,WAAW;CAyCtB"}
@@ -18,6 +18,22 @@ function generateNonce(length = 32) {
18
18
  return result;
19
19
  }
20
20
  /** Handles SIM-based phone authentication via the Glide API. */
21
+ /**
22
+ * Validates and appends fe_code to a request body if present.
23
+ * @throws {MagicalAuthError} if fe_code is not a valid 64-character hex string.
24
+ */
25
+ function applyFeCode(body, feCode) {
26
+ if (feCode !== undefined) {
27
+ if (!device_binding_1.HEX_64.test(feCode)) {
28
+ throw new errors_1.MagicalAuthError({
29
+ code: errors_1.ErrorCode.INVALID_CREDENTIAL,
30
+ message: 'fe_code must be a 64-character hex string',
31
+ status: 400,
32
+ });
33
+ }
34
+ body.fe_code = feCode;
35
+ }
36
+ }
21
37
  class MagicalAuth {
22
38
  constructor(settings, oauthClient, logger) {
23
39
  this.settings = settings;
@@ -133,6 +149,10 @@ class MagicalAuth {
133
149
  session: req.session,
134
150
  credential: req.credential,
135
151
  };
152
+ // Forward device binding code when provided. For device-bound sessions (link
153
+ // protocol), the server validates this against the hash committed during prepare(),
154
+ // extending device binding verification through the entire flow.
155
+ applyFeCode(body, req.fe_code);
136
156
  const url = `${this.settings.baseUrl}/magic-auth/v2/auth/verify-phone-number`;
137
157
  this.logger.debug('VerifyPhoneNumber request', { url });
138
158
  try {
@@ -174,6 +194,8 @@ class MagicalAuth {
174
194
  session: req.session,
175
195
  credential: req.credential,
176
196
  };
197
+ // Forward device binding code when provided (see verifyPhoneNumber for details).
198
+ applyFeCode(body, req.fe_code);
177
199
  const url = `${this.settings.baseUrl}/magic-auth/v2/auth/get-phone-number`;
178
200
  this.logger.debug('GetPhoneNumber request', { url });
179
201
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@glideidentity/glide-be-sdk-node",
3
- "version": "2.1.0",
3
+ "version": "2.1.1",
4
4
  "description": "Glide SDK for Node.js - carrier-based phone verification",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -21,7 +21,7 @@
21
21
  "clean": "rm -rf dist"
22
22
  },
23
23
  "dependencies": {
24
- "@glideidentity/glide-be-sdk-node-core": "2.1.0"
24
+ "@glideidentity/glide-be-sdk-node-core": "2.1.1"
25
25
  },
26
26
  "publishConfig": {
27
27
  "registry": "https://us-central1-npm.pkg.dev/platform-devops-09ff133a/npm-packages/"