@auth-gate/core 0.7.1 → 0.8.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
@@ -49,9 +49,14 @@ __export(index_exports, {
49
49
  SUPPORTED_PROVIDERS: () => SUPPORTED_PROVIDERS,
50
50
  SessionDecryptionError: () => SessionDecryptionError,
51
51
  TokenVerificationError: () => TokenVerificationError,
52
+ checkFeature: () => checkFeature,
52
53
  createAuthGateClient: () => createAuthGateClient,
54
+ hasAllPermissions: () => hasAllPermissions,
55
+ hasAnyPermission: () => hasAnyPermission,
53
56
  hasFeature: () => hasFeature,
54
- hasPlan: () => hasPlan
57
+ hasPermission: () => hasPermission,
58
+ hasPlan: () => hasPlan,
59
+ hasRole: () => hasRole
55
60
  });
56
61
  module.exports = __toCommonJS(index_exports);
57
62
 
@@ -903,6 +908,253 @@ var AuthGateClient = class {
903
908
  });
904
909
  }
905
910
  // ---------------------------------------------------------------------------
911
+ // Organizations
912
+ // ---------------------------------------------------------------------------
913
+ /**
914
+ * Create a new organization.
915
+ *
916
+ * @param data - Organization creation data including name, slug, optional image URL, and metadata.
917
+ * @returns The raw `Response` from the AuthGate proxy.
918
+ */
919
+ async createOrg(data) {
920
+ return fetch(`${this.config.baseUrl}/api/proxy/orgs`, {
921
+ method: "POST",
922
+ headers: {
923
+ Authorization: `Bearer ${this.config.apiKey}`,
924
+ "Content-Type": "application/json"
925
+ },
926
+ body: JSON.stringify({
927
+ name: data.name,
928
+ slug: data.slug,
929
+ image_url: data.imageUrl,
930
+ metadata: data.metadata
931
+ })
932
+ });
933
+ }
934
+ /**
935
+ * List all organizations accessible to the current project.
936
+ *
937
+ * @returns The raw `Response` from the AuthGate proxy.
938
+ */
939
+ async listOrgs() {
940
+ return fetch(`${this.config.baseUrl}/api/proxy/orgs`, {
941
+ method: "GET",
942
+ headers: {
943
+ Authorization: `Bearer ${this.config.apiKey}`
944
+ }
945
+ });
946
+ }
947
+ /**
948
+ * Get a single organization by ID or slug.
949
+ *
950
+ * @param orgIdOrSlug - The organization ID or slug.
951
+ * @returns The raw `Response` from the AuthGate proxy.
952
+ */
953
+ async getOrg(orgIdOrSlug) {
954
+ return fetch(`${this.config.baseUrl}/api/proxy/orgs/${orgIdOrSlug}`, {
955
+ method: "GET",
956
+ headers: {
957
+ Authorization: `Bearer ${this.config.apiKey}`
958
+ }
959
+ });
960
+ }
961
+ /**
962
+ * Update an organization's details.
963
+ *
964
+ * @param orgIdOrSlug - The organization ID or slug.
965
+ * @param data - Fields to update. All fields are optional.
966
+ * @returns The raw `Response` from the AuthGate proxy.
967
+ */
968
+ async updateOrg(orgIdOrSlug, data) {
969
+ return fetch(
970
+ `${this.config.baseUrl}/api/proxy/orgs/${orgIdOrSlug}`,
971
+ {
972
+ method: "PATCH",
973
+ headers: {
974
+ Authorization: `Bearer ${this.config.apiKey}`,
975
+ "Content-Type": "application/json"
976
+ },
977
+ body: JSON.stringify({
978
+ name: data.name,
979
+ slug: data.slug,
980
+ image_url: data.imageUrl,
981
+ max_members: data.maxMembers,
982
+ metadata: data.metadata
983
+ })
984
+ }
985
+ );
986
+ }
987
+ /**
988
+ * Delete an organization.
989
+ *
990
+ * @param orgIdOrSlug - The organization ID or slug.
991
+ * @returns The raw `Response` from the AuthGate proxy.
992
+ */
993
+ async deleteOrg(orgIdOrSlug) {
994
+ return fetch(`${this.config.baseUrl}/api/proxy/orgs/${orgIdOrSlug}`, {
995
+ method: "DELETE",
996
+ headers: {
997
+ Authorization: `Bearer ${this.config.apiKey}`
998
+ }
999
+ });
1000
+ }
1001
+ /**
1002
+ * List all members of an organization.
1003
+ *
1004
+ * @param orgIdOrSlug - The organization ID or slug.
1005
+ * @returns The raw `Response` from the AuthGate proxy.
1006
+ */
1007
+ async listOrgMembers(orgIdOrSlug) {
1008
+ return fetch(
1009
+ `${this.config.baseUrl}/api/proxy/orgs/${orgIdOrSlug}/members`,
1010
+ {
1011
+ method: "GET",
1012
+ headers: {
1013
+ Authorization: `Bearer ${this.config.apiKey}`
1014
+ }
1015
+ }
1016
+ );
1017
+ }
1018
+ /**
1019
+ * Update a member's role within an organization.
1020
+ *
1021
+ * @param orgIdOrSlug - The organization ID or slug.
1022
+ * @param memberId - The member's user ID.
1023
+ * @param data - The new role to assign.
1024
+ * @returns The raw `Response` from the AuthGate proxy.
1025
+ */
1026
+ async updateOrgMember(orgIdOrSlug, memberId, data) {
1027
+ return fetch(
1028
+ `${this.config.baseUrl}/api/proxy/orgs/${orgIdOrSlug}/members/${memberId}`,
1029
+ {
1030
+ method: "PATCH",
1031
+ headers: {
1032
+ Authorization: `Bearer ${this.config.apiKey}`,
1033
+ "Content-Type": "application/json"
1034
+ },
1035
+ body: JSON.stringify({
1036
+ role_key: data.roleKey
1037
+ })
1038
+ }
1039
+ );
1040
+ }
1041
+ /**
1042
+ * Remove a member from an organization.
1043
+ *
1044
+ * @param orgIdOrSlug - The organization ID or slug.
1045
+ * @param memberId - The member's user ID.
1046
+ * @returns The raw `Response` from the AuthGate proxy.
1047
+ */
1048
+ async removeOrgMember(orgIdOrSlug, memberId) {
1049
+ return fetch(
1050
+ `${this.config.baseUrl}/api/proxy/orgs/${orgIdOrSlug}/members/${memberId}`,
1051
+ {
1052
+ method: "DELETE",
1053
+ headers: {
1054
+ Authorization: `Bearer ${this.config.apiKey}`
1055
+ }
1056
+ }
1057
+ );
1058
+ }
1059
+ /**
1060
+ * Invite a user to an organization by email.
1061
+ *
1062
+ * @param orgIdOrSlug - The organization ID or slug.
1063
+ * @param data - The invitee's email and optional role.
1064
+ * @returns The raw `Response` from the AuthGate proxy.
1065
+ */
1066
+ async inviteToOrg(orgIdOrSlug, data) {
1067
+ return fetch(
1068
+ `${this.config.baseUrl}/api/proxy/orgs/${orgIdOrSlug}/invitations`,
1069
+ {
1070
+ method: "POST",
1071
+ headers: {
1072
+ Authorization: `Bearer ${this.config.apiKey}`,
1073
+ "Content-Type": "application/json"
1074
+ },
1075
+ body: JSON.stringify({
1076
+ email: data.email,
1077
+ role_key: data.roleKey
1078
+ })
1079
+ }
1080
+ );
1081
+ }
1082
+ /**
1083
+ * List all pending invitations for an organization.
1084
+ *
1085
+ * @param orgIdOrSlug - The organization ID or slug.
1086
+ * @returns The raw `Response` from the AuthGate proxy.
1087
+ */
1088
+ async listOrgInvitations(orgIdOrSlug) {
1089
+ return fetch(
1090
+ `${this.config.baseUrl}/api/proxy/orgs/${orgIdOrSlug}/invitations`,
1091
+ {
1092
+ method: "GET",
1093
+ headers: {
1094
+ Authorization: `Bearer ${this.config.apiKey}`
1095
+ }
1096
+ }
1097
+ );
1098
+ }
1099
+ /**
1100
+ * Revoke a pending organization invitation.
1101
+ *
1102
+ * @param orgIdOrSlug - The organization ID or slug.
1103
+ * @param invitationId - The invitation ID to revoke.
1104
+ * @returns The raw `Response` from the AuthGate proxy.
1105
+ */
1106
+ async revokeOrgInvitation(orgIdOrSlug, invitationId) {
1107
+ return fetch(
1108
+ `${this.config.baseUrl}/api/proxy/orgs/${orgIdOrSlug}/invitations/${invitationId}`,
1109
+ {
1110
+ method: "DELETE",
1111
+ headers: {
1112
+ Authorization: `Bearer ${this.config.apiKey}`
1113
+ }
1114
+ }
1115
+ );
1116
+ }
1117
+ /**
1118
+ * Accept an organization invitation using a token.
1119
+ *
1120
+ * @param data - The invitation token received via email.
1121
+ * @returns The raw `Response` from the AuthGate proxy.
1122
+ */
1123
+ async acceptOrgInvitation(data) {
1124
+ return fetch(
1125
+ `${this.config.baseUrl}/api/proxy/orgs/invitations/accept`,
1126
+ {
1127
+ method: "POST",
1128
+ headers: {
1129
+ Authorization: `Bearer ${this.config.apiKey}`,
1130
+ "Content-Type": "application/json"
1131
+ },
1132
+ body: JSON.stringify({
1133
+ token: data.token
1134
+ })
1135
+ }
1136
+ );
1137
+ }
1138
+ /**
1139
+ * Leave an organization as the current user.
1140
+ *
1141
+ * @param orgIdOrSlug - The organization ID or slug.
1142
+ * @returns The raw `Response` from the AuthGate proxy.
1143
+ */
1144
+ async leaveOrg(orgIdOrSlug) {
1145
+ return fetch(
1146
+ `${this.config.baseUrl}/api/proxy/orgs/${orgIdOrSlug}/leave`,
1147
+ {
1148
+ method: "POST",
1149
+ headers: {
1150
+ Authorization: `Bearer ${this.config.apiKey}`,
1151
+ "Content-Type": "application/json"
1152
+ },
1153
+ body: "{}"
1154
+ }
1155
+ );
1156
+ }
1157
+ // ---------------------------------------------------------------------------
906
1158
  // Cookie config accessors
907
1159
  // ---------------------------------------------------------------------------
908
1160
  /** The name of the session cookie (default: `"__authgate"`). */
@@ -1026,3 +1278,52 @@ function hasFeature(entitlements, feature) {
1026
1278
  const lower = feature.toLowerCase();
1027
1279
  return entitlements.features.some((f) => f.toLowerCase() === lower);
1028
1280
  }
1281
+ function checkFeature(entitlements, feature) {
1282
+ if (!(entitlements == null ? void 0 : entitlements.featureDetails)) {
1283
+ const allowed = hasFeature(entitlements, feature);
1284
+ return { type: "boolean", feature, allowed };
1285
+ }
1286
+ const lower = feature.toLowerCase();
1287
+ const key = Object.keys(entitlements.featureDetails).find(
1288
+ (k) => k.toLowerCase() === lower
1289
+ );
1290
+ if (key) return entitlements.featureDetails[key];
1291
+ return { type: "boolean", feature, allowed: false };
1292
+ }
1293
+
1294
+ // src/organizations.ts
1295
+ function hasPermission(membership, permission) {
1296
+ var _a;
1297
+ if (!((_a = membership == null ? void 0 : membership.role) == null ? void 0 : _a.permissions)) return false;
1298
+ return matchesPermission(membership.role.permissions, permission);
1299
+ }
1300
+ function hasRole(membership, roleKey) {
1301
+ var _a;
1302
+ if (!((_a = membership == null ? void 0 : membership.role) == null ? void 0 : _a.key)) return false;
1303
+ return membership.role.key === roleKey;
1304
+ }
1305
+ function hasAnyPermission(membership, permissions) {
1306
+ var _a;
1307
+ if (!((_a = membership == null ? void 0 : membership.role) == null ? void 0 : _a.permissions)) return false;
1308
+ return permissions.some(
1309
+ (p) => matchesPermission(membership.role.permissions, p)
1310
+ );
1311
+ }
1312
+ function hasAllPermissions(membership, permissions) {
1313
+ var _a;
1314
+ if (!((_a = membership == null ? void 0 : membership.role) == null ? void 0 : _a.permissions)) return false;
1315
+ return permissions.every(
1316
+ (p) => matchesPermission(membership.role.permissions, p)
1317
+ );
1318
+ }
1319
+ function matchesPermission(granted, required) {
1320
+ for (const perm of granted) {
1321
+ if (perm === "*") return true;
1322
+ if (perm === required) return true;
1323
+ if (perm.endsWith(":*")) {
1324
+ const prefix = perm.slice(0, -1);
1325
+ if (required.startsWith(prefix)) return true;
1326
+ }
1327
+ }
1328
+ return false;
1329
+ }
package/dist/index.d.cts CHANGED
@@ -448,6 +448,120 @@ declare class AuthGateClient {
448
448
  * @returns The raw `Response`.
449
449
  */
450
450
  mfaSmsSendCode(challenge: string): Promise<Response>;
451
+ /**
452
+ * Create a new organization.
453
+ *
454
+ * @param data - Organization creation data including name, slug, optional image URL, and metadata.
455
+ * @returns The raw `Response` from the AuthGate proxy.
456
+ */
457
+ createOrg(data: {
458
+ name: string;
459
+ slug: string;
460
+ imageUrl?: string;
461
+ metadata?: Record<string, unknown>;
462
+ }): Promise<Response>;
463
+ /**
464
+ * List all organizations accessible to the current project.
465
+ *
466
+ * @returns The raw `Response` from the AuthGate proxy.
467
+ */
468
+ listOrgs(): Promise<Response>;
469
+ /**
470
+ * Get a single organization by ID or slug.
471
+ *
472
+ * @param orgIdOrSlug - The organization ID or slug.
473
+ * @returns The raw `Response` from the AuthGate proxy.
474
+ */
475
+ getOrg(orgIdOrSlug: string): Promise<Response>;
476
+ /**
477
+ * Update an organization's details.
478
+ *
479
+ * @param orgIdOrSlug - The organization ID or slug.
480
+ * @param data - Fields to update. All fields are optional.
481
+ * @returns The raw `Response` from the AuthGate proxy.
482
+ */
483
+ updateOrg(orgIdOrSlug: string, data: {
484
+ name?: string;
485
+ slug?: string;
486
+ imageUrl?: string;
487
+ maxMembers?: number | null;
488
+ metadata?: Record<string, unknown>;
489
+ }): Promise<Response>;
490
+ /**
491
+ * Delete an organization.
492
+ *
493
+ * @param orgIdOrSlug - The organization ID or slug.
494
+ * @returns The raw `Response` from the AuthGate proxy.
495
+ */
496
+ deleteOrg(orgIdOrSlug: string): Promise<Response>;
497
+ /**
498
+ * List all members of an organization.
499
+ *
500
+ * @param orgIdOrSlug - The organization ID or slug.
501
+ * @returns The raw `Response` from the AuthGate proxy.
502
+ */
503
+ listOrgMembers(orgIdOrSlug: string): Promise<Response>;
504
+ /**
505
+ * Update a member's role within an organization.
506
+ *
507
+ * @param orgIdOrSlug - The organization ID or slug.
508
+ * @param memberId - The member's user ID.
509
+ * @param data - The new role to assign.
510
+ * @returns The raw `Response` from the AuthGate proxy.
511
+ */
512
+ updateOrgMember(orgIdOrSlug: string, memberId: string, data: {
513
+ roleKey: string;
514
+ }): Promise<Response>;
515
+ /**
516
+ * Remove a member from an organization.
517
+ *
518
+ * @param orgIdOrSlug - The organization ID or slug.
519
+ * @param memberId - The member's user ID.
520
+ * @returns The raw `Response` from the AuthGate proxy.
521
+ */
522
+ removeOrgMember(orgIdOrSlug: string, memberId: string): Promise<Response>;
523
+ /**
524
+ * Invite a user to an organization by email.
525
+ *
526
+ * @param orgIdOrSlug - The organization ID or slug.
527
+ * @param data - The invitee's email and optional role.
528
+ * @returns The raw `Response` from the AuthGate proxy.
529
+ */
530
+ inviteToOrg(orgIdOrSlug: string, data: {
531
+ email: string;
532
+ roleKey?: string;
533
+ }): Promise<Response>;
534
+ /**
535
+ * List all pending invitations for an organization.
536
+ *
537
+ * @param orgIdOrSlug - The organization ID or slug.
538
+ * @returns The raw `Response` from the AuthGate proxy.
539
+ */
540
+ listOrgInvitations(orgIdOrSlug: string): Promise<Response>;
541
+ /**
542
+ * Revoke a pending organization invitation.
543
+ *
544
+ * @param orgIdOrSlug - The organization ID or slug.
545
+ * @param invitationId - The invitation ID to revoke.
546
+ * @returns The raw `Response` from the AuthGate proxy.
547
+ */
548
+ revokeOrgInvitation(orgIdOrSlug: string, invitationId: string): Promise<Response>;
549
+ /**
550
+ * Accept an organization invitation using a token.
551
+ *
552
+ * @param data - The invitation token received via email.
553
+ * @returns The raw `Response` from the AuthGate proxy.
554
+ */
555
+ acceptOrgInvitation(data: {
556
+ token: string;
557
+ }): Promise<Response>;
558
+ /**
559
+ * Leave an organization as the current user.
560
+ *
561
+ * @param orgIdOrSlug - The organization ID or slug.
562
+ * @returns The raw `Response` from the AuthGate proxy.
563
+ */
564
+ leaveOrg(orgIdOrSlug: string): Promise<Response>;
451
565
  /** The name of the session cookie (default: `"__authgate"`). */
452
566
  get cookieName(): string;
453
567
  /** The name of the OAuth nonce cookie (`"__authgate_nonce"`). */
@@ -591,15 +705,31 @@ interface BillingPrice {
591
705
  interval: "daily" | "weekly" | "monthly" | "yearly";
592
706
  intervalCount: number;
593
707
  }
708
+ /** A single item within a subscription (price + product). */
709
+ interface BillingSubscriptionItem {
710
+ id: string;
711
+ quantity: number;
712
+ price: BillingPrice;
713
+ product: {
714
+ id: string;
715
+ name: string;
716
+ description: string | null;
717
+ features: string[];
718
+ };
719
+ }
594
720
  /** An active subscription for an end user. */
595
721
  interface BillingSubscription {
596
722
  id: string;
597
723
  status: "active" | "past_due" | "canceled" | "paused" | "trialing" | "unpaid";
724
+ /** Convenience: derived from the first subscription item's product. */
598
725
  plan: {
599
726
  id: string;
600
727
  name: string;
601
728
  } | null;
729
+ /** Convenience: derived from the first subscription item's price. */
602
730
  price: BillingPrice | null;
731
+ /** The full list of subscription items returned by the API. */
732
+ items: BillingSubscriptionItem[];
603
733
  currentPeriodStart: string;
604
734
  currentPeriodEnd: string;
605
735
  cancelAtPeriodEnd: boolean;
@@ -610,10 +740,30 @@ interface BillingEntitlement {
610
740
  plan: string | null;
611
741
  features: string[];
612
742
  status: string | null;
613
- subscription: {
614
- id: string;
615
- currentPeriodEnd: string;
616
- } | null;
743
+ currentPeriodEnd: string | null;
744
+ cancelAtPeriodEnd: boolean;
745
+ }
746
+ /** Typed entitlement detail for a boolean feature. */
747
+ interface BooleanEntitlementDetail {
748
+ type: "boolean";
749
+ feature: string;
750
+ allowed: boolean;
751
+ }
752
+ /** Typed entitlement detail for a metered feature. */
753
+ interface MeteredEntitlementDetail {
754
+ type: "metered";
755
+ feature: string;
756
+ allowed: boolean;
757
+ used: number;
758
+ limit: number;
759
+ remaining: number;
760
+ }
761
+ /** A single feature entitlement detail. */
762
+ type EntitlementDetail = BooleanEntitlementDetail | MeteredEntitlementDetail;
763
+ /** Extended entitlement data with typed feature details. */
764
+ interface BillingEntitlementV2 extends BillingEntitlement {
765
+ /** Typed feature details with metered usage info. */
766
+ featureDetails?: Record<string, EntitlementDetail>;
617
767
  }
618
768
  /** A single usage event to report. */
619
769
  interface UsageEvent {
@@ -638,5 +788,96 @@ declare function hasPlan(entitlements: BillingEntitlement | null | undefined, pl
638
788
  * @returns `true` if the user has the given feature.
639
789
  */
640
790
  declare function hasFeature(entitlements: BillingEntitlement | null | undefined, feature: string): boolean;
791
+ /**
792
+ * Check a specific feature entitlement, returning typed detail with metered usage info.
793
+ *
794
+ * @param entitlements - The extended entitlement object from the billing API.
795
+ * @param feature - The feature name to check (case-insensitive).
796
+ * @returns The typed entitlement detail, or a denied boolean detail if not found.
797
+ */
798
+ declare function checkFeature(entitlements: BillingEntitlementV2 | null | undefined, feature: string): EntitlementDetail;
799
+
800
+ /** An organization within a project. */
801
+ interface Organization {
802
+ id: string;
803
+ name: string;
804
+ slug: string;
805
+ imageUrl: string | null;
806
+ metadata: Record<string, unknown> | null;
807
+ createdAt: string;
808
+ }
809
+ /** A role definition with its permissions. */
810
+ interface OrgRole {
811
+ key: string;
812
+ name: string;
813
+ permissions: string[];
814
+ }
815
+ /** The current user's membership in an organization. */
816
+ interface OrgMembership {
817
+ id: string;
818
+ orgId: string;
819
+ role: OrgRole;
820
+ createdAt: string;
821
+ }
822
+ /** A member of an organization with user details. */
823
+ interface OrgMember {
824
+ id: string;
825
+ endUserId: string;
826
+ name: string | null;
827
+ email: string | null;
828
+ avatarUrl: string | null;
829
+ role: OrgRole;
830
+ createdAt: string;
831
+ }
832
+ /** An invitation to join an organization. */
833
+ interface OrgInvitation {
834
+ id: string;
835
+ email: string;
836
+ roleKey: string | null;
837
+ status: "pending" | "accepted" | "revoked" | "expired";
838
+ expiresAt: string;
839
+ createdAt: string;
840
+ }
841
+ /** An organization paired with the current user's membership. */
842
+ interface OrgWithMembership {
843
+ organization: Organization;
844
+ membership: OrgMembership;
845
+ }
846
+ /**
847
+ * Check whether a membership includes a specific permission.
848
+ *
849
+ * Supports wildcard matching:
850
+ * - `"*"` matches all permissions.
851
+ * - `"resource:*"` matches any permission starting with `"resource:"`.
852
+ *
853
+ * @param membership - The user's org membership (or null).
854
+ * @param permission - The permission string to check, e.g. `"documents:write"`.
855
+ * @returns `true` if the membership grants the permission.
856
+ */
857
+ declare function hasPermission(membership: OrgMembership | null | undefined, permission: string): boolean;
858
+ /**
859
+ * Check whether a membership has a specific role key.
860
+ *
861
+ * @param membership - The user's org membership (or null).
862
+ * @param roleKey - The role key to check, e.g. `"admin"`.
863
+ * @returns `true` if the membership's role key matches.
864
+ */
865
+ declare function hasRole(membership: OrgMembership | null | undefined, roleKey: string): boolean;
866
+ /**
867
+ * Check whether a membership has at least one of the given permissions.
868
+ *
869
+ * @param membership - The user's org membership (or null).
870
+ * @param permissions - Array of permission strings.
871
+ * @returns `true` if at least one permission is granted.
872
+ */
873
+ declare function hasAnyPermission(membership: OrgMembership | null | undefined, permissions: string[]): boolean;
874
+ /**
875
+ * Check whether a membership has all of the given permissions.
876
+ *
877
+ * @param membership - The user's org membership (or null).
878
+ * @param permissions - Array of permission strings.
879
+ * @returns `true` if every permission is granted.
880
+ */
881
+ declare function hasAllPermissions(membership: OrgMembership | null | undefined, permissions: string[]): boolean;
641
882
 
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 };
883
+ export { AuthGateClient, type AuthGateConfig, AuthGateError, type AuthGateUser, type BackupCodesResponse, type BillingEntitlement, type BillingEntitlementV2, type BillingPlan, type BillingPrice, type BillingSubscription, type BillingSubscriptionItem, type BooleanEntitlementDetail, ConfigurationError, type CookieOptions, DEFAULT_COOKIE_NAME, type EntitlementDetail, InvalidStateError, type MeteredEntitlementDetail, type MfaChallengeResponse, type MfaStatus, NONCE_COOKIE_NAME, type OAuthProvider, type OrgInvitation, type OrgMember, type OrgMembership, type OrgRole, type OrgWithMembership, type Organization, REFRESH_TOKEN_COOKIE_NAME, SESSION_MAX_AGE, STATE_TTL_MS, SUPPORTED_PROVIDERS, SessionDecryptionError, type SessionPayload, TokenVerificationError, type TokenVerifyResult, type TotpSetupResponse, type UsageEvent, checkFeature, createAuthGateClient, hasAllPermissions, hasAnyPermission, hasFeature, hasPermission, hasPlan, hasRole };
package/dist/index.d.ts CHANGED
@@ -448,6 +448,120 @@ declare class AuthGateClient {
448
448
  * @returns The raw `Response`.
449
449
  */
450
450
  mfaSmsSendCode(challenge: string): Promise<Response>;
451
+ /**
452
+ * Create a new organization.
453
+ *
454
+ * @param data - Organization creation data including name, slug, optional image URL, and metadata.
455
+ * @returns The raw `Response` from the AuthGate proxy.
456
+ */
457
+ createOrg(data: {
458
+ name: string;
459
+ slug: string;
460
+ imageUrl?: string;
461
+ metadata?: Record<string, unknown>;
462
+ }): Promise<Response>;
463
+ /**
464
+ * List all organizations accessible to the current project.
465
+ *
466
+ * @returns The raw `Response` from the AuthGate proxy.
467
+ */
468
+ listOrgs(): Promise<Response>;
469
+ /**
470
+ * Get a single organization by ID or slug.
471
+ *
472
+ * @param orgIdOrSlug - The organization ID or slug.
473
+ * @returns The raw `Response` from the AuthGate proxy.
474
+ */
475
+ getOrg(orgIdOrSlug: string): Promise<Response>;
476
+ /**
477
+ * Update an organization's details.
478
+ *
479
+ * @param orgIdOrSlug - The organization ID or slug.
480
+ * @param data - Fields to update. All fields are optional.
481
+ * @returns The raw `Response` from the AuthGate proxy.
482
+ */
483
+ updateOrg(orgIdOrSlug: string, data: {
484
+ name?: string;
485
+ slug?: string;
486
+ imageUrl?: string;
487
+ maxMembers?: number | null;
488
+ metadata?: Record<string, unknown>;
489
+ }): Promise<Response>;
490
+ /**
491
+ * Delete an organization.
492
+ *
493
+ * @param orgIdOrSlug - The organization ID or slug.
494
+ * @returns The raw `Response` from the AuthGate proxy.
495
+ */
496
+ deleteOrg(orgIdOrSlug: string): Promise<Response>;
497
+ /**
498
+ * List all members of an organization.
499
+ *
500
+ * @param orgIdOrSlug - The organization ID or slug.
501
+ * @returns The raw `Response` from the AuthGate proxy.
502
+ */
503
+ listOrgMembers(orgIdOrSlug: string): Promise<Response>;
504
+ /**
505
+ * Update a member's role within an organization.
506
+ *
507
+ * @param orgIdOrSlug - The organization ID or slug.
508
+ * @param memberId - The member's user ID.
509
+ * @param data - The new role to assign.
510
+ * @returns The raw `Response` from the AuthGate proxy.
511
+ */
512
+ updateOrgMember(orgIdOrSlug: string, memberId: string, data: {
513
+ roleKey: string;
514
+ }): Promise<Response>;
515
+ /**
516
+ * Remove a member from an organization.
517
+ *
518
+ * @param orgIdOrSlug - The organization ID or slug.
519
+ * @param memberId - The member's user ID.
520
+ * @returns The raw `Response` from the AuthGate proxy.
521
+ */
522
+ removeOrgMember(orgIdOrSlug: string, memberId: string): Promise<Response>;
523
+ /**
524
+ * Invite a user to an organization by email.
525
+ *
526
+ * @param orgIdOrSlug - The organization ID or slug.
527
+ * @param data - The invitee's email and optional role.
528
+ * @returns The raw `Response` from the AuthGate proxy.
529
+ */
530
+ inviteToOrg(orgIdOrSlug: string, data: {
531
+ email: string;
532
+ roleKey?: string;
533
+ }): Promise<Response>;
534
+ /**
535
+ * List all pending invitations for an organization.
536
+ *
537
+ * @param orgIdOrSlug - The organization ID or slug.
538
+ * @returns The raw `Response` from the AuthGate proxy.
539
+ */
540
+ listOrgInvitations(orgIdOrSlug: string): Promise<Response>;
541
+ /**
542
+ * Revoke a pending organization invitation.
543
+ *
544
+ * @param orgIdOrSlug - The organization ID or slug.
545
+ * @param invitationId - The invitation ID to revoke.
546
+ * @returns The raw `Response` from the AuthGate proxy.
547
+ */
548
+ revokeOrgInvitation(orgIdOrSlug: string, invitationId: string): Promise<Response>;
549
+ /**
550
+ * Accept an organization invitation using a token.
551
+ *
552
+ * @param data - The invitation token received via email.
553
+ * @returns The raw `Response` from the AuthGate proxy.
554
+ */
555
+ acceptOrgInvitation(data: {
556
+ token: string;
557
+ }): Promise<Response>;
558
+ /**
559
+ * Leave an organization as the current user.
560
+ *
561
+ * @param orgIdOrSlug - The organization ID or slug.
562
+ * @returns The raw `Response` from the AuthGate proxy.
563
+ */
564
+ leaveOrg(orgIdOrSlug: string): Promise<Response>;
451
565
  /** The name of the session cookie (default: `"__authgate"`). */
452
566
  get cookieName(): string;
453
567
  /** The name of the OAuth nonce cookie (`"__authgate_nonce"`). */
@@ -591,15 +705,31 @@ interface BillingPrice {
591
705
  interval: "daily" | "weekly" | "monthly" | "yearly";
592
706
  intervalCount: number;
593
707
  }
708
+ /** A single item within a subscription (price + product). */
709
+ interface BillingSubscriptionItem {
710
+ id: string;
711
+ quantity: number;
712
+ price: BillingPrice;
713
+ product: {
714
+ id: string;
715
+ name: string;
716
+ description: string | null;
717
+ features: string[];
718
+ };
719
+ }
594
720
  /** An active subscription for an end user. */
595
721
  interface BillingSubscription {
596
722
  id: string;
597
723
  status: "active" | "past_due" | "canceled" | "paused" | "trialing" | "unpaid";
724
+ /** Convenience: derived from the first subscription item's product. */
598
725
  plan: {
599
726
  id: string;
600
727
  name: string;
601
728
  } | null;
729
+ /** Convenience: derived from the first subscription item's price. */
602
730
  price: BillingPrice | null;
731
+ /** The full list of subscription items returned by the API. */
732
+ items: BillingSubscriptionItem[];
603
733
  currentPeriodStart: string;
604
734
  currentPeriodEnd: string;
605
735
  cancelAtPeriodEnd: boolean;
@@ -610,10 +740,30 @@ interface BillingEntitlement {
610
740
  plan: string | null;
611
741
  features: string[];
612
742
  status: string | null;
613
- subscription: {
614
- id: string;
615
- currentPeriodEnd: string;
616
- } | null;
743
+ currentPeriodEnd: string | null;
744
+ cancelAtPeriodEnd: boolean;
745
+ }
746
+ /** Typed entitlement detail for a boolean feature. */
747
+ interface BooleanEntitlementDetail {
748
+ type: "boolean";
749
+ feature: string;
750
+ allowed: boolean;
751
+ }
752
+ /** Typed entitlement detail for a metered feature. */
753
+ interface MeteredEntitlementDetail {
754
+ type: "metered";
755
+ feature: string;
756
+ allowed: boolean;
757
+ used: number;
758
+ limit: number;
759
+ remaining: number;
760
+ }
761
+ /** A single feature entitlement detail. */
762
+ type EntitlementDetail = BooleanEntitlementDetail | MeteredEntitlementDetail;
763
+ /** Extended entitlement data with typed feature details. */
764
+ interface BillingEntitlementV2 extends BillingEntitlement {
765
+ /** Typed feature details with metered usage info. */
766
+ featureDetails?: Record<string, EntitlementDetail>;
617
767
  }
618
768
  /** A single usage event to report. */
619
769
  interface UsageEvent {
@@ -638,5 +788,96 @@ declare function hasPlan(entitlements: BillingEntitlement | null | undefined, pl
638
788
  * @returns `true` if the user has the given feature.
639
789
  */
640
790
  declare function hasFeature(entitlements: BillingEntitlement | null | undefined, feature: string): boolean;
791
+ /**
792
+ * Check a specific feature entitlement, returning typed detail with metered usage info.
793
+ *
794
+ * @param entitlements - The extended entitlement object from the billing API.
795
+ * @param feature - The feature name to check (case-insensitive).
796
+ * @returns The typed entitlement detail, or a denied boolean detail if not found.
797
+ */
798
+ declare function checkFeature(entitlements: BillingEntitlementV2 | null | undefined, feature: string): EntitlementDetail;
799
+
800
+ /** An organization within a project. */
801
+ interface Organization {
802
+ id: string;
803
+ name: string;
804
+ slug: string;
805
+ imageUrl: string | null;
806
+ metadata: Record<string, unknown> | null;
807
+ createdAt: string;
808
+ }
809
+ /** A role definition with its permissions. */
810
+ interface OrgRole {
811
+ key: string;
812
+ name: string;
813
+ permissions: string[];
814
+ }
815
+ /** The current user's membership in an organization. */
816
+ interface OrgMembership {
817
+ id: string;
818
+ orgId: string;
819
+ role: OrgRole;
820
+ createdAt: string;
821
+ }
822
+ /** A member of an organization with user details. */
823
+ interface OrgMember {
824
+ id: string;
825
+ endUserId: string;
826
+ name: string | null;
827
+ email: string | null;
828
+ avatarUrl: string | null;
829
+ role: OrgRole;
830
+ createdAt: string;
831
+ }
832
+ /** An invitation to join an organization. */
833
+ interface OrgInvitation {
834
+ id: string;
835
+ email: string;
836
+ roleKey: string | null;
837
+ status: "pending" | "accepted" | "revoked" | "expired";
838
+ expiresAt: string;
839
+ createdAt: string;
840
+ }
841
+ /** An organization paired with the current user's membership. */
842
+ interface OrgWithMembership {
843
+ organization: Organization;
844
+ membership: OrgMembership;
845
+ }
846
+ /**
847
+ * Check whether a membership includes a specific permission.
848
+ *
849
+ * Supports wildcard matching:
850
+ * - `"*"` matches all permissions.
851
+ * - `"resource:*"` matches any permission starting with `"resource:"`.
852
+ *
853
+ * @param membership - The user's org membership (or null).
854
+ * @param permission - The permission string to check, e.g. `"documents:write"`.
855
+ * @returns `true` if the membership grants the permission.
856
+ */
857
+ declare function hasPermission(membership: OrgMembership | null | undefined, permission: string): boolean;
858
+ /**
859
+ * Check whether a membership has a specific role key.
860
+ *
861
+ * @param membership - The user's org membership (or null).
862
+ * @param roleKey - The role key to check, e.g. `"admin"`.
863
+ * @returns `true` if the membership's role key matches.
864
+ */
865
+ declare function hasRole(membership: OrgMembership | null | undefined, roleKey: string): boolean;
866
+ /**
867
+ * Check whether a membership has at least one of the given permissions.
868
+ *
869
+ * @param membership - The user's org membership (or null).
870
+ * @param permissions - Array of permission strings.
871
+ * @returns `true` if at least one permission is granted.
872
+ */
873
+ declare function hasAnyPermission(membership: OrgMembership | null | undefined, permissions: string[]): boolean;
874
+ /**
875
+ * Check whether a membership has all of the given permissions.
876
+ *
877
+ * @param membership - The user's org membership (or null).
878
+ * @param permissions - Array of permission strings.
879
+ * @returns `true` if every permission is granted.
880
+ */
881
+ declare function hasAllPermissions(membership: OrgMembership | null | undefined, permissions: string[]): boolean;
641
882
 
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 };
883
+ export { AuthGateClient, type AuthGateConfig, AuthGateError, type AuthGateUser, type BackupCodesResponse, type BillingEntitlement, type BillingEntitlementV2, type BillingPlan, type BillingPrice, type BillingSubscription, type BillingSubscriptionItem, type BooleanEntitlementDetail, ConfigurationError, type CookieOptions, DEFAULT_COOKIE_NAME, type EntitlementDetail, InvalidStateError, type MeteredEntitlementDetail, type MfaChallengeResponse, type MfaStatus, NONCE_COOKIE_NAME, type OAuthProvider, type OrgInvitation, type OrgMember, type OrgMembership, type OrgRole, type OrgWithMembership, type Organization, REFRESH_TOKEN_COOKIE_NAME, SESSION_MAX_AGE, STATE_TTL_MS, SUPPORTED_PROVIDERS, SessionDecryptionError, type SessionPayload, TokenVerificationError, type TokenVerifyResult, type TotpSetupResponse, type UsageEvent, checkFeature, createAuthGateClient, hasAllPermissions, hasAnyPermission, hasFeature, hasPermission, hasPlan, hasRole };
package/dist/index.mjs CHANGED
@@ -866,6 +866,253 @@ var AuthGateClient = class {
866
866
  });
867
867
  }
868
868
  // ---------------------------------------------------------------------------
869
+ // Organizations
870
+ // ---------------------------------------------------------------------------
871
+ /**
872
+ * Create a new organization.
873
+ *
874
+ * @param data - Organization creation data including name, slug, optional image URL, and metadata.
875
+ * @returns The raw `Response` from the AuthGate proxy.
876
+ */
877
+ async createOrg(data) {
878
+ return fetch(`${this.config.baseUrl}/api/proxy/orgs`, {
879
+ method: "POST",
880
+ headers: {
881
+ Authorization: `Bearer ${this.config.apiKey}`,
882
+ "Content-Type": "application/json"
883
+ },
884
+ body: JSON.stringify({
885
+ name: data.name,
886
+ slug: data.slug,
887
+ image_url: data.imageUrl,
888
+ metadata: data.metadata
889
+ })
890
+ });
891
+ }
892
+ /**
893
+ * List all organizations accessible to the current project.
894
+ *
895
+ * @returns The raw `Response` from the AuthGate proxy.
896
+ */
897
+ async listOrgs() {
898
+ return fetch(`${this.config.baseUrl}/api/proxy/orgs`, {
899
+ method: "GET",
900
+ headers: {
901
+ Authorization: `Bearer ${this.config.apiKey}`
902
+ }
903
+ });
904
+ }
905
+ /**
906
+ * Get a single organization by ID or slug.
907
+ *
908
+ * @param orgIdOrSlug - The organization ID or slug.
909
+ * @returns The raw `Response` from the AuthGate proxy.
910
+ */
911
+ async getOrg(orgIdOrSlug) {
912
+ return fetch(`${this.config.baseUrl}/api/proxy/orgs/${orgIdOrSlug}`, {
913
+ method: "GET",
914
+ headers: {
915
+ Authorization: `Bearer ${this.config.apiKey}`
916
+ }
917
+ });
918
+ }
919
+ /**
920
+ * Update an organization's details.
921
+ *
922
+ * @param orgIdOrSlug - The organization ID or slug.
923
+ * @param data - Fields to update. All fields are optional.
924
+ * @returns The raw `Response` from the AuthGate proxy.
925
+ */
926
+ async updateOrg(orgIdOrSlug, data) {
927
+ return fetch(
928
+ `${this.config.baseUrl}/api/proxy/orgs/${orgIdOrSlug}`,
929
+ {
930
+ method: "PATCH",
931
+ headers: {
932
+ Authorization: `Bearer ${this.config.apiKey}`,
933
+ "Content-Type": "application/json"
934
+ },
935
+ body: JSON.stringify({
936
+ name: data.name,
937
+ slug: data.slug,
938
+ image_url: data.imageUrl,
939
+ max_members: data.maxMembers,
940
+ metadata: data.metadata
941
+ })
942
+ }
943
+ );
944
+ }
945
+ /**
946
+ * Delete an organization.
947
+ *
948
+ * @param orgIdOrSlug - The organization ID or slug.
949
+ * @returns The raw `Response` from the AuthGate proxy.
950
+ */
951
+ async deleteOrg(orgIdOrSlug) {
952
+ return fetch(`${this.config.baseUrl}/api/proxy/orgs/${orgIdOrSlug}`, {
953
+ method: "DELETE",
954
+ headers: {
955
+ Authorization: `Bearer ${this.config.apiKey}`
956
+ }
957
+ });
958
+ }
959
+ /**
960
+ * List all members of an organization.
961
+ *
962
+ * @param orgIdOrSlug - The organization ID or slug.
963
+ * @returns The raw `Response` from the AuthGate proxy.
964
+ */
965
+ async listOrgMembers(orgIdOrSlug) {
966
+ return fetch(
967
+ `${this.config.baseUrl}/api/proxy/orgs/${orgIdOrSlug}/members`,
968
+ {
969
+ method: "GET",
970
+ headers: {
971
+ Authorization: `Bearer ${this.config.apiKey}`
972
+ }
973
+ }
974
+ );
975
+ }
976
+ /**
977
+ * Update a member's role within an organization.
978
+ *
979
+ * @param orgIdOrSlug - The organization ID or slug.
980
+ * @param memberId - The member's user ID.
981
+ * @param data - The new role to assign.
982
+ * @returns The raw `Response` from the AuthGate proxy.
983
+ */
984
+ async updateOrgMember(orgIdOrSlug, memberId, data) {
985
+ return fetch(
986
+ `${this.config.baseUrl}/api/proxy/orgs/${orgIdOrSlug}/members/${memberId}`,
987
+ {
988
+ method: "PATCH",
989
+ headers: {
990
+ Authorization: `Bearer ${this.config.apiKey}`,
991
+ "Content-Type": "application/json"
992
+ },
993
+ body: JSON.stringify({
994
+ role_key: data.roleKey
995
+ })
996
+ }
997
+ );
998
+ }
999
+ /**
1000
+ * Remove a member from an organization.
1001
+ *
1002
+ * @param orgIdOrSlug - The organization ID or slug.
1003
+ * @param memberId - The member's user ID.
1004
+ * @returns The raw `Response` from the AuthGate proxy.
1005
+ */
1006
+ async removeOrgMember(orgIdOrSlug, memberId) {
1007
+ return fetch(
1008
+ `${this.config.baseUrl}/api/proxy/orgs/${orgIdOrSlug}/members/${memberId}`,
1009
+ {
1010
+ method: "DELETE",
1011
+ headers: {
1012
+ Authorization: `Bearer ${this.config.apiKey}`
1013
+ }
1014
+ }
1015
+ );
1016
+ }
1017
+ /**
1018
+ * Invite a user to an organization by email.
1019
+ *
1020
+ * @param orgIdOrSlug - The organization ID or slug.
1021
+ * @param data - The invitee's email and optional role.
1022
+ * @returns The raw `Response` from the AuthGate proxy.
1023
+ */
1024
+ async inviteToOrg(orgIdOrSlug, data) {
1025
+ return fetch(
1026
+ `${this.config.baseUrl}/api/proxy/orgs/${orgIdOrSlug}/invitations`,
1027
+ {
1028
+ method: "POST",
1029
+ headers: {
1030
+ Authorization: `Bearer ${this.config.apiKey}`,
1031
+ "Content-Type": "application/json"
1032
+ },
1033
+ body: JSON.stringify({
1034
+ email: data.email,
1035
+ role_key: data.roleKey
1036
+ })
1037
+ }
1038
+ );
1039
+ }
1040
+ /**
1041
+ * List all pending invitations for an organization.
1042
+ *
1043
+ * @param orgIdOrSlug - The organization ID or slug.
1044
+ * @returns The raw `Response` from the AuthGate proxy.
1045
+ */
1046
+ async listOrgInvitations(orgIdOrSlug) {
1047
+ return fetch(
1048
+ `${this.config.baseUrl}/api/proxy/orgs/${orgIdOrSlug}/invitations`,
1049
+ {
1050
+ method: "GET",
1051
+ headers: {
1052
+ Authorization: `Bearer ${this.config.apiKey}`
1053
+ }
1054
+ }
1055
+ );
1056
+ }
1057
+ /**
1058
+ * Revoke a pending organization invitation.
1059
+ *
1060
+ * @param orgIdOrSlug - The organization ID or slug.
1061
+ * @param invitationId - The invitation ID to revoke.
1062
+ * @returns The raw `Response` from the AuthGate proxy.
1063
+ */
1064
+ async revokeOrgInvitation(orgIdOrSlug, invitationId) {
1065
+ return fetch(
1066
+ `${this.config.baseUrl}/api/proxy/orgs/${orgIdOrSlug}/invitations/${invitationId}`,
1067
+ {
1068
+ method: "DELETE",
1069
+ headers: {
1070
+ Authorization: `Bearer ${this.config.apiKey}`
1071
+ }
1072
+ }
1073
+ );
1074
+ }
1075
+ /**
1076
+ * Accept an organization invitation using a token.
1077
+ *
1078
+ * @param data - The invitation token received via email.
1079
+ * @returns The raw `Response` from the AuthGate proxy.
1080
+ */
1081
+ async acceptOrgInvitation(data) {
1082
+ return fetch(
1083
+ `${this.config.baseUrl}/api/proxy/orgs/invitations/accept`,
1084
+ {
1085
+ method: "POST",
1086
+ headers: {
1087
+ Authorization: `Bearer ${this.config.apiKey}`,
1088
+ "Content-Type": "application/json"
1089
+ },
1090
+ body: JSON.stringify({
1091
+ token: data.token
1092
+ })
1093
+ }
1094
+ );
1095
+ }
1096
+ /**
1097
+ * Leave an organization as the current user.
1098
+ *
1099
+ * @param orgIdOrSlug - The organization ID or slug.
1100
+ * @returns The raw `Response` from the AuthGate proxy.
1101
+ */
1102
+ async leaveOrg(orgIdOrSlug) {
1103
+ return fetch(
1104
+ `${this.config.baseUrl}/api/proxy/orgs/${orgIdOrSlug}/leave`,
1105
+ {
1106
+ method: "POST",
1107
+ headers: {
1108
+ Authorization: `Bearer ${this.config.apiKey}`,
1109
+ "Content-Type": "application/json"
1110
+ },
1111
+ body: "{}"
1112
+ }
1113
+ );
1114
+ }
1115
+ // ---------------------------------------------------------------------------
869
1116
  // Cookie config accessors
870
1117
  // ---------------------------------------------------------------------------
871
1118
  /** The name of the session cookie (default: `"__authgate"`). */
@@ -989,6 +1236,55 @@ function hasFeature(entitlements, feature) {
989
1236
  const lower = feature.toLowerCase();
990
1237
  return entitlements.features.some((f) => f.toLowerCase() === lower);
991
1238
  }
1239
+ function checkFeature(entitlements, feature) {
1240
+ if (!(entitlements == null ? void 0 : entitlements.featureDetails)) {
1241
+ const allowed = hasFeature(entitlements, feature);
1242
+ return { type: "boolean", feature, allowed };
1243
+ }
1244
+ const lower = feature.toLowerCase();
1245
+ const key = Object.keys(entitlements.featureDetails).find(
1246
+ (k) => k.toLowerCase() === lower
1247
+ );
1248
+ if (key) return entitlements.featureDetails[key];
1249
+ return { type: "boolean", feature, allowed: false };
1250
+ }
1251
+
1252
+ // src/organizations.ts
1253
+ function hasPermission(membership, permission) {
1254
+ var _a;
1255
+ if (!((_a = membership == null ? void 0 : membership.role) == null ? void 0 : _a.permissions)) return false;
1256
+ return matchesPermission(membership.role.permissions, permission);
1257
+ }
1258
+ function hasRole(membership, roleKey) {
1259
+ var _a;
1260
+ if (!((_a = membership == null ? void 0 : membership.role) == null ? void 0 : _a.key)) return false;
1261
+ return membership.role.key === roleKey;
1262
+ }
1263
+ function hasAnyPermission(membership, permissions) {
1264
+ var _a;
1265
+ if (!((_a = membership == null ? void 0 : membership.role) == null ? void 0 : _a.permissions)) return false;
1266
+ return permissions.some(
1267
+ (p) => matchesPermission(membership.role.permissions, p)
1268
+ );
1269
+ }
1270
+ function hasAllPermissions(membership, permissions) {
1271
+ var _a;
1272
+ if (!((_a = membership == null ? void 0 : membership.role) == null ? void 0 : _a.permissions)) return false;
1273
+ return permissions.every(
1274
+ (p) => matchesPermission(membership.role.permissions, p)
1275
+ );
1276
+ }
1277
+ function matchesPermission(granted, required) {
1278
+ for (const perm of granted) {
1279
+ if (perm === "*") return true;
1280
+ if (perm === required) return true;
1281
+ if (perm.endsWith(":*")) {
1282
+ const prefix = perm.slice(0, -1);
1283
+ if (required.startsWith(prefix)) return true;
1284
+ }
1285
+ }
1286
+ return false;
1287
+ }
992
1288
  export {
993
1289
  AuthGateClient,
994
1290
  AuthGateError,
@@ -1002,7 +1298,12 @@ export {
1002
1298
  SUPPORTED_PROVIDERS,
1003
1299
  SessionDecryptionError,
1004
1300
  TokenVerificationError,
1301
+ checkFeature,
1005
1302
  createAuthGateClient,
1303
+ hasAllPermissions,
1304
+ hasAnyPermission,
1006
1305
  hasFeature,
1007
- hasPlan
1306
+ hasPermission,
1307
+ hasPlan,
1308
+ hasRole
1008
1309
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@auth-gate/core",
3
- "version": "0.7.1",
3
+ "version": "0.8.0",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {