@hanzo/iam 0.4.1 → 0.5.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/src/client.ts CHANGED
@@ -7,6 +7,7 @@ import type {
7
7
  IamApiResponse,
8
8
  IamUser,
9
9
  IamOrganization,
10
+ IamInvitation,
10
11
  IamProject,
11
12
  OidcDiscovery,
12
13
  TokenResponse,
@@ -252,12 +253,30 @@ export class IamClient {
252
253
 
253
254
  /** List organizations (for the configured owner). */
254
255
  async getOrganizations(token?: string): Promise<IamOrganization[]> {
256
+ // Try the admin-level endpoint first (returns full org details).
257
+ // Falls back to the public get-organization-names endpoint which
258
+ // returns all org names without requiring admin privileges.
255
259
  const owner = this.orgName ?? "admin";
256
- const resp = await this.request<IamApiResponse<IamOrganization[]>>(
257
- "/api/get-organizations",
258
- { params: { owner }, token },
259
- );
260
- return resp.data ?? [];
260
+ try {
261
+ const resp = await this.request<IamApiResponse<IamOrganization[]>>(
262
+ "/api/get-organizations",
263
+ { params: { owner }, token },
264
+ );
265
+ if (resp.data && resp.data.length > 0) return resp.data;
266
+ } catch {
267
+ // Admin endpoint failed — fall through to public endpoint
268
+ }
269
+
270
+ // Public fallback: get-organization-names (no auth required)
271
+ try {
272
+ const resp = await this.request<IamApiResponse<IamOrganization[]>>(
273
+ "/api/get-organization-names",
274
+ { params: { owner }, token },
275
+ );
276
+ return resp.data ?? [];
277
+ } catch {
278
+ return [];
279
+ }
261
280
  }
262
281
 
263
282
  /** Get a specific organization. */
@@ -289,6 +308,88 @@ export class IamClient {
289
308
  return org ? [org] : [];
290
309
  }
291
310
 
311
+ /** Create a new organization. */
312
+ async createOrganization(
313
+ org: Partial<IamOrganization>,
314
+ token?: string,
315
+ ): Promise<IamApiResponse<IamOrganization>> {
316
+ return this.request<IamApiResponse<IamOrganization>>(
317
+ "/api/add-organization",
318
+ { method: "POST", body: org, token },
319
+ );
320
+ }
321
+
322
+ /** Update an existing organization. */
323
+ async updateOrganization(
324
+ org: Partial<IamOrganization>,
325
+ token?: string,
326
+ ): Promise<IamApiResponse<IamOrganization>> {
327
+ return this.request<IamApiResponse<IamOrganization>>(
328
+ "/api/update-organization",
329
+ { method: "POST", body: org, token },
330
+ );
331
+ }
332
+
333
+ /** Delete an organization by owner and name. */
334
+ async deleteOrganization(
335
+ org: { owner: string; name: string },
336
+ token?: string,
337
+ ): Promise<IamApiResponse<IamOrganization>> {
338
+ return this.request<IamApiResponse<IamOrganization>>(
339
+ "/api/delete-organization",
340
+ { method: "POST", body: org, token },
341
+ );
342
+ }
343
+
344
+ // -----------------------------------------------------------------------
345
+ // Invitation
346
+ // -----------------------------------------------------------------------
347
+
348
+ /** List invitations for an owner (organization). */
349
+ async getInvitations(
350
+ owner: string,
351
+ token?: string,
352
+ ): Promise<IamInvitation[]> {
353
+ const resp = await this.request<IamApiResponse<IamInvitation[]>>(
354
+ "/api/get-invitations",
355
+ { params: { owner }, token },
356
+ );
357
+ return resp.data ?? [];
358
+ }
359
+
360
+ /** Create a new invitation. */
361
+ async createInvitation(
362
+ invitation: Partial<IamInvitation>,
363
+ token?: string,
364
+ ): Promise<IamApiResponse<IamInvitation>> {
365
+ return this.request<IamApiResponse<IamInvitation>>(
366
+ "/api/add-invitation",
367
+ { method: "POST", body: invitation, token },
368
+ );
369
+ }
370
+
371
+ /** Send an invitation by owner and name. */
372
+ async sendInvitation(
373
+ invitation: { owner: string; name: string },
374
+ token?: string,
375
+ ): Promise<IamApiResponse<IamInvitation>> {
376
+ return this.request<IamApiResponse<IamInvitation>>(
377
+ "/api/send-invitation",
378
+ { method: "POST", body: invitation, token },
379
+ );
380
+ }
381
+
382
+ /** Verify an invitation code. */
383
+ async verifyInvitation(
384
+ code: string,
385
+ token?: string,
386
+ ): Promise<IamApiResponse<IamInvitation>> {
387
+ return this.request<IamApiResponse<IamInvitation>>(
388
+ "/api/verify-invitation",
389
+ { params: { code }, token },
390
+ );
391
+ }
392
+
292
393
  // -----------------------------------------------------------------------
293
394
  // Project
294
395
  // -----------------------------------------------------------------------
package/src/index.ts CHANGED
@@ -14,7 +14,7 @@
14
14
  * });
15
15
  *
16
16
  * const billing = new BillingClient({
17
- * commerceUrl: "https://commerce.hanzo.ai",
17
+ * commerceUrl: "https://commerce-api.hanzo.ai/api",
18
18
  * });
19
19
  * ```
20
20
  */
@@ -43,6 +43,7 @@ export type {
43
43
  IamJwtClaims,
44
44
  IamUser,
45
45
  IamOrganization,
46
+ IamInvitation,
46
47
  IamProject,
47
48
  Subscription,
48
49
  Plan,
package/src/nextauth.ts CHANGED
@@ -1,17 +1,17 @@
1
1
  /**
2
- * NextAuth.js / Auth.js provider for IAM (OIDC-based).
2
+ * NextAuth.js provider for Hanzo IAM (OIDC-based).
3
3
  *
4
- * Provides a canonical NextAuth/Auth.js provider configuration
5
- * so all Next.js apps can share one implementation.
4
+ * Consolidates the HanzoIamProvider and IamProvider implementations
5
+ * so all Next.js apps can share one canonical implementation.
6
6
  *
7
7
  * @example
8
8
  * ```ts
9
9
  * // next-auth config
10
- * import { IamProvider } from "@hanzo/iam/nextauth";
10
+ * import { HanzoIamProvider } from "@hanzo/iam/nextauth";
11
11
  *
12
12
  * export default NextAuth({
13
13
  * providers: [
14
- * IamProvider({
14
+ * HanzoIamProvider({
15
15
  * serverUrl: process.env.IAM_SERVER_URL!,
16
16
  * clientId: process.env.IAM_CLIENT_ID!,
17
17
  * clientSecret: process.env.IAM_CLIENT_SECRET!,
@@ -23,7 +23,7 @@
23
23
  * @packageDocumentation
24
24
  */
25
25
 
26
- export interface IamProfile extends Record<string, unknown> {
26
+ interface HanzoIamProfile extends Record<string, unknown> {
27
27
  sub: string;
28
28
  name: string;
29
29
  email: string;
@@ -35,7 +35,7 @@ export interface IamProfile extends Record<string, unknown> {
35
35
  }
36
36
 
37
37
  /**
38
- * NextAuth.js / Auth.js compatible OAuth provider for IAM.
38
+ * NextAuth.js / Auth.js compatible OAuth provider for Hanzo IAM.
39
39
  *
40
40
  * Uses standard OIDC well-known endpoint for automatic configuration.
41
41
  * JWT id_token validation (issuer, audience, signature) is handled by
@@ -43,7 +43,7 @@ export interface IamProfile extends Record<string, unknown> {
43
43
  *
44
44
  * Pass `checks: ["state", "pkce"]` in options for PKCE alignment.
45
45
  */
46
- export function IamProvider<P extends IamProfile>(
46
+ export function HanzoIamProvider<P extends HanzoIamProfile>(
47
47
  options: {
48
48
  serverUrl: string;
49
49
  clientId: string;
@@ -59,8 +59,8 @@ export function IamProvider<P extends IamProfile>(
59
59
  const checks = options.checks ?? ["state"];
60
60
 
61
61
  return {
62
- id: "iam",
63
- name: "IAM",
62
+ id: "hanzo-iam",
63
+ name: "Hanzo IAM",
64
64
  type: "oauth",
65
65
  wellKnown: `${issuer}/.well-known/openid-configuration`,
66
66
  idToken: true,
@@ -88,8 +88,6 @@ export function IamProvider<P extends IamProfile>(
88
88
  };
89
89
  }
90
90
 
91
- // Backwards-compatible aliases
92
- /** @deprecated Use IamProvider instead */
93
- export { IamProvider as HanzoIamProvider };
94
- /** @deprecated Use IamProfile instead */
95
- export type { IamProfile as HanzoIamProfile };
91
+ // Re-export with alias for backwards compat
92
+ export { HanzoIamProvider as IamProvider };
93
+ export type { HanzoIamProfile };