@korajs/auth 0.4.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/README.md CHANGED
@@ -17,6 +17,23 @@ Offline-first authentication for Kora.js applications.
17
17
  - **Passkeys (WebAuthn)** -- passwordless authentication with platform authenticators
18
18
  - **Encrypted token storage** -- AES-256-GCM encryption for sensitive environments
19
19
  - **End-to-end encryption** -- encrypt operation data before sync with `OperationEncryptor`
20
+ - **Sync auth binding** -- `createKoraAuthSync()` wires tokens, JWT scopes, and device node ids to `createApp`
21
+
22
+ The client APIs work in browser, Tauri desktop WebView, and mobile JavaScript environments. For desktop apps, run auth routes on your remote sync/auth server and point `AuthClient.serverUrl` at that server. Email/password auth, token refresh, sync authorization, MFA, organizations, and RBAC work across web and desktop clients. Passkeys should be feature-detected because WebAuthn support depends on the operating system WebView.
23
+
24
+ For production desktop and mobile apps, pass a custom token storage adapter backed by the platform credential store and attach a stable device identity:
25
+
26
+ ```typescript
27
+ import { createKoraAuth } from '@korajs/auth'
28
+
29
+ const authClient = createKoraAuth({
30
+ serverUrl: 'https://acme.example.com',
31
+ credentialStore: secureStore,
32
+ deviceKeyStore,
33
+ })
34
+ ```
35
+
36
+ `createKoraAuth()` uses IndexedDB for the device key pair when available. React Native and other runtimes without IndexedDB should pass a platform-backed `deviceKeyStore`.
20
37
 
21
38
  ## Installation
22
39
 
@@ -29,10 +46,10 @@ pnpm add @korajs/auth
29
46
  ### Client-side (React)
30
47
 
31
48
  ```tsx
32
- import { AuthClient } from '@korajs/auth'
49
+ import { createKoraAuth } from '@korajs/auth'
33
50
  import { AuthProvider, useAuth } from '@korajs/auth/react'
34
51
 
35
- const authClient = new AuthClient({ serverUrl: 'http://localhost:3001' })
52
+ const authClient = createKoraAuth({ serverUrl: 'http://localhost:3001' })
36
53
 
37
54
  function App() {
38
55
  return (
@@ -43,15 +60,20 @@ function App() {
43
60
  }
44
61
 
45
62
  function MyApp() {
46
- const { user, isAuthenticated, isLoading, signIn, signOut, error } = useAuth()
63
+ const { user, isAuthenticated, isLoading, signIn, signInWithOAuth, signOut, error } = useAuth()
47
64
 
48
65
  if (isLoading) return <div>Loading...</div>
49
66
 
50
67
  if (!isAuthenticated) {
51
68
  return (
52
- <button onClick={() => signIn({ email: 'user@example.com', password: 'password' })}>
53
- Sign In
54
- </button>
69
+ <>
70
+ <button onClick={() => signIn({ email: 'user@example.com', password: 'password' })}>
71
+ Sign In
72
+ </button>
73
+ <button onClick={() => signInWithOAuth('google')}>
74
+ Sign In with Google
75
+ </button>
76
+ </>
55
77
  )
56
78
  }
57
79
 
@@ -64,41 +86,66 @@ function MyApp() {
64
86
  }
65
87
  ```
66
88
 
67
- ### Server-side
68
-
69
- ```typescript
70
- import { BuiltInAuthRoutes, InMemoryUserStore, TokenManager } from '@korajs/auth/server'
71
-
72
- const userStore = new InMemoryUserStore()
73
- const tokenManager = new TokenManager({ secret: process.env.AUTH_SECRET! })
74
- const authRoutes = new BuiltInAuthRoutes({ userStore, tokenManager })
89
+ ### Sync integration
75
90
 
76
- // Wire into your HTTP server:
77
- app.post('/auth/signup', async (req, res) => {
78
- const result = await authRoutes.handleSignUp(req.body)
79
- res.status(result.status).json(result.body)
91
+ ```tsx
92
+ import { createKoraAuthSync } from '@korajs/auth'
93
+ import { createApp } from 'korajs'
94
+
95
+ const app = createApp({
96
+ schema,
97
+ sync: {
98
+ url: 'ws://localhost:3001/kora-sync',
99
+ authClient: createKoraAuthSync({ authClient, schema }),
100
+ },
80
101
  })
102
+ ```
81
103
 
82
- app.post('/auth/signin', async (req, res) => {
83
- const result = await authRoutes.handleSignIn(req.body)
84
- res.status(result.status).json(result.body)
104
+ ### Server-side
105
+
106
+ ```typescript
107
+ import {
108
+ createKoraAuthServer,
109
+ createSqliteOAuthStores,
110
+ googleProvider,
111
+ } from '@korajs/auth/server'
112
+
113
+ const oauthStores = await createSqliteOAuthStores({
114
+ filename: './auth.db',
85
115
  })
86
116
 
87
- app.post('/auth/refresh', async (req, res) => {
88
- const result = await authRoutes.handleRefresh(req.body)
89
- res.status(result.status).json(result.body)
117
+ const auth = createKoraAuthServer({
118
+ jwtSecret: process.env.KORA_AUTH_SECRET!,
119
+ oauth: {
120
+ providers: [
121
+ googleProvider({
122
+ clientId: process.env.GOOGLE_CLIENT_ID!,
123
+ clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
124
+ redirectUri: 'https://app.example.com/auth/oauth/google/callback',
125
+ }),
126
+ ],
127
+ stateStore: oauthStores.stateStore,
128
+ linkedIdentityStore: oauthStores.linkedIdentityStore,
129
+ },
90
130
  })
91
131
 
92
- app.get('/auth/me', async (req, res) => {
93
- const token = req.headers.authorization?.replace('Bearer ', '') ?? ''
94
- const result = await authRoutes.handleGetMe(token)
132
+ // Wire into your HTTP server:
133
+ app.all('/auth/*', async (req, res) => {
134
+ const result = await auth.handleRequest({
135
+ method: req.method,
136
+ path: req.path,
137
+ body: req.body,
138
+ headers: req.headers,
139
+ query: req.query,
140
+ ip: req.ip,
141
+ })
95
142
  res.status(result.status).json(result.body)
96
143
  })
97
144
 
98
145
  // Bridge to Kora sync server:
99
146
  const syncServer = new KoraSyncServer({
100
147
  store,
101
- auth: authRoutes.toSyncAuthProvider(),
148
+ auth: auth.auth,
102
149
  })
103
150
  ```
104
151
 
@@ -108,6 +155,8 @@ const syncServer = new KoraSyncServer({
108
155
 
109
156
  | Export | Description |
110
157
  |--------|-------------|
158
+ | `createKoraAuth` | Quickstart client factory with storage and device identity defaults |
159
+ | `createKoraAuthSync` | Sync auth binding for `createApp({ sync: { authClient } })` |
111
160
  | `AuthClient` | Client-side auth manager (sign-up, sign-in, sign-out, token refresh) |
112
161
  | `OrgClient` | Client-side organization management |
113
162
  | `TokenStore` | Client-side token persistence (localStorage) |
@@ -139,10 +188,14 @@ const syncServer = new KoraSyncServer({
139
188
 
140
189
  | Export | Description |
141
190
  |--------|-------------|
191
+ | `createKoraAuthServer` | Quickstart server factory with auth routes and sync provider |
142
192
  | `BuiltInAuthRoutes` | HTTP route handlers for all auth operations |
143
193
  | `TokenManager` | JWT issuing, validation, refresh rotation, revocation |
144
194
  | `InMemoryUserStore` | Dev/test user store |
145
195
  | `InMemoryTokenRevocationStore` | Dev/test token revocation store |
196
+ | `OAuthManager` / provider helpers | OAuth authorization code flow and provider configs |
197
+ | `InMemoryLinkedIdentityStore` | Dev/test OAuth account-linking store |
198
+ | `createSqliteOAuthStores` / `createPostgresOAuthStores` | Durable OAuth state and linked identity stores |
146
199
  | `SessionManager` / `InMemorySessionStore` | Server-side session management |
147
200
  | `TotpManager` / `InMemoryTotpStore` | TOTP MFA with recovery codes |
148
201
  | `OrgRoutes` / `InMemoryOrgStore` | Organization CRUD, invitations, member management |
@@ -0,0 +1,203 @@
1
+ // src/bindings/create-auth-session.ts
2
+ function createAuthSession(client) {
3
+ let state = client.state;
4
+ let isLoading = true;
5
+ let initError = null;
6
+ let lastError = null;
7
+ const listeners = /* @__PURE__ */ new Set();
8
+ let snapshot = buildSnapshot2();
9
+ const refreshSnapshot = () => {
10
+ snapshot = buildSnapshot2();
11
+ };
12
+ const notify = () => {
13
+ refreshSnapshot();
14
+ for (const listener of listeners) {
15
+ listener();
16
+ }
17
+ };
18
+ function buildSnapshot2() {
19
+ return {
20
+ state,
21
+ user: client.currentUser,
22
+ isAuthenticated: state === "authenticated",
23
+ isLoading,
24
+ initError,
25
+ error: lastError
26
+ };
27
+ }
28
+ const captureError = (error) => {
29
+ lastError = error instanceof Error ? error.message : String(error);
30
+ notify();
31
+ };
32
+ const run = async (action) => {
33
+ lastError = null;
34
+ try {
35
+ await action();
36
+ } catch (error) {
37
+ captureError(error);
38
+ }
39
+ };
40
+ const runWithResult = async (action) => {
41
+ lastError = null;
42
+ try {
43
+ return await action();
44
+ } catch (error) {
45
+ captureError(error);
46
+ return null;
47
+ }
48
+ };
49
+ const unsubscribeAuth = client.onAuthChange((nextState) => {
50
+ state = nextState;
51
+ notify();
52
+ });
53
+ void client.initialize().then(() => {
54
+ state = client.state;
55
+ isLoading = false;
56
+ notify();
57
+ }).catch((error) => {
58
+ initError = error instanceof Error ? error : new Error(String(error));
59
+ isLoading = false;
60
+ notify();
61
+ });
62
+ return {
63
+ client,
64
+ getSnapshot: () => snapshot,
65
+ subscribe(listener) {
66
+ listeners.add(listener);
67
+ return () => {
68
+ listeners.delete(listener);
69
+ };
70
+ },
71
+ signUp: (params) => run(async () => {
72
+ await client.signUp(params);
73
+ }),
74
+ signIn: (params) => run(async () => {
75
+ await client.signIn(params);
76
+ }),
77
+ signInWithOAuth: async (provider, options) => {
78
+ lastError = null;
79
+ try {
80
+ return await client.signInWithOAuth(provider, options);
81
+ } catch (error) {
82
+ captureError(error);
83
+ throw error instanceof Error ? error : new Error(String(error));
84
+ }
85
+ },
86
+ completeOAuthSignIn: (provider, params) => run(async () => {
87
+ await client.completeOAuthSignIn(provider, params);
88
+ }),
89
+ getOAuthAuthorizationUrl: async (provider, options) => {
90
+ lastError = null;
91
+ try {
92
+ return await client.getOAuthAuthorizationUrl(provider, options);
93
+ } catch (error) {
94
+ captureError(error);
95
+ throw error instanceof Error ? error : new Error(String(error));
96
+ }
97
+ },
98
+ linkOAuth: (provider, params) => runWithResult(async () => client.linkOAuth(provider, params)),
99
+ listLinkedAccounts: () => runWithResult(async () => client.listLinkedAccounts()).then((value) => value ?? []),
100
+ unlinkOAuth: (provider) => run(async () => {
101
+ await client.unlinkOAuth(provider);
102
+ }),
103
+ signOut: () => run(async () => {
104
+ await client.signOut();
105
+ }),
106
+ destroy() {
107
+ unsubscribeAuth();
108
+ listeners.clear();
109
+ }
110
+ };
111
+ }
112
+
113
+ // src/bindings/create-org-session.ts
114
+ var ROLE_LEVELS = {
115
+ viewer: 10,
116
+ billing: 15,
117
+ member: 20,
118
+ admin: 30,
119
+ owner: 40
120
+ };
121
+ function checkOrgPermission(currentRole, requiredRole) {
122
+ if (!currentRole) return false;
123
+ const currentLevel = ROLE_LEVELS[currentRole] ?? 0;
124
+ const requiredLevel = ROLE_LEVELS[requiredRole] ?? 0;
125
+ return currentLevel >= requiredLevel;
126
+ }
127
+ function createOrgSession(client) {
128
+ let snapshot = buildSnapshot(client);
129
+ const listeners = /* @__PURE__ */ new Set();
130
+ const notify = () => {
131
+ snapshot = buildSnapshot(client);
132
+ for (const listener of listeners) {
133
+ listener();
134
+ }
135
+ };
136
+ const unsubscribeOrgChange = client.onOrgChange(notify);
137
+ return {
138
+ client,
139
+ getSnapshot: () => snapshot,
140
+ subscribe(listener) {
141
+ listeners.add(listener);
142
+ return () => {
143
+ listeners.delete(listener);
144
+ };
145
+ },
146
+ checkPermission(requiredRole) {
147
+ return checkOrgPermission(snapshot.role, requiredRole);
148
+ },
149
+ destroy() {
150
+ unsubscribeOrgChange();
151
+ listeners.clear();
152
+ }
153
+ };
154
+ }
155
+ function buildSnapshot(client) {
156
+ return {
157
+ orgId: client.activeOrgId,
158
+ org: client.activeOrg,
159
+ role: client.activeRole
160
+ };
161
+ }
162
+ function createOrgMembersActions(client, orgId, onError) {
163
+ return {
164
+ async refresh() {
165
+ await client.listMembers(orgId);
166
+ },
167
+ async invite(email, role) {
168
+ try {
169
+ return await client.inviteMember(orgId, { email, role });
170
+ } catch (error) {
171
+ const message = error instanceof Error ? error.message : String(error);
172
+ onError(message);
173
+ throw error;
174
+ }
175
+ },
176
+ async removeMember(userId) {
177
+ try {
178
+ await client.removeMember(orgId, userId);
179
+ } catch (error) {
180
+ onError(error instanceof Error ? error.message : String(error));
181
+ }
182
+ },
183
+ async updateRole(userId, role) {
184
+ try {
185
+ await client.updateMemberRole(orgId, userId, role);
186
+ } catch (error) {
187
+ onError(error instanceof Error ? error.message : String(error));
188
+ }
189
+ }
190
+ };
191
+ }
192
+ async function loadOrgMembers(client, orgId) {
193
+ return client.listMembers(orgId);
194
+ }
195
+
196
+ export {
197
+ createAuthSession,
198
+ checkOrgPermission,
199
+ createOrgSession,
200
+ createOrgMembersActions,
201
+ loadOrgMembers
202
+ };
203
+ //# sourceMappingURL=chunk-7OXBRSJL.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/bindings/create-auth-session.ts","../src/bindings/create-org-session.ts"],"sourcesContent":["import type {\n\tAuthClient,\n\tAuthState,\n\tAuthUser,\n\tLinkedOAuthAccount,\n\tOAuthAuthorizationOptions,\n\tOAuthAuthorizationResult,\n\tOAuthCallbackParams,\n} from '../client/auth-client'\n\nexport interface AuthSessionSnapshot {\n\tstate: AuthState\n\tuser: AuthUser | null\n\tisAuthenticated: boolean\n\tisLoading: boolean\n\tinitError: Error | null\n\terror: string | null\n}\n\nexport interface AuthSession {\n\treadonly client: AuthClient\n\tgetSnapshot(): AuthSessionSnapshot\n\tsubscribe(listener: () => void): () => void\n\tsignUp(params: {\n\t\temail: string\n\t\tpassword: string\n\t\tname?: string\n\t\tdeviceId?: string\n\t\tdevicePublicKey?: string\n\t}): Promise<void>\n\tsignIn(params: {\n\t\temail: string\n\t\tpassword: string\n\t\tdeviceId?: string\n\t\tdevicePublicKey?: string\n\t}): Promise<void>\n\tsignInWithOAuth(\n\t\tprovider: string,\n\t\toptions?: OAuthAuthorizationOptions,\n\t): Promise<OAuthAuthorizationResult>\n\tcompleteOAuthSignIn(provider: string, params: OAuthCallbackParams): Promise<void>\n\tgetOAuthAuthorizationUrl(\n\t\tprovider: string,\n\t\toptions?: OAuthAuthorizationOptions,\n\t): Promise<OAuthAuthorizationResult>\n\tlinkOAuth(provider: string, params: OAuthCallbackParams): Promise<LinkedOAuthAccount | null>\n\tlistLinkedAccounts(): Promise<LinkedOAuthAccount[]>\n\tunlinkOAuth(provider: string): Promise<void>\n\tsignOut(): Promise<void>\n\tdestroy(): void\n}\n\n/**\n * Framework-agnostic auth session: initialization, reactive snapshot, and client methods.\n */\nexport function createAuthSession(client: AuthClient): AuthSession {\n\tlet state: AuthState = client.state\n\tlet isLoading = true\n\tlet initError: Error | null = null\n\tlet lastError: string | null = null\n\n\tconst listeners = new Set<() => void>()\n\tlet snapshot = buildSnapshot()\n\n\tconst refreshSnapshot = (): void => {\n\t\tsnapshot = buildSnapshot()\n\t}\n\n\tconst notify = (): void => {\n\t\trefreshSnapshot()\n\t\tfor (const listener of listeners) {\n\t\t\tlistener()\n\t\t}\n\t}\n\n\tfunction buildSnapshot(): AuthSessionSnapshot {\n\t\treturn {\n\t\t\tstate,\n\t\t\tuser: client.currentUser,\n\t\t\tisAuthenticated: state === 'authenticated',\n\t\t\tisLoading,\n\t\t\tinitError,\n\t\t\terror: lastError,\n\t\t}\n\t}\n\n\tconst captureError = (error: unknown): void => {\n\t\tlastError = error instanceof Error ? error.message : String(error)\n\t\tnotify()\n\t}\n\n\tconst run = async (action: () => Promise<void>): Promise<void> => {\n\t\tlastError = null\n\t\ttry {\n\t\t\tawait action()\n\t\t} catch (error) {\n\t\t\tcaptureError(error)\n\t\t}\n\t}\n\n\tconst runWithResult = async <T>(action: () => Promise<T>): Promise<T | null> => {\n\t\tlastError = null\n\t\ttry {\n\t\t\treturn await action()\n\t\t} catch (error) {\n\t\t\tcaptureError(error)\n\t\t\treturn null\n\t\t}\n\t}\n\n\tconst unsubscribeAuth = client.onAuthChange((nextState) => {\n\t\tstate = nextState\n\t\tnotify()\n\t})\n\n\tvoid client\n\t\t.initialize()\n\t\t.then(() => {\n\t\t\tstate = client.state\n\t\t\tisLoading = false\n\t\t\tnotify()\n\t\t})\n\t\t.catch((error: unknown) => {\n\t\t\tinitError = error instanceof Error ? error : new Error(String(error))\n\t\t\tisLoading = false\n\t\t\tnotify()\n\t\t})\n\n\treturn {\n\t\tclient,\n\t\tgetSnapshot: () => snapshot,\n\t\tsubscribe(listener) {\n\t\t\tlisteners.add(listener)\n\t\t\treturn () => {\n\t\t\t\tlisteners.delete(listener)\n\t\t\t}\n\t\t},\n\t\tsignUp: (params) =>\n\t\t\trun(async () => {\n\t\t\t\tawait client.signUp(params)\n\t\t\t}),\n\t\tsignIn: (params) =>\n\t\t\trun(async () => {\n\t\t\t\tawait client.signIn(params)\n\t\t\t}),\n\t\tsignInWithOAuth: async (provider, options) => {\n\t\t\tlastError = null\n\t\t\ttry {\n\t\t\t\treturn await client.signInWithOAuth(provider, options)\n\t\t\t} catch (error) {\n\t\t\t\tcaptureError(error)\n\t\t\t\tthrow error instanceof Error ? error : new Error(String(error))\n\t\t\t}\n\t\t},\n\t\tcompleteOAuthSignIn: (provider, params) =>\n\t\t\trun(async () => {\n\t\t\t\tawait client.completeOAuthSignIn(provider, params)\n\t\t\t}),\n\t\tgetOAuthAuthorizationUrl: async (provider, options) => {\n\t\t\tlastError = null\n\t\t\ttry {\n\t\t\t\treturn await client.getOAuthAuthorizationUrl(provider, options)\n\t\t\t} catch (error) {\n\t\t\t\tcaptureError(error)\n\t\t\t\tthrow error instanceof Error ? error : new Error(String(error))\n\t\t\t}\n\t\t},\n\t\tlinkOAuth: (provider, params) =>\n\t\t\trunWithResult(async () => client.linkOAuth(provider, params)),\n\t\tlistLinkedAccounts: () =>\n\t\t\trunWithResult(async () => client.listLinkedAccounts()).then((value) => value ?? []),\n\t\tunlinkOAuth: (provider) =>\n\t\t\trun(async () => {\n\t\t\t\tawait client.unlinkOAuth(provider)\n\t\t\t}),\n\t\tsignOut: () =>\n\t\t\trun(async () => {\n\t\t\t\tawait client.signOut()\n\t\t\t}),\n\t\tdestroy() {\n\t\t\tunsubscribeAuth()\n\t\t\tlisteners.clear()\n\t\t},\n\t}\n}\n","import type {\n\tClientInvitation,\n\tClientMembership,\n\tClientOrganization,\n\tOrgClient,\n} from '../client/org-client'\n\nexport interface OrgSnapshot {\n\torgId: string | null\n\torg: ClientOrganization | null\n\trole: string | null\n}\n\nexport interface OrgSession {\n\treadonly client: OrgClient\n\tgetSnapshot(): OrgSnapshot\n\tsubscribe(listener: () => void): () => void\n\tcheckPermission(requiredRole: string): boolean\n\tdestroy(): void\n}\n\nconst ROLE_LEVELS: Record<string, number> = {\n\tviewer: 10,\n\tbilling: 15,\n\tmember: 20,\n\tadmin: 30,\n\towner: 40,\n}\n\nexport function checkOrgPermission(currentRole: string | null, requiredRole: string): boolean {\n\tif (!currentRole) return false\n\tconst currentLevel = ROLE_LEVELS[currentRole] ?? 0\n\tconst requiredLevel = ROLE_LEVELS[requiredRole] ?? 0\n\treturn currentLevel >= requiredLevel\n}\n\n/**\n * Framework-agnostic org session with reactive snapshot subscription.\n */\nexport function createOrgSession(client: OrgClient): OrgSession {\n\tlet snapshot = buildSnapshot(client)\n\tconst listeners = new Set<() => void>()\n\n\tconst notify = (): void => {\n\t\tsnapshot = buildSnapshot(client)\n\t\tfor (const listener of listeners) {\n\t\t\tlistener()\n\t\t}\n\t}\n\n\tconst unsubscribeOrgChange = client.onOrgChange(notify)\n\n\treturn {\n\t\tclient,\n\t\tgetSnapshot: () => snapshot,\n\t\tsubscribe(listener: () => void): () => void {\n\t\t\tlisteners.add(listener)\n\t\t\treturn () => {\n\t\t\t\tlisteners.delete(listener)\n\t\t\t}\n\t\t},\n\t\tcheckPermission(requiredRole: string): boolean {\n\t\t\treturn checkOrgPermission(snapshot.role, requiredRole)\n\t\t},\n\t\tdestroy(): void {\n\t\t\tunsubscribeOrgChange()\n\t\t\tlisteners.clear()\n\t\t},\n\t}\n}\n\nfunction buildSnapshot(client: OrgClient): OrgSnapshot {\n\treturn {\n\t\torgId: client.activeOrgId,\n\t\torg: client.activeOrg,\n\t\trole: client.activeRole,\n\t}\n}\n\nexport interface UseOrgMembersActions {\n\trefresh: () => Promise<void>\n\tinvite: (email: string, role: string) => Promise<ClientInvitation>\n\tremoveMember: (userId: string) => Promise<void>\n\tupdateRole: (userId: string, role: string) => Promise<void>\n}\n\n/**\n * Shared org member management actions (loading state remains framework-specific).\n */\nexport function createOrgMembersActions(\n\tclient: OrgClient,\n\torgId: string,\n\tonError: (message: string) => void,\n): UseOrgMembersActions {\n\treturn {\n\t\tasync refresh(): Promise<void> {\n\t\t\tawait client.listMembers(orgId)\n\t\t},\n\t\tasync invite(email: string, role: string): Promise<ClientInvitation> {\n\t\t\ttry {\n\t\t\t\treturn await client.inviteMember(orgId, { email, role })\n\t\t\t} catch (error) {\n\t\t\t\tconst message = error instanceof Error ? error.message : String(error)\n\t\t\t\tonError(message)\n\t\t\t\tthrow error\n\t\t\t}\n\t\t},\n\t\tasync removeMember(userId: string): Promise<void> {\n\t\t\ttry {\n\t\t\t\tawait client.removeMember(orgId, userId)\n\t\t\t} catch (error) {\n\t\t\t\tonError(error instanceof Error ? error.message : String(error))\n\t\t\t}\n\t\t},\n\t\tasync updateRole(userId: string, role: string): Promise<void> {\n\t\t\ttry {\n\t\t\t\tawait client.updateMemberRole(orgId, userId, role)\n\t\t\t} catch (error) {\n\t\t\t\tonError(error instanceof Error ? error.message : String(error))\n\t\t\t}\n\t\t},\n\t}\n}\n\nexport async function loadOrgMembers(\n\tclient: OrgClient,\n\torgId: string,\n): Promise<ClientMembership[]> {\n\treturn client.listMembers(orgId)\n}\n"],"mappings":"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","names":["buildSnapshot"]}