@nulvless/nulvless-js 0.1.4 → 0.1.6

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/README.md CHANGED
@@ -18,7 +18,7 @@ npm install @nulvless/nulvless-js
18
18
 
19
19
  ### Browser
20
20
 
21
- Create the client with your project URL and publishable key. The session is stored and renewed for you.
21
+ Create the client with your project URL and publishable key. The session is stored and renewed for you. The project URL is `https://<project>.nulvless.co`, or your own [custom domain](https://nulvless.com/docs/guides/custom-domains) (e.g. `https://api.example.com`) on plans that include it.
22
22
 
23
23
  ```ts
24
24
  import { createClient } from '@nulvless/nulvless-js'
package/dist/index.cjs CHANGED
@@ -317,6 +317,10 @@ var FactorsClient = class extends AuthSubClient {
317
317
  * the factor on the user's device.
318
318
  *
319
319
  * For TOTP: use `secret` for manual entry or `url` to generate a QR code.
320
+ * For SMS: pass `phone` to send the codes to a number other than the user's.
321
+ *
322
+ * A user holds up to 10 authenticator apps and SMS factors combined, and one
323
+ * email factor and one set of recovery codes.
320
324
  *
321
325
  * After the user configures their device, call `enable` with the `token` and
322
326
  * the first OTP code to activate the factor.
@@ -332,8 +336,9 @@ var FactorsClient = class extends AuthSubClient {
332
336
  async enroll(params, options) {
333
337
  const auth = await this.bearer(options);
334
338
  if (!auth.ok) return { data: null, error: auth.error };
335
- const { nonce, type, name } = params;
336
- return this.http.post(route`/factors/${type}`, name ? { name } : {}, {
339
+ const { nonce, type, name, phone } = params;
340
+ const body = { ...name ? { name } : {}, ...phone ? { phone } : {} };
341
+ return this.http.post(route`/factors/${type}`, body, {
337
342
  ...options,
338
343
  nonce,
339
344
  headers: { ...options?.headers, ...auth.headers }
@@ -379,7 +384,6 @@ var FactorsClient = class extends AuthSubClient {
379
384
 
380
385
  // src/auth/users/index.ts
381
386
  var UsersClient = class extends AuthSubClient {
382
- // ─── Profile ────────────────────────────────────────────────────────────────
383
387
  /**
384
388
  * Returns the authenticated user's full profile.
385
389
  */
@@ -404,7 +408,6 @@ var UsersClient = class extends AuthSubClient {
404
408
  headers: { ...options?.headers, ...auth.headers }
405
409
  });
406
410
  }
407
- // ─── Identities ─────────────────────────────────────────────────────────────
408
411
  /**
409
412
  * Lists all identities (email, phone, OAuth) linked to the authenticated user.
410
413
  *
@@ -495,7 +498,6 @@ var UsersClient = class extends AuthSubClient {
495
498
  headers: { ...options?.headers, ...auth.headers }
496
499
  });
497
500
  }
498
- // ─── Credential updates ──────────────────────────────────────────────────────
499
501
  /**
500
502
  * Sends an OTP to the new email address to initiate an email change.
501
503
  *
@@ -695,14 +697,19 @@ var ChallengesClient = class extends AuthSubClient {
695
697
  * Requires an authenticated session. Prompt the user for the code, then call
696
698
  * `verify({ token, code })`.
697
699
  *
700
+ * A `totp` challenge accepts a code from any of the user's authenticator
701
+ * apps. For `sms_otp`, pass `factor_id` to pick which phone receives it.
702
+ *
698
703
  * @example
699
- * const { data } = await nulvless.auth.challenges.create('totp')
704
+ * const { data } = await nulvless.auth.challenges.create({ type: 'totp' })
705
+ * const { data: sms } = await nulvless.auth.challenges.create({ type: 'sms_otp', factor_id })
700
706
  */
701
- async create(targetType, options) {
707
+ async create(params, options) {
702
708
  const auth = await this.bearer(options);
703
709
  if (!auth.ok) return { data: null, error: auth.error };
704
- return this.http.post(route`/challenges/${targetType}`, void 0, {
710
+ return this.http.post(route`/challenges/${params.type}`, void 0, {
705
711
  ...options,
712
+ ...params.factor_id ? { query: { factor_id: params.factor_id } } : {},
706
713
  headers: { ...options?.headers, ...auth.headers }
707
714
  });
708
715
  }
@@ -722,7 +729,7 @@ var ChallengesClient = class extends AuthSubClient {
722
729
  return this.http.patch(
723
730
  route`/challenges/${params.type}`,
724
731
  { token: params.token },
725
- options
732
+ params.factor_id ? { ...options, query: { factor_id: params.factor_id } } : options
726
733
  );
727
734
  }
728
735
  /**
@@ -922,7 +929,6 @@ var OAuthClient = class extends AuthSubClient {
922
929
  super(http, getToken);
923
930
  this.grants = new OAuthGrantsClient(http, getToken);
924
931
  }
925
- // ─── Authorization redirect (platform key) ──────────────────────────────────
926
932
  /**
927
933
  * Builds the OAuth authorization URL and, in the browser, redirects the user
928
934
  * agent to it. On the server the URL is returned for manual handling.
@@ -967,7 +973,6 @@ var OAuthClient = class extends AuthSubClient {
967
973
  }
968
974
  return { data: { url: url.toString() }, error: null };
969
975
  }
970
- // ─── Token endpoint (public) ────────────────────────────────────────────────
971
976
  /**
972
977
  * Exchanges an authorization code for tokens
973
978
  * (`POST /oauth/token`, `grant_type=authorization_code`).
@@ -997,7 +1002,6 @@ var OAuthClient = class extends AuthSubClient {
997
1002
  { ...options, skipApiKey: true }
998
1003
  );
999
1004
  }
1000
- // ─── Dynamic registration (platform key) ────────────────────────────────────
1001
1005
  /**
1002
1006
  * Dynamically registers a new OAuth app (RFC 7591, `POST /oauth/register`).
1003
1007
  *
@@ -1007,7 +1011,6 @@ var OAuthClient = class extends AuthSubClient {
1007
1011
  register(params, options) {
1008
1012
  return this.http.post("/oauth/register", params, { ...options, skipApiKey: true });
1009
1013
  }
1010
- // ─── Consent flow (authenticated user) ──────────────────────────────────────
1011
1014
  /**
1012
1015
  * Loads a pending authorization for the consent screen
1013
1016
  * (`GET /oauth/authorizations/:id`).
@@ -1042,7 +1045,6 @@ var OAuthClient = class extends AuthSubClient {
1042
1045
  headers: { ...options?.headers, ...auth.headers }
1043
1046
  });
1044
1047
  }
1045
- // ─── UserInfo (authenticated user) ──────────────────────────────────────────
1046
1048
  /**
1047
1049
  * Returns OIDC UserInfo claims for the access token (`GET /oauth/userinfo`).
1048
1050
  *
@@ -1058,7 +1060,6 @@ var OAuthClient = class extends AuthSubClient {
1058
1060
  headers: { ...options?.headers, ...auth.headers }
1059
1061
  });
1060
1062
  }
1061
- // ─── Public OIDC metadata (no auth) ─────────────────────────────────────────
1062
1063
  /**
1063
1064
  * Returns the OpenID Connect discovery document
1064
1065
  * (`GET /.well-known/openid-configuration`). Public — no auth required.
@@ -1283,12 +1284,6 @@ var AdminClient = class {
1283
1284
  roles;
1284
1285
  grants;
1285
1286
  oauthClients;
1286
- /**
1287
- * Returns basic platform information (id, name, slug).
1288
- */
1289
- getPlatform(options) {
1290
- return this.http.get("/admin/platform", options);
1291
- }
1292
1287
  };
1293
1288
 
1294
1289
  // src/session/stored.ts
@@ -1463,14 +1458,12 @@ var AuthClient = class {
1463
1458
  async getAccessToken() {
1464
1459
  return this.session?.getValidToken() ?? null;
1465
1460
  }
1466
- // ─── Helpers ──────────────────────────────────────────────────────────────
1467
1461
  async persistSession(result) {
1468
1462
  if (!result.error && result.data.access_token && this.session) {
1469
1463
  await this.session.save(result.data);
1470
1464
  }
1471
1465
  return result;
1472
1466
  }
1473
- // ─── Sign-up / Sign-in ─────────────────────────────────────────────────────
1474
1467
  /**
1475
1468
  * Creates a new user account.
1476
1469
  *
@@ -1631,7 +1624,6 @@ var AuthClient = class {
1631
1624
  headers: { ...options?.headers, ...auth.headers }
1632
1625
  });
1633
1626
  }
1634
- // ─── Challenge ─────────────────────────────────────────────────────────────
1635
1627
  /**
1636
1628
  * Looks up whether an identifier exists and which sign-in method applies.
1637
1629
  *
@@ -1658,7 +1650,6 @@ var AuthClient = class {
1658
1650
  async verifyChallenge(params, options) {
1659
1651
  return this.challenges.verify(params, options);
1660
1652
  }
1661
- // ─── Account lifecycle ─────────────────────────────────────────────────────
1662
1653
  /**
1663
1654
  * Activates an account via the confirmation link sent to the user's email/phone.
1664
1655
  */
@@ -1692,7 +1683,6 @@ var AuthClient = class {
1692
1683
  resetPassword(params, options) {
1693
1684
  return this.http.post("/recover/reset-password", params, options);
1694
1685
  }
1695
- // ─── Session ───────────────────────────────────────────────────────────────
1696
1686
  /**
1697
1687
  * Validates the current session and optionally checks a grant.
1698
1688
  *
@@ -1811,7 +1801,6 @@ var AuthBrowserClient = class extends AuthClient {
1811
1801
  on(event, handler) {
1812
1802
  return this.emitter.on(event, handler);
1813
1803
  }
1814
- // ─── Session persistence override ─────────────────────────────────────────
1815
1804
  async persistSession(result) {
1816
1805
  const out = await super.persistSession(result);
1817
1806
  if (!out.error) {
@@ -1826,7 +1815,6 @@ var AuthBrowserClient = class extends AuthClient {
1826
1815
  }
1827
1816
  return out;
1828
1817
  }
1829
- // ─── Active session helpers ────────────────────────────────────────────────
1830
1818
  /**
1831
1819
  * Returns the session currently stored in storage, or `null` if there is none.
1832
1820
  *
@@ -1858,7 +1846,6 @@ var AuthBrowserClient = class extends AuthClient {
1858
1846
  await this.session?.save(data);
1859
1847
  }
1860
1848
  }
1861
- // ─── Multi-account ─────────────────────────────────────────────────────────
1862
1849
  /**
1863
1850
  * Adds an account to the accounts store without switching the active session.
1864
1851
  *
@@ -1937,7 +1924,6 @@ var AuthBrowserClient = class extends AuthClient {
1937
1924
  }
1938
1925
  await this.session?.clear();
1939
1926
  }
1940
- // ─── signOut override ──────────────────────────────────────────────────────
1941
1927
  async signOut(scope, options) {
1942
1928
  const stored = await this.session?.get();
1943
1929
  const userId = stored ? stored.user?.id ?? extractUserId({ access_token: stored.access_token }) : null;
@@ -2459,7 +2445,7 @@ var NulvlessServerClient = class {
2459
2445
  constructor(baseUrl, privateKey, options) {
2460
2446
  const base = baseUrl.replace(/\/+$/, "");
2461
2447
  this.auth = new AuthServerClient(new HttpClient({ baseUrl: `${base}/auth`, apiKey: privateKey, ...options }));
2462
- this.comms = new CommsClient(new HttpClient({ baseUrl: `${base}/notifications`, apiKey: privateKey, ...options }));
2448
+ this.comms = new CommsClient(new HttpClient({ baseUrl: `${base}/comms`, apiKey: privateKey, ...options }));
2463
2449
  }
2464
2450
  };
2465
2451