lemma-sdk 0.2.41 → 0.2.43

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.
Files changed (32) hide show
  1. package/README.md +5 -2
  2. package/dist/browser/lemma-client.js +22 -61
  3. package/dist/namespaces/conversations.d.ts +6 -0
  4. package/dist/namespaces/conversations.js +2 -0
  5. package/dist/namespaces/files.js +12 -21
  6. package/dist/openapi_client/index.d.ts +2 -1
  7. package/dist/openapi_client/index.js +2 -1
  8. package/dist/openapi_client/models/ConversationResponse.d.ts +5 -0
  9. package/dist/openapi_client/models/ConversationStatus.d.ts +11 -0
  10. package/dist/openapi_client/models/ConversationStatus.js +16 -0
  11. package/dist/openapi_client/models/ConversationType.d.ts +7 -0
  12. package/dist/openapi_client/models/ConversationType.js +12 -0
  13. package/dist/openapi_client/models/CreateConversationRequest.d.ts +3 -0
  14. package/dist/openapi_client/models/CreateFolderRequest.d.ts +0 -3
  15. package/dist/openapi_client/models/DatastoreFileUploadRequest.d.ts +0 -2
  16. package/dist/openapi_client/models/FileResponse.d.ts +0 -2
  17. package/dist/openapi_client/models/UpdateConversationRequest.d.ts +1 -0
  18. package/dist/openapi_client/models/update.d.ts +0 -3
  19. package/dist/openapi_client/services/AgentConversationsService.d.ts +5 -1
  20. package/dist/openapi_client/services/AgentConversationsService.js +5 -1
  21. package/dist/openapi_client/services/FilesService.d.ts +8 -17
  22. package/dist/openapi_client/services/FilesService.js +8 -25
  23. package/dist/react/AuthGuard.d.ts +2 -16
  24. package/dist/react/AuthGuard.js +130 -169
  25. package/dist/react/useAssistantSession.d.ts +6 -0
  26. package/dist/react/useAssistantSession.js +4 -0
  27. package/dist/react/useConversations.d.ts +7 -1
  28. package/dist/react/useConversations.js +10 -4
  29. package/dist/types.d.ts +2 -2
  30. package/package.json +1 -1
  31. package/dist/openapi_client/models/FileNamespace.d.ts +0 -4
  32. package/dist/openapi_client/models/FileNamespace.js +0 -9
@@ -1,5 +1,7 @@
1
1
  import type { ConversationListResponse } from '../models/ConversationListResponse.js';
2
2
  import type { ConversationResponse } from '../models/ConversationResponse.js';
3
+ import type { ConversationStatus } from '../models/ConversationStatus.js';
4
+ import type { ConversationType } from '../models/ConversationType.js';
3
5
  import type { CreateConversationRequest } from '../models/CreateConversationRequest.js';
4
6
  import type { MessageListResponse } from '../models/MessageListResponse.js';
5
7
  import type { SendMessageRequest } from '../models/SendMessageRequest.js';
@@ -11,12 +13,14 @@ export declare class AgentConversationsService {
11
13
  * List root conversations for the current user in a pod. Use agent_name to list conversations for a specific pod agent; omit it to list default pod assistant conversations. Child conversations are omitted from this root list.
12
14
  * @param podId
13
15
  * @param agentName
16
+ * @param status
17
+ * @param type
14
18
  * @param pageToken
15
19
  * @param limit
16
20
  * @returns ConversationListResponse Successful Response
17
21
  * @throws ApiError
18
22
  */
19
- static agentConversationList(podId: string, agentName?: (string | null), pageToken?: (string | null), limit?: number): CancelablePromise<ConversationListResponse>;
23
+ static agentConversationList(podId: string, agentName?: (string | null), status?: (ConversationStatus | null), type?: (ConversationType | null), pageToken?: (string | null), limit?: number): CancelablePromise<ConversationListResponse>;
20
24
  /**
21
25
  * Create Pod Agent Conversation
22
26
  * Create a new pod-scoped conversation. When agent_name is omitted, the conversation uses the default pod assistant. Workflow and sub-agent executions also use conversations as their external execution handle.
@@ -6,12 +6,14 @@ export class AgentConversationsService {
6
6
  * List root conversations for the current user in a pod. Use agent_name to list conversations for a specific pod agent; omit it to list default pod assistant conversations. Child conversations are omitted from this root list.
7
7
  * @param podId
8
8
  * @param agentName
9
+ * @param status
10
+ * @param type
9
11
  * @param pageToken
10
12
  * @param limit
11
13
  * @returns ConversationListResponse Successful Response
12
14
  * @throws ApiError
13
15
  */
14
- static agentConversationList(podId, agentName, pageToken, limit = 20) {
16
+ static agentConversationList(podId, agentName, status, type, pageToken, limit = 20) {
15
17
  return __request(OpenAPI, {
16
18
  method: 'GET',
17
19
  url: '/pods/{pod_id}/conversations',
@@ -20,6 +22,8 @@ export class AgentConversationsService {
20
22
  },
21
23
  query: {
22
24
  'agent_name': agentName,
25
+ 'status': status,
26
+ 'type': type,
23
27
  'page_token': pageToken,
24
28
  'limit': limit,
25
29
  },
@@ -4,7 +4,6 @@ import type { DatastoreFileUploadRequest } from '../models/DatastoreFileUploadRe
4
4
  import type { DatastoreMessageResponse } from '../models/DatastoreMessageResponse.js';
5
5
  import type { DirectoryTreeResponse } from '../models/DirectoryTreeResponse.js';
6
6
  import type { FileListResponse } from '../models/FileListResponse.js';
7
- import { FileNamespace } from '../models/FileNamespace.js';
8
7
  import type { FileResponse } from '../models/FileResponse.js';
9
8
  import type { FileSearchRequest } from '../models/FileSearchRequest.js';
10
9
  import type { FileSearchResponse } from '../models/FileSearchResponse.js';
@@ -15,13 +14,12 @@ export declare class FilesService {
15
14
  * List Files
16
15
  * @param podId
17
16
  * @param directoryPath
18
- * @param namespace
19
17
  * @param limit
20
18
  * @param pageToken
21
19
  * @returns FileListResponse Successful Response
22
20
  * @throws ApiError
23
21
  */
24
- static fileList(podId: string, directoryPath?: string, namespace?: (FileNamespace | null), limit?: number, pageToken?: (string | null)): CancelablePromise<FileListResponse>;
22
+ static fileList(podId: string, directoryPath?: string, limit?: number, pageToken?: (string | null)): CancelablePromise<FileListResponse>;
25
23
  /**
26
24
  * Upload File
27
25
  * @param podId
@@ -34,20 +32,18 @@ export declare class FilesService {
34
32
  * Delete File Or Folder
35
33
  * @param podId
36
34
  * @param path
37
- * @param namespace
38
35
  * @returns DatastoreMessageResponse Successful Response
39
36
  * @throws ApiError
40
37
  */
41
- static fileDelete(podId: string, path: string, namespace?: (FileNamespace | null)): CancelablePromise<DatastoreMessageResponse>;
38
+ static fileDelete(podId: string, path: string): CancelablePromise<DatastoreMessageResponse>;
42
39
  /**
43
40
  * Get File
44
41
  * @param podId
45
42
  * @param path
46
- * @param namespace
47
43
  * @returns FileResponse Successful Response
48
44
  * @throws ApiError
49
45
  */
50
- static fileGet(podId: string, path: string, namespace?: (FileNamespace | null)): CancelablePromise<FileResponse>;
46
+ static fileGet(podId: string, path: string): CancelablePromise<FileResponse>;
51
47
  /**
52
48
  * Update File
53
49
  * @param podId
@@ -60,39 +56,35 @@ export declare class FilesService {
60
56
  * Get Converted File Metadata
61
57
  * @param podId
62
58
  * @param path
63
- * @param namespace
64
59
  * @returns ConvertedFileResponse Successful Response
65
60
  * @throws ApiError
66
61
  */
67
- static fileConvertedGet(podId: string, path: string, namespace?: (FileNamespace | null)): CancelablePromise<ConvertedFileResponse>;
62
+ static fileConvertedGet(podId: string, path: string): CancelablePromise<ConvertedFileResponse>;
68
63
  /**
69
64
  * Download Converted File Artifact
70
65
  * @param podId
71
66
  * @param path
72
67
  * @param artifact
73
- * @param namespace
74
68
  * @returns binary File bytes
75
69
  * @throws ApiError
76
70
  */
77
- static fileConvertedDownload(podId: string, path: string, artifact?: string, namespace?: (FileNamespace | null)): CancelablePromise<Blob>;
71
+ static fileConvertedDownload(podId: string, path: string, artifact?: string): CancelablePromise<Blob>;
78
72
  /**
79
73
  * Render Converted File As HTML
80
74
  * @param podId
81
75
  * @param path
82
- * @param namespace
83
76
  * @returns string Rendered HTML
84
77
  * @throws ApiError
85
78
  */
86
- static fileConvertedRender(podId: string, path: string, namespace?: (FileNamespace | null)): CancelablePromise<string>;
79
+ static fileConvertedRender(podId: string, path: string): CancelablePromise<string>;
87
80
  /**
88
81
  * Download File
89
82
  * @param podId
90
83
  * @param path
91
- * @param namespace
92
84
  * @returns binary File bytes
93
85
  * @throws ApiError
94
86
  */
95
- static fileDownload(podId: string, path: string, namespace?: (FileNamespace | null)): CancelablePromise<Blob>;
87
+ static fileDownload(podId: string, path: string): CancelablePromise<Blob>;
96
88
  /**
97
89
  * Create Folder
98
90
  * @param podId
@@ -113,10 +105,9 @@ export declare class FilesService {
113
105
  * Get Directory Tree
114
106
  * @param podId
115
107
  * @param rootPath
116
- * @param namespace
117
108
  * @param filesPerDirectory
118
109
  * @returns DirectoryTreeResponse Successful Response
119
110
  * @throws ApiError
120
111
  */
121
- static fileTree(podId: string, rootPath?: string, namespace?: FileNamespace, filesPerDirectory?: number): CancelablePromise<DirectoryTreeResponse>;
112
+ static fileTree(podId: string, rootPath?: string, filesPerDirectory?: number): CancelablePromise<DirectoryTreeResponse>;
122
113
  }
@@ -1,4 +1,3 @@
1
- import { FileNamespace } from '../models/FileNamespace.js';
2
1
  import { OpenAPI } from '../core/OpenAPI.js';
3
2
  import { request as __request } from '../core/request.js';
4
3
  export class FilesService {
@@ -6,13 +5,12 @@ export class FilesService {
6
5
  * List Files
7
6
  * @param podId
8
7
  * @param directoryPath
9
- * @param namespace
10
8
  * @param limit
11
9
  * @param pageToken
12
10
  * @returns FileListResponse Successful Response
13
11
  * @throws ApiError
14
12
  */
15
- static fileList(podId, directoryPath = '/', namespace, limit = 100, pageToken) {
13
+ static fileList(podId, directoryPath = '/', limit = 100, pageToken) {
16
14
  return __request(OpenAPI, {
17
15
  method: 'GET',
18
16
  url: '/pods/{pod_id}/datastore/files',
@@ -21,7 +19,6 @@ export class FilesService {
21
19
  },
22
20
  query: {
23
21
  'directory_path': directoryPath,
24
- 'namespace': namespace,
25
22
  'limit': limit,
26
23
  'page_token': pageToken,
27
24
  },
@@ -55,11 +52,10 @@ export class FilesService {
55
52
  * Delete File Or Folder
56
53
  * @param podId
57
54
  * @param path
58
- * @param namespace
59
55
  * @returns DatastoreMessageResponse Successful Response
60
56
  * @throws ApiError
61
57
  */
62
- static fileDelete(podId, path, namespace) {
58
+ static fileDelete(podId, path) {
63
59
  return __request(OpenAPI, {
64
60
  method: 'DELETE',
65
61
  url: '/pods/{pod_id}/datastore/files/by-path',
@@ -68,7 +64,6 @@ export class FilesService {
68
64
  },
69
65
  query: {
70
66
  'path': path,
71
- 'namespace': namespace,
72
67
  },
73
68
  errors: {
74
69
  422: `Validation Error`,
@@ -79,11 +74,10 @@ export class FilesService {
79
74
  * Get File
80
75
  * @param podId
81
76
  * @param path
82
- * @param namespace
83
77
  * @returns FileResponse Successful Response
84
78
  * @throws ApiError
85
79
  */
86
- static fileGet(podId, path, namespace) {
80
+ static fileGet(podId, path) {
87
81
  return __request(OpenAPI, {
88
82
  method: 'GET',
89
83
  url: '/pods/{pod_id}/datastore/files/by-path',
@@ -92,7 +86,6 @@ export class FilesService {
92
86
  },
93
87
  query: {
94
88
  'path': path,
95
- 'namespace': namespace,
96
89
  },
97
90
  errors: {
98
91
  422: `Validation Error`,
@@ -124,11 +117,10 @@ export class FilesService {
124
117
  * Get Converted File Metadata
125
118
  * @param podId
126
119
  * @param path
127
- * @param namespace
128
120
  * @returns ConvertedFileResponse Successful Response
129
121
  * @throws ApiError
130
122
  */
131
- static fileConvertedGet(podId, path, namespace) {
123
+ static fileConvertedGet(podId, path) {
132
124
  return __request(OpenAPI, {
133
125
  method: 'GET',
134
126
  url: '/pods/{pod_id}/datastore/files/converted/by-path',
@@ -137,7 +129,6 @@ export class FilesService {
137
129
  },
138
130
  query: {
139
131
  'path': path,
140
- 'namespace': namespace,
141
132
  },
142
133
  errors: {
143
134
  422: `Validation Error`,
@@ -149,11 +140,10 @@ export class FilesService {
149
140
  * @param podId
150
141
  * @param path
151
142
  * @param artifact
152
- * @param namespace
153
143
  * @returns binary File bytes
154
144
  * @throws ApiError
155
145
  */
156
- static fileConvertedDownload(podId, path, artifact = 'document.md', namespace) {
146
+ static fileConvertedDownload(podId, path, artifact = 'document.md') {
157
147
  return __request(OpenAPI, {
158
148
  method: 'GET',
159
149
  url: '/pods/{pod_id}/datastore/files/converted/download',
@@ -163,7 +153,6 @@ export class FilesService {
163
153
  query: {
164
154
  'path': path,
165
155
  'artifact': artifact,
166
- 'namespace': namespace,
167
156
  },
168
157
  errors: {
169
158
  422: `Validation Error`,
@@ -174,11 +163,10 @@ export class FilesService {
174
163
  * Render Converted File As HTML
175
164
  * @param podId
176
165
  * @param path
177
- * @param namespace
178
166
  * @returns string Rendered HTML
179
167
  * @throws ApiError
180
168
  */
181
- static fileConvertedRender(podId, path, namespace) {
169
+ static fileConvertedRender(podId, path) {
182
170
  return __request(OpenAPI, {
183
171
  method: 'GET',
184
172
  url: '/pods/{pod_id}/datastore/files/converted/render',
@@ -187,7 +175,6 @@ export class FilesService {
187
175
  },
188
176
  query: {
189
177
  'path': path,
190
- 'namespace': namespace,
191
178
  },
192
179
  errors: {
193
180
  422: `Validation Error`,
@@ -198,11 +185,10 @@ export class FilesService {
198
185
  * Download File
199
186
  * @param podId
200
187
  * @param path
201
- * @param namespace
202
188
  * @returns binary File bytes
203
189
  * @throws ApiError
204
190
  */
205
- static fileDownload(podId, path, namespace) {
191
+ static fileDownload(podId, path) {
206
192
  return __request(OpenAPI, {
207
193
  method: 'GET',
208
194
  url: '/pods/{pod_id}/datastore/files/download',
@@ -211,7 +197,6 @@ export class FilesService {
211
197
  },
212
198
  query: {
213
199
  'path': path,
214
- 'namespace': namespace,
215
200
  },
216
201
  errors: {
217
202
  422: `Validation Error`,
@@ -264,12 +249,11 @@ export class FilesService {
264
249
  * Get Directory Tree
265
250
  * @param podId
266
251
  * @param rootPath
267
- * @param namespace
268
252
  * @param filesPerDirectory
269
253
  * @returns DirectoryTreeResponse Successful Response
270
254
  * @throws ApiError
271
255
  */
272
- static fileTree(podId, rootPath = '/', namespace = FileNamespace.PERSONAL, filesPerDirectory = 3) {
256
+ static fileTree(podId, rootPath = '/', filesPerDirectory = 3) {
273
257
  return __request(OpenAPI, {
274
258
  method: 'GET',
275
259
  url: '/pods/{pod_id}/datastore/files/tree',
@@ -278,7 +262,6 @@ export class FilesService {
278
262
  },
279
263
  query: {
280
264
  'root_path': rootPath,
281
- 'namespace': namespace,
282
265
  'files_per_directory': filesPerDirectory,
283
266
  },
284
267
  errors: {
@@ -3,23 +3,9 @@ import type { LemmaClient } from "../client.js";
3
3
  export interface AuthGuardProps {
4
4
  client: LemmaClient;
5
5
  children: ReactNode;
6
- /** Optional custom loading element. Defaults to a blank screen. */
6
+ appName?: string;
7
7
  loadingFallback?: ReactNode;
8
- /** Optional custom unauthenticated element. Defaults to a centered sign-in page. */
9
8
  unauthenticatedFallback?: ReactNode;
10
- /** Optional custom element shown when user is authenticated but lacks pod membership. */
11
9
  accessRequestFallback?: ReactNode;
12
10
  }
13
- /**
14
- * AuthGuard wraps your application and handles auth state:
15
- * - Loading: shows loadingFallback (blank by default)
16
- * - Unauthenticated: shows sign-in page (or custom unauthenticatedFallback)
17
- * - Authenticated and member: renders children
18
- * - Authenticated but not pod member: shows request-access page
19
- *
20
- * Usage:
21
- * <AuthGuard client={getClient()}>
22
- * <App />
23
- * </AuthGuard>
24
- */
25
- export declare function AuthGuard({ client, children, loadingFallback, unauthenticatedFallback, accessRequestFallback, }: AuthGuardProps): import("react/jsx-runtime").JSX.Element;
11
+ export declare function AuthGuard({ client, children, appName, loadingFallback, unauthenticatedFallback, accessRequestFallback, }: AuthGuardProps): import("react/jsx-runtime").JSX.Element;
@@ -1,185 +1,146 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- import { useCallback, useEffect, useState } from "react";
3
- import { ApiError } from "../http.js";
2
+ import { useCallback } from "react";
4
3
  import { useAuth } from "./useAuth.js";
5
- function DefaultSignInPage({ onSignIn }) {
6
- return (_jsx("div", { style: {
7
- display: "flex",
8
- flexDirection: "column",
4
+ import { usePodAccess } from "./usePodAccess.js";
5
+ const pageStyle = {
6
+ display: "flex",
7
+ alignItems: "center",
8
+ justifyContent: "center",
9
+ minHeight: "100vh",
10
+ padding: "24px",
11
+ fontFamily: "Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif",
12
+ background: "linear-gradient(135deg, #f8fafc 0%, #eef2f7 46%, #f9fafb 100%)",
13
+ color: "#172033",
14
+ };
15
+ const panelStyle = {
16
+ width: "100%",
17
+ maxWidth: "440px",
18
+ border: "1px solid rgba(23, 32, 51, 0.1)",
19
+ borderRadius: "14px",
20
+ backgroundColor: "rgba(255, 255, 255, 0.94)",
21
+ boxShadow: "0 18px 60px rgba(23, 32, 51, 0.12)",
22
+ padding: "28px",
23
+ };
24
+ const eyebrowStyle = {
25
+ margin: "0 0 10px",
26
+ fontSize: "12px",
27
+ fontWeight: 700,
28
+ letterSpacing: "0.08em",
29
+ textTransform: "uppercase",
30
+ color: "#5f6f8a",
31
+ };
32
+ const titleStyle = {
33
+ margin: "0",
34
+ color: "#111827",
35
+ fontSize: "24px",
36
+ fontWeight: 700,
37
+ lineHeight: 1.18,
38
+ };
39
+ const bodyStyle = {
40
+ margin: "12px 0 0",
41
+ color: "#526173",
42
+ fontSize: "14px",
43
+ lineHeight: 1.55,
44
+ };
45
+ const buttonRowStyle = {
46
+ display: "flex",
47
+ gap: "10px",
48
+ marginTop: "24px",
49
+ flexWrap: "wrap",
50
+ };
51
+ function buttonStyle(variant, disabled = false) {
52
+ return {
53
+ flex: "1 1 160px",
54
+ minHeight: "42px",
55
+ border: variant === "primary" ? "1px solid #182235" : "1px solid rgba(23, 32, 51, 0.14)",
56
+ borderRadius: "10px",
57
+ backgroundColor: disabled
58
+ ? "#d5dbe5"
59
+ : variant === "primary"
60
+ ? "#182235"
61
+ : "#ffffff",
62
+ color: disabled
63
+ ? "#6b7280"
64
+ : variant === "primary"
65
+ ? "#ffffff"
66
+ : "#172033",
67
+ fontSize: "14px",
68
+ fontWeight: 650,
69
+ cursor: disabled ? "not-allowed" : "pointer",
70
+ };
71
+ }
72
+ function StatusPill({ status }) {
73
+ const label = status === "pending"
74
+ ? "Request pending"
75
+ : status === "error"
76
+ ? "Needs attention"
77
+ : "Access required";
78
+ return (_jsx("span", { style: {
79
+ display: "inline-flex",
9
80
  alignItems: "center",
10
- justifyContent: "center",
11
- minHeight: "100vh",
12
- fontFamily: "system-ui, -apple-system, sans-serif",
13
- backgroundColor: "#f9fafb",
14
- gap: "16px",
15
- }, children: _jsxs("div", { style: {
16
- backgroundColor: "#fff",
17
- borderRadius: "12px",
18
- boxShadow: "0 1px 4px rgba(0,0,0,0.1)",
19
- padding: "40px 48px",
20
- textAlign: "center",
21
- maxWidth: "360px",
22
- width: "100%",
23
- }, children: [_jsx("div", { style: {
24
- width: "40px",
25
- height: "40px",
26
- borderRadius: "8px",
27
- backgroundColor: "#111827",
28
- margin: "0 auto 20px",
29
- } }), _jsx("h1", { style: { margin: "0 0 8px", fontSize: "20px", fontWeight: 600, color: "#111827" }, children: "Sign in to continue" }), _jsx("p", { style: { margin: "0 0 24px", fontSize: "14px", color: "#6b7280" }, children: "You need to be signed in to access this app." }), _jsx("button", { onClick: onSignIn, style: {
30
- width: "100%",
31
- padding: "10px 16px",
32
- backgroundColor: "#111827",
33
- color: "#fff",
34
- border: "none",
35
- borderRadius: "8px",
36
- fontSize: "14px",
37
- fontWeight: 500,
38
- cursor: "pointer",
39
- }, children: "Sign In" })] }) }));
81
+ borderRadius: "999px",
82
+ border: "1px solid rgba(95, 111, 138, 0.24)",
83
+ backgroundColor: "#f5f7fb",
84
+ color: "#526173",
85
+ padding: "5px 9px",
86
+ fontSize: "12px",
87
+ fontWeight: 650,
88
+ marginBottom: "16px",
89
+ }, children: label }));
90
+ }
91
+ function DefaultSignInPage({ appName, onSignIn, }) {
92
+ return (_jsx("div", { style: pageStyle, children: _jsxs("div", { style: panelStyle, children: [_jsx("p", { style: eyebrowStyle, children: appName }), _jsx("h1", { style: titleStyle, children: "Sign in to continue" }), _jsx("p", { style: bodyStyle, children: "Sign in with Lemma to open this workspace." }), _jsx("div", { style: buttonRowStyle, children: _jsx("button", { onClick: onSignIn, style: buttonStyle("primary"), children: "Sign in" }) })] }) }));
40
93
  }
41
- function DefaultRequestAccessPage({ isPending, isSubmitting, error, onRequestAccess, }) {
94
+ function DefaultRequestAccessPage({ appName, status, isSubmitting, signedInAs, error, onRequestAccess, onRetry, }) {
95
+ const isPending = status === "pending";
96
+ const isError = status === "error";
97
+ const title = isPending
98
+ ? "Your request is waiting for approval"
99
+ : isError
100
+ ? "We could not verify access"
101
+ : "Request access to this pod";
42
102
  const message = isPending
43
- ? "Access request sent. An admin can approve it from the pod settings."
44
- : "You are signed in, but you are not a member of this pod yet.";
45
- return (_jsx("div", { style: {
46
- display: "flex",
47
- flexDirection: "column",
48
- alignItems: "center",
49
- justifyContent: "center",
50
- minHeight: "100vh",
51
- fontFamily: "system-ui, -apple-system, sans-serif",
52
- backgroundColor: "#f9fafb",
53
- gap: "16px",
54
- }, children: _jsxs("div", { style: {
55
- backgroundColor: "#fff",
56
- borderRadius: "12px",
57
- boxShadow: "0 1px 4px rgba(0,0,0,0.1)",
58
- padding: "40px 48px",
59
- textAlign: "center",
60
- maxWidth: "420px",
61
- width: "100%",
62
- }, children: [_jsx("h1", { style: { margin: "0 0 8px", fontSize: "20px", fontWeight: 600, color: "#111827" }, children: "Request pod access" }), _jsx("p", { style: { margin: "0 0 24px", fontSize: "14px", color: "#6b7280" }, children: message }), _jsx("button", { onClick: onRequestAccess, disabled: isSubmitting || isPending, style: {
63
- width: "100%",
64
- padding: "10px 16px",
65
- backgroundColor: isSubmitting || isPending ? "#9ca3af" : "#111827",
66
- color: "#fff",
67
- border: "none",
68
- borderRadius: "8px",
69
- fontSize: "14px",
70
- fontWeight: 500,
71
- cursor: isSubmitting || isPending ? "not-allowed" : "pointer",
72
- }, children: isSubmitting ? "Submitting..." : isPending ? "Request Sent" : "Request Access" }), error ? (_jsx("p", { style: { margin: "12px 0 0", fontSize: "13px", color: "#b91c1c" }, children: error })) : null] }) }));
103
+ ? "An admin can approve your request from pod settings. You can refresh this screen after they add you."
104
+ : "You are signed in, but this pod is gated to members. Send an access request and an admin can let you in.";
105
+ return (_jsx("div", { style: pageStyle, children: _jsxs("div", { style: panelStyle, children: [_jsx("p", { style: eyebrowStyle, children: appName }), _jsx(StatusPill, { status: status }), _jsx("h1", { style: titleStyle, children: title }), _jsx("p", { style: bodyStyle, children: message }), signedInAs ? (_jsxs("p", { style: {
106
+ margin: "18px 0 0",
107
+ borderRadius: "10px",
108
+ backgroundColor: "#f5f7fb",
109
+ padding: "10px 12px",
110
+ color: "#526173",
111
+ fontSize: "13px",
112
+ }, children: ["Signed in as ", _jsx("strong", { style: { color: "#172033" }, children: signedInAs })] })) : null, error ? (_jsx("p", { style: { margin: "14px 0 0", color: "#b42318", fontSize: "13px", lineHeight: 1.45 }, children: error.message })) : null, _jsxs("div", { style: buttonRowStyle, children: [_jsx("button", { onClick: onRequestAccess, disabled: isSubmitting || isPending, style: buttonStyle("primary", isSubmitting || isPending), children: isSubmitting ? "Sending..." : isPending ? "Request sent" : "Request access" }), _jsx("button", { onClick: onRetry, style: buttonStyle("secondary"), children: isError ? "Try again" : "Refresh" })] })] }) }));
73
113
  }
74
- /**
75
- * AuthGuard wraps your application and handles auth state:
76
- * - Loading: shows loadingFallback (blank by default)
77
- * - Unauthenticated: shows sign-in page (or custom unauthenticatedFallback)
78
- * - Authenticated and member: renders children
79
- * - Authenticated but not pod member: shows request-access page
80
- *
81
- * Usage:
82
- * <AuthGuard client={getClient()}>
83
- * <App />
84
- * </AuthGuard>
85
- */
86
- export function AuthGuard({ client, children, loadingFallback = null, unauthenticatedFallback, accessRequestFallback, }) {
114
+ export function AuthGuard({ client, children, appName = "App", loadingFallback = null, unauthenticatedFallback, accessRequestFallback, }) {
87
115
  const { isLoading, isAuthenticated, redirectToAuth } = useAuth(client);
88
- const [membershipState, setMembershipState] = useState("idle");
89
- const [membershipError, setMembershipError] = useState(null);
90
- const [isSubmittingJoinRequest, setIsSubmittingJoinRequest] = useState(false);
91
- const [joinRequest, setJoinRequest] = useState(null);
92
- const checkMembership = useCallback(async () => {
93
- if (!isAuthenticated || !client.podId) {
94
- setMembershipState("member");
95
- return;
96
- }
97
- setMembershipState("checking");
98
- setMembershipError(null);
99
- try {
100
- const currentUser = await client.users.current();
101
- await client.podMembers.lookupByUserId(client.podId, currentUser.id);
102
- setMembershipState("member");
103
- setJoinRequest(null);
104
- return;
105
- }
106
- catch (error) {
107
- const apiError = error instanceof ApiError ? error : null;
108
- const isMissingMembership = apiError?.statusCode === 404 || apiError?.statusCode === 403;
109
- if (!isMissingMembership) {
110
- throw error;
111
- }
112
- }
113
- try {
114
- const existingRequest = await client.podJoinRequests.me(client.podId);
115
- setJoinRequest(existingRequest);
116
- }
117
- catch {
118
- // non-fatal: request could still be created by the user manually
119
- }
120
- setMembershipState("missing");
121
- }, [client, isAuthenticated]);
122
- useEffect(() => {
123
- let cancelled = false;
124
- const run = async () => {
125
- if (!isAuthenticated) {
126
- setMembershipState("idle");
127
- setJoinRequest(null);
128
- setMembershipError(null);
129
- return;
130
- }
131
- try {
132
- await checkMembership();
133
- }
134
- catch (error) {
135
- if (cancelled)
136
- return;
137
- const message = error instanceof Error
138
- ? error.message
139
- : "Failed to verify pod membership. Please try again.";
140
- setMembershipError(message);
141
- setMembershipState("missing");
142
- }
143
- };
144
- void run();
145
- return () => {
146
- cancelled = true;
147
- };
148
- }, [checkMembership, isAuthenticated]);
149
- const handleRequestAccess = useCallback(async () => {
150
- if (!client.podId || isSubmittingJoinRequest || joinRequest?.status === "PENDING") {
151
- return;
152
- }
153
- setIsSubmittingJoinRequest(true);
154
- setMembershipError(null);
155
- try {
156
- const request = await client.podJoinRequests.create(client.podId);
157
- setJoinRequest(request);
158
- }
159
- catch (error) {
160
- const message = error instanceof Error
161
- ? error.message
162
- : "Failed to create access request. Please try again.";
163
- setMembershipError(message);
164
- }
165
- finally {
166
- setIsSubmittingJoinRequest(false);
167
- }
168
- }, [client, isSubmittingJoinRequest, joinRequest]);
169
- if (isLoading || (isAuthenticated && membershipState === "checking")) {
116
+ const hasPodScope = Boolean(client.podId);
117
+ const podAccess = usePodAccess({
118
+ client,
119
+ enabled: isAuthenticated && hasPodScope,
120
+ autoLoad: isAuthenticated && hasPodScope,
121
+ });
122
+ const handleRequestAccess = useCallback(() => {
123
+ void podAccess.requestAccess();
124
+ }, [podAccess]);
125
+ const handleRetry = useCallback(() => {
126
+ void podAccess.refresh();
127
+ }, [podAccess]);
128
+ if (isLoading || (isAuthenticated && hasPodScope && podAccess.status === "checking")) {
170
129
  return _jsx(_Fragment, { children: loadingFallback });
171
130
  }
172
131
  if (!isAuthenticated) {
173
132
  if (unauthenticatedFallback !== undefined) {
174
133
  return _jsx(_Fragment, { children: unauthenticatedFallback });
175
134
  }
176
- return _jsx(DefaultSignInPage, { onSignIn: redirectToAuth });
135
+ return _jsx(DefaultSignInPage, { appName: appName, onSignIn: redirectToAuth });
177
136
  }
178
- if (membershipState === "missing") {
179
- if (accessRequestFallback !== undefined) {
180
- return _jsx(_Fragment, { children: accessRequestFallback });
181
- }
182
- return (_jsx(DefaultRequestAccessPage, { isPending: joinRequest?.status === "PENDING", isSubmitting: isSubmittingJoinRequest, error: membershipError, onRequestAccess: handleRequestAccess }));
137
+ if (!hasPodScope || podAccess.hasAccess) {
138
+ return _jsx(_Fragment, { children: children });
139
+ }
140
+ if (accessRequestFallback !== undefined) {
141
+ return _jsx(_Fragment, { children: accessRequestFallback });
183
142
  }
184
- return _jsx(_Fragment, { children: children });
143
+ const fullName = [podAccess.user?.first_name, podAccess.user?.last_name].filter(Boolean).join(" ");
144
+ const signedInAs = podAccess.user?.email ?? (fullName.length > 0 ? fullName : podAccess.user?.id ?? null);
145
+ return (_jsx(DefaultRequestAccessPage, { appName: appName, status: podAccess.status, isSubmitting: podAccess.isRequestingAccess, signedInAs: signedInAs, error: podAccess.error, onRequestAccess: handleRequestAccess, onRetry: handleRetry }));
185
146
  }