@gram-ai/elements 1.26.1 → 1.27.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.
Files changed (90) hide show
  1. package/README.md +83 -15
  2. package/dist/components/Chat/stories/ConnectionConfiguration.stories.d.ts +1 -1
  3. package/dist/components/ui/calendar.d.ts +25 -0
  4. package/dist/components/ui/time-range-picker.d.ts +46 -0
  5. package/dist/components/ui/time-range-picker.stories.d.ts +37 -0
  6. package/dist/core-Cqad6-xW.js +36 -0
  7. package/dist/core-Cqad6-xW.js.map +1 -0
  8. package/dist/core-DBxmxwCi.cjs +2 -0
  9. package/dist/core-DBxmxwCi.cjs.map +1 -0
  10. package/dist/elements.cjs +1 -1
  11. package/dist/elements.css +1 -1
  12. package/dist/elements.js +18 -14
  13. package/dist/hooks/useModel.d.ts +2 -0
  14. package/dist/index-CP-wWZCV.cjs +172 -0
  15. package/dist/index-CP-wWZCV.cjs.map +1 -0
  16. package/dist/{index-DfqYP0CD.js → index-oO5BAmPI.js} +12578 -11964
  17. package/dist/index-oO5BAmPI.js.map +1 -0
  18. package/dist/index.d.ts +5 -1
  19. package/dist/lib/auth.d.ts +12 -4
  20. package/dist/lib/models.d.ts +1 -1
  21. package/dist/{profiler-ZLr2-8s7.cjs → profiler-CEpc7O5Q.cjs} +2 -2
  22. package/dist/{profiler-ZLr2-8s7.cjs.map → profiler-CEpc7O5Q.cjs.map} +1 -1
  23. package/dist/{profiler-WoFj2UH8.js → profiler-ECh1zoXF.js} +2 -2
  24. package/dist/{profiler-WoFj2UH8.js.map → profiler-ECh1zoXF.js.map} +1 -1
  25. package/dist/server/bun.cjs +2 -0
  26. package/dist/server/bun.cjs.map +1 -0
  27. package/dist/server/bun.d.ts +8 -0
  28. package/dist/server/bun.js +26 -0
  29. package/dist/server/bun.js.map +1 -0
  30. package/dist/server/core.d.ts +37 -0
  31. package/dist/server/express.cjs +2 -0
  32. package/dist/server/express.cjs.map +1 -0
  33. package/dist/server/express.d.ts +9 -0
  34. package/dist/server/express.js +21 -0
  35. package/dist/server/express.js.map +1 -0
  36. package/dist/server/fastify.cjs +2 -0
  37. package/dist/server/fastify.cjs.map +1 -0
  38. package/dist/server/fastify.d.ts +9 -0
  39. package/dist/server/fastify.js +19 -0
  40. package/dist/server/fastify.js.map +1 -0
  41. package/dist/server/hono.cjs +2 -0
  42. package/dist/server/hono.cjs.map +1 -0
  43. package/dist/server/hono.d.ts +9 -0
  44. package/dist/server/hono.js +20 -0
  45. package/dist/server/hono.js.map +1 -0
  46. package/dist/server/nextjs.cjs +2 -0
  47. package/dist/server/nextjs.cjs.map +1 -0
  48. package/dist/server/nextjs.d.ts +8 -0
  49. package/dist/server/nextjs.js +26 -0
  50. package/dist/server/nextjs.js.map +1 -0
  51. package/dist/server/tanstack-start.cjs +2 -0
  52. package/dist/server/tanstack-start.cjs.map +1 -0
  53. package/dist/server/tanstack-start.d.ts +25 -0
  54. package/dist/server/tanstack-start.js +39 -0
  55. package/dist/server/tanstack-start.js.map +1 -0
  56. package/dist/server.cjs +1 -1
  57. package/dist/server.cjs.map +1 -1
  58. package/dist/server.d.ts +10 -16
  59. package/dist/server.js +22 -29
  60. package/dist/server.js.map +1 -1
  61. package/dist/{startRecording-DzQo16WK.js → startRecording-CmZjjJoz.js} +2 -2
  62. package/dist/{startRecording-DzQo16WK.js.map → startRecording-CmZjjJoz.js.map} +1 -1
  63. package/dist/{startRecording-BGnWDInp.cjs → startRecording-qDCAu4Q0.cjs} +2 -2
  64. package/dist/{startRecording-BGnWDInp.cjs.map → startRecording-qDCAu4Q0.cjs.map} +1 -1
  65. package/dist/types/index.d.ts +22 -10
  66. package/package.json +63 -3
  67. package/src/components/Chat/stories/ConnectionConfiguration.stories.tsx +6 -8
  68. package/src/components/assistant-ui/thread.tsx +8 -14
  69. package/src/components/ui/calendar.tsx +262 -0
  70. package/src/components/ui/time-range-picker.stories.tsx +249 -0
  71. package/src/components/ui/time-range-picker.tsx +675 -0
  72. package/src/hooks/useAuth.ts +59 -7
  73. package/src/hooks/useFollowOnSuggestions.ts +7 -14
  74. package/src/hooks/useModel.ts +30 -0
  75. package/src/index.ts +17 -0
  76. package/src/lib/api.test.ts +4 -4
  77. package/src/lib/auth.ts +34 -4
  78. package/src/lib/models.ts +1 -0
  79. package/src/server/bun.ts +63 -0
  80. package/src/server/core.ts +84 -0
  81. package/src/server/express.ts +60 -0
  82. package/src/server/fastify.ts +61 -0
  83. package/src/server/hono.ts +55 -0
  84. package/src/server/nextjs.ts +58 -0
  85. package/src/server/tanstack-start.ts +110 -0
  86. package/src/server.ts +37 -49
  87. package/src/types/index.ts +25 -9
  88. package/dist/index-DdrZQXwQ.cjs +0 -147
  89. package/dist/index-DdrZQXwQ.cjs.map +0 -1
  90. package/dist/index-DfqYP0CD.js.map +0 -1
@@ -0,0 +1,110 @@
1
+ /**
2
+ * TanStack Start adapter for Gram Elements server handlers.
3
+ *
4
+ * Provides two approaches for session creation:
5
+ *
6
+ * 1. **Server Function (RPC)** — use `createTanStackStartSessionFn` to create
7
+ * a `createServerFn` that can be called directly from client code and passed
8
+ * to `session` in the Elements config.
9
+ *
10
+ * 2. **API Route** — use `createTanStackStartHandler` to create a handler for
11
+ * TanStack Start server routes (similar to the Next.js adapter).
12
+ *
13
+ * @example Server Function approach
14
+ * ```typescript
15
+ * // session.functions.ts
16
+ * import { createTanStackStartSessionFn } from '@gram-ai/elements/server/tanstack-start'
17
+ *
18
+ * export const getSession = createTanStackStartSessionFn({
19
+ * embedOrigin: 'http://localhost:3000',
20
+ * userIdentifier: 'user-123',
21
+ * expiresAfter: 3600,
22
+ * })
23
+ * ```
24
+ *
25
+ * @example API Route approach
26
+ * ```typescript
27
+ * // routes/api/chat.session.ts
28
+ * import { createTanStackStartHandler } from '@gram-ai/elements/server/tanstack-start'
29
+ *
30
+ * const handler = createTanStackStartHandler({
31
+ * embedOrigin: 'http://localhost:3000',
32
+ * userIdentifier: 'user-123',
33
+ * expiresAfter: 3600,
34
+ * })
35
+ * ```
36
+ */
37
+
38
+ import { createServerFn } from '@tanstack/react-start'
39
+ import { createChatSession, type SessionHandlerOptions } from './core'
40
+
41
+ /**
42
+ * Create a TanStack Start server function for session creation.
43
+ *
44
+ * The returned function can be called from client code (RPC-style) and passed
45
+ * to `session` in the Gram Elements config.
46
+ *
47
+ * @param options - Session configuration options
48
+ * @returns A `createServerFn` instance callable from the client
49
+ */
50
+ export function createTanStackStartSessionFn(options: SessionHandlerOptions) {
51
+ return createServerFn({ method: 'POST' })
52
+ .inputValidator((data: { projectSlug: string }) => data)
53
+ .handler(async ({ data }) => {
54
+ const result = await createChatSession({
55
+ projectSlug: data.projectSlug,
56
+ options,
57
+ })
58
+
59
+ if (result.status !== 200) {
60
+ throw new Error(`Failed to create chat session: ${result.body}`)
61
+ }
62
+
63
+ const parsed = JSON.parse(result.body) as { client_token: string }
64
+ return parsed.client_token
65
+ })
66
+ }
67
+
68
+ /**
69
+ * Create a TanStack Start server route handler for the chat session endpoint.
70
+ *
71
+ * Returns a function compatible with TanStack Start server route handlers
72
+ * that accepts a Web API `Request` and returns a `Response`.
73
+ *
74
+ * @param options - Session configuration options
75
+ * @returns Handler function `(request: Request) => Promise<Response>`
76
+ */
77
+ export function createTanStackStartHandler(
78
+ options:
79
+ | SessionHandlerOptions
80
+ | ((
81
+ request: Request
82
+ ) => SessionHandlerOptions | Promise<SessionHandlerOptions>)
83
+ ) {
84
+ return async (request: Request) => {
85
+ const projectSlug = request.headers.get('gram-project')
86
+
87
+ if (!projectSlug) {
88
+ return new Response(
89
+ JSON.stringify({ error: 'Missing Gram-Project header' }),
90
+ {
91
+ status: 400,
92
+ headers: { 'Content-Type': 'application/json' },
93
+ }
94
+ )
95
+ }
96
+
97
+ const sessionOptions =
98
+ typeof options === 'function' ? await options(request) : options
99
+
100
+ const result = await createChatSession({
101
+ projectSlug,
102
+ options: sessionOptions,
103
+ })
104
+
105
+ return new Response(result.body, {
106
+ status: result.status,
107
+ headers: result.headers,
108
+ })
109
+ }
110
+ }
package/src/server.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { IncomingMessage, ServerResponse } from 'node:http'
2
+ import { createChatSession, type SessionHandlerOptions } from './server/core'
2
3
 
3
4
  type ServerHandler<T> = (
4
5
  req: IncomingMessage,
@@ -23,67 +24,54 @@ interface ServerHandlers {
23
24
  session: ServerHandler<SessionHandlerOptions>
24
25
  }
25
26
 
27
+ /**
28
+ * @deprecated Use framework-specific adapters instead:
29
+ * - `@gram-ai/elements/server/express` for Express
30
+ * - `@gram-ai/elements/server/nextjs` for Next.js App Router
31
+ * - `@gram-ai/elements/server/fastify` for Fastify
32
+ * - `@gram-ai/elements/server/hono` for Hono
33
+ * - `@gram-ai/elements/server/bun` for Bun
34
+ */
26
35
  export const createElementsServerHandlers = (): ServerHandlers => {
27
36
  return {
28
37
  session: sessionHandler,
29
38
  }
30
39
  }
31
40
 
32
- interface SessionHandlerOptions {
33
- /**
34
- * The origin from which the token will be used
35
- */
36
- embedOrigin: string
37
-
38
- /**
39
- * Free-form user identifier
40
- */
41
- userIdentifier: string
42
-
43
- /**
44
- * Token expiration in seconds (max / default 3600)
45
- * @default 3600
46
- */
47
- expiresAfter?: number
48
- }
41
+ export type { SessionHandlerOptions }
49
42
 
50
43
  const sessionHandler: ServerHandler<SessionHandlerOptions> = async (
51
44
  req,
52
45
  res,
53
46
  options
54
47
  ) => {
55
- const base = process.env.GRAM_API_URL ?? 'https://app.getgram.ai'
56
- if (req.method === 'POST') {
57
- const projectSlug = Array.isArray(req.headers['gram-project'])
58
- ? req.headers['gram-project'][0]
59
- : req.headers['gram-project']
48
+ if (req.method !== 'POST') {
49
+ res.writeHead(405, { 'Content-Type': 'application/json' })
50
+ res.end(JSON.stringify({ error: 'Method not allowed' }))
51
+ return
52
+ }
60
53
 
61
- fetch(base + '/rpc/chatSessions.create', {
62
- method: 'POST',
63
- body: JSON.stringify({
64
- embed_origin: options?.embedOrigin,
65
- user_identifier: options?.userIdentifier,
66
- expires_after: options?.expiresAfter,
67
- }),
68
- headers: {
69
- 'Content-Type': 'application/json',
70
- 'Gram-Project': typeof projectSlug === 'string' ? projectSlug : '',
71
- 'Gram-Key': process.env.GRAM_API_KEY ?? '',
72
- },
73
- })
74
- .then(async (response) => {
75
- const body = await response.text()
76
- res.writeHead(response.status, { 'Content-Type': 'application/json' })
77
- res.end(body)
78
- })
79
- .catch((error) => {
80
- console.error('Failed to create chat session:', error)
81
- res.writeHead(500, { 'Content-Type': 'application/json' })
82
- res.end(
83
- JSON.stringify({
84
- error: 'Failed to create chat session: ' + error.message,
85
- })
86
- )
87
- })
54
+ const projectSlug = Array.isArray(req.headers['gram-project'])
55
+ ? req.headers['gram-project'][0]
56
+ : req.headers['gram-project']
57
+
58
+ if (!projectSlug || typeof projectSlug !== 'string') {
59
+ res.writeHead(400, { 'Content-Type': 'application/json' })
60
+ res.end(JSON.stringify({ error: 'Missing Gram-Project header' }))
61
+ return
88
62
  }
63
+
64
+ if (!options) {
65
+ res.writeHead(400, { 'Content-Type': 'application/json' })
66
+ res.end(JSON.stringify({ error: 'Missing session options' }))
67
+ return
68
+ }
69
+
70
+ const result = await createChatSession({
71
+ projectSlug,
72
+ options,
73
+ })
74
+
75
+ res.writeHead(result.status, result.headers)
76
+ res.end(result.body)
89
77
  }
@@ -363,11 +363,16 @@ export type BaseApiConfig = {
363
363
  headers?: Record<string, string>
364
364
  }
365
365
 
366
+ /**
367
+ * @deprecated Use `{ session: mySessionFn }` instead. Will be removed in a future major version.
368
+ */
366
369
  export type SessionAuthConfig = {
367
370
  /**
368
371
  * The function to use to retrieve the session token from the backend endpoint.
369
372
  * By default, this will attempt to fetch the session token from `/chat/session`.
370
373
  *
374
+ * @deprecated Use `session` instead: `{ session: mySessionFn }`.
375
+ *
371
376
  * @example
372
377
  * const config: ElementsConfig = {
373
378
  * api: {
@@ -381,19 +386,14 @@ export type SessionAuthConfig = {
381
386
  }
382
387
 
383
388
  /**
384
- * The static session auth config is used to authenticate the Elements library using a static session token only.
385
- *
386
- * @example
387
- * const config: ElementsConfig = {
388
- * api: {
389
- * sessionToken: 'your-session-token',
390
- * },
391
- * }
389
+ * @deprecated Use `{ session: 'your-token' }` instead. Will be removed in a future major version.
392
390
  */
393
391
  export type StaticSessionAuthConfig = {
394
392
  /**
395
393
  * A static session token to use if you haven't yet configured a session endpoint.
396
394
  *
395
+ * @deprecated Use `session` instead: `{ session: 'your-token' }`.
396
+ *
397
397
  * @example
398
398
  * const config: ElementsConfig = {
399
399
  * api: {
@@ -404,11 +404,27 @@ export type StaticSessionAuthConfig = {
404
404
  sessionToken: string
405
405
  }
406
406
 
407
+ export type DangerousApiKeyAuthConfig = {
408
+ /** WARNING: Exposes API key in browser. Dev/testing only. */
409
+ dangerousApiKey: string
410
+ }
411
+
412
+ export type UnifiedSessionAuthConfig = {
413
+ /** String = static token (shows expiry warning). Function = dynamic fetcher. */
414
+ session: string | GetSessionFn
415
+ }
416
+
407
417
  /**
408
- * API configuration - can be just the URL, or URL with session auth, or URL with API key auth.
418
+ * API configuration - base URL, session auth (static token or fetcher function),
419
+ * or dangerousApiKey for quick dev/testing without a backend session endpoint.
420
+ *
421
+ * The legacy `sessionFn` / `sessionToken` fields still work but are deprecated
422
+ * in favour of the unified `session` field.
409
423
  */
410
424
  export type ApiConfig =
411
425
  | BaseApiConfig
426
+ | (BaseApiConfig & UnifiedSessionAuthConfig)
427
+ | (BaseApiConfig & DangerousApiKeyAuthConfig)
412
428
  | (BaseApiConfig & SessionAuthConfig)
413
429
  | (BaseApiConfig & StaticSessionAuthConfig)
414
430