@auth-gate/core 0.5.0 → 0.6.0

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.cjs CHANGED
@@ -39,6 +39,7 @@ var index_exports = {};
39
39
  __export(index_exports, {
40
40
  AuthGateClient: () => AuthGateClient,
41
41
  AuthGateError: () => AuthGateError,
42
+ ConfigurationError: () => ConfigurationError,
42
43
  DEFAULT_COOKIE_NAME: () => DEFAULT_COOKIE_NAME,
43
44
  InvalidStateError: () => InvalidStateError,
44
45
  NONCE_COOKIE_NAME: () => NONCE_COOKIE_NAME,
@@ -48,7 +49,9 @@ __export(index_exports, {
48
49
  SUPPORTED_PROVIDERS: () => SUPPORTED_PROVIDERS,
49
50
  SessionDecryptionError: () => SessionDecryptionError,
50
51
  TokenVerificationError: () => TokenVerificationError,
51
- createAuthGateClient: () => createAuthGateClient
52
+ createAuthGateClient: () => createAuthGateClient,
53
+ hasFeature: () => hasFeature,
54
+ hasPlan: () => hasPlan
52
55
  });
53
56
  module.exports = __toCommonJS(index_exports);
54
57
 
@@ -296,6 +299,12 @@ var InvalidStateError = class extends AuthGateError {
296
299
  this.name = "InvalidStateError";
297
300
  }
298
301
  };
302
+ var ConfigurationError = class extends AuthGateError {
303
+ constructor(message) {
304
+ super(message);
305
+ this.name = "ConfigurationError";
306
+ }
307
+ };
299
308
 
300
309
  // src/client.ts
301
310
  var AuthGateClient = class {
@@ -306,6 +315,28 @@ var AuthGateClient = class {
306
315
  this.encryptionKey = null;
307
316
  this.stateKey = null;
308
317
  var _a, _b, _c;
318
+ if (!config.apiKey || typeof config.apiKey !== "string" || config.apiKey.trim() === "") {
319
+ throw new ConfigurationError(
320
+ "[AuthGate] Missing or empty `apiKey`. Get your API key from the AuthGate dashboard \u2192 Project \u2192 API Key."
321
+ );
322
+ }
323
+ if (!config.baseUrl || typeof config.baseUrl !== "string" || config.baseUrl.trim() === "") {
324
+ throw new ConfigurationError(
325
+ '[AuthGate] Missing or empty `baseUrl`. Set this to your AuthGate service URL (e.g. "https://authgate.dev").'
326
+ );
327
+ }
328
+ try {
329
+ new URL(config.baseUrl);
330
+ } catch (e) {
331
+ throw new ConfigurationError(
332
+ `[AuthGate] Invalid \`baseUrl\`: "${config.baseUrl}". Must be a valid URL (e.g. "https://authgate.dev").`
333
+ );
334
+ }
335
+ if (config.callbackPath !== void 0 && !config.callbackPath.startsWith("/")) {
336
+ throw new ConfigurationError(
337
+ `[AuthGate] Invalid \`callbackPath\`: "${config.callbackPath}". Must start with "/" (e.g. "/api/auth/callback").`
338
+ );
339
+ }
309
340
  this.config = __spreadProps(__spreadValues({}, config), {
310
341
  cookieName: (_a = config.cookieName) != null ? _a : DEFAULT_COOKIE_NAME,
311
342
  sessionMaxAge: (_b = config.sessionMaxAge) != null ? _b : SESSION_MAX_AGE,
@@ -927,7 +958,71 @@ var AuthGateClient = class {
927
958
  path: "/"
928
959
  };
929
960
  }
961
+ // ---------------------------------------------------------------------------
962
+ // Config validation (async, called by framework factories)
963
+ // ---------------------------------------------------------------------------
964
+ /**
965
+ * Validate the SDK configuration against the AuthGate server.
966
+ *
967
+ * Checks that the API key is valid and (optionally) that a callback URL
968
+ * is registered for the project. This is called automatically by framework
969
+ * factories (`createAuthGate`, `createAuthRoutes`) and logs errors to the
970
+ * console — it does NOT throw.
971
+ *
972
+ * @param callbackUrl - The full callback URL to check registration for.
973
+ * @internal
974
+ */
975
+ async validateConfig(callbackUrl) {
976
+ try {
977
+ const response = await fetch(
978
+ `${this.config.baseUrl}/api/v1/config/validate`,
979
+ {
980
+ method: "POST",
981
+ headers: {
982
+ Authorization: `Bearer ${this.config.apiKey}`,
983
+ "Content-Type": "application/json"
984
+ },
985
+ body: JSON.stringify({
986
+ callback_url: callbackUrl
987
+ })
988
+ }
989
+ );
990
+ if (response.status === 401) {
991
+ console.error(
992
+ "\n[AuthGate] \u2717 Invalid API key.\n The API key you provided is not recognized or has been revoked.\n \u2192 Go to your AuthGate dashboard \u2192 Project \u2192 API Key to get a valid key.\n"
993
+ );
994
+ return;
995
+ }
996
+ if (!response.ok) {
997
+ console.warn(
998
+ "[AuthGate] Could not validate config (server returned " + response.status + "). Auth flows may fail."
999
+ );
1000
+ return;
1001
+ }
1002
+ const data = await response.json();
1003
+ if (callbackUrl && data.callback_url_registered === false) {
1004
+ console.error(
1005
+ "\n[AuthGate] \u2717 Callback URL not registered: " + callbackUrl + "\n This URL must be added to your project's allowed callback URLs.\n \u2192 Go to your AuthGate dashboard \u2192 Project \u2192 Callback URLs \u2192 Add URL.\n"
1006
+ );
1007
+ }
1008
+ } catch (e) {
1009
+ console.warn(
1010
+ "[AuthGate] Could not reach AuthGate server at " + this.config.baseUrl + " to validate config. Auth flows may fail if the URL is wrong."
1011
+ );
1012
+ }
1013
+ }
930
1014
  };
931
1015
  function createAuthGateClient(config) {
932
1016
  return new AuthGateClient(config);
933
1017
  }
1018
+
1019
+ // src/billing.ts
1020
+ function hasPlan(entitlements, plan) {
1021
+ if (!(entitlements == null ? void 0 : entitlements.plan)) return false;
1022
+ return entitlements.plan.toLowerCase() === plan.toLowerCase();
1023
+ }
1024
+ function hasFeature(entitlements, feature) {
1025
+ if (!(entitlements == null ? void 0 : entitlements.features)) return false;
1026
+ const lower = feature.toLowerCase();
1027
+ return entitlements.features.some((f) => f.toLowerCase() === lower);
1028
+ }
package/dist/index.d.cts CHANGED
@@ -472,6 +472,18 @@ declare class AuthGateClient {
472
472
  * Short-lived (10 minutes) to match the state TTL.
473
473
  */
474
474
  getNonceCookieOptions(): CookieOptions;
475
+ /**
476
+ * Validate the SDK configuration against the AuthGate server.
477
+ *
478
+ * Checks that the API key is valid and (optionally) that a callback URL
479
+ * is registered for the project. This is called automatically by framework
480
+ * factories (`createAuthGate`, `createAuthRoutes`) and logs errors to the
481
+ * console — it does NOT throw.
482
+ *
483
+ * @param callbackUrl - The full callback URL to check registration for.
484
+ * @internal
485
+ */
486
+ validateConfig(callbackUrl?: string): Promise<void>;
475
487
  }
476
488
  /**
477
489
  * Create an {@link AuthGateClient} instance.
@@ -552,5 +564,79 @@ declare class SessionDecryptionError extends AuthGateError {
552
564
  declare class InvalidStateError extends AuthGateError {
553
565
  constructor(message?: string);
554
566
  }
567
+ /**
568
+ * Thrown when the AuthGate SDK is initialized with invalid configuration.
569
+ *
570
+ * Check the error message for details on which config field is invalid
571
+ * and how to fix it.
572
+ */
573
+ declare class ConfigurationError extends AuthGateError {
574
+ constructor(message: string);
575
+ }
576
+
577
+ /** A product/plan in the billing catalog. */
578
+ interface BillingPlan {
579
+ id: string;
580
+ name: string;
581
+ description: string | null;
582
+ features: string[];
583
+ prices: BillingPrice[];
584
+ }
585
+ /** A price attached to a plan. */
586
+ interface BillingPrice {
587
+ id: string;
588
+ type: "recurring" | "metered" | "tiered";
589
+ amount: number | null;
590
+ currency: string;
591
+ interval: "daily" | "weekly" | "monthly" | "yearly";
592
+ intervalCount: number;
593
+ }
594
+ /** An active subscription for an end user. */
595
+ interface BillingSubscription {
596
+ id: string;
597
+ status: "active" | "past_due" | "canceled" | "paused" | "trialing" | "unpaid";
598
+ plan: {
599
+ id: string;
600
+ name: string;
601
+ } | null;
602
+ price: BillingPrice | null;
603
+ currentPeriodStart: string;
604
+ currentPeriodEnd: string;
605
+ cancelAtPeriodEnd: boolean;
606
+ trialEnd: string | null;
607
+ }
608
+ /** Entitlement data for an end user — what plan they're on and what features they have. */
609
+ interface BillingEntitlement {
610
+ plan: string | null;
611
+ features: string[];
612
+ status: string | null;
613
+ subscription: {
614
+ id: string;
615
+ currentPeriodEnd: string;
616
+ } | null;
617
+ }
618
+ /** A single usage event to report. */
619
+ interface UsageEvent {
620
+ metric: string;
621
+ quantity: number;
622
+ idempotencyKey?: string;
623
+ timestamp?: string;
624
+ }
625
+ /**
626
+ * Check whether the user's entitlements include a specific plan.
627
+ *
628
+ * @param entitlements - The entitlement object from the billing API.
629
+ * @param plan - The plan name to check (case-insensitive).
630
+ * @returns `true` if the user is on the given plan.
631
+ */
632
+ declare function hasPlan(entitlements: BillingEntitlement | null | undefined, plan: string): boolean;
633
+ /**
634
+ * Check whether the user's entitlements include a specific feature.
635
+ *
636
+ * @param entitlements - The entitlement object from the billing API.
637
+ * @param feature - The feature name to check (case-insensitive).
638
+ * @returns `true` if the user has the given feature.
639
+ */
640
+ declare function hasFeature(entitlements: BillingEntitlement | null | undefined, feature: string): boolean;
555
641
 
556
- export { AuthGateClient, type AuthGateConfig, AuthGateError, type AuthGateUser, type BackupCodesResponse, type CookieOptions, DEFAULT_COOKIE_NAME, InvalidStateError, type MfaChallengeResponse, type MfaStatus, NONCE_COOKIE_NAME, type OAuthProvider, REFRESH_TOKEN_COOKIE_NAME, SESSION_MAX_AGE, STATE_TTL_MS, SUPPORTED_PROVIDERS, SessionDecryptionError, type SessionPayload, TokenVerificationError, type TokenVerifyResult, type TotpSetupResponse, createAuthGateClient };
642
+ export { AuthGateClient, type AuthGateConfig, AuthGateError, type AuthGateUser, type BackupCodesResponse, type BillingEntitlement, type BillingPlan, type BillingPrice, type BillingSubscription, ConfigurationError, type CookieOptions, DEFAULT_COOKIE_NAME, InvalidStateError, type MfaChallengeResponse, type MfaStatus, NONCE_COOKIE_NAME, type OAuthProvider, REFRESH_TOKEN_COOKIE_NAME, SESSION_MAX_AGE, STATE_TTL_MS, SUPPORTED_PROVIDERS, SessionDecryptionError, type SessionPayload, TokenVerificationError, type TokenVerifyResult, type TotpSetupResponse, type UsageEvent, createAuthGateClient, hasFeature, hasPlan };
package/dist/index.d.ts CHANGED
@@ -472,6 +472,18 @@ declare class AuthGateClient {
472
472
  * Short-lived (10 minutes) to match the state TTL.
473
473
  */
474
474
  getNonceCookieOptions(): CookieOptions;
475
+ /**
476
+ * Validate the SDK configuration against the AuthGate server.
477
+ *
478
+ * Checks that the API key is valid and (optionally) that a callback URL
479
+ * is registered for the project. This is called automatically by framework
480
+ * factories (`createAuthGate`, `createAuthRoutes`) and logs errors to the
481
+ * console — it does NOT throw.
482
+ *
483
+ * @param callbackUrl - The full callback URL to check registration for.
484
+ * @internal
485
+ */
486
+ validateConfig(callbackUrl?: string): Promise<void>;
475
487
  }
476
488
  /**
477
489
  * Create an {@link AuthGateClient} instance.
@@ -552,5 +564,79 @@ declare class SessionDecryptionError extends AuthGateError {
552
564
  declare class InvalidStateError extends AuthGateError {
553
565
  constructor(message?: string);
554
566
  }
567
+ /**
568
+ * Thrown when the AuthGate SDK is initialized with invalid configuration.
569
+ *
570
+ * Check the error message for details on which config field is invalid
571
+ * and how to fix it.
572
+ */
573
+ declare class ConfigurationError extends AuthGateError {
574
+ constructor(message: string);
575
+ }
576
+
577
+ /** A product/plan in the billing catalog. */
578
+ interface BillingPlan {
579
+ id: string;
580
+ name: string;
581
+ description: string | null;
582
+ features: string[];
583
+ prices: BillingPrice[];
584
+ }
585
+ /** A price attached to a plan. */
586
+ interface BillingPrice {
587
+ id: string;
588
+ type: "recurring" | "metered" | "tiered";
589
+ amount: number | null;
590
+ currency: string;
591
+ interval: "daily" | "weekly" | "monthly" | "yearly";
592
+ intervalCount: number;
593
+ }
594
+ /** An active subscription for an end user. */
595
+ interface BillingSubscription {
596
+ id: string;
597
+ status: "active" | "past_due" | "canceled" | "paused" | "trialing" | "unpaid";
598
+ plan: {
599
+ id: string;
600
+ name: string;
601
+ } | null;
602
+ price: BillingPrice | null;
603
+ currentPeriodStart: string;
604
+ currentPeriodEnd: string;
605
+ cancelAtPeriodEnd: boolean;
606
+ trialEnd: string | null;
607
+ }
608
+ /** Entitlement data for an end user — what plan they're on and what features they have. */
609
+ interface BillingEntitlement {
610
+ plan: string | null;
611
+ features: string[];
612
+ status: string | null;
613
+ subscription: {
614
+ id: string;
615
+ currentPeriodEnd: string;
616
+ } | null;
617
+ }
618
+ /** A single usage event to report. */
619
+ interface UsageEvent {
620
+ metric: string;
621
+ quantity: number;
622
+ idempotencyKey?: string;
623
+ timestamp?: string;
624
+ }
625
+ /**
626
+ * Check whether the user's entitlements include a specific plan.
627
+ *
628
+ * @param entitlements - The entitlement object from the billing API.
629
+ * @param plan - The plan name to check (case-insensitive).
630
+ * @returns `true` if the user is on the given plan.
631
+ */
632
+ declare function hasPlan(entitlements: BillingEntitlement | null | undefined, plan: string): boolean;
633
+ /**
634
+ * Check whether the user's entitlements include a specific feature.
635
+ *
636
+ * @param entitlements - The entitlement object from the billing API.
637
+ * @param feature - The feature name to check (case-insensitive).
638
+ * @returns `true` if the user has the given feature.
639
+ */
640
+ declare function hasFeature(entitlements: BillingEntitlement | null | undefined, feature: string): boolean;
555
641
 
556
- export { AuthGateClient, type AuthGateConfig, AuthGateError, type AuthGateUser, type BackupCodesResponse, type CookieOptions, DEFAULT_COOKIE_NAME, InvalidStateError, type MfaChallengeResponse, type MfaStatus, NONCE_COOKIE_NAME, type OAuthProvider, REFRESH_TOKEN_COOKIE_NAME, SESSION_MAX_AGE, STATE_TTL_MS, SUPPORTED_PROVIDERS, SessionDecryptionError, type SessionPayload, TokenVerificationError, type TokenVerifyResult, type TotpSetupResponse, createAuthGateClient };
642
+ export { AuthGateClient, type AuthGateConfig, AuthGateError, type AuthGateUser, type BackupCodesResponse, type BillingEntitlement, type BillingPlan, type BillingPrice, type BillingSubscription, ConfigurationError, type CookieOptions, DEFAULT_COOKIE_NAME, InvalidStateError, type MfaChallengeResponse, type MfaStatus, NONCE_COOKIE_NAME, type OAuthProvider, REFRESH_TOKEN_COOKIE_NAME, SESSION_MAX_AGE, STATE_TTL_MS, SUPPORTED_PROVIDERS, SessionDecryptionError, type SessionPayload, TokenVerificationError, type TokenVerifyResult, type TotpSetupResponse, type UsageEvent, createAuthGateClient, hasFeature, hasPlan };
package/dist/index.mjs CHANGED
@@ -262,6 +262,12 @@ var InvalidStateError = class extends AuthGateError {
262
262
  this.name = "InvalidStateError";
263
263
  }
264
264
  };
265
+ var ConfigurationError = class extends AuthGateError {
266
+ constructor(message) {
267
+ super(message);
268
+ this.name = "ConfigurationError";
269
+ }
270
+ };
265
271
 
266
272
  // src/client.ts
267
273
  var AuthGateClient = class {
@@ -272,6 +278,28 @@ var AuthGateClient = class {
272
278
  this.encryptionKey = null;
273
279
  this.stateKey = null;
274
280
  var _a, _b, _c;
281
+ if (!config.apiKey || typeof config.apiKey !== "string" || config.apiKey.trim() === "") {
282
+ throw new ConfigurationError(
283
+ "[AuthGate] Missing or empty `apiKey`. Get your API key from the AuthGate dashboard \u2192 Project \u2192 API Key."
284
+ );
285
+ }
286
+ if (!config.baseUrl || typeof config.baseUrl !== "string" || config.baseUrl.trim() === "") {
287
+ throw new ConfigurationError(
288
+ '[AuthGate] Missing or empty `baseUrl`. Set this to your AuthGate service URL (e.g. "https://authgate.dev").'
289
+ );
290
+ }
291
+ try {
292
+ new URL(config.baseUrl);
293
+ } catch (e) {
294
+ throw new ConfigurationError(
295
+ `[AuthGate] Invalid \`baseUrl\`: "${config.baseUrl}". Must be a valid URL (e.g. "https://authgate.dev").`
296
+ );
297
+ }
298
+ if (config.callbackPath !== void 0 && !config.callbackPath.startsWith("/")) {
299
+ throw new ConfigurationError(
300
+ `[AuthGate] Invalid \`callbackPath\`: "${config.callbackPath}". Must start with "/" (e.g. "/api/auth/callback").`
301
+ );
302
+ }
275
303
  this.config = __spreadProps(__spreadValues({}, config), {
276
304
  cookieName: (_a = config.cookieName) != null ? _a : DEFAULT_COOKIE_NAME,
277
305
  sessionMaxAge: (_b = config.sessionMaxAge) != null ? _b : SESSION_MAX_AGE,
@@ -893,13 +921,78 @@ var AuthGateClient = class {
893
921
  path: "/"
894
922
  };
895
923
  }
924
+ // ---------------------------------------------------------------------------
925
+ // Config validation (async, called by framework factories)
926
+ // ---------------------------------------------------------------------------
927
+ /**
928
+ * Validate the SDK configuration against the AuthGate server.
929
+ *
930
+ * Checks that the API key is valid and (optionally) that a callback URL
931
+ * is registered for the project. This is called automatically by framework
932
+ * factories (`createAuthGate`, `createAuthRoutes`) and logs errors to the
933
+ * console — it does NOT throw.
934
+ *
935
+ * @param callbackUrl - The full callback URL to check registration for.
936
+ * @internal
937
+ */
938
+ async validateConfig(callbackUrl) {
939
+ try {
940
+ const response = await fetch(
941
+ `${this.config.baseUrl}/api/v1/config/validate`,
942
+ {
943
+ method: "POST",
944
+ headers: {
945
+ Authorization: `Bearer ${this.config.apiKey}`,
946
+ "Content-Type": "application/json"
947
+ },
948
+ body: JSON.stringify({
949
+ callback_url: callbackUrl
950
+ })
951
+ }
952
+ );
953
+ if (response.status === 401) {
954
+ console.error(
955
+ "\n[AuthGate] \u2717 Invalid API key.\n The API key you provided is not recognized or has been revoked.\n \u2192 Go to your AuthGate dashboard \u2192 Project \u2192 API Key to get a valid key.\n"
956
+ );
957
+ return;
958
+ }
959
+ if (!response.ok) {
960
+ console.warn(
961
+ "[AuthGate] Could not validate config (server returned " + response.status + "). Auth flows may fail."
962
+ );
963
+ return;
964
+ }
965
+ const data = await response.json();
966
+ if (callbackUrl && data.callback_url_registered === false) {
967
+ console.error(
968
+ "\n[AuthGate] \u2717 Callback URL not registered: " + callbackUrl + "\n This URL must be added to your project's allowed callback URLs.\n \u2192 Go to your AuthGate dashboard \u2192 Project \u2192 Callback URLs \u2192 Add URL.\n"
969
+ );
970
+ }
971
+ } catch (e) {
972
+ console.warn(
973
+ "[AuthGate] Could not reach AuthGate server at " + this.config.baseUrl + " to validate config. Auth flows may fail if the URL is wrong."
974
+ );
975
+ }
976
+ }
896
977
  };
897
978
  function createAuthGateClient(config) {
898
979
  return new AuthGateClient(config);
899
980
  }
981
+
982
+ // src/billing.ts
983
+ function hasPlan(entitlements, plan) {
984
+ if (!(entitlements == null ? void 0 : entitlements.plan)) return false;
985
+ return entitlements.plan.toLowerCase() === plan.toLowerCase();
986
+ }
987
+ function hasFeature(entitlements, feature) {
988
+ if (!(entitlements == null ? void 0 : entitlements.features)) return false;
989
+ const lower = feature.toLowerCase();
990
+ return entitlements.features.some((f) => f.toLowerCase() === lower);
991
+ }
900
992
  export {
901
993
  AuthGateClient,
902
994
  AuthGateError,
995
+ ConfigurationError,
903
996
  DEFAULT_COOKIE_NAME,
904
997
  InvalidStateError,
905
998
  NONCE_COOKIE_NAME,
@@ -909,5 +1002,7 @@ export {
909
1002
  SUPPORTED_PROVIDERS,
910
1003
  SessionDecryptionError,
911
1004
  TokenVerificationError,
912
- createAuthGateClient
1005
+ createAuthGateClient,
1006
+ hasFeature,
1007
+ hasPlan
913
1008
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@auth-gate/core",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {