okrapdf 0.8.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.
@@ -0,0 +1,432 @@
1
+ import {
2
+ createOkra
3
+ } from "../chunk-AG3A2T3B.js";
4
+ import "../chunk-HITG34US.js";
5
+
6
+ // src/react/provider.ts
7
+ import { createContext, useContext, useMemo, createElement } from "react";
8
+ var OkraContext = createContext(null);
9
+ function OkraProvider({ apiKey, baseUrl, children }) {
10
+ const value = useMemo(() => {
11
+ const client = createOkra({ apiKey, baseUrl });
12
+ return { client, apiKey };
13
+ }, [apiKey, baseUrl]);
14
+ return createElement(OkraContext.Provider, { value }, children);
15
+ }
16
+ function useOkra() {
17
+ const ctx = useContext(OkraContext);
18
+ if (!ctx) {
19
+ throw new Error("useOkra must be used within an <OkraProvider>");
20
+ }
21
+ return ctx;
22
+ }
23
+
24
+ // src/react/use-document-session.ts
25
+ import { useState, useCallback, useRef } from "react";
26
+ function useDocumentSession(options = {}) {
27
+ const { wait = true } = options;
28
+ const { client } = useOkra();
29
+ const [session, setSession] = useState(null);
30
+ const [status, setStatus] = useState("idle");
31
+ const [error, setError] = useState(null);
32
+ const [documentStatus, setDocumentStatus] = useState(null);
33
+ const uploadIdRef = useRef(0);
34
+ const upload = useCallback(
35
+ async (source) => {
36
+ const currentId = ++uploadIdRef.current;
37
+ try {
38
+ setError(null);
39
+ setStatus("uploading");
40
+ setDocumentStatus(null);
41
+ setSession(null);
42
+ const sess = await client.sessions.create(source, { wait });
43
+ if (currentId !== uploadIdRef.current) return;
44
+ const docStatus = await sess.status();
45
+ setDocumentStatus(docStatus);
46
+ setSession(sess);
47
+ setStatus("ready");
48
+ } catch (err) {
49
+ if (currentId !== uploadIdRef.current) return;
50
+ const e = err instanceof Error ? err : new Error(String(err));
51
+ setError(e);
52
+ setStatus("error");
53
+ }
54
+ },
55
+ [client, wait]
56
+ );
57
+ return { session, status, error, upload, documentStatus };
58
+ }
59
+
60
+ // src/react/use-document-status.ts
61
+ import { useState as useState2, useEffect, useRef as useRef2, useCallback as useCallback2 } from "react";
62
+ var COMPLETE_PHASES = /* @__PURE__ */ new Set(["complete", "awaiting_review"]);
63
+ var PROCESSING_PHASES = /* @__PURE__ */ new Set(["uploading", "parsing", "hydrating", "verifying"]);
64
+ function useDocumentStatus(sessionOrId, options = {}) {
65
+ const { pollInterval = 2e3, enabled = true } = options;
66
+ const { client } = useOkra();
67
+ const [data, setData] = useState2(null);
68
+ const [isLoading, setIsLoading] = useState2(false);
69
+ const [error, setError] = useState2(null);
70
+ const abortRef = useRef2(null);
71
+ const session = typeof sessionOrId === "string" ? client.sessions.from(sessionOrId) : sessionOrId;
72
+ const docId = session?.id ?? null;
73
+ const fetchStatus = useCallback2(async () => {
74
+ if (!session || !enabled) return;
75
+ try {
76
+ abortRef.current?.abort();
77
+ const ac = new AbortController();
78
+ abortRef.current = ac;
79
+ setIsLoading(true);
80
+ const s = await session.status(ac.signal);
81
+ setData(s);
82
+ setError(null);
83
+ } catch (err) {
84
+ if (err.name === "AbortError") return;
85
+ setError(err instanceof Error ? err : new Error(String(err)));
86
+ } finally {
87
+ setIsLoading(false);
88
+ }
89
+ }, [session, enabled]);
90
+ useEffect(() => {
91
+ setData(null);
92
+ setError(null);
93
+ }, [docId]);
94
+ useEffect(() => {
95
+ fetchStatus();
96
+ return () => abortRef.current?.abort();
97
+ }, [fetchStatus]);
98
+ useEffect(() => {
99
+ if (!session || !pollInterval || !enabled) return;
100
+ if (data && COMPLETE_PHASES.has(data.phase)) return;
101
+ const interval = setInterval(fetchStatus, pollInterval);
102
+ return () => clearInterval(interval);
103
+ }, [session, pollInterval, enabled, data?.phase, fetchStatus]);
104
+ return {
105
+ data,
106
+ isLoading,
107
+ error,
108
+ isComplete: data ? COMPLETE_PHASES.has(data.phase) : false,
109
+ isProcessing: data ? PROCESSING_PHASES.has(data.phase) : false,
110
+ refetch: fetchStatus
111
+ };
112
+ }
113
+
114
+ // src/react/use-pages.ts
115
+ import { useState as useState3, useEffect as useEffect2, useRef as useRef3, useCallback as useCallback3 } from "react";
116
+ function usePages(sessionOrId, options = {}) {
117
+ const { enabled = true } = options;
118
+ const { client } = useOkra();
119
+ const [data, setData] = useState3([]);
120
+ const [isLoading, setIsLoading] = useState3(false);
121
+ const [error, setError] = useState3(null);
122
+ const abortRef = useRef3(null);
123
+ const session = typeof sessionOrId === "string" ? client.sessions.from(sessionOrId) : sessionOrId;
124
+ const docId = session?.id ?? null;
125
+ const fetchPages = useCallback3(async () => {
126
+ if (!session || !enabled) return;
127
+ try {
128
+ abortRef.current?.abort();
129
+ const ac = new AbortController();
130
+ abortRef.current = ac;
131
+ setIsLoading(true);
132
+ const result = await session.pages({ signal: ac.signal });
133
+ setData(result);
134
+ setError(null);
135
+ } catch (err) {
136
+ if (err.name === "AbortError") return;
137
+ setError(err instanceof Error ? err : new Error(String(err)));
138
+ } finally {
139
+ setIsLoading(false);
140
+ }
141
+ }, [session, enabled]);
142
+ useEffect2(() => {
143
+ setData([]);
144
+ setError(null);
145
+ }, [docId]);
146
+ useEffect2(() => {
147
+ fetchPages();
148
+ return () => abortRef.current?.abort();
149
+ }, [fetchPages]);
150
+ return { data, isLoading, error, refetch: fetchPages };
151
+ }
152
+
153
+ // src/react/use-page-content.ts
154
+ import { useState as useState4, useEffect as useEffect3, useRef as useRef4, useCallback as useCallback4 } from "react";
155
+ function usePageContent(sessionOrId, pageNumber, options = {}) {
156
+ const { pollInterval = 3e3 } = options;
157
+ const { client } = useOkra();
158
+ const [data, setData] = useState4(null);
159
+ const [isLoading, setIsLoading] = useState4(false);
160
+ const [error, setError] = useState4(null);
161
+ const abortRef = useRef4(null);
162
+ const hasContentRef = useRef4(false);
163
+ const session = typeof sessionOrId === "string" ? client.sessions.from(sessionOrId) : sessionOrId;
164
+ const fetchPage = useCallback4(async () => {
165
+ if (!session || !pageNumber) return;
166
+ try {
167
+ abortRef.current?.abort();
168
+ const ac = new AbortController();
169
+ abortRef.current = ac;
170
+ setIsLoading(true);
171
+ const result = await session.page(pageNumber, ac.signal);
172
+ setData(result);
173
+ setError(null);
174
+ hasContentRef.current = !!result.content;
175
+ } catch (err) {
176
+ if (err.name === "AbortError") return;
177
+ setError(err instanceof Error ? err : new Error(String(err)));
178
+ } finally {
179
+ setIsLoading(false);
180
+ }
181
+ }, [session, pageNumber]);
182
+ useEffect3(() => {
183
+ setData(null);
184
+ hasContentRef.current = false;
185
+ setError(null);
186
+ }, [pageNumber]);
187
+ useEffect3(() => {
188
+ fetchPage();
189
+ return () => abortRef.current?.abort();
190
+ }, [fetchPage]);
191
+ useEffect3(() => {
192
+ if (!session || !pageNumber || !pollInterval) return;
193
+ if (hasContentRef.current) return;
194
+ const interval = setInterval(fetchPage, pollInterval);
195
+ return () => clearInterval(interval);
196
+ }, [session, pageNumber, pollInterval, fetchPage]);
197
+ return {
198
+ data,
199
+ content: data?.content ?? "",
200
+ isLoading,
201
+ error,
202
+ refetch: fetchPage
203
+ };
204
+ }
205
+
206
+ // src/react/use-chat.ts
207
+ import { useState as useState5, useRef as useRef5, useCallback as useCallback5 } from "react";
208
+ var _idCounter = 0;
209
+ function genId() {
210
+ return `msg_${Date.now()}_${++_idCounter}`;
211
+ }
212
+ function useChat(config) {
213
+ const { session, stream = true, onFinish, onError } = config;
214
+ const [messages, setMessages] = useState5([]);
215
+ const [input, setInput] = useState5("");
216
+ const [isLoading, setIsLoading] = useState5(false);
217
+ const abortRef = useRef5(null);
218
+ const stop = useCallback5(() => {
219
+ abortRef.current?.abort();
220
+ abortRef.current = null;
221
+ setIsLoading(false);
222
+ }, []);
223
+ const append = useCallback5(
224
+ (msg) => {
225
+ const full = { id: genId(), createdAt: /* @__PURE__ */ new Date(), ...msg };
226
+ setMessages((prev) => [...prev, full]);
227
+ },
228
+ []
229
+ );
230
+ const sendMessages = useCallback5(
231
+ async (_allMessages, userQuery) => {
232
+ if (!session) return;
233
+ setIsLoading(true);
234
+ const controller = new AbortController();
235
+ abortRef.current = controller;
236
+ try {
237
+ if (stream) {
238
+ const assistantId = genId();
239
+ let fullText = "";
240
+ let sources;
241
+ setMessages((prev) => [
242
+ ...prev,
243
+ { id: assistantId, role: "assistant", content: "", createdAt: /* @__PURE__ */ new Date() }
244
+ ]);
245
+ const gen = session.stream(userQuery, { signal: controller.signal });
246
+ for await (const event of gen) {
247
+ if (controller.signal.aborted) break;
248
+ if (event.type === "text_delta") {
249
+ fullText += event.text;
250
+ setMessages(
251
+ (prev) => prev.map(
252
+ (m) => m.id === assistantId ? { ...m, content: fullText } : m
253
+ )
254
+ );
255
+ } else if (event.type === "done") {
256
+ fullText = event.answer || fullText;
257
+ sources = event.sources;
258
+ } else if (event.type === "error") {
259
+ throw new Error(event.message);
260
+ }
261
+ }
262
+ const finalMsg = {
263
+ id: assistantId,
264
+ role: "assistant",
265
+ content: fullText,
266
+ createdAt: /* @__PURE__ */ new Date(),
267
+ sources
268
+ };
269
+ setMessages(
270
+ (prev) => prev.map((m) => m.id === assistantId ? finalMsg : m)
271
+ );
272
+ onFinish?.(finalMsg);
273
+ } else {
274
+ const result = await session.prompt(userQuery, {
275
+ signal: controller.signal
276
+ });
277
+ if (controller.signal.aborted) return;
278
+ const assistantMsg = {
279
+ id: genId(),
280
+ role: "assistant",
281
+ content: result.answer,
282
+ createdAt: /* @__PURE__ */ new Date(),
283
+ sources: result.sources
284
+ };
285
+ setMessages((prev) => [...prev, assistantMsg]);
286
+ onFinish?.(assistantMsg);
287
+ }
288
+ } catch (err) {
289
+ if (controller.signal.aborted) return;
290
+ const error = err instanceof Error ? err : new Error(String(err));
291
+ onError?.(error);
292
+ } finally {
293
+ setIsLoading(false);
294
+ abortRef.current = null;
295
+ }
296
+ },
297
+ [session, stream, onFinish, onError]
298
+ );
299
+ const handleInputChange = useCallback5(
300
+ (e) => {
301
+ setInput(e.target.value);
302
+ },
303
+ []
304
+ );
305
+ const handleSubmit = useCallback5(
306
+ (e) => {
307
+ e?.preventDefault?.();
308
+ const trimmed = input.trim();
309
+ if (!trimmed || isLoading || !session) return;
310
+ const userMsg = {
311
+ id: genId(),
312
+ role: "user",
313
+ content: trimmed,
314
+ createdAt: /* @__PURE__ */ new Date()
315
+ };
316
+ const nextMessages = [...messages, userMsg];
317
+ setMessages(nextMessages);
318
+ setInput("");
319
+ sendMessages(nextMessages, trimmed);
320
+ },
321
+ [input, isLoading, session, messages, sendMessages]
322
+ );
323
+ return {
324
+ messages,
325
+ input,
326
+ handleInputChange,
327
+ handleSubmit,
328
+ isLoading,
329
+ stop,
330
+ append,
331
+ setMessages
332
+ };
333
+ }
334
+
335
+ // src/react/use-document-query.ts
336
+ import { useState as useState6, useEffect as useEffect4, useRef as useRef6, useCallback as useCallback6 } from "react";
337
+ var DEFAULT_CACHE_TIME = 5 * 60 * 1e3;
338
+ var cache = /* @__PURE__ */ new Map();
339
+ function cacheKey(documentId, query, schema) {
340
+ const schemaStr = schema ? JSON.stringify(schema) : "";
341
+ return `${documentId}::${query}::${schemaStr}`;
342
+ }
343
+ function getCached(key, cacheTime) {
344
+ const entry = cache.get(key);
345
+ if (!entry) return null;
346
+ if (Date.now() - entry.timestamp > cacheTime) {
347
+ cache.delete(key);
348
+ return null;
349
+ }
350
+ return entry.result;
351
+ }
352
+ function setCache(key, result) {
353
+ cache.set(key, { result, timestamp: Date.now() });
354
+ }
355
+ function useDocumentQuery(options) {
356
+ const { client } = useOkra();
357
+ const {
358
+ documentId,
359
+ query,
360
+ schema,
361
+ skip = false,
362
+ model,
363
+ timeoutMs,
364
+ cacheTime = DEFAULT_CACHE_TIME
365
+ } = options;
366
+ const key = documentId ? cacheKey(documentId, query, schema) : "";
367
+ const cached = key ? getCached(key, cacheTime) : null;
368
+ const [result, setResult] = useState6(cached);
369
+ const [isLoading, setIsLoading] = useState6(false);
370
+ const [error, setError] = useState6(null);
371
+ const abortRef = useRef6(null);
372
+ const fetchIdRef = useRef6(0);
373
+ const doFetch = useCallback6(async (bypassCache = false) => {
374
+ if (!documentId || !query.trim() || skip) return;
375
+ if (!bypassCache) {
376
+ const hit = getCached(key, cacheTime);
377
+ if (hit) {
378
+ setResult(hit);
379
+ setError(null);
380
+ setIsLoading(false);
381
+ return;
382
+ }
383
+ }
384
+ const fetchId = ++fetchIdRef.current;
385
+ abortRef.current?.abort();
386
+ const controller = new AbortController();
387
+ abortRef.current = controller;
388
+ setIsLoading(true);
389
+ setError(null);
390
+ try {
391
+ const session = client.sessions.from(documentId);
392
+ const res = schema ? await session.prompt(query, { schema, model, timeoutMs, signal: controller.signal }) : await session.prompt(query, { model, timeoutMs, signal: controller.signal });
393
+ if (fetchId !== fetchIdRef.current) return;
394
+ const typed = res;
395
+ setCache(key, typed);
396
+ setResult(typed);
397
+ } catch (err) {
398
+ if (controller.signal.aborted) return;
399
+ if (fetchId !== fetchIdRef.current) return;
400
+ setError(err instanceof Error ? err : new Error(String(err)));
401
+ } finally {
402
+ if (fetchId === fetchIdRef.current) {
403
+ setIsLoading(false);
404
+ }
405
+ }
406
+ }, [client, documentId, query, schema, skip, model, timeoutMs, key, cacheTime]);
407
+ useEffect4(() => {
408
+ doFetch();
409
+ return () => {
410
+ abortRef.current?.abort();
411
+ };
412
+ }, [doFetch]);
413
+ const data = result?.data ?? null;
414
+ return {
415
+ data,
416
+ result,
417
+ isLoading,
418
+ error,
419
+ refetch: () => doFetch(true)
420
+ };
421
+ }
422
+ export {
423
+ OkraProvider,
424
+ useChat,
425
+ useDocumentQuery,
426
+ useDocumentSession,
427
+ useDocumentStatus,
428
+ useOkra,
429
+ usePageContent,
430
+ usePages
431
+ };
432
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/react/provider.ts","../../src/react/use-document-session.ts","../../src/react/use-document-status.ts","../../src/react/use-pages.ts","../../src/react/use-page-content.ts","../../src/react/use-chat.ts","../../src/react/use-document-query.ts"],"sourcesContent":["import { createContext, useContext, useMemo, createElement } from 'react';\nimport { createOkra } from '../providers';\nimport type { OkraClient } from '../client';\n\n// ---------------------------------------------------------------------------\n// Context\n// ---------------------------------------------------------------------------\n\nexport interface OkraContextValue {\n client: OkraClient;\n apiKey: string;\n}\n\nconst OkraContext = createContext<OkraContextValue | null>(null);\n\n// ---------------------------------------------------------------------------\n// Provider\n// ---------------------------------------------------------------------------\n\nexport interface OkraProviderProps {\n apiKey: string;\n baseUrl?: string;\n children: React.ReactNode;\n}\n\n/**\n * Provides the OkraPDF runtime client to all child hooks.\n *\n * ```tsx\n * <OkraProvider apiKey={process.env.OKRA_API_KEY!}>\n * <App />\n * </OkraProvider>\n * ```\n */\nexport function OkraProvider({ apiKey, baseUrl, children }: OkraProviderProps) {\n const value = useMemo<OkraContextValue>(() => {\n const client = createOkra({ apiKey, baseUrl });\n return { client, apiKey };\n }, [apiKey, baseUrl]);\n\n return createElement(OkraContext.Provider, { value }, children);\n}\n\n// ---------------------------------------------------------------------------\n// Hook\n// ---------------------------------------------------------------------------\n\n/**\n * Access the OkraPDF runtime client from context.\n *\n * ```ts\n * const { client } = useOkra();\n * const session = await client.sessions.create(file);\n * ```\n */\nexport function useOkra(): OkraContextValue {\n const ctx = useContext(OkraContext);\n if (!ctx) {\n throw new Error('useOkra must be used within an <OkraProvider>');\n }\n return ctx;\n}\n","import { useState, useCallback, useRef } from 'react';\nimport type { OkraSession, DocumentStatus } from '../types';\nimport { useOkra } from './provider';\nimport type { SessionStatus, UseDocumentSessionReturn } from './types';\n\nexport interface UseDocumentSessionOptions {\n /** If true (default), waits for extraction to complete before session is ready */\n wait?: boolean;\n}\n\n/**\n * Upload a document and get an interactive session.\n *\n * ```tsx\n * const { session, status, upload } = useDocumentSession();\n * await upload(file); // or upload('https://...')\n * // session is ready when status === 'ready'\n * ```\n */\nexport function useDocumentSession(\n options: UseDocumentSessionOptions = {},\n): UseDocumentSessionReturn {\n const { wait = true } = options;\n const { client } = useOkra();\n\n const [session, setSession] = useState<OkraSession | null>(null);\n const [status, setStatus] = useState<SessionStatus>('idle');\n const [error, setError] = useState<Error | null>(null);\n const [documentStatus, setDocumentStatus] = useState<DocumentStatus | null>(null);\n\n const uploadIdRef = useRef(0);\n\n const upload = useCallback(\n async (source: string | File | Blob) => {\n const currentId = ++uploadIdRef.current;\n\n try {\n setError(null);\n setStatus('uploading');\n setDocumentStatus(null);\n setSession(null);\n\n const sess = await client.sessions.create(source, { wait });\n\n if (currentId !== uploadIdRef.current) return;\n\n const docStatus = await sess.status();\n setDocumentStatus(docStatus);\n setSession(sess);\n setStatus('ready');\n } catch (err) {\n if (currentId !== uploadIdRef.current) return;\n const e = err instanceof Error ? err : new Error(String(err));\n setError(e);\n setStatus('error');\n }\n },\n [client, wait],\n );\n\n return { session, status, error, upload, documentStatus };\n}\n","import { useState, useEffect, useRef, useCallback } from 'react';\nimport type { OkraSession, DocumentStatus } from '../types';\nimport { useOkra } from './provider';\n\nexport interface UseDocumentStatusOptions {\n /** Poll interval in ms while processing (default: 2000). 0 to disable. */\n pollInterval?: number;\n /** Skip fetching entirely */\n enabled?: boolean;\n}\n\nexport interface UseDocumentStatusReturn {\n data: DocumentStatus | null;\n isLoading: boolean;\n error: Error | null;\n isComplete: boolean;\n isProcessing: boolean;\n refetch: () => void;\n}\n\nconst COMPLETE_PHASES = new Set(['complete', 'awaiting_review']);\nconst PROCESSING_PHASES = new Set(['uploading', 'parsing', 'hydrating', 'verifying']);\n\n/**\n * Poll document processing status from the CF Worker.\n * Accepts either a session object or a raw document ID.\n *\n * ```tsx\n * const { data, isComplete, isProcessing } = useDocumentStatus(session);\n * // or\n * const { data } = useDocumentStatus('doc-abc123');\n * ```\n */\nexport function useDocumentStatus(\n sessionOrId: OkraSession | string | null,\n options: UseDocumentStatusOptions = {},\n): UseDocumentStatusReturn {\n const { pollInterval = 2000, enabled = true } = options;\n const { client } = useOkra();\n\n const [data, setData] = useState<DocumentStatus | null>(null);\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n const abortRef = useRef<AbortController | null>(null);\n\n // Resolve to session object\n const session = typeof sessionOrId === 'string'\n ? client.sessions.from(sessionOrId)\n : sessionOrId;\n const docId = session?.id ?? null;\n\n const fetchStatus = useCallback(async () => {\n if (!session || !enabled) return;\n try {\n abortRef.current?.abort();\n const ac = new AbortController();\n abortRef.current = ac;\n setIsLoading(true);\n const s = await session.status(ac.signal);\n setData(s);\n setError(null);\n } catch (err) {\n if ((err as Error).name === 'AbortError') return;\n setError(err instanceof Error ? err : new Error(String(err)));\n } finally {\n setIsLoading(false);\n }\n }, [session, enabled]);\n\n // Reset on doc change\n useEffect(() => {\n setData(null);\n setError(null);\n }, [docId]);\n\n // Initial fetch\n useEffect(() => {\n fetchStatus();\n return () => abortRef.current?.abort();\n }, [fetchStatus]);\n\n // Poll while processing\n useEffect(() => {\n if (!session || !pollInterval || !enabled) return;\n if (data && COMPLETE_PHASES.has(data.phase)) return;\n\n const interval = setInterval(fetchStatus, pollInterval);\n return () => clearInterval(interval);\n }, [session, pollInterval, enabled, data?.phase, fetchStatus]);\n\n return {\n data,\n isLoading,\n error,\n isComplete: data ? COMPLETE_PHASES.has(data.phase) : false,\n isProcessing: data ? PROCESSING_PHASES.has(data.phase) : false,\n refetch: fetchStatus,\n };\n}\n","import { useState, useEffect, useRef, useCallback } from 'react';\nimport type { OkraSession, Page } from '../types';\nimport { useOkra } from './provider';\n\nexport interface UsePagesOptions {\n /** Skip fetching (default: true) */\n enabled?: boolean;\n}\n\nexport interface UsePagesReturn {\n data: Page[];\n isLoading: boolean;\n error: Error | null;\n refetch: () => void;\n}\n\n/**\n * Fetch all pages for a document.\n *\n * ```tsx\n * const { data: pages, isLoading } = usePages(session);\n * // or with a document ID\n * const { data: pages } = usePages('doc-abc123');\n * ```\n */\nexport function usePages(\n sessionOrId: OkraSession | string | null,\n options: UsePagesOptions = {},\n): UsePagesReturn {\n const { enabled = true } = options;\n const { client } = useOkra();\n\n const [data, setData] = useState<Page[]>([]);\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n const abortRef = useRef<AbortController | null>(null);\n\n const session = typeof sessionOrId === 'string'\n ? client.sessions.from(sessionOrId)\n : sessionOrId;\n const docId = session?.id ?? null;\n\n const fetchPages = useCallback(async () => {\n if (!session || !enabled) return;\n try {\n abortRef.current?.abort();\n const ac = new AbortController();\n abortRef.current = ac;\n setIsLoading(true);\n const result = await session.pages({ signal: ac.signal });\n setData(result);\n setError(null);\n } catch (err) {\n if ((err as Error).name === 'AbortError') return;\n setError(err instanceof Error ? err : new Error(String(err)));\n } finally {\n setIsLoading(false);\n }\n }, [session, enabled]);\n\n // Reset on doc change\n useEffect(() => {\n setData([]);\n setError(null);\n }, [docId]);\n\n useEffect(() => {\n fetchPages();\n return () => abortRef.current?.abort();\n }, [fetchPages]);\n\n return { data, isLoading, error, refetch: fetchPages };\n}\n","import { useState, useEffect, useRef, useCallback } from 'react';\nimport type { OkraSession, Page } from '../types';\nimport { useOkra } from './provider';\n\nexport interface UsePageContentOptions {\n /** Poll interval while content not yet ready (default: 3000). 0 to disable. */\n pollInterval?: number;\n}\n\nexport interface UsePageContentReturn {\n data: Page | null;\n content: string;\n isLoading: boolean;\n error: Error | null;\n refetch: () => void;\n}\n\n/**\n * Fetch a single page's content (markdown + blocks + entities).\n * Polls until content arrives if the page is still processing.\n *\n * ```tsx\n * const { content, data, isLoading } = usePageContent(session, 1);\n * ```\n */\nexport function usePageContent(\n sessionOrId: OkraSession | string | null,\n pageNumber: number,\n options: UsePageContentOptions = {},\n): UsePageContentReturn {\n const { pollInterval = 3000 } = options;\n const { client } = useOkra();\n\n const [data, setData] = useState<Page | null>(null);\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n const abortRef = useRef<AbortController | null>(null);\n const hasContentRef = useRef(false);\n\n const session = typeof sessionOrId === 'string'\n ? client.sessions.from(sessionOrId)\n : sessionOrId;\n\n const fetchPage = useCallback(async () => {\n if (!session || !pageNumber) return;\n try {\n abortRef.current?.abort();\n const ac = new AbortController();\n abortRef.current = ac;\n setIsLoading(true);\n const result = await session.page(pageNumber, ac.signal);\n setData(result);\n setError(null);\n hasContentRef.current = !!result.content;\n } catch (err) {\n if ((err as Error).name === 'AbortError') return;\n setError(err instanceof Error ? err : new Error(String(err)));\n } finally {\n setIsLoading(false);\n }\n }, [session, pageNumber]);\n\n // Reset on page change\n useEffect(() => {\n setData(null);\n hasContentRef.current = false;\n setError(null);\n }, [pageNumber]);\n\n // Initial fetch\n useEffect(() => {\n fetchPage();\n return () => abortRef.current?.abort();\n }, [fetchPage]);\n\n // Poll until content arrives\n useEffect(() => {\n if (!session || !pageNumber || !pollInterval) return;\n if (hasContentRef.current) return;\n\n const interval = setInterval(fetchPage, pollInterval);\n return () => clearInterval(interval);\n }, [session, pageNumber, pollInterval, fetchPage]);\n\n return {\n data,\n content: data?.content ?? '',\n isLoading,\n error,\n refetch: fetchPage,\n };\n}\n","import { useState, useRef, useCallback } from 'react';\nimport type { Message, UseChatReturn, ChatConfig } from './types';\n\nlet _idCounter = 0;\nfunction genId(): string {\n return `msg_${Date.now()}_${++_idCounter}`;\n}\n\nexport function useChat(config: ChatConfig): UseChatReturn {\n const { session, stream = true, onFinish, onError } = config;\n\n const [messages, setMessages] = useState<Message[]>([]);\n const [input, setInput] = useState('');\n const [isLoading, setIsLoading] = useState(false);\n\n const abortRef = useRef<AbortController | null>(null);\n\n const stop = useCallback(() => {\n abortRef.current?.abort();\n abortRef.current = null;\n setIsLoading(false);\n }, []);\n\n const append = useCallback(\n (msg: Pick<Message, 'role' | 'content'>) => {\n const full: Message = { id: genId(), createdAt: new Date(), ...msg };\n setMessages((prev) => [...prev, full]);\n },\n [],\n );\n\n const sendMessages = useCallback(\n async (_allMessages: Message[], userQuery: string) => {\n if (!session) return;\n setIsLoading(true);\n\n const controller = new AbortController();\n abortRef.current = controller;\n\n try {\n if (stream) {\n // Streaming path — accumulate text_delta events\n const assistantId = genId();\n let fullText = '';\n let sources: Array<{ page: number; snippet: string }> | undefined;\n\n // Add placeholder assistant message\n setMessages((prev) => [\n ...prev,\n { id: assistantId, role: 'assistant', content: '', createdAt: new Date() },\n ]);\n\n const gen = session.stream(userQuery, { signal: controller.signal });\n\n for await (const event of gen) {\n if (controller.signal.aborted) break;\n\n if (event.type === 'text_delta') {\n fullText += event.text;\n setMessages((prev) =>\n prev.map((m) =>\n m.id === assistantId ? { ...m, content: fullText } : m,\n ),\n );\n } else if (event.type === 'done') {\n fullText = event.answer || fullText;\n sources = event.sources;\n } else if (event.type === 'error') {\n throw new Error(event.message);\n }\n }\n\n const finalMsg: Message = {\n id: assistantId,\n role: 'assistant',\n content: fullText,\n createdAt: new Date(),\n sources,\n };\n\n setMessages((prev) =>\n prev.map((m) => (m.id === assistantId ? finalMsg : m)),\n );\n\n onFinish?.(finalMsg);\n } else {\n // Non-streaming path\n const result = await session.prompt(userQuery, {\n signal: controller.signal,\n });\n\n if (controller.signal.aborted) return;\n\n const assistantMsg: Message = {\n id: genId(),\n role: 'assistant',\n content: result.answer,\n createdAt: new Date(),\n sources: result.sources,\n };\n\n setMessages((prev) => [...prev, assistantMsg]);\n onFinish?.(assistantMsg);\n }\n } catch (err) {\n if (controller.signal.aborted) return;\n const error = err instanceof Error ? err : new Error(String(err));\n onError?.(error);\n } finally {\n setIsLoading(false);\n abortRef.current = null;\n }\n },\n [session, stream, onFinish, onError],\n );\n\n const handleInputChange = useCallback(\n (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {\n setInput(e.target.value);\n },\n [],\n );\n\n const handleSubmit = useCallback(\n (e?: { preventDefault?: () => void }) => {\n e?.preventDefault?.();\n const trimmed = input.trim();\n if (!trimmed || isLoading || !session) return;\n\n const userMsg: Message = {\n id: genId(),\n role: 'user',\n content: trimmed,\n createdAt: new Date(),\n };\n\n const nextMessages = [...messages, userMsg];\n setMessages(nextMessages);\n setInput('');\n sendMessages(nextMessages, trimmed);\n },\n [input, isLoading, session, messages, sendMessages],\n );\n\n return {\n messages,\n input,\n handleInputChange,\n handleSubmit,\n isLoading,\n stop,\n append,\n setMessages,\n };\n}\n","import { useState, useEffect, useRef, useCallback } from 'react';\nimport type { GenerateResult, StructuredSchema } from '../types';\nimport { useOkra } from './provider';\n\n// ---------------------------------------------------------------------------\n// In-memory cache — shared across all useDocumentQuery instances\n// Key: documentId + query + schema hash\n// ---------------------------------------------------------------------------\n\ninterface CacheEntry<T = unknown> {\n result: GenerateResult<T>;\n timestamp: number;\n}\n\nconst DEFAULT_CACHE_TIME = 5 * 60 * 1000; // 5 minutes\nconst cache = new Map<string, CacheEntry>();\n\nfunction cacheKey(documentId: string, query: string, schema?: unknown): string {\n const schemaStr = schema ? JSON.stringify(schema) : '';\n return `${documentId}::${query}::${schemaStr}`;\n}\n\nfunction getCached<T>(key: string, cacheTime: number): GenerateResult<T> | null {\n const entry = cache.get(key);\n if (!entry) return null;\n if (Date.now() - entry.timestamp > cacheTime) {\n cache.delete(key);\n return null;\n }\n return entry.result as GenerateResult<T>;\n}\n\nfunction setCache<T>(key: string, result: GenerateResult<T>): void {\n cache.set(key, { result, timestamp: Date.now() });\n}\n\n// ---------------------------------------------------------------------------\n// Hook\n// ---------------------------------------------------------------------------\n\nexport interface UseDocumentQueryOptions<T = undefined> {\n /** Document ID (e.g. \"doc-xxx\" or \"ocr-xxx\") */\n documentId: string | null;\n /** The query/prompt to run against the document */\n query: string;\n /** JSON schema or Zod schema for structured output */\n schema?: StructuredSchema<T>;\n /** Skip the query (e.g. while waiting for doc to be ready) */\n skip?: boolean;\n /** Model override */\n model?: string;\n /** Timeout in ms */\n timeoutMs?: number;\n /** How long cached results stay valid in ms (default: 300000 / 5 min) */\n cacheTime?: number;\n}\n\nexport interface UseDocumentQueryReturn<T = undefined> {\n data: T | null;\n result: GenerateResult<T> | null;\n isLoading: boolean;\n error: Error | null;\n refetch: () => void;\n}\n\n/**\n * Run a one-shot query against a document, optionally with structured output.\n * Results are cached in-memory for `cacheTime` ms (default 5 min).\n *\n * ```tsx\n * const { data } = useDocumentQuery({\n * documentId: \"doc-xxx\",\n * query: \"Generate 4 chat suggestions\",\n * schema: z.object({ suggestions: z.array(z.object({ id: z.string(), text: z.string() })) }),\n * skip: !isReady,\n * })\n * ```\n */\nexport function useDocumentQuery<T = undefined>(\n options: UseDocumentQueryOptions<T>,\n): UseDocumentQueryReturn<T> {\n const { client } = useOkra();\n const {\n documentId,\n query,\n schema,\n skip = false,\n model,\n timeoutMs,\n cacheTime = DEFAULT_CACHE_TIME,\n } = options;\n\n const key = documentId ? cacheKey(documentId, query, schema) : '';\n const cached = key ? getCached<T>(key, cacheTime) : null;\n\n const [result, setResult] = useState<GenerateResult<T> | null>(cached);\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n const abortRef = useRef<AbortController | null>(null);\n const fetchIdRef = useRef(0);\n\n const doFetch = useCallback(async (bypassCache = false) => {\n if (!documentId || !query.trim() || skip) return;\n\n // Check cache unless explicitly bypassing (refetch)\n if (!bypassCache) {\n const hit = getCached<T>(key, cacheTime);\n if (hit) {\n setResult(hit);\n setError(null);\n setIsLoading(false);\n return;\n }\n }\n\n const fetchId = ++fetchIdRef.current;\n abortRef.current?.abort();\n const controller = new AbortController();\n abortRef.current = controller;\n\n setIsLoading(true);\n setError(null);\n\n try {\n const session = client.sessions.from(documentId);\n const res = schema\n ? await session.prompt<T>(query, { schema, model, timeoutMs, signal: controller.signal } as any)\n : await session.prompt(query, { model, timeoutMs, signal: controller.signal });\n\n if (fetchId !== fetchIdRef.current) return;\n const typed = res as GenerateResult<T>;\n setCache(key, typed);\n setResult(typed);\n } catch (err) {\n if (controller.signal.aborted) return;\n if (fetchId !== fetchIdRef.current) return;\n setError(err instanceof Error ? err : new Error(String(err)));\n } finally {\n if (fetchId === fetchIdRef.current) {\n setIsLoading(false);\n }\n }\n }, [client, documentId, query, schema, skip, model, timeoutMs, key, cacheTime]);\n\n useEffect(() => {\n doFetch();\n return () => { abortRef.current?.abort(); };\n }, [doFetch]);\n\n const data = result?.data ?? null;\n\n return {\n data,\n result,\n isLoading,\n error,\n refetch: () => doFetch(true),\n };\n}\n"],"mappings":"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","names":["useState","useRef","useCallback","useState","useRef","useCallback","useState","useEffect","useRef","useCallback","useState","useRef","useCallback","useEffect","useState","useEffect","useRef","useCallback","useState","useRef","useCallback","useEffect","useState","useRef","useCallback","useState","useEffect","useRef","useCallback","useState","useRef","useCallback","useEffect"]}