@blinkdotnew/react 1.0.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/dist/index.d.mts +186 -0
- package/dist/index.d.ts +186 -0
- package/dist/index.js +400 -0
- package/dist/index.mjs +358 -0
- package/package.json +70 -0
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import { BlinkClient, Agent, UIMessage, AgentResponse } from '@blinkdotnew/sdk';
|
|
2
|
+
export * from '@blinkdotnew/sdk';
|
|
3
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
4
|
+
import { ReactNode } from 'react';
|
|
5
|
+
|
|
6
|
+
interface BlinkContextValue {
|
|
7
|
+
client: BlinkClient;
|
|
8
|
+
projectId: string;
|
|
9
|
+
}
|
|
10
|
+
interface BlinkProviderProps {
|
|
11
|
+
/** Your Blink project ID */
|
|
12
|
+
projectId: string;
|
|
13
|
+
/** Publishable key for client-side usage */
|
|
14
|
+
publishableKey?: string;
|
|
15
|
+
/** Secret key for server-side usage (do not expose in browser!) */
|
|
16
|
+
secretKey?: string;
|
|
17
|
+
/** Children components */
|
|
18
|
+
children: ReactNode;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Provides Blink client to all child components
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```tsx
|
|
25
|
+
* import { BlinkProvider } from '@blinkdotnew/react'
|
|
26
|
+
*
|
|
27
|
+
* function App() {
|
|
28
|
+
* return (
|
|
29
|
+
* <BlinkProvider
|
|
30
|
+
* projectId="proj_abc123"
|
|
31
|
+
* publishableKey="blnk_pk_..."
|
|
32
|
+
* >
|
|
33
|
+
* <MyApp />
|
|
34
|
+
* </BlinkProvider>
|
|
35
|
+
* )
|
|
36
|
+
* }
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
declare function BlinkProvider({ projectId, publishableKey, secretKey, children, }: BlinkProviderProps): react_jsx_runtime.JSX.Element;
|
|
40
|
+
/**
|
|
41
|
+
* Get the Blink client from context
|
|
42
|
+
*
|
|
43
|
+
* @throws If used outside BlinkProvider
|
|
44
|
+
*/
|
|
45
|
+
declare function useBlink(): BlinkContextValue;
|
|
46
|
+
/**
|
|
47
|
+
* Get the Blink client instance directly
|
|
48
|
+
*
|
|
49
|
+
* @throws If used outside BlinkProvider
|
|
50
|
+
*/
|
|
51
|
+
declare function useBlinkClient(): BlinkClient;
|
|
52
|
+
interface BlinkAuthContextValue {
|
|
53
|
+
isAuthenticated: boolean;
|
|
54
|
+
isLoading: boolean;
|
|
55
|
+
user: any | null;
|
|
56
|
+
signIn: (email: string, password: string) => Promise<void>;
|
|
57
|
+
signUp: (email: string, password: string) => Promise<void>;
|
|
58
|
+
signOut: () => Promise<void>;
|
|
59
|
+
}
|
|
60
|
+
interface BlinkAuthProviderProps {
|
|
61
|
+
children: ReactNode;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Provides authentication state to all child components
|
|
65
|
+
*
|
|
66
|
+
* Must be nested inside BlinkProvider
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* ```tsx
|
|
70
|
+
* import { BlinkProvider, BlinkAuthProvider } from '@blinkdotnew/react'
|
|
71
|
+
*
|
|
72
|
+
* function App() {
|
|
73
|
+
* return (
|
|
74
|
+
* <BlinkProvider projectId="proj_abc123" publishableKey="blnk_pk_...">
|
|
75
|
+
* <BlinkAuthProvider>
|
|
76
|
+
* <MyApp />
|
|
77
|
+
* </BlinkAuthProvider>
|
|
78
|
+
* </BlinkProvider>
|
|
79
|
+
* )
|
|
80
|
+
* }
|
|
81
|
+
* ```
|
|
82
|
+
*/
|
|
83
|
+
declare function BlinkAuthProvider({ children }: BlinkAuthProviderProps): react_jsx_runtime.JSX.Element;
|
|
84
|
+
/**
|
|
85
|
+
* Get authentication state and methods
|
|
86
|
+
*
|
|
87
|
+
* @throws If used outside BlinkAuthProvider
|
|
88
|
+
*/
|
|
89
|
+
declare function useBlinkAuth(): BlinkAuthContextValue;
|
|
90
|
+
|
|
91
|
+
interface UseAgentOptions {
|
|
92
|
+
/**
|
|
93
|
+
* Agent instance created with `new Agent()`
|
|
94
|
+
*
|
|
95
|
+
* @example
|
|
96
|
+
* ```tsx
|
|
97
|
+
* const myAgent = new Agent({
|
|
98
|
+
* model: 'openai/gpt-4o',
|
|
99
|
+
* tools: [webSearch],
|
|
100
|
+
* })
|
|
101
|
+
*
|
|
102
|
+
* const chat = useAgent({ agent: myAgent })
|
|
103
|
+
* ```
|
|
104
|
+
*/
|
|
105
|
+
agent: Agent;
|
|
106
|
+
/** Initial messages */
|
|
107
|
+
initialMessages?: UIMessage[];
|
|
108
|
+
/** Callback when response is received */
|
|
109
|
+
onFinish?: (response: AgentResponse) => void;
|
|
110
|
+
/** Callback on error */
|
|
111
|
+
onError?: (error: Error) => void;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Options for addToolOutput
|
|
115
|
+
*/
|
|
116
|
+
interface AddToolOutputOptions {
|
|
117
|
+
toolCallId: string;
|
|
118
|
+
tool: string;
|
|
119
|
+
output: any;
|
|
120
|
+
}
|
|
121
|
+
interface UseAgentReturn {
|
|
122
|
+
/** Current messages */
|
|
123
|
+
messages: UIMessage[];
|
|
124
|
+
/** Current input value */
|
|
125
|
+
input: string;
|
|
126
|
+
/** Set input value */
|
|
127
|
+
setInput: (input: string) => void;
|
|
128
|
+
/** Whether the agent is processing */
|
|
129
|
+
isLoading: boolean;
|
|
130
|
+
/** Any error that occurred */
|
|
131
|
+
error: Error | null;
|
|
132
|
+
/** Send a message */
|
|
133
|
+
sendMessage: (content?: string) => Promise<void>;
|
|
134
|
+
/** Append a message without sending */
|
|
135
|
+
append: (message: UIMessage) => void;
|
|
136
|
+
/** Handle input change (for controlled inputs) */
|
|
137
|
+
handleInputChange: (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => void;
|
|
138
|
+
/** Handle form submit */
|
|
139
|
+
handleSubmit: (e?: React.FormEvent) => void;
|
|
140
|
+
/** Add tool output for HITL (Human-in-the-Loop) */
|
|
141
|
+
addToolOutput: (options: AddToolOutputOptions) => void;
|
|
142
|
+
/** Clear messages */
|
|
143
|
+
clearMessages: () => void;
|
|
144
|
+
/** Stop generation */
|
|
145
|
+
stop: () => void;
|
|
146
|
+
/** Reload last message */
|
|
147
|
+
reload: () => Promise<void>;
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* React hook for AI agent chat functionality
|
|
151
|
+
*
|
|
152
|
+
* Compatible with AI SDK's useChat pattern but powered by Blink.
|
|
153
|
+
*
|
|
154
|
+
* **Official usage pattern:**
|
|
155
|
+
* 1. Create agent: `const myAgent = new Agent({...})`
|
|
156
|
+
* 2. Use in hook: `useAgent({ agent: myAgent })`
|
|
157
|
+
*
|
|
158
|
+
* @example
|
|
159
|
+
* ```tsx
|
|
160
|
+
* import { Agent, useAgent, webSearch, dbTools } from '@blinkdotnew/react'
|
|
161
|
+
*
|
|
162
|
+
* // 1. Define agent (can be shared across components)
|
|
163
|
+
* const myAgent = new Agent({
|
|
164
|
+
* model: 'openai/gpt-4o',
|
|
165
|
+
* system: 'You are a helpful assistant.',
|
|
166
|
+
* tools: [webSearch, ...dbTools],
|
|
167
|
+
* })
|
|
168
|
+
*
|
|
169
|
+
* // 2. Use in component
|
|
170
|
+
* function Chat() {
|
|
171
|
+
* const { messages, input, handleInputChange, handleSubmit, isLoading } = useAgent({
|
|
172
|
+
* agent: myAgent,
|
|
173
|
+
* })
|
|
174
|
+
*
|
|
175
|
+
* return (
|
|
176
|
+
* <form onSubmit={handleSubmit}>
|
|
177
|
+
* <input value={input} onChange={handleInputChange} />
|
|
178
|
+
* <button type="submit" disabled={isLoading}>Send</button>
|
|
179
|
+
* </form>
|
|
180
|
+
* )
|
|
181
|
+
* }
|
|
182
|
+
* ```
|
|
183
|
+
*/
|
|
184
|
+
declare function useAgent(options: UseAgentOptions): UseAgentReturn;
|
|
185
|
+
|
|
186
|
+
export { type AddToolOutputOptions, BlinkAuthProvider, type BlinkAuthProviderProps, BlinkProvider, type BlinkProviderProps, type UseAgentOptions, type UseAgentReturn, useAgent, useBlink, useBlinkAuth, useBlinkClient };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import { BlinkClient, Agent, UIMessage, AgentResponse } from '@blinkdotnew/sdk';
|
|
2
|
+
export * from '@blinkdotnew/sdk';
|
|
3
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
4
|
+
import { ReactNode } from 'react';
|
|
5
|
+
|
|
6
|
+
interface BlinkContextValue {
|
|
7
|
+
client: BlinkClient;
|
|
8
|
+
projectId: string;
|
|
9
|
+
}
|
|
10
|
+
interface BlinkProviderProps {
|
|
11
|
+
/** Your Blink project ID */
|
|
12
|
+
projectId: string;
|
|
13
|
+
/** Publishable key for client-side usage */
|
|
14
|
+
publishableKey?: string;
|
|
15
|
+
/** Secret key for server-side usage (do not expose in browser!) */
|
|
16
|
+
secretKey?: string;
|
|
17
|
+
/** Children components */
|
|
18
|
+
children: ReactNode;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Provides Blink client to all child components
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```tsx
|
|
25
|
+
* import { BlinkProvider } from '@blinkdotnew/react'
|
|
26
|
+
*
|
|
27
|
+
* function App() {
|
|
28
|
+
* return (
|
|
29
|
+
* <BlinkProvider
|
|
30
|
+
* projectId="proj_abc123"
|
|
31
|
+
* publishableKey="blnk_pk_..."
|
|
32
|
+
* >
|
|
33
|
+
* <MyApp />
|
|
34
|
+
* </BlinkProvider>
|
|
35
|
+
* )
|
|
36
|
+
* }
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
declare function BlinkProvider({ projectId, publishableKey, secretKey, children, }: BlinkProviderProps): react_jsx_runtime.JSX.Element;
|
|
40
|
+
/**
|
|
41
|
+
* Get the Blink client from context
|
|
42
|
+
*
|
|
43
|
+
* @throws If used outside BlinkProvider
|
|
44
|
+
*/
|
|
45
|
+
declare function useBlink(): BlinkContextValue;
|
|
46
|
+
/**
|
|
47
|
+
* Get the Blink client instance directly
|
|
48
|
+
*
|
|
49
|
+
* @throws If used outside BlinkProvider
|
|
50
|
+
*/
|
|
51
|
+
declare function useBlinkClient(): BlinkClient;
|
|
52
|
+
interface BlinkAuthContextValue {
|
|
53
|
+
isAuthenticated: boolean;
|
|
54
|
+
isLoading: boolean;
|
|
55
|
+
user: any | null;
|
|
56
|
+
signIn: (email: string, password: string) => Promise<void>;
|
|
57
|
+
signUp: (email: string, password: string) => Promise<void>;
|
|
58
|
+
signOut: () => Promise<void>;
|
|
59
|
+
}
|
|
60
|
+
interface BlinkAuthProviderProps {
|
|
61
|
+
children: ReactNode;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Provides authentication state to all child components
|
|
65
|
+
*
|
|
66
|
+
* Must be nested inside BlinkProvider
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* ```tsx
|
|
70
|
+
* import { BlinkProvider, BlinkAuthProvider } from '@blinkdotnew/react'
|
|
71
|
+
*
|
|
72
|
+
* function App() {
|
|
73
|
+
* return (
|
|
74
|
+
* <BlinkProvider projectId="proj_abc123" publishableKey="blnk_pk_...">
|
|
75
|
+
* <BlinkAuthProvider>
|
|
76
|
+
* <MyApp />
|
|
77
|
+
* </BlinkAuthProvider>
|
|
78
|
+
* </BlinkProvider>
|
|
79
|
+
* )
|
|
80
|
+
* }
|
|
81
|
+
* ```
|
|
82
|
+
*/
|
|
83
|
+
declare function BlinkAuthProvider({ children }: BlinkAuthProviderProps): react_jsx_runtime.JSX.Element;
|
|
84
|
+
/**
|
|
85
|
+
* Get authentication state and methods
|
|
86
|
+
*
|
|
87
|
+
* @throws If used outside BlinkAuthProvider
|
|
88
|
+
*/
|
|
89
|
+
declare function useBlinkAuth(): BlinkAuthContextValue;
|
|
90
|
+
|
|
91
|
+
interface UseAgentOptions {
|
|
92
|
+
/**
|
|
93
|
+
* Agent instance created with `new Agent()`
|
|
94
|
+
*
|
|
95
|
+
* @example
|
|
96
|
+
* ```tsx
|
|
97
|
+
* const myAgent = new Agent({
|
|
98
|
+
* model: 'openai/gpt-4o',
|
|
99
|
+
* tools: [webSearch],
|
|
100
|
+
* })
|
|
101
|
+
*
|
|
102
|
+
* const chat = useAgent({ agent: myAgent })
|
|
103
|
+
* ```
|
|
104
|
+
*/
|
|
105
|
+
agent: Agent;
|
|
106
|
+
/** Initial messages */
|
|
107
|
+
initialMessages?: UIMessage[];
|
|
108
|
+
/** Callback when response is received */
|
|
109
|
+
onFinish?: (response: AgentResponse) => void;
|
|
110
|
+
/** Callback on error */
|
|
111
|
+
onError?: (error: Error) => void;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Options for addToolOutput
|
|
115
|
+
*/
|
|
116
|
+
interface AddToolOutputOptions {
|
|
117
|
+
toolCallId: string;
|
|
118
|
+
tool: string;
|
|
119
|
+
output: any;
|
|
120
|
+
}
|
|
121
|
+
interface UseAgentReturn {
|
|
122
|
+
/** Current messages */
|
|
123
|
+
messages: UIMessage[];
|
|
124
|
+
/** Current input value */
|
|
125
|
+
input: string;
|
|
126
|
+
/** Set input value */
|
|
127
|
+
setInput: (input: string) => void;
|
|
128
|
+
/** Whether the agent is processing */
|
|
129
|
+
isLoading: boolean;
|
|
130
|
+
/** Any error that occurred */
|
|
131
|
+
error: Error | null;
|
|
132
|
+
/** Send a message */
|
|
133
|
+
sendMessage: (content?: string) => Promise<void>;
|
|
134
|
+
/** Append a message without sending */
|
|
135
|
+
append: (message: UIMessage) => void;
|
|
136
|
+
/** Handle input change (for controlled inputs) */
|
|
137
|
+
handleInputChange: (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => void;
|
|
138
|
+
/** Handle form submit */
|
|
139
|
+
handleSubmit: (e?: React.FormEvent) => void;
|
|
140
|
+
/** Add tool output for HITL (Human-in-the-Loop) */
|
|
141
|
+
addToolOutput: (options: AddToolOutputOptions) => void;
|
|
142
|
+
/** Clear messages */
|
|
143
|
+
clearMessages: () => void;
|
|
144
|
+
/** Stop generation */
|
|
145
|
+
stop: () => void;
|
|
146
|
+
/** Reload last message */
|
|
147
|
+
reload: () => Promise<void>;
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* React hook for AI agent chat functionality
|
|
151
|
+
*
|
|
152
|
+
* Compatible with AI SDK's useChat pattern but powered by Blink.
|
|
153
|
+
*
|
|
154
|
+
* **Official usage pattern:**
|
|
155
|
+
* 1. Create agent: `const myAgent = new Agent({...})`
|
|
156
|
+
* 2. Use in hook: `useAgent({ agent: myAgent })`
|
|
157
|
+
*
|
|
158
|
+
* @example
|
|
159
|
+
* ```tsx
|
|
160
|
+
* import { Agent, useAgent, webSearch, dbTools } from '@blinkdotnew/react'
|
|
161
|
+
*
|
|
162
|
+
* // 1. Define agent (can be shared across components)
|
|
163
|
+
* const myAgent = new Agent({
|
|
164
|
+
* model: 'openai/gpt-4o',
|
|
165
|
+
* system: 'You are a helpful assistant.',
|
|
166
|
+
* tools: [webSearch, ...dbTools],
|
|
167
|
+
* })
|
|
168
|
+
*
|
|
169
|
+
* // 2. Use in component
|
|
170
|
+
* function Chat() {
|
|
171
|
+
* const { messages, input, handleInputChange, handleSubmit, isLoading } = useAgent({
|
|
172
|
+
* agent: myAgent,
|
|
173
|
+
* })
|
|
174
|
+
*
|
|
175
|
+
* return (
|
|
176
|
+
* <form onSubmit={handleSubmit}>
|
|
177
|
+
* <input value={input} onChange={handleInputChange} />
|
|
178
|
+
* <button type="submit" disabled={isLoading}>Send</button>
|
|
179
|
+
* </form>
|
|
180
|
+
* )
|
|
181
|
+
* }
|
|
182
|
+
* ```
|
|
183
|
+
*/
|
|
184
|
+
declare function useAgent(options: UseAgentOptions): UseAgentReturn;
|
|
185
|
+
|
|
186
|
+
export { type AddToolOutputOptions, BlinkAuthProvider, type BlinkAuthProviderProps, BlinkProvider, type BlinkProviderProps, type UseAgentOptions, type UseAgentReturn, useAgent, useBlink, useBlinkAuth, useBlinkClient };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,400 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
|
|
21
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
22
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
23
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
24
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
25
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
26
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
27
|
+
mod
|
|
28
|
+
));
|
|
29
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
30
|
+
|
|
31
|
+
// src/index.ts
|
|
32
|
+
var index_exports = {};
|
|
33
|
+
__export(index_exports, {
|
|
34
|
+
BlinkAuthProvider: () => BlinkAuthProvider,
|
|
35
|
+
BlinkProvider: () => BlinkProvider,
|
|
36
|
+
useAgent: () => useAgent,
|
|
37
|
+
useBlink: () => useBlink,
|
|
38
|
+
useBlinkAuth: () => useBlinkAuth,
|
|
39
|
+
useBlinkClient: () => useBlinkClient
|
|
40
|
+
});
|
|
41
|
+
module.exports = __toCommonJS(index_exports);
|
|
42
|
+
__reExport(index_exports, require("@blinkdotnew/sdk"), module.exports);
|
|
43
|
+
|
|
44
|
+
// src/context.tsx
|
|
45
|
+
var import_react = __toESM(require("react"));
|
|
46
|
+
var import_sdk = require("@blinkdotnew/sdk");
|
|
47
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
48
|
+
var BlinkContext = (0, import_react.createContext)(null);
|
|
49
|
+
function BlinkProvider({
|
|
50
|
+
projectId,
|
|
51
|
+
publishableKey,
|
|
52
|
+
secretKey,
|
|
53
|
+
children
|
|
54
|
+
}) {
|
|
55
|
+
const client = (0, import_react.useMemo)(
|
|
56
|
+
() => (0, import_sdk.createClient)({
|
|
57
|
+
projectId,
|
|
58
|
+
publishableKey,
|
|
59
|
+
secretKey
|
|
60
|
+
}),
|
|
61
|
+
[projectId, publishableKey, secretKey]
|
|
62
|
+
);
|
|
63
|
+
const value = (0, import_react.useMemo)(
|
|
64
|
+
() => ({
|
|
65
|
+
client,
|
|
66
|
+
projectId
|
|
67
|
+
}),
|
|
68
|
+
[client, projectId]
|
|
69
|
+
);
|
|
70
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(BlinkContext.Provider, { value, children });
|
|
71
|
+
}
|
|
72
|
+
function useBlink() {
|
|
73
|
+
const context = (0, import_react.useContext)(BlinkContext);
|
|
74
|
+
if (!context) {
|
|
75
|
+
throw new Error("useBlink must be used within a BlinkProvider");
|
|
76
|
+
}
|
|
77
|
+
return context;
|
|
78
|
+
}
|
|
79
|
+
function useBlinkClient() {
|
|
80
|
+
return useBlink().client;
|
|
81
|
+
}
|
|
82
|
+
var BlinkAuthContext = (0, import_react.createContext)(null);
|
|
83
|
+
function BlinkAuthProvider({ children }) {
|
|
84
|
+
const { client } = useBlink();
|
|
85
|
+
const [isLoading, setIsLoading] = import_react.default.useState(true);
|
|
86
|
+
const [user, setUser] = import_react.default.useState(null);
|
|
87
|
+
import_react.default.useEffect(() => {
|
|
88
|
+
let mounted = true;
|
|
89
|
+
const initAuth = async () => {
|
|
90
|
+
try {
|
|
91
|
+
const currentUser = await client.auth.me();
|
|
92
|
+
if (mounted) {
|
|
93
|
+
setUser(currentUser);
|
|
94
|
+
}
|
|
95
|
+
} catch {
|
|
96
|
+
if (mounted) {
|
|
97
|
+
setUser(null);
|
|
98
|
+
}
|
|
99
|
+
} finally {
|
|
100
|
+
if (mounted) {
|
|
101
|
+
setIsLoading(false);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
initAuth();
|
|
106
|
+
const unsubscribe = client.auth.onAuthStateChanged((state) => {
|
|
107
|
+
setUser(state.user);
|
|
108
|
+
});
|
|
109
|
+
return () => {
|
|
110
|
+
mounted = false;
|
|
111
|
+
unsubscribe();
|
|
112
|
+
};
|
|
113
|
+
}, [client]);
|
|
114
|
+
const signIn = import_react.default.useCallback(
|
|
115
|
+
async (email, password) => {
|
|
116
|
+
const result = await client.auth.signInWithEmail(email, password);
|
|
117
|
+
setUser(result);
|
|
118
|
+
},
|
|
119
|
+
[client]
|
|
120
|
+
);
|
|
121
|
+
const signUp = import_react.default.useCallback(
|
|
122
|
+
async (email, password) => {
|
|
123
|
+
const result = await client.auth.signUp({ email, password });
|
|
124
|
+
setUser(result);
|
|
125
|
+
},
|
|
126
|
+
[client]
|
|
127
|
+
);
|
|
128
|
+
const signOut = import_react.default.useCallback(async () => {
|
|
129
|
+
await client.auth.signOut();
|
|
130
|
+
setUser(null);
|
|
131
|
+
}, [client]);
|
|
132
|
+
const value = (0, import_react.useMemo)(
|
|
133
|
+
() => ({
|
|
134
|
+
isAuthenticated: !!user,
|
|
135
|
+
isLoading,
|
|
136
|
+
user,
|
|
137
|
+
signIn,
|
|
138
|
+
signUp,
|
|
139
|
+
signOut
|
|
140
|
+
}),
|
|
141
|
+
[isLoading, user, signIn, signUp, signOut]
|
|
142
|
+
);
|
|
143
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(BlinkAuthContext.Provider, { value, children });
|
|
144
|
+
}
|
|
145
|
+
function useBlinkAuth() {
|
|
146
|
+
const context = (0, import_react.useContext)(BlinkAuthContext);
|
|
147
|
+
if (!context) {
|
|
148
|
+
throw new Error("useBlinkAuth must be used within a BlinkAuthProvider");
|
|
149
|
+
}
|
|
150
|
+
return context;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// src/use-agent.ts
|
|
154
|
+
var import_react2 = require("react");
|
|
155
|
+
function useAgent(options) {
|
|
156
|
+
const client = useBlinkClient();
|
|
157
|
+
const { agent: agentInput, initialMessages = [], onFinish, onError } = options;
|
|
158
|
+
const [messages, setMessages] = (0, import_react2.useState)(initialMessages);
|
|
159
|
+
const [input, setInput] = (0, import_react2.useState)("");
|
|
160
|
+
const [isLoading, setIsLoading] = (0, import_react2.useState)(false);
|
|
161
|
+
const [error, setError] = (0, import_react2.useState)(null);
|
|
162
|
+
const abortControllerRef = (0, import_react2.useRef)(null);
|
|
163
|
+
const agent = (0, import_react2.useMemo)(() => {
|
|
164
|
+
return client.ai.bindAgent(agentInput);
|
|
165
|
+
}, [agentInput, client]);
|
|
166
|
+
const agentModel = agent.model;
|
|
167
|
+
const generateId = (0, import_react2.useCallback)(() => {
|
|
168
|
+
return `msg_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`;
|
|
169
|
+
}, []);
|
|
170
|
+
const parseStream = (0, import_react2.useCallback)(
|
|
171
|
+
async (response, assistantMessageId) => {
|
|
172
|
+
if (!response.body) {
|
|
173
|
+
throw new Error("No response body");
|
|
174
|
+
}
|
|
175
|
+
const reader = response.body.getReader();
|
|
176
|
+
const decoder = new TextDecoder();
|
|
177
|
+
let buffer = "";
|
|
178
|
+
let currentText = "";
|
|
179
|
+
let currentParts = [];
|
|
180
|
+
let finishData = null;
|
|
181
|
+
try {
|
|
182
|
+
while (true) {
|
|
183
|
+
const { done, value } = await reader.read();
|
|
184
|
+
if (done) break;
|
|
185
|
+
buffer += decoder.decode(value, { stream: true });
|
|
186
|
+
const lines = buffer.split("\n");
|
|
187
|
+
buffer = lines.pop() || "";
|
|
188
|
+
for (const line of lines) {
|
|
189
|
+
const trimmedLine = line.trim();
|
|
190
|
+
if (!trimmedLine || !trimmedLine.startsWith("data:")) continue;
|
|
191
|
+
if (trimmedLine === "data: [DONE]" || trimmedLine === "data:[DONE]") continue;
|
|
192
|
+
try {
|
|
193
|
+
const jsonStr = trimmedLine.startsWith("data: ") ? trimmedLine.slice(6) : trimmedLine.slice(5);
|
|
194
|
+
if (!jsonStr.trim()) continue;
|
|
195
|
+
const json = JSON.parse(jsonStr);
|
|
196
|
+
switch (json.type) {
|
|
197
|
+
// Handle text events (AI SDK v5 uses 'text-delta' with 'delta' property)
|
|
198
|
+
case "text-delta":
|
|
199
|
+
case "text": {
|
|
200
|
+
const textChunk = json.delta || json.textDelta || json.value || json.text || "";
|
|
201
|
+
currentText += textChunk;
|
|
202
|
+
setMessages(
|
|
203
|
+
(prev) => prev.map(
|
|
204
|
+
(m) => m.id === assistantMessageId ? { ...m, content: currentText, parts: [...currentParts.filter((p) => p.type !== "text"), { type: "text", text: currentText }] } : m
|
|
205
|
+
)
|
|
206
|
+
);
|
|
207
|
+
break;
|
|
208
|
+
}
|
|
209
|
+
// Handle tool call events
|
|
210
|
+
case "tool-call":
|
|
211
|
+
case "tool-call-start": {
|
|
212
|
+
const existingTool = currentParts.find(
|
|
213
|
+
(p) => p.type === "tool-invocation" && p.toolCallId === json.toolCallId
|
|
214
|
+
);
|
|
215
|
+
if (!existingTool) {
|
|
216
|
+
const toolPart = {
|
|
217
|
+
type: "tool-invocation",
|
|
218
|
+
toolCallId: json.toolCallId,
|
|
219
|
+
toolName: json.toolName,
|
|
220
|
+
state: "pending",
|
|
221
|
+
input: json.args || {}
|
|
222
|
+
};
|
|
223
|
+
currentParts = [...currentParts.filter((p) => p.type !== "text"), toolPart];
|
|
224
|
+
setMessages(
|
|
225
|
+
(prev) => prev.map(
|
|
226
|
+
(m) => m.id === assistantMessageId ? { ...m, parts: [...currentParts, { type: "text", text: currentText }] } : m
|
|
227
|
+
)
|
|
228
|
+
);
|
|
229
|
+
}
|
|
230
|
+
break;
|
|
231
|
+
}
|
|
232
|
+
// Handle tool result events
|
|
233
|
+
case "tool-result": {
|
|
234
|
+
currentParts = currentParts.map(
|
|
235
|
+
(p) => p.type === "tool-invocation" && p.toolCallId === json.toolCallId ? { ...p, state: "result", output: json.result } : p
|
|
236
|
+
);
|
|
237
|
+
setMessages(
|
|
238
|
+
(prev) => prev.map(
|
|
239
|
+
(m) => m.id === assistantMessageId ? { ...m, parts: [...currentParts.filter((p) => p.type !== "text"), { type: "text", text: currentText }] } : m
|
|
240
|
+
)
|
|
241
|
+
);
|
|
242
|
+
break;
|
|
243
|
+
}
|
|
244
|
+
// Handle finish event
|
|
245
|
+
case "finish":
|
|
246
|
+
case "done": {
|
|
247
|
+
finishData = json;
|
|
248
|
+
break;
|
|
249
|
+
}
|
|
250
|
+
// Ignore other event types (start, text-start, text-end, etc.)
|
|
251
|
+
default:
|
|
252
|
+
break;
|
|
253
|
+
}
|
|
254
|
+
} catch {
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
} finally {
|
|
259
|
+
reader.releaseLock();
|
|
260
|
+
}
|
|
261
|
+
return { text: currentText, finishData };
|
|
262
|
+
},
|
|
263
|
+
[]
|
|
264
|
+
);
|
|
265
|
+
const sendMessage = (0, import_react2.useCallback)(
|
|
266
|
+
async (content) => {
|
|
267
|
+
const messageContent = content ?? input;
|
|
268
|
+
if (!messageContent.trim() && messages.length === 0) return;
|
|
269
|
+
setError(null);
|
|
270
|
+
setIsLoading(true);
|
|
271
|
+
abortControllerRef.current = new AbortController();
|
|
272
|
+
try {
|
|
273
|
+
let newMessages = [...messages];
|
|
274
|
+
if (messageContent.trim()) {
|
|
275
|
+
const userMessage = {
|
|
276
|
+
id: generateId(),
|
|
277
|
+
role: "user",
|
|
278
|
+
content: messageContent.trim()
|
|
279
|
+
};
|
|
280
|
+
newMessages = [...newMessages, userMessage];
|
|
281
|
+
setMessages(newMessages);
|
|
282
|
+
setInput("");
|
|
283
|
+
}
|
|
284
|
+
const assistantMessageId = generateId();
|
|
285
|
+
const assistantMessage = {
|
|
286
|
+
id: assistantMessageId,
|
|
287
|
+
role: "assistant",
|
|
288
|
+
content: "",
|
|
289
|
+
parts: []
|
|
290
|
+
};
|
|
291
|
+
setMessages([...newMessages, assistantMessage]);
|
|
292
|
+
const response = await agent.stream({
|
|
293
|
+
messages: newMessages,
|
|
294
|
+
signal: abortControllerRef.current.signal
|
|
295
|
+
});
|
|
296
|
+
const { text, finishData } = await parseStream(response, assistantMessageId);
|
|
297
|
+
setMessages(
|
|
298
|
+
(prev) => prev.map(
|
|
299
|
+
(m) => m.id === assistantMessageId ? { ...m, content: text } : m
|
|
300
|
+
)
|
|
301
|
+
);
|
|
302
|
+
if (onFinish && finishData) {
|
|
303
|
+
onFinish({
|
|
304
|
+
text,
|
|
305
|
+
finishReason: finishData.finishReason || "stop",
|
|
306
|
+
steps: [],
|
|
307
|
+
usage: finishData.usage || { inputTokens: 0, outputTokens: 0 },
|
|
308
|
+
_billing: finishData._billing || { model: agentModel, creditsCharged: 0, costUSD: 0 }
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
} catch (err) {
|
|
312
|
+
const error2 = err instanceof Error ? err : new Error(String(err));
|
|
313
|
+
if (error2.name !== "AbortError") {
|
|
314
|
+
setError(error2);
|
|
315
|
+
onError?.(error2);
|
|
316
|
+
}
|
|
317
|
+
} finally {
|
|
318
|
+
setIsLoading(false);
|
|
319
|
+
abortControllerRef.current = null;
|
|
320
|
+
}
|
|
321
|
+
},
|
|
322
|
+
[agent, agentModel, messages, input, generateId, parseStream, onFinish, onError]
|
|
323
|
+
);
|
|
324
|
+
const append = (0, import_react2.useCallback)((message) => {
|
|
325
|
+
setMessages((prev) => [...prev, { ...message, id: message.id || generateId() }]);
|
|
326
|
+
}, [generateId]);
|
|
327
|
+
const handleInputChange = (0, import_react2.useCallback)(
|
|
328
|
+
(e) => {
|
|
329
|
+
setInput(e.target.value);
|
|
330
|
+
},
|
|
331
|
+
[]
|
|
332
|
+
);
|
|
333
|
+
const handleSubmit = (0, import_react2.useCallback)(
|
|
334
|
+
(e) => {
|
|
335
|
+
e?.preventDefault();
|
|
336
|
+
sendMessage();
|
|
337
|
+
},
|
|
338
|
+
[sendMessage]
|
|
339
|
+
);
|
|
340
|
+
const addToolOutput = (0, import_react2.useCallback)(
|
|
341
|
+
({ toolCallId, tool, output }) => {
|
|
342
|
+
setMessages(
|
|
343
|
+
(prev) => prev.map((m) => {
|
|
344
|
+
if (m.role !== "assistant" || !m.parts) return m;
|
|
345
|
+
const updatedParts = m.parts.map(
|
|
346
|
+
(p) => p.type === "tool-invocation" && p.toolCallId === toolCallId && p.toolName === tool ? { ...p, state: "output-available", output } : p
|
|
347
|
+
);
|
|
348
|
+
return { ...m, parts: updatedParts };
|
|
349
|
+
})
|
|
350
|
+
);
|
|
351
|
+
},
|
|
352
|
+
[]
|
|
353
|
+
);
|
|
354
|
+
const clearMessages = (0, import_react2.useCallback)(() => {
|
|
355
|
+
setMessages(initialMessages);
|
|
356
|
+
setError(null);
|
|
357
|
+
}, [initialMessages]);
|
|
358
|
+
const stop = (0, import_react2.useCallback)(() => {
|
|
359
|
+
abortControllerRef.current?.abort();
|
|
360
|
+
}, []);
|
|
361
|
+
const reload = (0, import_react2.useCallback)(async () => {
|
|
362
|
+
let lastUserIndex = -1;
|
|
363
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
364
|
+
if (messages[i].role === "user") {
|
|
365
|
+
lastUserIndex = i;
|
|
366
|
+
break;
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
if (lastUserIndex === -1) return;
|
|
370
|
+
const messagesUpToLastUser = messages.slice(0, lastUserIndex + 1);
|
|
371
|
+
setMessages(messagesUpToLastUser);
|
|
372
|
+
await sendMessage();
|
|
373
|
+
}, [messages, sendMessage]);
|
|
374
|
+
return {
|
|
375
|
+
messages,
|
|
376
|
+
input,
|
|
377
|
+
setInput,
|
|
378
|
+
isLoading,
|
|
379
|
+
error,
|
|
380
|
+
sendMessage,
|
|
381
|
+
append,
|
|
382
|
+
handleInputChange,
|
|
383
|
+
handleSubmit,
|
|
384
|
+
addToolOutput,
|
|
385
|
+
clearMessages,
|
|
386
|
+
stop,
|
|
387
|
+
reload
|
|
388
|
+
};
|
|
389
|
+
}
|
|
390
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
391
|
+
0 && (module.exports = {
|
|
392
|
+
BlinkAuthProvider,
|
|
393
|
+
BlinkProvider,
|
|
394
|
+
useAgent,
|
|
395
|
+
useBlink,
|
|
396
|
+
useBlinkAuth,
|
|
397
|
+
useBlinkClient,
|
|
398
|
+
...require("@blinkdotnew/sdk")
|
|
399
|
+
});
|
|
400
|
+
//# sourceMappingURL=index.js.map
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
export * from "@blinkdotnew/sdk";
|
|
3
|
+
|
|
4
|
+
// src/context.tsx
|
|
5
|
+
import React, { createContext, useContext, useMemo } from "react";
|
|
6
|
+
import { createClient } from "@blinkdotnew/sdk";
|
|
7
|
+
import { jsx } from "react/jsx-runtime";
|
|
8
|
+
var BlinkContext = createContext(null);
|
|
9
|
+
function BlinkProvider({
|
|
10
|
+
projectId,
|
|
11
|
+
publishableKey,
|
|
12
|
+
secretKey,
|
|
13
|
+
children
|
|
14
|
+
}) {
|
|
15
|
+
const client = useMemo(
|
|
16
|
+
() => createClient({
|
|
17
|
+
projectId,
|
|
18
|
+
publishableKey,
|
|
19
|
+
secretKey
|
|
20
|
+
}),
|
|
21
|
+
[projectId, publishableKey, secretKey]
|
|
22
|
+
);
|
|
23
|
+
const value = useMemo(
|
|
24
|
+
() => ({
|
|
25
|
+
client,
|
|
26
|
+
projectId
|
|
27
|
+
}),
|
|
28
|
+
[client, projectId]
|
|
29
|
+
);
|
|
30
|
+
return /* @__PURE__ */ jsx(BlinkContext.Provider, { value, children });
|
|
31
|
+
}
|
|
32
|
+
function useBlink() {
|
|
33
|
+
const context = useContext(BlinkContext);
|
|
34
|
+
if (!context) {
|
|
35
|
+
throw new Error("useBlink must be used within a BlinkProvider");
|
|
36
|
+
}
|
|
37
|
+
return context;
|
|
38
|
+
}
|
|
39
|
+
function useBlinkClient() {
|
|
40
|
+
return useBlink().client;
|
|
41
|
+
}
|
|
42
|
+
var BlinkAuthContext = createContext(null);
|
|
43
|
+
function BlinkAuthProvider({ children }) {
|
|
44
|
+
const { client } = useBlink();
|
|
45
|
+
const [isLoading, setIsLoading] = React.useState(true);
|
|
46
|
+
const [user, setUser] = React.useState(null);
|
|
47
|
+
React.useEffect(() => {
|
|
48
|
+
let mounted = true;
|
|
49
|
+
const initAuth = async () => {
|
|
50
|
+
try {
|
|
51
|
+
const currentUser = await client.auth.me();
|
|
52
|
+
if (mounted) {
|
|
53
|
+
setUser(currentUser);
|
|
54
|
+
}
|
|
55
|
+
} catch {
|
|
56
|
+
if (mounted) {
|
|
57
|
+
setUser(null);
|
|
58
|
+
}
|
|
59
|
+
} finally {
|
|
60
|
+
if (mounted) {
|
|
61
|
+
setIsLoading(false);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
initAuth();
|
|
66
|
+
const unsubscribe = client.auth.onAuthStateChanged((state) => {
|
|
67
|
+
setUser(state.user);
|
|
68
|
+
});
|
|
69
|
+
return () => {
|
|
70
|
+
mounted = false;
|
|
71
|
+
unsubscribe();
|
|
72
|
+
};
|
|
73
|
+
}, [client]);
|
|
74
|
+
const signIn = React.useCallback(
|
|
75
|
+
async (email, password) => {
|
|
76
|
+
const result = await client.auth.signInWithEmail(email, password);
|
|
77
|
+
setUser(result);
|
|
78
|
+
},
|
|
79
|
+
[client]
|
|
80
|
+
);
|
|
81
|
+
const signUp = React.useCallback(
|
|
82
|
+
async (email, password) => {
|
|
83
|
+
const result = await client.auth.signUp({ email, password });
|
|
84
|
+
setUser(result);
|
|
85
|
+
},
|
|
86
|
+
[client]
|
|
87
|
+
);
|
|
88
|
+
const signOut = React.useCallback(async () => {
|
|
89
|
+
await client.auth.signOut();
|
|
90
|
+
setUser(null);
|
|
91
|
+
}, [client]);
|
|
92
|
+
const value = useMemo(
|
|
93
|
+
() => ({
|
|
94
|
+
isAuthenticated: !!user,
|
|
95
|
+
isLoading,
|
|
96
|
+
user,
|
|
97
|
+
signIn,
|
|
98
|
+
signUp,
|
|
99
|
+
signOut
|
|
100
|
+
}),
|
|
101
|
+
[isLoading, user, signIn, signUp, signOut]
|
|
102
|
+
);
|
|
103
|
+
return /* @__PURE__ */ jsx(BlinkAuthContext.Provider, { value, children });
|
|
104
|
+
}
|
|
105
|
+
function useBlinkAuth() {
|
|
106
|
+
const context = useContext(BlinkAuthContext);
|
|
107
|
+
if (!context) {
|
|
108
|
+
throw new Error("useBlinkAuth must be used within a BlinkAuthProvider");
|
|
109
|
+
}
|
|
110
|
+
return context;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// src/use-agent.ts
|
|
114
|
+
import { useCallback, useRef, useState, useMemo as useMemo2 } from "react";
|
|
115
|
+
function useAgent(options) {
|
|
116
|
+
const client = useBlinkClient();
|
|
117
|
+
const { agent: agentInput, initialMessages = [], onFinish, onError } = options;
|
|
118
|
+
const [messages, setMessages] = useState(initialMessages);
|
|
119
|
+
const [input, setInput] = useState("");
|
|
120
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
121
|
+
const [error, setError] = useState(null);
|
|
122
|
+
const abortControllerRef = useRef(null);
|
|
123
|
+
const agent = useMemo2(() => {
|
|
124
|
+
return client.ai.bindAgent(agentInput);
|
|
125
|
+
}, [agentInput, client]);
|
|
126
|
+
const agentModel = agent.model;
|
|
127
|
+
const generateId = useCallback(() => {
|
|
128
|
+
return `msg_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`;
|
|
129
|
+
}, []);
|
|
130
|
+
const parseStream = useCallback(
|
|
131
|
+
async (response, assistantMessageId) => {
|
|
132
|
+
if (!response.body) {
|
|
133
|
+
throw new Error("No response body");
|
|
134
|
+
}
|
|
135
|
+
const reader = response.body.getReader();
|
|
136
|
+
const decoder = new TextDecoder();
|
|
137
|
+
let buffer = "";
|
|
138
|
+
let currentText = "";
|
|
139
|
+
let currentParts = [];
|
|
140
|
+
let finishData = null;
|
|
141
|
+
try {
|
|
142
|
+
while (true) {
|
|
143
|
+
const { done, value } = await reader.read();
|
|
144
|
+
if (done) break;
|
|
145
|
+
buffer += decoder.decode(value, { stream: true });
|
|
146
|
+
const lines = buffer.split("\n");
|
|
147
|
+
buffer = lines.pop() || "";
|
|
148
|
+
for (const line of lines) {
|
|
149
|
+
const trimmedLine = line.trim();
|
|
150
|
+
if (!trimmedLine || !trimmedLine.startsWith("data:")) continue;
|
|
151
|
+
if (trimmedLine === "data: [DONE]" || trimmedLine === "data:[DONE]") continue;
|
|
152
|
+
try {
|
|
153
|
+
const jsonStr = trimmedLine.startsWith("data: ") ? trimmedLine.slice(6) : trimmedLine.slice(5);
|
|
154
|
+
if (!jsonStr.trim()) continue;
|
|
155
|
+
const json = JSON.parse(jsonStr);
|
|
156
|
+
switch (json.type) {
|
|
157
|
+
// Handle text events (AI SDK v5 uses 'text-delta' with 'delta' property)
|
|
158
|
+
case "text-delta":
|
|
159
|
+
case "text": {
|
|
160
|
+
const textChunk = json.delta || json.textDelta || json.value || json.text || "";
|
|
161
|
+
currentText += textChunk;
|
|
162
|
+
setMessages(
|
|
163
|
+
(prev) => prev.map(
|
|
164
|
+
(m) => m.id === assistantMessageId ? { ...m, content: currentText, parts: [...currentParts.filter((p) => p.type !== "text"), { type: "text", text: currentText }] } : m
|
|
165
|
+
)
|
|
166
|
+
);
|
|
167
|
+
break;
|
|
168
|
+
}
|
|
169
|
+
// Handle tool call events
|
|
170
|
+
case "tool-call":
|
|
171
|
+
case "tool-call-start": {
|
|
172
|
+
const existingTool = currentParts.find(
|
|
173
|
+
(p) => p.type === "tool-invocation" && p.toolCallId === json.toolCallId
|
|
174
|
+
);
|
|
175
|
+
if (!existingTool) {
|
|
176
|
+
const toolPart = {
|
|
177
|
+
type: "tool-invocation",
|
|
178
|
+
toolCallId: json.toolCallId,
|
|
179
|
+
toolName: json.toolName,
|
|
180
|
+
state: "pending",
|
|
181
|
+
input: json.args || {}
|
|
182
|
+
};
|
|
183
|
+
currentParts = [...currentParts.filter((p) => p.type !== "text"), toolPart];
|
|
184
|
+
setMessages(
|
|
185
|
+
(prev) => prev.map(
|
|
186
|
+
(m) => m.id === assistantMessageId ? { ...m, parts: [...currentParts, { type: "text", text: currentText }] } : m
|
|
187
|
+
)
|
|
188
|
+
);
|
|
189
|
+
}
|
|
190
|
+
break;
|
|
191
|
+
}
|
|
192
|
+
// Handle tool result events
|
|
193
|
+
case "tool-result": {
|
|
194
|
+
currentParts = currentParts.map(
|
|
195
|
+
(p) => p.type === "tool-invocation" && p.toolCallId === json.toolCallId ? { ...p, state: "result", output: json.result } : p
|
|
196
|
+
);
|
|
197
|
+
setMessages(
|
|
198
|
+
(prev) => prev.map(
|
|
199
|
+
(m) => m.id === assistantMessageId ? { ...m, parts: [...currentParts.filter((p) => p.type !== "text"), { type: "text", text: currentText }] } : m
|
|
200
|
+
)
|
|
201
|
+
);
|
|
202
|
+
break;
|
|
203
|
+
}
|
|
204
|
+
// Handle finish event
|
|
205
|
+
case "finish":
|
|
206
|
+
case "done": {
|
|
207
|
+
finishData = json;
|
|
208
|
+
break;
|
|
209
|
+
}
|
|
210
|
+
// Ignore other event types (start, text-start, text-end, etc.)
|
|
211
|
+
default:
|
|
212
|
+
break;
|
|
213
|
+
}
|
|
214
|
+
} catch {
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
} finally {
|
|
219
|
+
reader.releaseLock();
|
|
220
|
+
}
|
|
221
|
+
return { text: currentText, finishData };
|
|
222
|
+
},
|
|
223
|
+
[]
|
|
224
|
+
);
|
|
225
|
+
const sendMessage = useCallback(
|
|
226
|
+
async (content) => {
|
|
227
|
+
const messageContent = content ?? input;
|
|
228
|
+
if (!messageContent.trim() && messages.length === 0) return;
|
|
229
|
+
setError(null);
|
|
230
|
+
setIsLoading(true);
|
|
231
|
+
abortControllerRef.current = new AbortController();
|
|
232
|
+
try {
|
|
233
|
+
let newMessages = [...messages];
|
|
234
|
+
if (messageContent.trim()) {
|
|
235
|
+
const userMessage = {
|
|
236
|
+
id: generateId(),
|
|
237
|
+
role: "user",
|
|
238
|
+
content: messageContent.trim()
|
|
239
|
+
};
|
|
240
|
+
newMessages = [...newMessages, userMessage];
|
|
241
|
+
setMessages(newMessages);
|
|
242
|
+
setInput("");
|
|
243
|
+
}
|
|
244
|
+
const assistantMessageId = generateId();
|
|
245
|
+
const assistantMessage = {
|
|
246
|
+
id: assistantMessageId,
|
|
247
|
+
role: "assistant",
|
|
248
|
+
content: "",
|
|
249
|
+
parts: []
|
|
250
|
+
};
|
|
251
|
+
setMessages([...newMessages, assistantMessage]);
|
|
252
|
+
const response = await agent.stream({
|
|
253
|
+
messages: newMessages,
|
|
254
|
+
signal: abortControllerRef.current.signal
|
|
255
|
+
});
|
|
256
|
+
const { text, finishData } = await parseStream(response, assistantMessageId);
|
|
257
|
+
setMessages(
|
|
258
|
+
(prev) => prev.map(
|
|
259
|
+
(m) => m.id === assistantMessageId ? { ...m, content: text } : m
|
|
260
|
+
)
|
|
261
|
+
);
|
|
262
|
+
if (onFinish && finishData) {
|
|
263
|
+
onFinish({
|
|
264
|
+
text,
|
|
265
|
+
finishReason: finishData.finishReason || "stop",
|
|
266
|
+
steps: [],
|
|
267
|
+
usage: finishData.usage || { inputTokens: 0, outputTokens: 0 },
|
|
268
|
+
_billing: finishData._billing || { model: agentModel, creditsCharged: 0, costUSD: 0 }
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
} catch (err) {
|
|
272
|
+
const error2 = err instanceof Error ? err : new Error(String(err));
|
|
273
|
+
if (error2.name !== "AbortError") {
|
|
274
|
+
setError(error2);
|
|
275
|
+
onError?.(error2);
|
|
276
|
+
}
|
|
277
|
+
} finally {
|
|
278
|
+
setIsLoading(false);
|
|
279
|
+
abortControllerRef.current = null;
|
|
280
|
+
}
|
|
281
|
+
},
|
|
282
|
+
[agent, agentModel, messages, input, generateId, parseStream, onFinish, onError]
|
|
283
|
+
);
|
|
284
|
+
const append = useCallback((message) => {
|
|
285
|
+
setMessages((prev) => [...prev, { ...message, id: message.id || generateId() }]);
|
|
286
|
+
}, [generateId]);
|
|
287
|
+
const handleInputChange = useCallback(
|
|
288
|
+
(e) => {
|
|
289
|
+
setInput(e.target.value);
|
|
290
|
+
},
|
|
291
|
+
[]
|
|
292
|
+
);
|
|
293
|
+
const handleSubmit = useCallback(
|
|
294
|
+
(e) => {
|
|
295
|
+
e?.preventDefault();
|
|
296
|
+
sendMessage();
|
|
297
|
+
},
|
|
298
|
+
[sendMessage]
|
|
299
|
+
);
|
|
300
|
+
const addToolOutput = useCallback(
|
|
301
|
+
({ toolCallId, tool, output }) => {
|
|
302
|
+
setMessages(
|
|
303
|
+
(prev) => prev.map((m) => {
|
|
304
|
+
if (m.role !== "assistant" || !m.parts) return m;
|
|
305
|
+
const updatedParts = m.parts.map(
|
|
306
|
+
(p) => p.type === "tool-invocation" && p.toolCallId === toolCallId && p.toolName === tool ? { ...p, state: "output-available", output } : p
|
|
307
|
+
);
|
|
308
|
+
return { ...m, parts: updatedParts };
|
|
309
|
+
})
|
|
310
|
+
);
|
|
311
|
+
},
|
|
312
|
+
[]
|
|
313
|
+
);
|
|
314
|
+
const clearMessages = useCallback(() => {
|
|
315
|
+
setMessages(initialMessages);
|
|
316
|
+
setError(null);
|
|
317
|
+
}, [initialMessages]);
|
|
318
|
+
const stop = useCallback(() => {
|
|
319
|
+
abortControllerRef.current?.abort();
|
|
320
|
+
}, []);
|
|
321
|
+
const reload = useCallback(async () => {
|
|
322
|
+
let lastUserIndex = -1;
|
|
323
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
324
|
+
if (messages[i].role === "user") {
|
|
325
|
+
lastUserIndex = i;
|
|
326
|
+
break;
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
if (lastUserIndex === -1) return;
|
|
330
|
+
const messagesUpToLastUser = messages.slice(0, lastUserIndex + 1);
|
|
331
|
+
setMessages(messagesUpToLastUser);
|
|
332
|
+
await sendMessage();
|
|
333
|
+
}, [messages, sendMessage]);
|
|
334
|
+
return {
|
|
335
|
+
messages,
|
|
336
|
+
input,
|
|
337
|
+
setInput,
|
|
338
|
+
isLoading,
|
|
339
|
+
error,
|
|
340
|
+
sendMessage,
|
|
341
|
+
append,
|
|
342
|
+
handleInputChange,
|
|
343
|
+
handleSubmit,
|
|
344
|
+
addToolOutput,
|
|
345
|
+
clearMessages,
|
|
346
|
+
stop,
|
|
347
|
+
reload
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
export {
|
|
351
|
+
BlinkAuthProvider,
|
|
352
|
+
BlinkProvider,
|
|
353
|
+
useAgent,
|
|
354
|
+
useBlink,
|
|
355
|
+
useBlinkAuth,
|
|
356
|
+
useBlinkClient
|
|
357
|
+
};
|
|
358
|
+
//# sourceMappingURL=index.mjs.map
|
package/package.json
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@blinkdotnew/react",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Blink SDK for React - AI agents, database, storage, and auth for modern SaaS/AI apps",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"blink",
|
|
7
|
+
"react",
|
|
8
|
+
"sdk",
|
|
9
|
+
"ai",
|
|
10
|
+
"agent",
|
|
11
|
+
"chat",
|
|
12
|
+
"typescript",
|
|
13
|
+
"hooks",
|
|
14
|
+
"useChat",
|
|
15
|
+
"useAgent"
|
|
16
|
+
],
|
|
17
|
+
"homepage": "https://blink.new",
|
|
18
|
+
"repository": {
|
|
19
|
+
"type": "git",
|
|
20
|
+
"url": "git+https://github.com/ShadowWalker2014/blink-sdk.git",
|
|
21
|
+
"directory": "packages/react"
|
|
22
|
+
},
|
|
23
|
+
"bugs": {
|
|
24
|
+
"url": "https://github.com/ShadowWalker2014/blink-sdk/issues"
|
|
25
|
+
},
|
|
26
|
+
"author": "Blink Team",
|
|
27
|
+
"license": "MIT",
|
|
28
|
+
"main": "dist/index.js",
|
|
29
|
+
"module": "dist/index.mjs",
|
|
30
|
+
"types": "dist/index.d.ts",
|
|
31
|
+
"exports": {
|
|
32
|
+
".": {
|
|
33
|
+
"types": "./dist/index.d.ts",
|
|
34
|
+
"import": "./dist/index.mjs",
|
|
35
|
+
"require": "./dist/index.js"
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
"files": [
|
|
39
|
+
"dist/**/*.js",
|
|
40
|
+
"dist/**/*.mjs",
|
|
41
|
+
"dist/**/*.d.ts",
|
|
42
|
+
"dist/**/*.d.mts"
|
|
43
|
+
],
|
|
44
|
+
"scripts": {
|
|
45
|
+
"build": "tsup",
|
|
46
|
+
"dev": "tsup --watch",
|
|
47
|
+
"type-check": "tsc --noEmit",
|
|
48
|
+
"clean": "rm -rf dist",
|
|
49
|
+
"prepublishOnly": "npm run build"
|
|
50
|
+
},
|
|
51
|
+
"dependencies": {
|
|
52
|
+
"@blinkdotnew/sdk": "^2.3.0"
|
|
53
|
+
},
|
|
54
|
+
"devDependencies": {
|
|
55
|
+
"@types/react": "^18.0.0",
|
|
56
|
+
"react": "^18.0.0",
|
|
57
|
+
"tsup": "^8.0.0",
|
|
58
|
+
"typescript": "^5.0.0"
|
|
59
|
+
},
|
|
60
|
+
"peerDependencies": {
|
|
61
|
+
"react": "^18.0.0 || ^19.0.0"
|
|
62
|
+
},
|
|
63
|
+
"publishConfig": {
|
|
64
|
+
"access": "public"
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
|