@hanzo/iam 0.6.1 → 0.6.2

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/src/react.ts CHANGED
@@ -46,7 +46,7 @@ import type { ReactNode } from "react";
46
46
  import { BrowserIamSdk } from "./browser.js";
47
47
  import type { BrowserIamConfig } from "./browser.js";
48
48
  import { IamClient } from "./client.js";
49
- import type { IamUser, IamOrganization, IamInvitation, IamProject, TokenResponse } from "./types.js";
49
+ import type { IamUser, IamOrganization, IamProject, TokenResponse } from "./types.js";
50
50
 
51
51
  // ---------------------------------------------------------------------------
52
52
  // Types
@@ -405,39 +405,26 @@ export function useOrganizations(): OrgState {
405
405
  const fetchOrgs = async () => {
406
406
  setIsLoading(true);
407
407
 
408
- // 1. Parse JWT claims for user's workspace org (immediate, no API call)
409
- // The user's "owner" is the signup org (for auth). Their personal org
410
- // (name == username) is their actual workspace.
408
+ // 1. Parse JWT sub claim for primary org (immediate, no API call)
411
409
  try {
412
- let b64 = accessToken.split(".")[1].replace(/-/g, "+").replace(/_/g, "/");
413
- while (b64.length % 4) b64 += "=";
414
- const payload = JSON.parse(atob(b64));
415
-
416
- const userOwner = (payload.owner as string) ?? "";
417
- const userName = (payload.name as string) ?? "";
418
- const sub = (payload.sub as string) ?? "";
419
- const isAdmin = !!payload.isAdmin;
420
-
421
- // Personal org is the default workspace
422
- const workspaceOrg = (userName && userName !== userOwner)
423
- ? userName
424
- : userOwner || (sub.includes("/") ? sub.split("/")[0] : "");
425
-
426
- if (workspaceOrg && !cancelled) {
427
- const immediateOrgs: IamOrganization[] = [
428
- { owner: "admin", name: workspaceOrg, displayName: workspaceOrg },
429
- ];
430
- // Admin users also see their signup org (they manage it)
431
- if (isAdmin && userOwner && userOwner !== workspaceOrg) {
432
- immediateOrgs.push({ owner: "admin", name: userOwner, displayName: userOwner });
433
- }
434
- setOrganizations(immediateOrgs);
435
- if (!currentOrgId) {
436
- setCurrentOrgId(workspaceOrg);
437
- try {
438
- localStorage.setItem(STORAGE_ORG_KEY, workspaceOrg);
439
- } catch {
440
- /* ok */
410
+ const payload = JSON.parse(atob(accessToken.split(".")[1]));
411
+ const sub = payload.sub as string;
412
+ if (sub?.includes("/")) {
413
+ const primaryOrg = sub.split("/")[0];
414
+ if (!cancelled) {
415
+ const syntheticOrg: IamOrganization = {
416
+ owner: "admin",
417
+ name: primaryOrg,
418
+ displayName: primaryOrg,
419
+ };
420
+ setOrganizations([syntheticOrg]);
421
+ if (!currentOrgId) {
422
+ setCurrentOrgId(primaryOrg);
423
+ try {
424
+ localStorage.setItem(STORAGE_ORG_KEY, primaryOrg);
425
+ } catch {
426
+ /* ok */
427
+ }
441
428
  }
442
429
  }
443
430
  }
@@ -602,200 +589,6 @@ export function useIamToken(): {
602
589
  };
603
590
  }
604
591
 
605
- // ---------------------------------------------------------------------------
606
- // useOrgManagement
607
- // ---------------------------------------------------------------------------
608
-
609
- export interface OrgManagementState {
610
- /** Create a new organization. */
611
- createOrg: (org: Partial<IamOrganization>) => Promise<void>;
612
- /** Update an existing organization. */
613
- updateOrg: (org: Partial<IamOrganization>) => Promise<void>;
614
- /** Delete an organization by owner and name. */
615
- deleteOrg: (org: { owner: string; name: string }) => Promise<void>;
616
- /** Whether a mutation is in progress. */
617
- isLoading: boolean;
618
- }
619
-
620
- /**
621
- * Manage organization CRUD operations.
622
- *
623
- * Provides create, update, and delete methods that call the IAM API
624
- * using the current user's access token.
625
- */
626
- export function useOrgManagement(): OrgManagementState {
627
- const { config, accessToken } = useIam();
628
- const [isLoading, setIsLoading] = useState(false);
629
-
630
- const client = useMemo(
631
- () =>
632
- new IamClient({
633
- serverUrl: config.serverUrl,
634
- clientId: config.clientId,
635
- }),
636
- [config.serverUrl, config.clientId],
637
- );
638
-
639
- const createOrg = useCallback(
640
- async (org: Partial<IamOrganization>) => {
641
- setIsLoading(true);
642
- try {
643
- await client.createOrganization(org, accessToken ?? undefined);
644
- } finally {
645
- setIsLoading(false);
646
- }
647
- },
648
- [client, accessToken],
649
- );
650
-
651
- const updateOrg = useCallback(
652
- async (org: Partial<IamOrganization>) => {
653
- setIsLoading(true);
654
- try {
655
- await client.updateOrganization(org, accessToken ?? undefined);
656
- } finally {
657
- setIsLoading(false);
658
- }
659
- },
660
- [client, accessToken],
661
- );
662
-
663
- const deleteOrg = useCallback(
664
- async (org: { owner: string; name: string }) => {
665
- setIsLoading(true);
666
- try {
667
- await client.deleteOrganization(org, accessToken ?? undefined);
668
- } finally {
669
- setIsLoading(false);
670
- }
671
- },
672
- [client, accessToken],
673
- );
674
-
675
- return { createOrg, updateOrg, deleteOrg, isLoading };
676
- }
677
-
678
- // ---------------------------------------------------------------------------
679
- // useInvitations
680
- // ---------------------------------------------------------------------------
681
-
682
- export interface InvitationsState {
683
- /** All invitations for the organization. */
684
- invitations: IamInvitation[];
685
- /** Create a new invitation. */
686
- createInvite: (invitation: Partial<IamInvitation>) => Promise<void>;
687
- /** Send an existing invitation. */
688
- sendInvite: (invitation: { owner: string; name: string }) => Promise<void>;
689
- /** Verify an invitation code. */
690
- verifyInvite: (code: string) => Promise<IamInvitation | null>;
691
- /** Whether invitations are loading. */
692
- isLoading: boolean;
693
- /** Re-fetch the invitations list. */
694
- refresh: () => Promise<void>;
695
- }
696
-
697
- /**
698
- * Manage invitations for an organization.
699
- *
700
- * Fetches the invitation list on mount and provides create, send,
701
- * and verify methods using the current user's access token.
702
- */
703
- export function useInvitations(orgName: string): InvitationsState {
704
- const { config, accessToken, isAuthenticated } = useIam();
705
- const [invitations, setInvitations] = useState<IamInvitation[]>([]);
706
- const [isLoading, setIsLoading] = useState(false);
707
-
708
- const client = useMemo(
709
- () =>
710
- new IamClient({
711
- serverUrl: config.serverUrl,
712
- clientId: config.clientId,
713
- }),
714
- [config.serverUrl, config.clientId],
715
- );
716
-
717
- const fetchInvitations = useCallback(async () => {
718
- if (!isAuthenticated || !accessToken || !orgName) return;
719
- setIsLoading(true);
720
- try {
721
- const data = await client.getInvitations(orgName, accessToken);
722
- setInvitations(data);
723
- } catch {
724
- setInvitations([]);
725
- } finally {
726
- setIsLoading(false);
727
- }
728
- }, [client, orgName, accessToken, isAuthenticated]);
729
-
730
- // Fetch invitations on mount and when orgName changes
731
- useEffect(() => {
732
- if (!isAuthenticated || !accessToken || !orgName) {
733
- setInvitations([]);
734
- return;
735
- }
736
-
737
- let cancelled = false;
738
-
739
- const load = async () => {
740
- setIsLoading(true);
741
- try {
742
- const data = await client.getInvitations(orgName, accessToken);
743
- if (!cancelled) setInvitations(data);
744
- } catch {
745
- if (!cancelled) setInvitations([]);
746
- } finally {
747
- if (!cancelled) setIsLoading(false);
748
- }
749
- };
750
-
751
- load();
752
- return () => {
753
- cancelled = true;
754
- };
755
- // eslint-disable-next-line react-hooks/exhaustive-deps
756
- }, [isAuthenticated, accessToken, orgName, config.serverUrl, config.clientId]);
757
-
758
- const createInvite = useCallback(
759
- async (invitation: Partial<IamInvitation>) => {
760
- setIsLoading(true);
761
- try {
762
- await client.createInvitation(invitation, accessToken ?? undefined);
763
- await fetchInvitations();
764
- } finally {
765
- setIsLoading(false);
766
- }
767
- },
768
- [client, accessToken, fetchInvitations],
769
- );
770
-
771
- const sendInvite = useCallback(
772
- async (invitation: { owner: string; name: string }) => {
773
- setIsLoading(true);
774
- try {
775
- await client.sendInvitation(invitation, accessToken ?? undefined);
776
- } finally {
777
- setIsLoading(false);
778
- }
779
- },
780
- [client, accessToken],
781
- );
782
-
783
- const verifyInvite = useCallback(
784
- async (code: string): Promise<IamInvitation | null> => {
785
- setIsLoading(true);
786
- try {
787
- const resp = await client.verifyInvitation(code, accessToken ?? undefined);
788
- return resp.data ?? null;
789
- } finally {
790
- setIsLoading(false);
791
- }
792
- },
793
- [client, accessToken],
794
- );
795
-
796
- return { invitations, createInvite, sendInvite, verifyInvite, isLoading, refresh: fetchInvitations };
797
- }
798
-
799
592
  // Re-export context for advanced use
800
593
  export { IamContext };
801
594
 
@@ -924,403 +717,3 @@ export function OrgProjectSwitcher({
924
717
  : null,
925
718
  );
926
719
  }
927
-
928
- // ---------------------------------------------------------------------------
929
- // UserOrgMenu — shared org switcher + user menu for all Hanzo apps
930
- // ---------------------------------------------------------------------------
931
-
932
- export interface UserOrgMenuProps {
933
- /** Additional CSS class for the outer container. */
934
- className?: string;
935
- /** Called when org changes. Use to sync external state (e.g., tenantStore). */
936
- onOrgChange?: (orgId: string) => void;
937
- /** Called when user clicks logout. */
938
- onLogout?: () => void;
939
- /** Whether to show the "Create Organization" option. Defaults to true. */
940
- showCreateOrg?: boolean;
941
- /** Optional endpoint for org creation (defaults to IAM's /api/add-organization). */
942
- createOrgEndpoint?: string;
943
- }
944
-
945
- /**
946
- * Shared user menu + organization switcher for all Hanzo apps.
947
- *
948
- * Shows current user info (name, email, avatar), a dropdown with org list,
949
- * "Create Organization" option, and logout button. Uses only `@hanzo/iam`
950
- * hooks — no external UI library required.
951
- *
952
- * @example
953
- * ```tsx
954
- * import { UserOrgMenu } from '@hanzo/iam/react'
955
- *
956
- * function TopBar() {
957
- * return (
958
- * <nav>
959
- * <UserOrgMenu
960
- * onOrgChange={(orgId) => myStore.setOrg(orgId)}
961
- * onLogout={() => router.push('/login')}
962
- * />
963
- * </nav>
964
- * )
965
- * }
966
- * ```
967
- */
968
- export function UserOrgMenu({
969
- className = "",
970
- onOrgChange,
971
- onLogout,
972
- showCreateOrg = true,
973
- createOrgEndpoint,
974
- }: UserOrgMenuProps) {
975
- const { config, isAuthenticated, accessToken, user, logout } = useIam();
976
- const orgState = useOrganizations();
977
- const [open, setOpen] = useState(false);
978
- const [createOpen, setCreateOpen] = useState(false);
979
- const [newOrgName, setNewOrgName] = useState("");
980
- const [newOrgDisplay, setNewOrgDisplay] = useState("");
981
- const [creating, setCreating] = useState(false);
982
- const [error, setError] = useState<string | null>(null);
983
- const menuRef = useRef<HTMLDivElement>(null);
984
-
985
- // Close on outside click
986
- useEffect(() => {
987
- const handler = (e: MouseEvent) => {
988
- if (menuRef.current && !menuRef.current.contains(e.target as Node)) {
989
- setOpen(false);
990
- }
991
- };
992
- document.addEventListener("mousedown", handler);
993
- return () => document.removeEventListener("mousedown", handler);
994
- }, []);
995
-
996
- const handleSwitchOrg = useCallback(
997
- (orgId: string) => {
998
- orgState.switchOrg(orgId);
999
- onOrgChange?.(orgId);
1000
- setOpen(false);
1001
- },
1002
- [orgState, onOrgChange],
1003
- );
1004
-
1005
- const handleLogout = useCallback(() => {
1006
- setOpen(false);
1007
- if (onLogout) {
1008
- onLogout();
1009
- } else {
1010
- logout?.();
1011
- }
1012
- }, [onLogout, logout]);
1013
-
1014
- const handleCreateOrg = useCallback(async () => {
1015
- const name = newOrgName.trim();
1016
- if (!name) return;
1017
-
1018
- setCreating(true);
1019
- setError(null);
1020
-
1021
- try {
1022
- const client = new IamClient({
1023
- serverUrl: config.serverUrl,
1024
- clientId: config.clientId,
1025
- });
1026
-
1027
- if (createOrgEndpoint) {
1028
- // Use custom endpoint (e.g., playground's /v1/orgs)
1029
- const res = await fetch(createOrgEndpoint, {
1030
- method: "POST",
1031
- headers: {
1032
- "Content-Type": "application/json",
1033
- ...(accessToken ? { Authorization: `Bearer ${accessToken}` } : {}),
1034
- },
1035
- body: JSON.stringify({
1036
- name,
1037
- displayName: newOrgDisplay.trim() || name,
1038
- }),
1039
- });
1040
- if (!res.ok) {
1041
- const body = await res.json().catch(() => ({}));
1042
- throw new Error(body.error || body.msg || `HTTP ${res.status}`);
1043
- }
1044
- } else {
1045
- // Use IAM directly
1046
- await client.createOrganization(
1047
- { owner: "admin", name, displayName: newOrgDisplay.trim() || name },
1048
- accessToken ?? undefined,
1049
- );
1050
- }
1051
-
1052
- // Switch to new org
1053
- orgState.switchOrg(name);
1054
- onOrgChange?.(name);
1055
- setNewOrgName("");
1056
- setNewOrgDisplay("");
1057
- setCreateOpen(false);
1058
- setOpen(false);
1059
-
1060
- // Reload to refresh org list
1061
- window.location.reload();
1062
- } catch (e) {
1063
- setError(e instanceof Error ? e.message : String(e));
1064
- } finally {
1065
- setCreating(false);
1066
- }
1067
- }, [newOrgName, newOrgDisplay, config, accessToken, createOrgEndpoint, orgState, onOrgChange]);
1068
-
1069
- if (!isAuthenticated) return null;
1070
-
1071
- const orgs = orgState.organizations ?? [];
1072
- const currentLabel =
1073
- orgs.find((o) => o.name === orgState.currentOrgId)?.displayName ??
1074
- orgState.currentOrgId ??
1075
- "Select org";
1076
-
1077
- const userName = user?.displayName || user?.name || user?.email || "User";
1078
- const userEmail = user?.email || "";
1079
- const userAvatar = user?.avatar || "";
1080
-
1081
- // Inline styles (no external CSS dependencies)
1082
- const menuStyle: React.CSSProperties = {
1083
- position: "absolute",
1084
- top: "100%",
1085
- right: 0,
1086
- marginTop: 4,
1087
- minWidth: 240,
1088
- borderRadius: 8,
1089
- border: "1px solid var(--border, #333)",
1090
- background: "var(--popover, #1a1a1a)",
1091
- color: "var(--popover-foreground, #fff)",
1092
- boxShadow: "0 8px 32px rgba(0,0,0,0.4)",
1093
- zIndex: 50,
1094
- overflow: "hidden",
1095
- };
1096
-
1097
- const itemStyle: React.CSSProperties = {
1098
- display: "flex",
1099
- alignItems: "center",
1100
- gap: 8,
1101
- padding: "8px 12px",
1102
- fontSize: 13,
1103
- cursor: "pointer",
1104
- transition: "background 0.1s",
1105
- width: "100%",
1106
- border: "none",
1107
- background: "transparent",
1108
- color: "inherit",
1109
- textAlign: "left",
1110
- };
1111
-
1112
- const activeItemStyle: React.CSSProperties = {
1113
- ...itemStyle,
1114
- background: "var(--accent, #2a2a2a)",
1115
- };
1116
-
1117
- const separatorStyle: React.CSSProperties = {
1118
- height: 1,
1119
- background: "var(--border, #333)",
1120
- margin: "4px 0",
1121
- };
1122
-
1123
- const labelStyle: React.CSSProperties = {
1124
- padding: "6px 12px",
1125
- fontSize: 11,
1126
- fontWeight: 600,
1127
- textTransform: "uppercase" as const,
1128
- letterSpacing: "0.05em",
1129
- color: "var(--muted-foreground, #888)",
1130
- };
1131
-
1132
- return createElement(
1133
- "div",
1134
- { ref: menuRef, className: `relative ${className}`, style: { position: "relative" } },
1135
-
1136
- // Trigger button
1137
- createElement(
1138
- "button",
1139
- {
1140
- onClick: () => setOpen(!open),
1141
- style: {
1142
- display: "flex",
1143
- alignItems: "center",
1144
- gap: 8,
1145
- padding: "6px 10px",
1146
- borderRadius: 6,
1147
- border: "none",
1148
- background: "transparent",
1149
- cursor: "pointer",
1150
- color: "inherit",
1151
- fontSize: 13,
1152
- fontWeight: 500,
1153
- },
1154
- "aria-label": "User menu",
1155
- },
1156
- userAvatar
1157
- ? createElement("img", {
1158
- src: userAvatar,
1159
- alt: userName,
1160
- style: { width: 24, height: 24, borderRadius: "50%", objectFit: "cover" as const },
1161
- })
1162
- : createElement(
1163
- "div",
1164
- {
1165
- style: {
1166
- width: 24,
1167
- height: 24,
1168
- borderRadius: "50%",
1169
- background: "var(--primary, #3b82f6)",
1170
- display: "flex",
1171
- alignItems: "center",
1172
- justifyContent: "center",
1173
- fontSize: 11,
1174
- fontWeight: 600,
1175
- color: "#fff",
1176
- },
1177
- },
1178
- userName.charAt(0).toUpperCase(),
1179
- ),
1180
- createElement("span", { style: { maxWidth: 120, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" as const } }, currentLabel),
1181
- createElement("span", { style: { fontSize: 10, opacity: 0.5 } }, open ? "\u25B2" : "\u25BC"),
1182
- ),
1183
-
1184
- // Dropdown menu
1185
- open &&
1186
- createElement(
1187
- "div",
1188
- { style: menuStyle },
1189
-
1190
- // User info section
1191
- createElement(
1192
- "div",
1193
- { style: { padding: "10px 12px", borderBottom: "1px solid var(--border, #333)" } },
1194
- createElement("div", { style: { fontSize: 13, fontWeight: 600 } }, userName),
1195
- userEmail && createElement("div", { style: { fontSize: 11, opacity: 0.6, marginTop: 2 } }, userEmail),
1196
- ),
1197
-
1198
- // Organization section
1199
- createElement("div", { style: labelStyle }, "Organization"),
1200
- ...orgs.map((org) =>
1201
- createElement(
1202
- "button",
1203
- {
1204
- key: org.name,
1205
- onClick: () => handleSwitchOrg(org.name),
1206
- style: org.name === orgState.currentOrgId ? activeItemStyle : itemStyle,
1207
- onMouseEnter: (e: React.MouseEvent<HTMLButtonElement>) => { (e.target as HTMLElement).style.background = "var(--accent, #2a2a2a)"; },
1208
- onMouseLeave: (e: React.MouseEvent<HTMLButtonElement>) => { if (org.name !== orgState.currentOrgId) (e.target as HTMLElement).style.background = "transparent"; },
1209
- },
1210
- org.name === orgState.currentOrgId ? "\u2713 " : " ",
1211
- org.displayName || org.name,
1212
- ),
1213
- ),
1214
-
1215
- // Create org option
1216
- showCreateOrg &&
1217
- createElement(
1218
- "div",
1219
- null,
1220
- createElement("div", { style: separatorStyle }),
1221
- !createOpen
1222
- ? createElement(
1223
- "button",
1224
- {
1225
- onClick: () => setCreateOpen(true),
1226
- style: itemStyle,
1227
- onMouseEnter: (e: React.MouseEvent<HTMLButtonElement>) => { (e.target as HTMLElement).style.background = "var(--accent, #2a2a2a)"; },
1228
- onMouseLeave: (e: React.MouseEvent<HTMLButtonElement>) => { (e.target as HTMLElement).style.background = "transparent"; },
1229
- },
1230
- "+ Create Organization",
1231
- )
1232
- : createElement(
1233
- "div",
1234
- { style: { padding: "8px 12px" } },
1235
- createElement("input", {
1236
- type: "text",
1237
- placeholder: "org-name",
1238
- value: newOrgName,
1239
- onChange: (e: React.ChangeEvent<HTMLInputElement>) => setNewOrgName(e.target.value),
1240
- style: {
1241
- width: "100%",
1242
- padding: "6px 8px",
1243
- fontSize: 12,
1244
- borderRadius: 4,
1245
- border: "1px solid var(--border, #333)",
1246
- background: "var(--background, #111)",
1247
- color: "inherit",
1248
- marginBottom: 4,
1249
- },
1250
- disabled: creating,
1251
- }),
1252
- createElement("input", {
1253
- type: "text",
1254
- placeholder: "Display Name",
1255
- value: newOrgDisplay,
1256
- onChange: (e: React.ChangeEvent<HTMLInputElement>) => setNewOrgDisplay(e.target.value),
1257
- style: {
1258
- width: "100%",
1259
- padding: "6px 8px",
1260
- fontSize: 12,
1261
- borderRadius: 4,
1262
- border: "1px solid var(--border, #333)",
1263
- background: "var(--background, #111)",
1264
- color: "inherit",
1265
- marginBottom: 4,
1266
- },
1267
- disabled: creating,
1268
- }),
1269
- error && createElement("div", { style: { fontSize: 11, color: "#ef4444", marginBottom: 4 } }, error),
1270
- createElement(
1271
- "div",
1272
- { style: { display: "flex", gap: 4 } },
1273
- createElement(
1274
- "button",
1275
- {
1276
- onClick: handleCreateOrg,
1277
- disabled: creating || !newOrgName.trim(),
1278
- style: {
1279
- flex: 1,
1280
- padding: "5px 8px",
1281
- fontSize: 12,
1282
- borderRadius: 4,
1283
- border: "none",
1284
- background: "var(--primary, #3b82f6)",
1285
- color: "#fff",
1286
- cursor: creating ? "wait" : "pointer",
1287
- opacity: creating || !newOrgName.trim() ? 0.5 : 1,
1288
- },
1289
- },
1290
- creating ? "Creating..." : "Create",
1291
- ),
1292
- createElement(
1293
- "button",
1294
- {
1295
- onClick: () => { setCreateOpen(false); setError(null); },
1296
- style: {
1297
- padding: "5px 8px",
1298
- fontSize: 12,
1299
- borderRadius: 4,
1300
- border: "1px solid var(--border, #333)",
1301
- background: "transparent",
1302
- color: "inherit",
1303
- cursor: "pointer",
1304
- },
1305
- },
1306
- "Cancel",
1307
- ),
1308
- ),
1309
- ),
1310
- ),
1311
-
1312
- // Logout
1313
- createElement("div", { style: separatorStyle }),
1314
- createElement(
1315
- "button",
1316
- {
1317
- onClick: handleLogout,
1318
- style: { ...itemStyle, color: "var(--destructive, #ef4444)" },
1319
- onMouseEnter: (e: React.MouseEvent<HTMLButtonElement>) => { (e.target as HTMLElement).style.background = "var(--accent, #2a2a2a)"; },
1320
- onMouseLeave: (e: React.MouseEvent<HTMLButtonElement>) => { (e.target as HTMLElement).style.background = "transparent"; },
1321
- },
1322
- "Sign out",
1323
- ),
1324
- ),
1325
- );
1326
- }
package/src/types.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Core types for the Hanzo IAM SDK.
3
- * Based on Casdoor data models.
3
+ * Hanzo IAM data models.
4
4
  */
5
5
 
6
6
  // ---------------------------------------------------------------------------
@@ -226,26 +226,6 @@ export type IamOrder = Order;
226
226
  export type IamUsageRecord = UsageRecord;
227
227
  export type IamUsageSummary = UsageSummary;
228
228
 
229
- // ---------------------------------------------------------------------------
230
- // Invitation
231
- // ---------------------------------------------------------------------------
232
-
233
- export type IamInvitation = {
234
- owner: string;
235
- name: string;
236
- displayName?: string;
237
- code: string;
238
- quota: number;
239
- usedCount: number;
240
- application?: string;
241
- email?: string;
242
- phone?: string;
243
- signupGroup?: string;
244
- state?: string;
245
- createdTime?: string;
246
- updatedTime?: string;
247
- };
248
-
249
229
  // ---------------------------------------------------------------------------
250
230
  // Project
251
231
  // ---------------------------------------------------------------------------