@anuma/sdk 3.6.1 → 3.6.3

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.
@@ -75,6 +75,138 @@ var init_clientConfig = __esm({
75
75
  }
76
76
  });
77
77
 
78
+ // src/client/core/serverSentEvents.gen.ts
79
+ function createSseClient({
80
+ onRequest,
81
+ onSseError,
82
+ onSseEvent,
83
+ responseTransformer,
84
+ responseValidator,
85
+ sseDefaultRetryDelay,
86
+ sseMaxRetryAttempts,
87
+ sseMaxRetryDelay,
88
+ sseSleepFn,
89
+ url,
90
+ ...options
91
+ }) {
92
+ let lastEventId;
93
+ const sleep4 = sseSleepFn ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
94
+ const createStream = async function* () {
95
+ let retryDelay = sseDefaultRetryDelay ?? 3e3;
96
+ let attempt = 0;
97
+ const signal = options.signal ?? new AbortController().signal;
98
+ while (true) {
99
+ if (signal.aborted) break;
100
+ attempt++;
101
+ const headers = options.headers instanceof Headers ? options.headers : new Headers(options.headers);
102
+ if (lastEventId !== void 0) {
103
+ headers.set("Last-Event-ID", lastEventId);
104
+ }
105
+ try {
106
+ const requestInit = {
107
+ redirect: "follow",
108
+ ...options,
109
+ body: options.serializedBody,
110
+ headers,
111
+ signal
112
+ };
113
+ let request = new Request(url, requestInit);
114
+ if (onRequest) {
115
+ request = await onRequest(url, requestInit);
116
+ }
117
+ const _fetch = options.fetch ?? globalThis.fetch;
118
+ const response = await _fetch(request);
119
+ if (!response.ok) throw new Error(`SSE failed: ${response.status} ${response.statusText}`);
120
+ if (!response.body) throw new Error("No body in SSE response");
121
+ const reader = response.body.pipeThrough(new TextDecoderStream()).getReader();
122
+ let buffer = "";
123
+ const abortHandler = () => {
124
+ try {
125
+ reader.cancel();
126
+ } catch {
127
+ }
128
+ };
129
+ signal.addEventListener("abort", abortHandler);
130
+ try {
131
+ while (true) {
132
+ const { done, value } = await reader.read();
133
+ if (done) break;
134
+ buffer += value;
135
+ buffer = buffer.replace(/\r\n?/g, "\n");
136
+ const chunks = buffer.split("\n\n");
137
+ buffer = chunks.pop() ?? "";
138
+ for (const chunk of chunks) {
139
+ const lines = chunk.split("\n");
140
+ const dataLines = [];
141
+ let eventName;
142
+ for (const line of lines) {
143
+ if (line.startsWith("data:")) {
144
+ dataLines.push(line.replace(/^data:\s*/, ""));
145
+ } else if (line.startsWith("event:")) {
146
+ eventName = line.replace(/^event:\s*/, "");
147
+ } else if (line.startsWith("id:")) {
148
+ lastEventId = line.replace(/^id:\s*/, "");
149
+ } else if (line.startsWith("retry:")) {
150
+ const parsed = Number.parseInt(line.replace(/^retry:\s*/, ""), 10);
151
+ if (!Number.isNaN(parsed)) {
152
+ retryDelay = parsed;
153
+ }
154
+ }
155
+ }
156
+ let data;
157
+ let parsedJson = false;
158
+ if (dataLines.length) {
159
+ const rawData = dataLines.join("\n");
160
+ try {
161
+ data = JSON.parse(rawData);
162
+ parsedJson = true;
163
+ } catch {
164
+ data = rawData;
165
+ }
166
+ }
167
+ if (parsedJson) {
168
+ if (responseValidator) {
169
+ await responseValidator(data);
170
+ }
171
+ if (responseTransformer) {
172
+ data = await responseTransformer(data);
173
+ }
174
+ }
175
+ onSseEvent?.({
176
+ data,
177
+ event: eventName,
178
+ id: lastEventId,
179
+ retry: retryDelay
180
+ });
181
+ if (dataLines.length) {
182
+ yield data;
183
+ }
184
+ }
185
+ }
186
+ } finally {
187
+ signal.removeEventListener("abort", abortHandler);
188
+ reader.releaseLock();
189
+ }
190
+ break;
191
+ } catch (error) {
192
+ onSseError?.(error);
193
+ if (sseMaxRetryAttempts !== void 0 && attempt >= sseMaxRetryAttempts) {
194
+ break;
195
+ }
196
+ const backoff = Math.min(retryDelay * 2 ** (attempt - 1), sseMaxRetryDelay ?? 3e4);
197
+ await sleep4(backoff);
198
+ }
199
+ }
200
+ };
201
+ const stream = createStream();
202
+ return { stream };
203
+ }
204
+ var init_serverSentEvents_gen = __esm({
205
+ "src/client/core/serverSentEvents.gen.ts"() {
206
+ "use strict";
207
+ }
208
+ });
209
+
78
210
  // src/lib/logger.ts
79
211
  function setLogger(logger) {
80
212
  currentLogger = logger;
@@ -2208,561 +2340,1379 @@ var init_constants = __esm({
2208
2340
  }
2209
2341
  });
2210
2342
 
2211
- // src/lib/memoryEngine/generate.ts
2212
- async function withEmbeddingRetry(call) {
2213
- let last;
2214
- let lastThrown;
2215
- let threw = false;
2216
- for (let attempt = 1; attempt <= EMBED_MAX_ATTEMPTS; attempt++) {
2217
- try {
2218
- threw = false;
2219
- last = await call();
2220
- if (!last.error) return last;
2221
- const status = last.response?.status;
2222
- const retryable = status === void 0 || status === 429 || status >= 500;
2223
- if (!retryable) return last;
2224
- } catch (err) {
2225
- threw = true;
2226
- lastThrown = err;
2227
- }
2228
- if (attempt < EMBED_MAX_ATTEMPTS) {
2229
- const base = 250 * 2 ** (attempt - 1);
2230
- await new Promise((r) => setTimeout(r, base + Math.random() * 0.4 * base));
2343
+ // src/client/core/bodySerializer.gen.ts
2344
+ var jsonBodySerializer;
2345
+ var init_bodySerializer_gen = __esm({
2346
+ "src/client/core/bodySerializer.gen.ts"() {
2347
+ "use strict";
2348
+ jsonBodySerializer = {
2349
+ bodySerializer: (body) => JSON.stringify(body, (_key, value) => typeof value === "bigint" ? value.toString() : value)
2350
+ };
2351
+ }
2352
+ });
2353
+
2354
+ // src/client/core/pathSerializer.gen.ts
2355
+ var separatorArrayExplode, separatorArrayNoExplode, separatorObjectExplode, serializeArrayParam, serializePrimitiveParam, serializeObjectParam;
2356
+ var init_pathSerializer_gen = __esm({
2357
+ "src/client/core/pathSerializer.gen.ts"() {
2358
+ "use strict";
2359
+ separatorArrayExplode = (style) => {
2360
+ switch (style) {
2361
+ case "label":
2362
+ return ".";
2363
+ case "matrix":
2364
+ return ";";
2365
+ case "simple":
2366
+ return ",";
2367
+ default:
2368
+ return "&";
2369
+ }
2370
+ };
2371
+ separatorArrayNoExplode = (style) => {
2372
+ switch (style) {
2373
+ case "form":
2374
+ return ",";
2375
+ case "pipeDelimited":
2376
+ return "|";
2377
+ case "spaceDelimited":
2378
+ return "%20";
2379
+ default:
2380
+ return ",";
2381
+ }
2382
+ };
2383
+ separatorObjectExplode = (style) => {
2384
+ switch (style) {
2385
+ case "label":
2386
+ return ".";
2387
+ case "matrix":
2388
+ return ";";
2389
+ case "simple":
2390
+ return ",";
2391
+ default:
2392
+ return "&";
2393
+ }
2394
+ };
2395
+ serializeArrayParam = ({
2396
+ allowReserved,
2397
+ explode,
2398
+ name,
2399
+ style,
2400
+ value
2401
+ }) => {
2402
+ if (!explode) {
2403
+ const joinedValues2 = (allowReserved ? value : value.map((v) => encodeURIComponent(v))).join(separatorArrayNoExplode(style));
2404
+ switch (style) {
2405
+ case "label":
2406
+ return `.${joinedValues2}`;
2407
+ case "matrix":
2408
+ return `;${name}=${joinedValues2}`;
2409
+ case "simple":
2410
+ return joinedValues2;
2411
+ default:
2412
+ return `${name}=${joinedValues2}`;
2413
+ }
2414
+ }
2415
+ const separator = separatorArrayExplode(style);
2416
+ const joinedValues = value.map((v) => {
2417
+ if (style === "label" || style === "simple") {
2418
+ return allowReserved ? v : encodeURIComponent(v);
2419
+ }
2420
+ return serializePrimitiveParam({
2421
+ allowReserved,
2422
+ name,
2423
+ value: v
2424
+ });
2425
+ }).join(separator);
2426
+ return style === "label" || style === "matrix" ? separator + joinedValues : joinedValues;
2427
+ };
2428
+ serializePrimitiveParam = ({
2429
+ allowReserved,
2430
+ name,
2431
+ value
2432
+ }) => {
2433
+ if (value === void 0 || value === null) {
2434
+ return "";
2435
+ }
2436
+ if (typeof value === "object") {
2437
+ throw new Error(
2438
+ "Deeply-nested arrays/objects aren\u2019t supported. Provide your own `querySerializer()` to handle these."
2439
+ );
2440
+ }
2441
+ return `${name}=${allowReserved ? value : encodeURIComponent(value)}`;
2442
+ };
2443
+ serializeObjectParam = ({
2444
+ allowReserved,
2445
+ explode,
2446
+ name,
2447
+ style,
2448
+ value,
2449
+ valueOnly
2450
+ }) => {
2451
+ if (value instanceof Date) {
2452
+ return valueOnly ? value.toISOString() : `${name}=${value.toISOString()}`;
2453
+ }
2454
+ if (style !== "deepObject" && !explode) {
2455
+ let values = [];
2456
+ Object.entries(value).forEach(([key, v]) => {
2457
+ values = [...values, key, allowReserved ? v : encodeURIComponent(v)];
2458
+ });
2459
+ const joinedValues2 = values.join(",");
2460
+ switch (style) {
2461
+ case "form":
2462
+ return `${name}=${joinedValues2}`;
2463
+ case "label":
2464
+ return `.${joinedValues2}`;
2465
+ case "matrix":
2466
+ return `;${name}=${joinedValues2}`;
2467
+ default:
2468
+ return joinedValues2;
2469
+ }
2470
+ }
2471
+ const separator = separatorObjectExplode(style);
2472
+ const joinedValues = Object.entries(value).map(
2473
+ ([key, v]) => serializePrimitiveParam({
2474
+ allowReserved,
2475
+ name: style === "deepObject" ? `${name}[${key}]` : key,
2476
+ value: v
2477
+ })
2478
+ ).join(separator);
2479
+ return style === "label" || style === "matrix" ? separator + joinedValues : joinedValues;
2480
+ };
2481
+ }
2482
+ });
2483
+
2484
+ // src/client/core/utils.gen.ts
2485
+ function getValidRequestBody(options) {
2486
+ const hasBody = options.body !== void 0;
2487
+ const isSerializedBody = hasBody && options.bodySerializer;
2488
+ if (isSerializedBody) {
2489
+ if ("serializedBody" in options) {
2490
+ const hasSerializedBody = options.serializedBody !== void 0 && options.serializedBody !== "";
2491
+ return hasSerializedBody ? options.serializedBody : null;
2231
2492
  }
2493
+ return options.body !== "" ? options.body : null;
2232
2494
  }
2233
- if (threw) throw lastThrown;
2234
- if (last?.error instanceof Error && last.response?.status === void 0) {
2235
- throw last.error;
2495
+ if (hasBody) {
2496
+ return options.body;
2236
2497
  }
2237
- return last;
2238
- }
2239
- function isFatalEmbeddingError(err) {
2240
- return err instanceof EmbeddingHttpError && (err.status === 401 || err.status === 402 || err.status === 403);
2241
- }
2242
- function embeddingErrorFrom(response) {
2243
- const message = typeof response.error === "object" && response.error && "error" in response.error ? response.error.error : "API embedding failed";
2244
- return new EmbeddingHttpError(message, response.response?.status);
2498
+ return void 0;
2245
2499
  }
2246
- async function generateEmbedding(text12, options) {
2247
- const { baseUrl = BASE_URL, getToken, apiKey, model, cache } = options;
2248
- if (cache) {
2249
- const cached = cache.get(text12);
2250
- if (cached) return Array.from(cached);
2500
+ var init_utils_gen = __esm({
2501
+ "src/client/core/utils.gen.ts"() {
2502
+ "use strict";
2251
2503
  }
2252
- let headers;
2253
- if (apiKey) {
2254
- headers = { "X-API-Key": apiKey };
2255
- } else if (getToken) {
2256
- const token = await getToken();
2504
+ });
2505
+
2506
+ // src/client/core/auth.gen.ts
2507
+ var getAuthToken;
2508
+ var init_auth_gen = __esm({
2509
+ "src/client/core/auth.gen.ts"() {
2510
+ "use strict";
2511
+ getAuthToken = async (auth, callback) => {
2512
+ const token = typeof callback === "function" ? await callback(auth) : callback;
2513
+ if (!token) {
2514
+ return;
2515
+ }
2516
+ if (auth.scheme === "bearer") {
2517
+ return `Bearer ${token}`;
2518
+ }
2519
+ if (auth.scheme === "basic") {
2520
+ return `Basic ${btoa(token)}`;
2521
+ }
2522
+ return token;
2523
+ };
2524
+ }
2525
+ });
2526
+
2527
+ // src/client/client/utils.gen.ts
2528
+ async function setAuthParams(options) {
2529
+ for (const auth of options.security ?? []) {
2530
+ if (checkForExistence(options, auth.name)) {
2531
+ continue;
2532
+ }
2533
+ const token = await getAuthToken(auth, options.auth);
2257
2534
  if (!token) {
2258
- throw new Error("No token available for embedding generation");
2535
+ continue;
2536
+ }
2537
+ const name = auth.name ?? "Authorization";
2538
+ switch (auth.in) {
2539
+ case "query":
2540
+ if (!options.query) {
2541
+ options.query = {};
2542
+ }
2543
+ options.query[name] = token;
2544
+ break;
2545
+ case "cookie":
2546
+ options.headers.append("Cookie", `${name}=${token}`);
2547
+ break;
2548
+ case "header":
2549
+ default:
2550
+ options.headers.set(name, token);
2551
+ break;
2259
2552
  }
2260
- headers = { Authorization: `Bearer ${token}` };
2261
- } else {
2262
- throw new Error("Either apiKey or getToken must be provided");
2263
- }
2264
- const response = await withEmbeddingRetry(
2265
- () => (0, import_client.postApiV1Embeddings)({
2266
- baseUrl,
2267
- body: {
2268
- // Mask PII from the request body only — the cache above still keys on
2269
- // the original `text`, so callers keep their original values.
2270
- input: options.maskInput ? options.maskInput(text12) : text12,
2271
- model: model ?? DEFAULT_API_EMBEDDING_MODEL
2272
- },
2273
- headers
2274
- })
2275
- );
2276
- if (response.error) {
2277
- throw embeddingErrorFrom(response);
2278
- }
2279
- if (!response.data?.data?.[0]?.embedding) {
2280
- throw new Error("No embedding returned from API");
2281
- }
2282
- const embedding = response.data.data[0].embedding;
2283
- if (options.onUsage && response.data.usage) {
2284
- options.onUsage({
2285
- promptTokens: response.data.usage.prompt_tokens ?? 0,
2286
- totalTokens: response.data.usage.total_tokens ?? 0
2287
- });
2288
- }
2289
- const f32Embedding = Float32Array.from(embedding);
2290
- if (cache) {
2291
- cache.set(text12, f32Embedding);
2292
- }
2293
- return Array.from(f32Embedding);
2294
- }
2295
- async function generateEmbeddingsBatch(texts, headers, baseUrl, model, onUsage, maskInput) {
2296
- const response = await withEmbeddingRetry(
2297
- () => (0, import_client.postApiV1Embeddings)({
2298
- baseUrl,
2299
- // Mask PII from the request body only; cache/order still key on originals.
2300
- body: { input: maskInput ? texts.map(maskInput) : texts, model },
2301
- headers
2302
- })
2303
- );
2304
- if (response.error) {
2305
- throw embeddingErrorFrom(response);
2306
- }
2307
- if (!response.data?.data) {
2308
- throw new Error("No embeddings returned from API");
2309
- }
2310
- if (onUsage && response.data.usage) {
2311
- onUsage({
2312
- promptTokens: response.data.usage.prompt_tokens ?? 0,
2313
- totalTokens: response.data.usage.total_tokens ?? 0
2314
- });
2315
2553
  }
2316
- return response.data.data.map((item) => item.embedding ?? []);
2317
2554
  }
2318
- async function generateEmbeddings(texts, options) {
2319
- if (texts.length === 0) return [];
2320
- const { baseUrl = BASE_URL, getToken, apiKey, model, batchSize, cache } = options;
2321
- const chunkSize = batchSize ?? DEFAULT_EMBEDDING_BATCH_SIZE;
2322
- const results = new Array(texts.length).fill(null);
2323
- const uncachedIndices = [];
2324
- const uncachedTexts = [];
2325
- for (let i = 0; i < texts.length; i++) {
2326
- if (cache) {
2327
- const cached = cache.get(texts[i]);
2328
- if (cached) {
2329
- results[i] = Array.from(cached);
2330
- continue;
2555
+ var PATH_PARAM_RE, defaultPathSerializer, createQuerySerializer, getParseAs, checkForExistence, buildUrl, getUrl, mergeConfigs, headersEntries, mergeHeaders, Interceptors, createInterceptors, defaultQuerySerializer, defaultHeaders, createConfig;
2556
+ var init_utils_gen2 = __esm({
2557
+ "src/client/client/utils.gen.ts"() {
2558
+ "use strict";
2559
+ init_auth_gen();
2560
+ init_bodySerializer_gen();
2561
+ init_pathSerializer_gen();
2562
+ PATH_PARAM_RE = /\{[^{}]+\}/g;
2563
+ defaultPathSerializer = ({ path, url: _url }) => {
2564
+ let url = _url;
2565
+ const matches = _url.match(PATH_PARAM_RE);
2566
+ if (matches) {
2567
+ for (const match of matches) {
2568
+ let explode = false;
2569
+ let name = match.substring(1, match.length - 1);
2570
+ let style = "simple";
2571
+ if (name.endsWith("*")) {
2572
+ explode = true;
2573
+ name = name.substring(0, name.length - 1);
2574
+ }
2575
+ if (name.startsWith(".")) {
2576
+ name = name.substring(1);
2577
+ style = "label";
2578
+ } else if (name.startsWith(";")) {
2579
+ name = name.substring(1);
2580
+ style = "matrix";
2581
+ }
2582
+ const value = path[name];
2583
+ if (value === void 0 || value === null) {
2584
+ continue;
2585
+ }
2586
+ if (Array.isArray(value)) {
2587
+ url = url.replace(match, serializeArrayParam({ explode, name, style, value }));
2588
+ continue;
2589
+ }
2590
+ if (typeof value === "object") {
2591
+ url = url.replace(
2592
+ match,
2593
+ serializeObjectParam({
2594
+ explode,
2595
+ name,
2596
+ style,
2597
+ value,
2598
+ valueOnly: true
2599
+ })
2600
+ );
2601
+ continue;
2602
+ }
2603
+ if (style === "matrix") {
2604
+ url = url.replace(
2605
+ match,
2606
+ `;${serializePrimitiveParam({
2607
+ name,
2608
+ value
2609
+ })}`
2610
+ );
2611
+ continue;
2612
+ }
2613
+ const replaceValue = encodeURIComponent(
2614
+ style === "label" ? `.${value}` : value
2615
+ );
2616
+ url = url.replace(match, replaceValue);
2617
+ }
2331
2618
  }
2332
- }
2333
- uncachedIndices.push(i);
2334
- uncachedTexts.push(texts[i]);
2335
- }
2336
- if (uncachedTexts.length === 0) {
2337
- return results;
2338
- }
2339
- let headers;
2340
- if (apiKey) {
2341
- headers = { "X-API-Key": apiKey };
2342
- } else if (getToken) {
2343
- const token = await getToken();
2344
- if (!token) {
2345
- throw new Error("No token available for embedding generation");
2346
- }
2347
- headers = { Authorization: `Bearer ${token}` };
2348
- } else {
2349
- throw new Error("Either apiKey or getToken must be provided");
2350
- }
2351
- const embeddingModel = model ?? DEFAULT_API_EMBEDDING_MODEL;
2352
- let newEmbeddings;
2353
- if (uncachedTexts.length <= chunkSize) {
2354
- newEmbeddings = await generateEmbeddingsBatch(
2355
- uncachedTexts,
2356
- headers,
2619
+ return url;
2620
+ };
2621
+ createQuerySerializer = ({
2622
+ parameters = {},
2623
+ ...args
2624
+ } = {}) => {
2625
+ const querySerializer = (queryParams) => {
2626
+ const search = [];
2627
+ if (queryParams && typeof queryParams === "object") {
2628
+ for (const name in queryParams) {
2629
+ const value = queryParams[name];
2630
+ if (value === void 0 || value === null) {
2631
+ continue;
2632
+ }
2633
+ const options = parameters[name] || args;
2634
+ if (Array.isArray(value)) {
2635
+ const serializedArray = serializeArrayParam({
2636
+ allowReserved: options.allowReserved,
2637
+ explode: true,
2638
+ name,
2639
+ style: "form",
2640
+ value,
2641
+ ...options.array
2642
+ });
2643
+ if (serializedArray) search.push(serializedArray);
2644
+ } else if (typeof value === "object") {
2645
+ const serializedObject = serializeObjectParam({
2646
+ allowReserved: options.allowReserved,
2647
+ explode: true,
2648
+ name,
2649
+ style: "deepObject",
2650
+ value,
2651
+ ...options.object
2652
+ });
2653
+ if (serializedObject) search.push(serializedObject);
2654
+ } else {
2655
+ const serializedPrimitive = serializePrimitiveParam({
2656
+ allowReserved: options.allowReserved,
2657
+ name,
2658
+ value
2659
+ });
2660
+ if (serializedPrimitive) search.push(serializedPrimitive);
2661
+ }
2662
+ }
2663
+ }
2664
+ return search.join("&");
2665
+ };
2666
+ return querySerializer;
2667
+ };
2668
+ getParseAs = (contentType) => {
2669
+ if (!contentType) {
2670
+ return "stream";
2671
+ }
2672
+ const cleanContent = contentType.split(";")[0]?.trim();
2673
+ if (!cleanContent) {
2674
+ return;
2675
+ }
2676
+ if (cleanContent.startsWith("application/json") || cleanContent.endsWith("+json")) {
2677
+ return "json";
2678
+ }
2679
+ if (cleanContent === "multipart/form-data") {
2680
+ return "formData";
2681
+ }
2682
+ if (["application/", "audio/", "image/", "video/"].some((type) => cleanContent.startsWith(type))) {
2683
+ return "blob";
2684
+ }
2685
+ if (cleanContent.startsWith("text/")) {
2686
+ return "text";
2687
+ }
2688
+ return;
2689
+ };
2690
+ checkForExistence = (options, name) => {
2691
+ if (!name) {
2692
+ return false;
2693
+ }
2694
+ if (options.headers.has(name) || options.query?.[name] || options.headers.get("Cookie")?.includes(`${name}=`)) {
2695
+ return true;
2696
+ }
2697
+ return false;
2698
+ };
2699
+ buildUrl = (options) => {
2700
+ const url = getUrl({
2701
+ baseUrl: options.baseUrl,
2702
+ path: options.path,
2703
+ query: options.query,
2704
+ querySerializer: typeof options.querySerializer === "function" ? options.querySerializer : createQuerySerializer(options.querySerializer),
2705
+ url: options.url
2706
+ });
2707
+ return url;
2708
+ };
2709
+ getUrl = ({
2357
2710
  baseUrl,
2358
- embeddingModel,
2359
- options.onUsage,
2360
- options.maskInput
2361
- );
2362
- } else {
2363
- const chunks = [];
2364
- for (let i = 0; i < uncachedTexts.length; i += chunkSize) {
2365
- chunks.push(uncachedTexts.slice(i, i + chunkSize));
2366
- }
2367
- const allEmbeddings = new Array(chunks.length);
2368
- let nextIndex = 0;
2369
- const worker = async () => {
2370
- while (nextIndex < chunks.length) {
2371
- const idx = nextIndex++;
2372
- allEmbeddings[idx] = await generateEmbeddingsBatch(
2373
- chunks[idx],
2374
- headers,
2375
- baseUrl,
2376
- embeddingModel,
2377
- options.onUsage,
2378
- options.maskInput
2379
- );
2711
+ path,
2712
+ query,
2713
+ querySerializer,
2714
+ url: _url
2715
+ }) => {
2716
+ const pathUrl = _url.startsWith("/") ? _url : `/${_url}`;
2717
+ let url = (baseUrl ?? "") + pathUrl;
2718
+ if (path) {
2719
+ url = defaultPathSerializer({ path, url });
2380
2720
  }
2721
+ let search = query ? querySerializer(query) : "";
2722
+ if (search.startsWith("?")) {
2723
+ search = search.substring(1);
2724
+ }
2725
+ if (search) {
2726
+ url += `?${search}`;
2727
+ }
2728
+ return url;
2381
2729
  };
2382
- const workers = Array.from(
2383
- { length: Math.min(DEFAULT_EMBEDDING_BATCH_CONCURRENCY, chunks.length) },
2384
- () => worker()
2385
- );
2386
- await Promise.all(workers);
2387
- newEmbeddings = allEmbeddings.flat();
2388
- }
2389
- for (let i = 0; i < uncachedIndices.length; i++) {
2390
- const f32Embedding = Float32Array.from(newEmbeddings[i]);
2391
- results[uncachedIndices[i]] = Array.from(f32Embedding);
2392
- if (cache) {
2393
- cache.set(uncachedTexts[i], f32Embedding);
2394
- }
2395
- }
2396
- return results;
2397
- }
2398
- var import_client, EMBED_MAX_ATTEMPTS, EmbeddingHttpError, DEFAULT_EMBEDDING_BATCH_SIZE, DEFAULT_EMBEDDING_BATCH_CONCURRENCY;
2399
- var init_generate = __esm({
2400
- "src/lib/memoryEngine/generate.ts"() {
2401
- "use strict";
2402
- import_client = require("@anuma/sdk");
2403
- init_clientConfig();
2404
- init_constants();
2405
- EMBED_MAX_ATTEMPTS = 4;
2406
- EmbeddingHttpError = class extends Error {
2407
- constructor(message, status) {
2408
- super(message);
2409
- this.name = "EmbeddingHttpError";
2410
- this.status = status;
2730
+ mergeConfigs = (a, b) => {
2731
+ const config = { ...a, ...b };
2732
+ if (config.baseUrl?.endsWith("/")) {
2733
+ config.baseUrl = config.baseUrl.substring(0, config.baseUrl.length - 1);
2411
2734
  }
2735
+ config.headers = mergeHeaders(a.headers, b.headers);
2736
+ return config;
2412
2737
  };
2413
- DEFAULT_EMBEDDING_BATCH_SIZE = 100;
2414
- DEFAULT_EMBEDDING_BATCH_CONCURRENCY = 3;
2415
- }
2416
- });
2417
-
2418
- // src/lib/memoryEngine/embeddings.ts
2419
- async function embedMessage(ctx, messageId, options) {
2420
- const message = await getMessageOp(ctx, messageId);
2421
- if (!message) {
2422
- return null;
2423
- }
2424
- if (message.vector && message.vector.length > 0) {
2425
- return message;
2426
- }
2427
- const embedding = await generateEmbedding(message.content, options);
2428
- const embeddingModel = options.model ?? DEFAULT_API_EMBEDDING_MODEL;
2429
- return updateMessageEmbeddingOp(ctx, messageId, embedding, embeddingModel);
2430
- }
2431
- async function embedAllMessages(ctx, options, filter) {
2432
- const embeddingModel = options.model ?? DEFAULT_API_EMBEDDING_MODEL;
2433
- let embeddedCount = 0;
2434
- const conversations = await getConversationsOp(ctx);
2435
- const targetConversations = filter?.conversationId ? conversations.filter((c) => c.conversationId === filter.conversationId) : conversations;
2436
- for (const conv of targetConversations) {
2437
- const messages = await getMessagesOp(ctx, conv.conversationId);
2438
- for (const message of messages) {
2439
- if (message.vector && message.vector.length > 0) {
2440
- continue;
2738
+ headersEntries = (headers) => {
2739
+ const entries = [];
2740
+ headers.forEach((value, key) => {
2741
+ entries.push([key, value]);
2742
+ });
2743
+ return entries;
2744
+ };
2745
+ mergeHeaders = (...headers) => {
2746
+ const mergedHeaders = new Headers();
2747
+ for (const header of headers) {
2748
+ if (!header || typeof header !== "object") {
2749
+ continue;
2750
+ }
2751
+ const iterator = header instanceof Headers ? headersEntries(header) : Object.entries(header);
2752
+ for (const [key, value] of iterator) {
2753
+ if (value === null) {
2754
+ mergedHeaders.delete(key);
2755
+ } else if (Array.isArray(value)) {
2756
+ for (const v of value) {
2757
+ mergedHeaders.append(key, v);
2758
+ }
2759
+ } else if (value !== void 0) {
2760
+ mergedHeaders.set(
2761
+ key,
2762
+ typeof value === "object" ? JSON.stringify(value) : value
2763
+ );
2764
+ }
2765
+ }
2441
2766
  }
2442
- if (filter?.roles && !filter.roles.includes(message.role)) {
2443
- continue;
2767
+ return mergedHeaders;
2768
+ };
2769
+ Interceptors = class {
2770
+ constructor() {
2771
+ this.fns = [];
2444
2772
  }
2445
- if (message.role === "system") {
2446
- continue;
2773
+ clear() {
2774
+ this.fns = [];
2447
2775
  }
2448
- const minLength = filter?.minContentLength ?? DEFAULT_MIN_CONTENT_LENGTH;
2449
- if (message.content.length < minLength) {
2450
- continue;
2776
+ eject(id) {
2777
+ const index = this.getInterceptorIndex(id);
2778
+ if (this.fns[index]) {
2779
+ this.fns[index] = null;
2780
+ }
2451
2781
  }
2452
- try {
2453
- const embedding = await generateEmbedding(message.content, options);
2454
- await updateMessageEmbeddingOp(ctx, message.uniqueId, embedding, embeddingModel);
2455
- embeddedCount++;
2456
- } catch (error) {
2457
- if (isFatalEmbeddingError(error)) throw error;
2458
- getLogger().error(`Failed to embed message ${message.uniqueId}:`, error);
2782
+ exists(id) {
2783
+ const index = this.getInterceptorIndex(id);
2784
+ return Boolean(this.fns[index]);
2459
2785
  }
2460
- }
2461
- }
2462
- return embeddedCount;
2463
- }
2464
- async function chunkAndEmbedMessage(ctx, messageId, options) {
2465
- const { chunkSize = DEFAULT_CHUNK_SIZE } = options;
2466
- const message = await getMessageOp(ctx, messageId);
2467
- if (!message) {
2468
- return null;
2469
- }
2470
- if (message.chunks && message.chunks.length > 0) {
2471
- return message;
2472
- }
2473
- const embeddingModel = options.model ?? DEFAULT_API_EMBEDDING_MODEL;
2474
- if (!shouldChunkMessage(message.content, chunkSize)) {
2475
- const embedding = await generateEmbedding(message.content, options);
2476
- return updateMessageEmbeddingOp(ctx, messageId, embedding, embeddingModel);
2477
- }
2478
- const textChunks = chunkText(message.content, options);
2479
- const chunkTexts = textChunks.map((c) => c.text);
2480
- const embeddings = await generateEmbeddings(chunkTexts, options);
2481
- const messageChunks = textChunks.map((chunk, i) => ({
2482
- text: chunk.text,
2483
- vector: embeddings[i],
2484
- startOffset: chunk.startOffset,
2485
- endOffset: chunk.endOffset
2486
- }));
2487
- return updateMessageChunksOp(ctx, messageId, messageChunks, embeddingModel);
2488
- }
2489
- async function chunkAndEmbedAllMessages(ctx, options, filter) {
2490
- const embeddingModel = options.model ?? DEFAULT_API_EMBEDDING_MODEL;
2491
- const { chunkSize = DEFAULT_CHUNK_SIZE } = options;
2492
- const minLength = filter?.minContentLength ?? DEFAULT_MIN_CONTENT_LENGTH;
2493
- const conversations = await getConversationsOp(ctx);
2494
- const targetConversations = filter?.conversationId ? conversations.filter((c) => c.conversationId === filter.conversationId) : conversations;
2495
- const shortMessages = [];
2496
- const longMessages = [];
2497
- for (const conv of targetConversations) {
2498
- const messages = await getMessagesOp(ctx, conv.conversationId);
2499
- for (const message of messages) {
2500
- const isStale = message.embeddingModel !== void 0 && message.embeddingModel !== null && message.embeddingModel !== embeddingModel;
2501
- if (message.chunks && message.chunks.length > 0 && !isStale) continue;
2502
- const hasVector = message.vector && message.vector.length > 0;
2503
- if (hasVector && !filter?.rechunkExisting && !isStale) continue;
2504
- if (filter?.roles && !filter.roles.includes(message.role)) continue;
2505
- if (message.role === "system") continue;
2506
- if (message.content.length < minLength) continue;
2507
- if (shouldChunkMessage(message.content, chunkSize)) {
2508
- longMessages.push({
2509
- uniqueId: message.uniqueId,
2510
- textChunks: chunkText(message.content, options)
2511
- });
2512
- } else {
2513
- shortMessages.push({ uniqueId: message.uniqueId, content: message.content });
2786
+ getInterceptorIndex(id) {
2787
+ if (typeof id === "number") {
2788
+ return this.fns[id] ? id : -1;
2789
+ }
2790
+ return this.fns.indexOf(id);
2514
2791
  }
2515
- }
2792
+ update(id, fn) {
2793
+ const index = this.getInterceptorIndex(id);
2794
+ if (this.fns[index]) {
2795
+ this.fns[index] = fn;
2796
+ return id;
2797
+ }
2798
+ return false;
2799
+ }
2800
+ use(fn) {
2801
+ this.fns.push(fn);
2802
+ return this.fns.length - 1;
2803
+ }
2804
+ };
2805
+ createInterceptors = () => ({
2806
+ error: new Interceptors(),
2807
+ request: new Interceptors(),
2808
+ response: new Interceptors()
2809
+ });
2810
+ defaultQuerySerializer = createQuerySerializer({
2811
+ allowReserved: false,
2812
+ array: {
2813
+ explode: true,
2814
+ style: "form"
2815
+ },
2816
+ object: {
2817
+ explode: true,
2818
+ style: "deepObject"
2819
+ }
2820
+ });
2821
+ defaultHeaders = {
2822
+ "Content-Type": "application/json"
2823
+ };
2824
+ createConfig = (override = {}) => ({
2825
+ ...jsonBodySerializer,
2826
+ headers: defaultHeaders,
2827
+ parseAs: "auto",
2828
+ querySerializer: defaultQuerySerializer,
2829
+ ...override
2830
+ });
2516
2831
  }
2517
- let embeddedCount = 0;
2518
- if (shortMessages.length > 0) {
2519
- try {
2520
- const texts = shortMessages.map((m) => m.content);
2521
- const embeddings = await generateEmbeddings(texts, options);
2522
- for (let i = 0; i < shortMessages.length; i++) {
2832
+ });
2833
+
2834
+ // src/client/client/client.gen.ts
2835
+ var createClient;
2836
+ var init_client_gen = __esm({
2837
+ "src/client/client/client.gen.ts"() {
2838
+ "use strict";
2839
+ init_serverSentEvents_gen();
2840
+ init_utils_gen();
2841
+ init_utils_gen2();
2842
+ createClient = (config = {}) => {
2843
+ let _config = mergeConfigs(createConfig(), config);
2844
+ const getConfig = () => ({ ..._config });
2845
+ const setConfig = (config2) => {
2846
+ _config = mergeConfigs(_config, config2);
2847
+ return getConfig();
2848
+ };
2849
+ const interceptors = createInterceptors();
2850
+ const beforeRequest = async (options) => {
2851
+ const opts = {
2852
+ ..._config,
2853
+ ...options,
2854
+ fetch: options.fetch ?? _config.fetch ?? globalThis.fetch,
2855
+ headers: mergeHeaders(_config.headers, options.headers),
2856
+ serializedBody: void 0
2857
+ };
2858
+ if (opts.security) {
2859
+ await setAuthParams(opts);
2860
+ }
2861
+ if (opts.requestValidator) {
2862
+ await opts.requestValidator(opts);
2863
+ }
2864
+ if (opts.body !== void 0 && opts.bodySerializer) {
2865
+ opts.serializedBody = opts.bodySerializer(opts.body);
2866
+ }
2867
+ if (opts.body === void 0 || opts.serializedBody === "") {
2868
+ opts.headers.delete("Content-Type");
2869
+ }
2870
+ const resolvedOpts = opts;
2871
+ const url = buildUrl(resolvedOpts);
2872
+ return { opts: resolvedOpts, url };
2873
+ };
2874
+ const request = async (options) => {
2875
+ const throwOnError = options.throwOnError ?? _config.throwOnError;
2876
+ let response;
2523
2877
  try {
2524
- await updateMessageEmbeddingOp(
2525
- ctx,
2526
- shortMessages[i].uniqueId,
2527
- embeddings[i],
2528
- embeddingModel
2529
- );
2530
- embeddedCount++;
2878
+ const { opts, url } = await beforeRequest(options);
2879
+ for (const fn of interceptors.request.fns) {
2880
+ if (fn) {
2881
+ await fn(opts);
2882
+ }
2883
+ }
2884
+ const _fetch = opts.fetch;
2885
+ const requestInit = {
2886
+ ...opts,
2887
+ body: getValidRequestBody(opts)
2888
+ };
2889
+ response = await _fetch(url, requestInit);
2890
+ for (const fn of interceptors.response.fns) {
2891
+ if (fn) {
2892
+ response = await fn(response, opts);
2893
+ }
2894
+ }
2895
+ const result = {
2896
+ response
2897
+ };
2898
+ if (response.ok) {
2899
+ const parseAs = (opts.parseAs === "auto" ? getParseAs(response.headers.get("Content-Type")) : opts.parseAs) ?? "json";
2900
+ if (response.status === 204 || response.headers.get("Content-Length") === "0") {
2901
+ let emptyData;
2902
+ switch (parseAs) {
2903
+ case "arrayBuffer":
2904
+ case "blob":
2905
+ case "text":
2906
+ emptyData = await response[parseAs]();
2907
+ break;
2908
+ case "formData":
2909
+ emptyData = new FormData();
2910
+ break;
2911
+ case "stream":
2912
+ emptyData = response.body;
2913
+ break;
2914
+ case "json":
2915
+ default:
2916
+ emptyData = {};
2917
+ break;
2918
+ }
2919
+ return {
2920
+ data: emptyData,
2921
+ ...result
2922
+ };
2923
+ }
2924
+ let data;
2925
+ switch (parseAs) {
2926
+ case "arrayBuffer":
2927
+ case "blob":
2928
+ case "formData":
2929
+ case "text":
2930
+ data = await response[parseAs]();
2931
+ break;
2932
+ case "json": {
2933
+ const text12 = await response.text();
2934
+ data = text12 ? JSON.parse(text12) : {};
2935
+ break;
2936
+ }
2937
+ case "stream":
2938
+ return {
2939
+ data: response.body,
2940
+ ...result
2941
+ };
2942
+ }
2943
+ if (parseAs === "json") {
2944
+ if (opts.responseValidator) {
2945
+ await opts.responseValidator(data);
2946
+ }
2947
+ if (opts.responseTransformer) {
2948
+ data = await opts.responseTransformer(data);
2949
+ }
2950
+ }
2951
+ return {
2952
+ data,
2953
+ ...result
2954
+ };
2955
+ }
2956
+ const textError = await response.text();
2957
+ let jsonError;
2958
+ try {
2959
+ jsonError = JSON.parse(textError);
2960
+ } catch {
2961
+ }
2962
+ throw jsonError ?? textError;
2531
2963
  } catch (error) {
2532
- getLogger().error(
2533
- `Failed to save embedding for message ${shortMessages[i].uniqueId}:`,
2534
- error
2535
- );
2964
+ let finalError = error;
2965
+ for (const fn of interceptors.error.fns) {
2966
+ if (fn) {
2967
+ finalError = await fn(finalError, response, options);
2968
+ }
2969
+ }
2970
+ finalError = finalError || {};
2971
+ if (throwOnError) {
2972
+ throw finalError;
2973
+ }
2974
+ return {
2975
+ error: finalError,
2976
+ response
2977
+ };
2536
2978
  }
2537
- }
2538
- } catch (error) {
2539
- if (isFatalEmbeddingError(error)) throw error;
2540
- getLogger().error("Failed to batch-embed short messages:", error);
2541
- }
2979
+ };
2980
+ const makeMethodFn = (method) => (options) => request({ ...options, method });
2981
+ const makeSseFn = (method) => async (options) => {
2982
+ const { opts, url } = await beforeRequest(options);
2983
+ return createSseClient({
2984
+ ...opts,
2985
+ body: opts.body,
2986
+ method,
2987
+ onRequest: async (url2, init) => {
2988
+ let request2 = new Request(url2, init);
2989
+ const requestInit = { ...init, url: url2 };
2990
+ for (const fn of interceptors.request.fns) {
2991
+ if (fn) {
2992
+ await fn(requestInit);
2993
+ request2 = new Request(requestInit.url, requestInit);
2994
+ }
2995
+ }
2996
+ return request2;
2997
+ },
2998
+ serializedBody: getValidRequestBody(opts),
2999
+ url
3000
+ });
3001
+ };
3002
+ const _buildUrl = (options) => buildUrl({ ..._config, ...options });
3003
+ return {
3004
+ buildUrl: _buildUrl,
3005
+ connect: makeMethodFn("CONNECT"),
3006
+ delete: makeMethodFn("DELETE"),
3007
+ get: makeMethodFn("GET"),
3008
+ getConfig,
3009
+ head: makeMethodFn("HEAD"),
3010
+ interceptors,
3011
+ options: makeMethodFn("OPTIONS"),
3012
+ patch: makeMethodFn("PATCH"),
3013
+ post: makeMethodFn("POST"),
3014
+ put: makeMethodFn("PUT"),
3015
+ request,
3016
+ setConfig,
3017
+ sse: {
3018
+ connect: makeSseFn("CONNECT"),
3019
+ delete: makeSseFn("DELETE"),
3020
+ get: makeSseFn("GET"),
3021
+ head: makeSseFn("HEAD"),
3022
+ options: makeSseFn("OPTIONS"),
3023
+ patch: makeSseFn("PATCH"),
3024
+ post: makeSseFn("POST"),
3025
+ put: makeSseFn("PUT"),
3026
+ trace: makeSseFn("TRACE")
3027
+ },
3028
+ trace: makeMethodFn("TRACE")
3029
+ };
3030
+ };
2542
3031
  }
2543
- for (const msg of longMessages) {
2544
- try {
2545
- const chunkTexts = msg.textChunks.map((c) => c.text);
2546
- const embeddings = await generateEmbeddings(chunkTexts, options);
2547
- const messageChunks = msg.textChunks.map((chunk, i) => ({
2548
- text: chunk.text,
2549
- vector: embeddings[i],
2550
- startOffset: chunk.startOffset,
2551
- endOffset: chunk.endOffset
2552
- }));
2553
- await updateMessageChunksOp(ctx, msg.uniqueId, messageChunks, embeddingModel);
2554
- embeddedCount++;
2555
- } catch (error) {
2556
- if (isFatalEmbeddingError(error)) throw error;
2557
- getLogger().error(`Failed to embed message ${msg.uniqueId}:`, error);
2558
- }
3032
+ });
3033
+
3034
+ // src/client/client/index.ts
3035
+ var init_client = __esm({
3036
+ "src/client/client/index.ts"() {
3037
+ "use strict";
3038
+ init_client_gen();
3039
+ init_utils_gen2();
2559
3040
  }
2560
- return embeddedCount;
2561
- }
2562
- var DEFAULT_MIN_CONTENT_LENGTH;
2563
- var init_embeddings = __esm({
2564
- "src/lib/memoryEngine/embeddings.ts"() {
3041
+ });
3042
+
3043
+ // src/client/client.gen.ts
3044
+ var client;
3045
+ var init_client_gen2 = __esm({
3046
+ "src/client/client.gen.ts"() {
2565
3047
  "use strict";
2566
- init_operations();
2567
- init_logger();
2568
- init_chunking();
2569
- init_constants();
2570
- init_generate();
2571
- init_generate();
2572
- DEFAULT_MIN_CONTENT_LENGTH = 10;
3048
+ init_clientConfig();
3049
+ init_client();
3050
+ client = createClient(createClientConfig(createConfig()));
2573
3051
  }
2574
3052
  });
2575
3053
 
2576
- // src/lib/pii/patterns.ts
2577
- function luhnCheck(digits) {
2578
- let sum = 0;
2579
- let alternate = false;
2580
- for (let i = digits.length - 1; i >= 0; i--) {
2581
- let n = parseInt(digits[i], 10);
2582
- if (alternate) {
2583
- n *= 2;
2584
- if (n > 9) n -= 9;
2585
- }
2586
- sum += n;
2587
- alternate = !alternate;
3054
+ // src/client/sdk.gen.ts
3055
+ var getApiV1Config, getApiV1CreditsBalance, getApiV1CreditsPacks, postApiV1CreditsPurchase, postApiV1Embeddings, getApiV1Models, postApiV1PhoneCalls, getApiV1PhoneCallsByCallId, postApiV1SubscriptionsCancel, postApiV1SubscriptionsCreateCheckoutSession, postApiV1SubscriptionsCustomerPortal, postApiV1SubscriptionsRenew, getApiV1SubscriptionsStatus, getApiV1WalletsBinding, postApiV1WalletsBinding, postApiV1WalletsBindingNonce, deleteApiV1WalletsBindingByAddress, postAuthOauthByProviderExchange, postAuthOauthByProviderRefresh, postAuthOauthByProviderRevoke;
3056
+ var init_sdk_gen = __esm({
3057
+ "src/client/sdk.gen.ts"() {
3058
+ "use strict";
3059
+ init_client_gen2();
3060
+ getApiV1Config = (options) => (options?.client ?? client).get({ url: "/api/v1/config", ...options });
3061
+ getApiV1CreditsBalance = (options) => (options?.client ?? client).get({ url: "/api/v1/credits/balance", ...options });
3062
+ getApiV1CreditsPacks = (options) => (options?.client ?? client).get({ url: "/api/v1/credits/packs", ...options });
3063
+ postApiV1CreditsPurchase = (options) => (options.client ?? client).post({
3064
+ url: "/api/v1/credits/purchase",
3065
+ ...options,
3066
+ headers: {
3067
+ "Content-Type": "application/json",
3068
+ ...options.headers
3069
+ }
3070
+ });
3071
+ postApiV1Embeddings = (options) => (options.client ?? client).post({
3072
+ url: "/api/v1/embeddings",
3073
+ ...options,
3074
+ headers: {
3075
+ "Content-Type": "application/json",
3076
+ ...options.headers
3077
+ }
3078
+ });
3079
+ getApiV1Models = (options) => (options?.client ?? client).get({ url: "/api/v1/models", ...options });
3080
+ postApiV1PhoneCalls = (options) => (options.client ?? client).post({
3081
+ url: "/api/v1/phone-calls",
3082
+ ...options,
3083
+ headers: {
3084
+ "Content-Type": "application/json",
3085
+ ...options.headers
3086
+ }
3087
+ });
3088
+ getApiV1PhoneCallsByCallId = (options) => (options.client ?? client).get({ url: "/api/v1/phone-calls/{call_id}", ...options });
3089
+ postApiV1SubscriptionsCancel = (options) => (options?.client ?? client).post({
3090
+ url: "/api/v1/subscriptions/cancel",
3091
+ ...options,
3092
+ headers: {
3093
+ "Content-Type": "application/json",
3094
+ ...options?.headers
3095
+ }
3096
+ });
3097
+ postApiV1SubscriptionsCreateCheckoutSession = (options) => (options.client ?? client).post({
3098
+ url: "/api/v1/subscriptions/create-checkout-session",
3099
+ ...options,
3100
+ headers: {
3101
+ "Content-Type": "application/json",
3102
+ ...options.headers
3103
+ }
3104
+ });
3105
+ postApiV1SubscriptionsCustomerPortal = (options) => (options.client ?? client).post({
3106
+ url: "/api/v1/subscriptions/customer-portal",
3107
+ ...options,
3108
+ headers: {
3109
+ "Content-Type": "application/json",
3110
+ ...options.headers
3111
+ }
3112
+ });
3113
+ postApiV1SubscriptionsRenew = (options) => (options?.client ?? client).post({ url: "/api/v1/subscriptions/renew", ...options });
3114
+ getApiV1SubscriptionsStatus = (options) => (options?.client ?? client).get({ url: "/api/v1/subscriptions/status", ...options });
3115
+ getApiV1WalletsBinding = (options) => (options?.client ?? client).get({ url: "/api/v1/wallets/binding", ...options });
3116
+ postApiV1WalletsBinding = (options) => (options.client ?? client).post({
3117
+ url: "/api/v1/wallets/binding",
3118
+ ...options,
3119
+ headers: {
3120
+ "Content-Type": "application/json",
3121
+ ...options.headers
3122
+ }
3123
+ });
3124
+ postApiV1WalletsBindingNonce = (options) => (options?.client ?? client).post({ url: "/api/v1/wallets/binding/nonce", ...options });
3125
+ deleteApiV1WalletsBindingByAddress = (options) => (options.client ?? client).delete({ url: "/api/v1/wallets/binding/{address}", ...options });
3126
+ postAuthOauthByProviderExchange = (options) => (options.client ?? client).post({
3127
+ url: "/auth/oauth/{provider}/exchange",
3128
+ ...options,
3129
+ headers: {
3130
+ "Content-Type": "application/json",
3131
+ ...options.headers
3132
+ }
3133
+ });
3134
+ postAuthOauthByProviderRefresh = (options) => (options.client ?? client).post({
3135
+ url: "/auth/oauth/{provider}/refresh",
3136
+ ...options,
3137
+ headers: {
3138
+ "Content-Type": "application/json",
3139
+ ...options.headers
3140
+ }
3141
+ });
3142
+ postAuthOauthByProviderRevoke = (options) => (options.client ?? client).post({
3143
+ url: "/auth/oauth/{provider}/revoke",
3144
+ ...options,
3145
+ headers: {
3146
+ "Content-Type": "application/json",
3147
+ ...options.headers
3148
+ }
3149
+ });
2588
3150
  }
2589
- return sum % 10 === 0;
2590
- }
2591
- var PII_PATTERNS;
2592
- var init_patterns = __esm({
2593
- "src/lib/pii/patterns.ts"() {
3151
+ });
3152
+
3153
+ // src/client/index.ts
3154
+ var init_client2 = __esm({
3155
+ "src/client/index.ts"() {
2594
3156
  "use strict";
2595
- PII_PATTERNS = [
2596
- // Email — standard RFC-ish pattern.
2597
- // Quantifiers are bounded (local-part ≤ 64, domain ≤ 255, TLD ≤ 24 —
2598
- // all at or above real RFC 5321 limits) so the engine cannot backtrack
2599
- // quadratically on adversarial input like "a.a.a.a…" with no "@".
2600
- {
2601
- category: "EMAIL",
2602
- regex: /\b[a-zA-Z0-9._%+-]{1,64}@[a-zA-Z0-9.-]{1,255}\.[a-zA-Z]{2,24}\b/g
2603
- },
2604
- // SSN — US Social Security Number, dashed form (must run before phone)
2605
- {
2606
- category: "SSN",
2607
- regex: /\b\d{3}-\d{2}-\d{4}\b/g,
2608
- validate: (match) => {
2609
- const parts = match.split("-");
2610
- const area = parseInt(parts[0], 10);
2611
- return area !== 0 && area !== 666 && area < 900;
2612
- }
2613
- },
2614
- // SSN — dashless or space-separated form. Only redacted with an "SSN" /
2615
- // "social security" cue nearby: a bare 9-digit run is too ambiguous
2616
- // (ZIP+4, account numbers, etc.) to redact unconditionally.
2617
- {
2618
- category: "SSN",
2619
- regex: /\b\d{3}[ ]?\d{2}[ ]?\d{4}\b/g,
2620
- context: /(?:\bssn\b|\bsocial\s+security(?:\s+(?:number|no\.?|#))?\b)[^\d\n]{0,12}$/i,
2621
- validate: (match) => {
2622
- const digits = match.replace(/\D/g, "");
2623
- if (digits.length !== 9) return false;
2624
- const area = parseInt(digits.slice(0, 3), 10);
2625
- return area !== 0 && area !== 666 && area < 900;
2626
- }
2627
- },
2628
- // Credit card numbers — 13-19 contiguous digits or groups of 4 separated by spaces/dashes
2629
- // Must run before phone to avoid partial matches
2630
- {
2631
- category: "CREDIT_CARD",
2632
- regex: /\b\d{4}[\s-]\d{4}[\s-]\d{4}[\s-]\d{1,7}\b|\b\d{13,19}\b/g,
2633
- validate: (match) => {
2634
- const digits = match.replace(/\D/g, "");
2635
- if (digits.length < 13 || digits.length > 19) return false;
2636
- return luhnCheck(digits);
2637
- }
2638
- },
2639
- // IPv4 addresses (must run before phone to avoid partial matches)
2640
- {
2641
- category: "IP_ADDRESS",
2642
- regex: /\b(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\b/g,
2643
- validate: (match) => {
2644
- return match !== "0.0.0.0" && match !== "127.0.0.1" && match !== "255.255.255.255";
2645
- }
2646
- },
2647
- // IPv6 addresses — full and compressed (::) forms. Each alternative requires
2648
- // either a full 8-group address or a "::" compression, so ordinary
2649
- // colon-separated text (timestamps like 12:34:56) does not match. Loopback
2650
- // (::1) and unspecified (::) are excluded.
2651
- {
2652
- category: "IP_ADDRESS",
2653
- regex: /(?:(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|(?:[0-9a-fA-F]{1,4}:){1,7}:|(?:[0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|(?:[0-9a-fA-F]{1,4}:){1,5}(?::[0-9a-fA-F]{1,4}){1,2}|(?:[0-9a-fA-F]{1,4}:){1,4}(?::[0-9a-fA-F]{1,4}){1,3}|(?:[0-9a-fA-F]{1,4}:){1,3}(?::[0-9a-fA-F]{1,4}){1,4}|(?:[0-9a-fA-F]{1,4}:){1,2}(?::[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:(?::[0-9a-fA-F]{1,4}){1,6}|:(?:(?::[0-9a-fA-F]{1,4}){1,7}|:))/g,
2654
- validate: (match) => match !== "::1" && match !== "::"
2655
- },
2656
- // Phone numbers. The separated form requires separator characters (dashes,
2657
- // spaces, dots, parens) to avoid matching bare digit sequences that are
2658
- // actually credit cards, IPs, or years. A second alternative matches E.164
2659
- // (a leading "+" then 10–15 digits, e.g. +14155552671), which is
2660
- // unambiguous; a bare 10-digit run with no "+" and no separators is
2661
- // intentionally not matched to avoid false positives.
2662
- {
2663
- category: "PHONE",
2664
- regex: /(?:\+\d{1,3}[\s.-])?\(?\d{3}\)?[\s.-]\d{3}[\s.-]\d{4}\b|\+\d{10,15}\b/g
2665
- },
2666
- // API keys / secrets — long token with a key-like prefix. The validator
2667
- // requires entropy (at least one digit, or a mix of upper- and lower-case)
2668
- // so long all-lowercase prose identifiers like
2669
- // "accessibility_is_important_for_everyone" or
2670
- // "access-control-list-management-feature" are not redacted. Real keys and
2671
- // tokens essentially always contain digits or mixed case.
2672
- {
2673
- category: "API_KEY",
2674
- regex: /\b(?:sk|pk|api|key|token|secret|bearer|access)[_-]?[a-zA-Z0-9_-]{20,}\b/gi,
2675
- validate: (match) => {
2676
- const hasDigit = /\d/.test(match);
2677
- const hasMixedCase = /[a-z]/.test(match) && /[A-Z]/.test(match);
2678
- return hasDigit || hasMixedCase;
2679
- }
2680
- },
2681
- // US street addresses — house number + Title-Case street name + suffix.
2682
- // Intentionally NOT case-insensitive: the `[A-Z][a-z]+` guard requires
2683
- // properly-capitalized street words, so "123 main street", "100 MAIN
2684
- // STREET" and prose like "3 blocks down the road" / "5 minutes to drive"
2685
- // are not treated as addresses. Whitespace is `[ \t]` only (no newline
2686
- // spanning), and the suffix must end the segment (punctuation / newline /
2687
- // end of string) so "Driveway" or "Wayfair" don't match on the suffix.
2688
- {
2689
- category: "US_ADDRESS",
2690
- regex: /\b\d{1,5}[ \t]+(?:[A-Z][a-z]+[ \t]+){1,3}(?:St(?:reet)?|Ave(?:nue)?|Blvd|Boulevard|Dr(?:ive)?|Ln|Lane|Rd|Road|Ct|Court|Pl(?:ace)?|Way|Cir(?:cle)?|Pkwy|Parkway|Hwy|Highway)\.?(?=[\s,.;:!?)]|$)/g,
2691
- validate: (match) => {
2692
- return !/^0/.test(match.trim());
2693
- }
2694
- },
2695
- // Dates of birth — common US date formats. Only redacted when a birth-date
2696
- // cue ("DOB", "born", "birthday", "date of birth") appears just before the
2697
- // date, so ordinary calendar dates ("meeting 12/25/2024", deadlines,
2698
- // invoices) are left intact for the model. A calendar validator also rejects
2699
- // impossible dates like 02/31/1990.
2700
- {
2701
- category: "DATE_OF_BIRTH",
2702
- regex: /\b(?:(?:0?[1-9]|1[0-2])[/-](?:0?[1-9]|[12]\d|3[01])[/-](?:19|20)\d{2})\b/g,
2703
- context: /(?:\bdob\b|\bd\.?o\.?b\.?|\bborn\b|\bbirth\s?date\b|\bbirthdate\b|\bbirthday\b|\bdate\s+of\s+birth\b)[^\d\n]{0,12}$/i,
2704
- validate: (match) => {
2705
- const m = match.match(/(\d{1,2})[/-](\d{1,2})[/-](\d{4})/);
2706
- if (!m) return false;
2707
- const month = parseInt(m[1], 10);
2708
- const day = parseInt(m[2], 10);
2709
- const year = parseInt(m[3], 10);
2710
- const isLeap = year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0);
2711
- const daysInMonth = [31, isLeap ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
2712
- return month >= 1 && month <= 12 && day >= 1 && day <= daysInMonth[month - 1];
2713
- }
2714
- }
2715
- ];
3157
+ init_sdk_gen();
2716
3158
  }
2717
3159
  });
2718
3160
 
2719
- // src/lib/pii/redactor.ts
2720
- function escapeRegExp(value) {
2721
- return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
3161
+ // src/lib/memoryEngine/generate.ts
3162
+ async function withEmbeddingRetry(call) {
3163
+ let last;
3164
+ let lastThrown;
3165
+ let threw = false;
3166
+ for (let attempt = 1; attempt <= EMBED_MAX_ATTEMPTS; attempt++) {
3167
+ try {
3168
+ threw = false;
3169
+ last = await call();
3170
+ if (!last.error) return last;
3171
+ const status = last.response?.status;
3172
+ const retryable = status === void 0 || status === 429 || status >= 500;
3173
+ if (!retryable) return last;
3174
+ } catch (err) {
3175
+ threw = true;
3176
+ lastThrown = err;
3177
+ }
3178
+ if (attempt < EMBED_MAX_ATTEMPTS) {
3179
+ const base = 250 * 2 ** (attempt - 1);
3180
+ await new Promise((r) => setTimeout(r, base + Math.random() * 0.4 * base));
3181
+ }
3182
+ }
3183
+ if (threw) throw lastThrown;
3184
+ if (last?.error instanceof Error && last.response?.status === void 0) {
3185
+ throw last.error;
3186
+ }
3187
+ return last;
2722
3188
  }
2723
- function isWordChar(ch) {
2724
- return /[A-Za-z0-9_]/.test(ch) || ch.charCodeAt(0) > 127;
3189
+ function isFatalEmbeddingError(err) {
3190
+ return err instanceof EmbeddingHttpError && (err.status === 401 || err.status === 402 || err.status === 403);
2725
3191
  }
2726
- function isPiiRedactor(value) {
2727
- return typeof value === "object" && value !== null && typeof value.redactMessages === "function" && typeof value.deAnonymize === "function";
3192
+ function embeddingErrorFrom(response) {
3193
+ const message = typeof response.error === "object" && response.error && "error" in response.error ? response.error.error : "API embedding failed";
3194
+ return new EmbeddingHttpError(message, response.response?.status);
2728
3195
  }
2729
- function resolvePiiRedactor(piiRedaction) {
2730
- if (piiRedaction === true) return new PiiRedactor();
2731
- if (!piiRedaction) return void 0;
2732
- if (isPiiRedactor(piiRedaction)) return piiRedaction;
2733
- console.warn(
2734
- "[PiiRedactor] `piiRedaction` is neither `true` nor a PiiRedactor instance; PII redaction is DISABLED for this request."
3196
+ async function generateEmbedding(text12, options) {
3197
+ const { baseUrl = BASE_URL, getToken, apiKey, model, cache } = options;
3198
+ if (cache) {
3199
+ const cached = cache.get(text12);
3200
+ if (cached) return Array.from(cached);
3201
+ }
3202
+ let headers;
3203
+ if (apiKey) {
3204
+ headers = { "X-API-Key": apiKey };
3205
+ } else if (getToken) {
3206
+ const token = await getToken();
3207
+ if (!token) {
3208
+ throw new Error("No token available for embedding generation");
3209
+ }
3210
+ headers = { Authorization: `Bearer ${token}` };
3211
+ } else {
3212
+ throw new Error("Either apiKey or getToken must be provided");
3213
+ }
3214
+ const response = await withEmbeddingRetry(
3215
+ () => postApiV1Embeddings({
3216
+ baseUrl,
3217
+ body: {
3218
+ // Mask PII from the request body only — the cache above still keys on
3219
+ // the original `text`, so callers keep their original values.
3220
+ input: options.maskInput ? options.maskInput(text12) : text12,
3221
+ model: model ?? DEFAULT_API_EMBEDDING_MODEL
3222
+ },
3223
+ headers
3224
+ })
2735
3225
  );
2736
- return void 0;
3226
+ if (response.error) {
3227
+ throw embeddingErrorFrom(response);
3228
+ }
3229
+ if (!response.data?.data?.[0]?.embedding) {
3230
+ throw new Error("No embedding returned from API");
3231
+ }
3232
+ const embedding = response.data.data[0].embedding;
3233
+ if (options.onUsage && response.data.usage) {
3234
+ options.onUsage({
3235
+ promptTokens: response.data.usage.prompt_tokens ?? 0,
3236
+ totalTokens: response.data.usage.total_tokens ?? 0
3237
+ });
3238
+ }
3239
+ const f32Embedding = Float32Array.from(embedding);
3240
+ if (cache) {
3241
+ cache.set(text12, f32Embedding);
3242
+ }
3243
+ return Array.from(f32Embedding);
2737
3244
  }
2738
- function createStreamingDeAnonymizer(redactor, emit) {
2739
- let buffer = "";
2740
- const trailingFragment = /\[[A-Za-z0-9_]*$/;
2741
- return {
2742
- push(chunk) {
2743
- if (!chunk) return;
2744
- buffer += chunk;
2745
- const m = buffer.match(trailingFragment);
2746
- if (!m || m.index === void 0) {
2747
- emit(redactor.deAnonymize(buffer));
2748
- buffer = "";
2749
- } else if (m.index > 0) {
2750
- emit(redactor.deAnonymize(buffer.slice(0, m.index)));
2751
- buffer = buffer.slice(m.index);
2752
- }
2753
- },
2754
- flush() {
2755
- if (buffer) {
2756
- emit(redactor.deAnonymize(buffer));
2757
- buffer = "";
2758
- }
2759
- }
2760
- };
3245
+ async function generateEmbeddingsBatch(texts, headers, baseUrl, model, onUsage, maskInput) {
3246
+ const response = await withEmbeddingRetry(
3247
+ () => postApiV1Embeddings({
3248
+ baseUrl,
3249
+ // Mask PII from the request body only; cache/order still key on originals.
3250
+ body: { input: maskInput ? texts.map(maskInput) : texts, model },
3251
+ headers
3252
+ })
3253
+ );
3254
+ if (response.error) {
3255
+ throw embeddingErrorFrom(response);
3256
+ }
3257
+ if (!response.data?.data) {
3258
+ throw new Error("No embeddings returned from API");
3259
+ }
3260
+ if (onUsage && response.data.usage) {
3261
+ onUsage({
3262
+ promptTokens: response.data.usage.prompt_tokens ?? 0,
3263
+ totalTokens: response.data.usage.total_tokens ?? 0
3264
+ });
3265
+ }
3266
+ return response.data.data.map((item) => item.embedding ?? []);
2761
3267
  }
2762
- var PiiRedactor;
2763
- var init_redactor = __esm({
2764
- "src/lib/pii/redactor.ts"() {
2765
- "use strict";
3268
+ async function generateEmbeddings(texts, options) {
3269
+ if (texts.length === 0) return [];
3270
+ const { baseUrl = BASE_URL, getToken, apiKey, model, batchSize, cache } = options;
3271
+ const chunkSize = batchSize ?? DEFAULT_EMBEDDING_BATCH_SIZE;
3272
+ const results = new Array(texts.length).fill(null);
3273
+ const uncachedIndices = [];
3274
+ const uncachedTexts = [];
3275
+ for (let i = 0; i < texts.length; i++) {
3276
+ if (cache) {
3277
+ const cached = cache.get(texts[i]);
3278
+ if (cached) {
3279
+ results[i] = Array.from(cached);
3280
+ continue;
3281
+ }
3282
+ }
3283
+ uncachedIndices.push(i);
3284
+ uncachedTexts.push(texts[i]);
3285
+ }
3286
+ if (uncachedTexts.length === 0) {
3287
+ return results;
3288
+ }
3289
+ let headers;
3290
+ if (apiKey) {
3291
+ headers = { "X-API-Key": apiKey };
3292
+ } else if (getToken) {
3293
+ const token = await getToken();
3294
+ if (!token) {
3295
+ throw new Error("No token available for embedding generation");
3296
+ }
3297
+ headers = { Authorization: `Bearer ${token}` };
3298
+ } else {
3299
+ throw new Error("Either apiKey or getToken must be provided");
3300
+ }
3301
+ const embeddingModel = model ?? DEFAULT_API_EMBEDDING_MODEL;
3302
+ let newEmbeddings;
3303
+ if (uncachedTexts.length <= chunkSize) {
3304
+ newEmbeddings = await generateEmbeddingsBatch(
3305
+ uncachedTexts,
3306
+ headers,
3307
+ baseUrl,
3308
+ embeddingModel,
3309
+ options.onUsage,
3310
+ options.maskInput
3311
+ );
3312
+ } else {
3313
+ const chunks = [];
3314
+ for (let i = 0; i < uncachedTexts.length; i += chunkSize) {
3315
+ chunks.push(uncachedTexts.slice(i, i + chunkSize));
3316
+ }
3317
+ const allEmbeddings = new Array(chunks.length);
3318
+ let nextIndex = 0;
3319
+ const worker = async () => {
3320
+ while (nextIndex < chunks.length) {
3321
+ const idx = nextIndex++;
3322
+ allEmbeddings[idx] = await generateEmbeddingsBatch(
3323
+ chunks[idx],
3324
+ headers,
3325
+ baseUrl,
3326
+ embeddingModel,
3327
+ options.onUsage,
3328
+ options.maskInput
3329
+ );
3330
+ }
3331
+ };
3332
+ const workers = Array.from(
3333
+ { length: Math.min(DEFAULT_EMBEDDING_BATCH_CONCURRENCY, chunks.length) },
3334
+ () => worker()
3335
+ );
3336
+ await Promise.all(workers);
3337
+ newEmbeddings = allEmbeddings.flat();
3338
+ }
3339
+ for (let i = 0; i < uncachedIndices.length; i++) {
3340
+ const f32Embedding = Float32Array.from(newEmbeddings[i]);
3341
+ results[uncachedIndices[i]] = Array.from(f32Embedding);
3342
+ if (cache) {
3343
+ cache.set(uncachedTexts[i], f32Embedding);
3344
+ }
3345
+ }
3346
+ return results;
3347
+ }
3348
+ var EMBED_MAX_ATTEMPTS, EmbeddingHttpError, DEFAULT_EMBEDDING_BATCH_SIZE, DEFAULT_EMBEDDING_BATCH_CONCURRENCY;
3349
+ var init_generate = __esm({
3350
+ "src/lib/memoryEngine/generate.ts"() {
3351
+ "use strict";
3352
+ init_client2();
3353
+ init_clientConfig();
3354
+ init_constants();
3355
+ EMBED_MAX_ATTEMPTS = 4;
3356
+ EmbeddingHttpError = class extends Error {
3357
+ constructor(message, status) {
3358
+ super(message);
3359
+ this.name = "EmbeddingHttpError";
3360
+ this.status = status;
3361
+ }
3362
+ };
3363
+ DEFAULT_EMBEDDING_BATCH_SIZE = 100;
3364
+ DEFAULT_EMBEDDING_BATCH_CONCURRENCY = 3;
3365
+ }
3366
+ });
3367
+
3368
+ // src/lib/memoryEngine/embeddings.ts
3369
+ async function embedMessage(ctx, messageId, options) {
3370
+ const message = await getMessageOp(ctx, messageId);
3371
+ if (!message) {
3372
+ return null;
3373
+ }
3374
+ if (message.vector && message.vector.length > 0) {
3375
+ return message;
3376
+ }
3377
+ const embedding = await generateEmbedding(message.content, options);
3378
+ const embeddingModel = options.model ?? DEFAULT_API_EMBEDDING_MODEL;
3379
+ return updateMessageEmbeddingOp(ctx, messageId, embedding, embeddingModel);
3380
+ }
3381
+ async function embedAllMessages(ctx, options, filter) {
3382
+ const embeddingModel = options.model ?? DEFAULT_API_EMBEDDING_MODEL;
3383
+ let embeddedCount = 0;
3384
+ const conversations = await getConversationsOp(ctx);
3385
+ const targetConversations = filter?.conversationId ? conversations.filter((c) => c.conversationId === filter.conversationId) : conversations;
3386
+ for (const conv of targetConversations) {
3387
+ const messages = await getMessagesOp(ctx, conv.conversationId);
3388
+ for (const message of messages) {
3389
+ if (message.vector && message.vector.length > 0) {
3390
+ continue;
3391
+ }
3392
+ if (filter?.roles && !filter.roles.includes(message.role)) {
3393
+ continue;
3394
+ }
3395
+ if (message.role === "system") {
3396
+ continue;
3397
+ }
3398
+ const minLength = filter?.minContentLength ?? DEFAULT_MIN_CONTENT_LENGTH;
3399
+ if (message.content.length < minLength) {
3400
+ continue;
3401
+ }
3402
+ try {
3403
+ const embedding = await generateEmbedding(message.content, options);
3404
+ await updateMessageEmbeddingOp(ctx, message.uniqueId, embedding, embeddingModel);
3405
+ embeddedCount++;
3406
+ } catch (error) {
3407
+ if (isFatalEmbeddingError(error)) throw error;
3408
+ getLogger().error(`Failed to embed message ${message.uniqueId}:`, error);
3409
+ }
3410
+ }
3411
+ }
3412
+ return embeddedCount;
3413
+ }
3414
+ async function chunkAndEmbedMessage(ctx, messageId, options) {
3415
+ const { chunkSize = DEFAULT_CHUNK_SIZE } = options;
3416
+ const message = await getMessageOp(ctx, messageId);
3417
+ if (!message) {
3418
+ return null;
3419
+ }
3420
+ if (message.chunks && message.chunks.length > 0) {
3421
+ return message;
3422
+ }
3423
+ const embeddingModel = options.model ?? DEFAULT_API_EMBEDDING_MODEL;
3424
+ if (!shouldChunkMessage(message.content, chunkSize)) {
3425
+ const embedding = await generateEmbedding(message.content, options);
3426
+ return updateMessageEmbeddingOp(ctx, messageId, embedding, embeddingModel);
3427
+ }
3428
+ const textChunks = chunkText(message.content, options);
3429
+ const chunkTexts = textChunks.map((c) => c.text);
3430
+ const embeddings = await generateEmbeddings(chunkTexts, options);
3431
+ const messageChunks = textChunks.map((chunk, i) => ({
3432
+ text: chunk.text,
3433
+ vector: embeddings[i],
3434
+ startOffset: chunk.startOffset,
3435
+ endOffset: chunk.endOffset
3436
+ }));
3437
+ return updateMessageChunksOp(ctx, messageId, messageChunks, embeddingModel);
3438
+ }
3439
+ async function chunkAndEmbedAllMessages(ctx, options, filter) {
3440
+ const embeddingModel = options.model ?? DEFAULT_API_EMBEDDING_MODEL;
3441
+ const { chunkSize = DEFAULT_CHUNK_SIZE } = options;
3442
+ const minLength = filter?.minContentLength ?? DEFAULT_MIN_CONTENT_LENGTH;
3443
+ const conversations = await getConversationsOp(ctx);
3444
+ const targetConversations = filter?.conversationId ? conversations.filter((c) => c.conversationId === filter.conversationId) : conversations;
3445
+ const shortMessages = [];
3446
+ const longMessages = [];
3447
+ for (const conv of targetConversations) {
3448
+ const messages = await getMessagesOp(ctx, conv.conversationId);
3449
+ for (const message of messages) {
3450
+ const isStale = message.embeddingModel !== void 0 && message.embeddingModel !== null && message.embeddingModel !== embeddingModel;
3451
+ if (message.chunks && message.chunks.length > 0 && !isStale) continue;
3452
+ const hasVector = message.vector && message.vector.length > 0;
3453
+ if (hasVector && !filter?.rechunkExisting && !isStale) continue;
3454
+ if (filter?.roles && !filter.roles.includes(message.role)) continue;
3455
+ if (message.role === "system") continue;
3456
+ if (message.content.length < minLength) continue;
3457
+ if (shouldChunkMessage(message.content, chunkSize)) {
3458
+ longMessages.push({
3459
+ uniqueId: message.uniqueId,
3460
+ textChunks: chunkText(message.content, options)
3461
+ });
3462
+ } else {
3463
+ shortMessages.push({ uniqueId: message.uniqueId, content: message.content });
3464
+ }
3465
+ }
3466
+ }
3467
+ let embeddedCount = 0;
3468
+ if (shortMessages.length > 0) {
3469
+ try {
3470
+ const texts = shortMessages.map((m) => m.content);
3471
+ const embeddings = await generateEmbeddings(texts, options);
3472
+ for (let i = 0; i < shortMessages.length; i++) {
3473
+ try {
3474
+ await updateMessageEmbeddingOp(
3475
+ ctx,
3476
+ shortMessages[i].uniqueId,
3477
+ embeddings[i],
3478
+ embeddingModel
3479
+ );
3480
+ embeddedCount++;
3481
+ } catch (error) {
3482
+ getLogger().error(
3483
+ `Failed to save embedding for message ${shortMessages[i].uniqueId}:`,
3484
+ error
3485
+ );
3486
+ }
3487
+ }
3488
+ } catch (error) {
3489
+ if (isFatalEmbeddingError(error)) throw error;
3490
+ getLogger().error("Failed to batch-embed short messages:", error);
3491
+ }
3492
+ }
3493
+ for (const msg of longMessages) {
3494
+ try {
3495
+ const chunkTexts = msg.textChunks.map((c) => c.text);
3496
+ const embeddings = await generateEmbeddings(chunkTexts, options);
3497
+ const messageChunks = msg.textChunks.map((chunk, i) => ({
3498
+ text: chunk.text,
3499
+ vector: embeddings[i],
3500
+ startOffset: chunk.startOffset,
3501
+ endOffset: chunk.endOffset
3502
+ }));
3503
+ await updateMessageChunksOp(ctx, msg.uniqueId, messageChunks, embeddingModel);
3504
+ embeddedCount++;
3505
+ } catch (error) {
3506
+ if (isFatalEmbeddingError(error)) throw error;
3507
+ getLogger().error(`Failed to embed message ${msg.uniqueId}:`, error);
3508
+ }
3509
+ }
3510
+ return embeddedCount;
3511
+ }
3512
+ var DEFAULT_MIN_CONTENT_LENGTH;
3513
+ var init_embeddings = __esm({
3514
+ "src/lib/memoryEngine/embeddings.ts"() {
3515
+ "use strict";
3516
+ init_operations();
3517
+ init_logger();
3518
+ init_chunking();
3519
+ init_constants();
3520
+ init_generate();
3521
+ init_generate();
3522
+ DEFAULT_MIN_CONTENT_LENGTH = 10;
3523
+ }
3524
+ });
3525
+
3526
+ // src/lib/pii/patterns.ts
3527
+ function luhnCheck(digits) {
3528
+ let sum = 0;
3529
+ let alternate = false;
3530
+ for (let i = digits.length - 1; i >= 0; i--) {
3531
+ let n = parseInt(digits[i], 10);
3532
+ if (alternate) {
3533
+ n *= 2;
3534
+ if (n > 9) n -= 9;
3535
+ }
3536
+ sum += n;
3537
+ alternate = !alternate;
3538
+ }
3539
+ return sum % 10 === 0;
3540
+ }
3541
+ var PII_PATTERNS;
3542
+ var init_patterns = __esm({
3543
+ "src/lib/pii/patterns.ts"() {
3544
+ "use strict";
3545
+ PII_PATTERNS = [
3546
+ // Email — standard RFC-ish pattern.
3547
+ // Quantifiers are bounded (local-part ≤ 64, domain ≤ 255, TLD ≤ 24 —
3548
+ // all at or above real RFC 5321 limits) so the engine cannot backtrack
3549
+ // quadratically on adversarial input like "a.a.a.a…" with no "@".
3550
+ {
3551
+ category: "EMAIL",
3552
+ regex: /\b[a-zA-Z0-9._%+-]{1,64}@[a-zA-Z0-9.-]{1,255}\.[a-zA-Z]{2,24}\b/g
3553
+ },
3554
+ // SSN — US Social Security Number, dashed form (must run before phone)
3555
+ {
3556
+ category: "SSN",
3557
+ regex: /\b\d{3}-\d{2}-\d{4}\b/g,
3558
+ validate: (match) => {
3559
+ const parts = match.split("-");
3560
+ const area = parseInt(parts[0], 10);
3561
+ return area !== 0 && area !== 666 && area < 900;
3562
+ }
3563
+ },
3564
+ // SSN — dashless or space-separated form. Only redacted with an "SSN" /
3565
+ // "social security" cue nearby: a bare 9-digit run is too ambiguous
3566
+ // (ZIP+4, account numbers, etc.) to redact unconditionally.
3567
+ {
3568
+ category: "SSN",
3569
+ regex: /\b\d{3}[ ]?\d{2}[ ]?\d{4}\b/g,
3570
+ context: /(?:\bssn\b|\bsocial\s+security(?:\s+(?:number|no\.?|#))?\b)[^\d\n]{0,12}$/i,
3571
+ validate: (match) => {
3572
+ const digits = match.replace(/\D/g, "");
3573
+ if (digits.length !== 9) return false;
3574
+ const area = parseInt(digits.slice(0, 3), 10);
3575
+ return area !== 0 && area !== 666 && area < 900;
3576
+ }
3577
+ },
3578
+ // Credit card numbers — 13-19 contiguous digits or groups of 4 separated by spaces/dashes
3579
+ // Must run before phone to avoid partial matches
3580
+ {
3581
+ category: "CREDIT_CARD",
3582
+ regex: /\b\d{4}[\s-]\d{4}[\s-]\d{4}[\s-]\d{1,7}\b|\b\d{13,19}\b/g,
3583
+ validate: (match) => {
3584
+ const digits = match.replace(/\D/g, "");
3585
+ if (digits.length < 13 || digits.length > 19) return false;
3586
+ return luhnCheck(digits);
3587
+ }
3588
+ },
3589
+ // IPv4 addresses (must run before phone to avoid partial matches)
3590
+ {
3591
+ category: "IP_ADDRESS",
3592
+ regex: /\b(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\b/g,
3593
+ validate: (match) => {
3594
+ return match !== "0.0.0.0" && match !== "127.0.0.1" && match !== "255.255.255.255";
3595
+ }
3596
+ },
3597
+ // IPv6 addresses — full and compressed (::) forms. Each alternative requires
3598
+ // either a full 8-group address or a "::" compression, so ordinary
3599
+ // colon-separated text (timestamps like 12:34:56) does not match. Loopback
3600
+ // (::1) and unspecified (::) are excluded.
3601
+ {
3602
+ category: "IP_ADDRESS",
3603
+ regex: /(?:(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|(?:[0-9a-fA-F]{1,4}:){1,7}:|(?:[0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|(?:[0-9a-fA-F]{1,4}:){1,5}(?::[0-9a-fA-F]{1,4}){1,2}|(?:[0-9a-fA-F]{1,4}:){1,4}(?::[0-9a-fA-F]{1,4}){1,3}|(?:[0-9a-fA-F]{1,4}:){1,3}(?::[0-9a-fA-F]{1,4}){1,4}|(?:[0-9a-fA-F]{1,4}:){1,2}(?::[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:(?::[0-9a-fA-F]{1,4}){1,6}|:(?:(?::[0-9a-fA-F]{1,4}){1,7}|:))/g,
3604
+ validate: (match) => match !== "::1" && match !== "::"
3605
+ },
3606
+ // Phone numbers. The separated form requires separator characters (dashes,
3607
+ // spaces, dots, parens) to avoid matching bare digit sequences that are
3608
+ // actually credit cards, IPs, or years. A second alternative matches E.164
3609
+ // (a leading "+" then 10–15 digits, e.g. +14155552671), which is
3610
+ // unambiguous; a bare 10-digit run with no "+" and no separators is
3611
+ // intentionally not matched to avoid false positives.
3612
+ {
3613
+ category: "PHONE",
3614
+ regex: /(?:\+\d{1,3}[\s.-])?\(?\d{3}\)?[\s.-]\d{3}[\s.-]\d{4}\b|\+\d{10,15}\b/g
3615
+ },
3616
+ // API keys / secrets — long token with a key-like prefix. The validator
3617
+ // requires entropy (at least one digit, or a mix of upper- and lower-case)
3618
+ // so long all-lowercase prose identifiers like
3619
+ // "accessibility_is_important_for_everyone" or
3620
+ // "access-control-list-management-feature" are not redacted. Real keys and
3621
+ // tokens essentially always contain digits or mixed case.
3622
+ {
3623
+ category: "API_KEY",
3624
+ regex: /\b(?:sk|pk|api|key|token|secret|bearer|access)[_-]?[a-zA-Z0-9_-]{20,}\b/gi,
3625
+ validate: (match) => {
3626
+ const hasDigit = /\d/.test(match);
3627
+ const hasMixedCase = /[a-z]/.test(match) && /[A-Z]/.test(match);
3628
+ return hasDigit || hasMixedCase;
3629
+ }
3630
+ },
3631
+ // US street addresses — house number + Title-Case street name + suffix.
3632
+ // Intentionally NOT case-insensitive: the `[A-Z][a-z]+` guard requires
3633
+ // properly-capitalized street words, so "123 main street", "100 MAIN
3634
+ // STREET" and prose like "3 blocks down the road" / "5 minutes to drive"
3635
+ // are not treated as addresses. Whitespace is `[ \t]` only (no newline
3636
+ // spanning), and the suffix must end the segment (punctuation / newline /
3637
+ // end of string) so "Driveway" or "Wayfair" don't match on the suffix.
3638
+ {
3639
+ category: "US_ADDRESS",
3640
+ regex: /\b\d{1,5}[ \t]+(?:[A-Z][a-z]+[ \t]+){1,3}(?:St(?:reet)?|Ave(?:nue)?|Blvd|Boulevard|Dr(?:ive)?|Ln|Lane|Rd|Road|Ct|Court|Pl(?:ace)?|Way|Cir(?:cle)?|Pkwy|Parkway|Hwy|Highway)\.?(?=[\s,.;:!?)]|$)/g,
3641
+ validate: (match) => {
3642
+ return !/^0/.test(match.trim());
3643
+ }
3644
+ },
3645
+ // Dates of birth — common US date formats. Only redacted when a birth-date
3646
+ // cue ("DOB", "born", "birthday", "date of birth") appears just before the
3647
+ // date, so ordinary calendar dates ("meeting 12/25/2024", deadlines,
3648
+ // invoices) are left intact for the model. A calendar validator also rejects
3649
+ // impossible dates like 02/31/1990.
3650
+ {
3651
+ category: "DATE_OF_BIRTH",
3652
+ regex: /\b(?:(?:0?[1-9]|1[0-2])[/-](?:0?[1-9]|[12]\d|3[01])[/-](?:19|20)\d{2})\b/g,
3653
+ context: /(?:\bdob\b|\bd\.?o\.?b\.?|\bborn\b|\bbirth\s?date\b|\bbirthdate\b|\bbirthday\b|\bdate\s+of\s+birth\b)[^\d\n]{0,12}$/i,
3654
+ validate: (match) => {
3655
+ const m = match.match(/(\d{1,2})[/-](\d{1,2})[/-](\d{4})/);
3656
+ if (!m) return false;
3657
+ const month = parseInt(m[1], 10);
3658
+ const day = parseInt(m[2], 10);
3659
+ const year = parseInt(m[3], 10);
3660
+ const isLeap = year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0);
3661
+ const daysInMonth = [31, isLeap ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
3662
+ return month >= 1 && month <= 12 && day >= 1 && day <= daysInMonth[month - 1];
3663
+ }
3664
+ }
3665
+ ];
3666
+ }
3667
+ });
3668
+
3669
+ // src/lib/pii/redactor.ts
3670
+ function escapeRegExp(value) {
3671
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
3672
+ }
3673
+ function isWordChar(ch) {
3674
+ return /[A-Za-z0-9_]/.test(ch) || ch.charCodeAt(0) > 127;
3675
+ }
3676
+ function isPiiRedactor(value) {
3677
+ return typeof value === "object" && value !== null && typeof value.redactMessages === "function" && typeof value.deAnonymize === "function";
3678
+ }
3679
+ function resolvePiiRedactor(piiRedaction) {
3680
+ if (piiRedaction === true) return new PiiRedactor();
3681
+ if (!piiRedaction) return void 0;
3682
+ if (isPiiRedactor(piiRedaction)) return piiRedaction;
3683
+ console.warn(
3684
+ "[PiiRedactor] `piiRedaction` is neither `true` nor a PiiRedactor instance; PII redaction is DISABLED for this request."
3685
+ );
3686
+ return void 0;
3687
+ }
3688
+ function createStreamingDeAnonymizer(redactor, emit) {
3689
+ let buffer = "";
3690
+ const trailingFragment = /\[[A-Za-z0-9_]*$/;
3691
+ return {
3692
+ push(chunk) {
3693
+ if (!chunk) return;
3694
+ buffer += chunk;
3695
+ const m = buffer.match(trailingFragment);
3696
+ if (!m || m.index === void 0) {
3697
+ emit(redactor.deAnonymize(buffer));
3698
+ buffer = "";
3699
+ } else if (m.index > 0) {
3700
+ emit(redactor.deAnonymize(buffer.slice(0, m.index)));
3701
+ buffer = buffer.slice(m.index);
3702
+ }
3703
+ },
3704
+ flush() {
3705
+ if (buffer) {
3706
+ emit(redactor.deAnonymize(buffer));
3707
+ buffer = "";
3708
+ }
3709
+ }
3710
+ };
3711
+ }
3712
+ var PiiRedactor;
3713
+ var init_redactor = __esm({
3714
+ "src/lib/pii/redactor.ts"() {
3715
+ "use strict";
2766
3716
  init_patterns();
2767
3717
  PiiRedactor = class {
2768
3718
  constructor(options = {}) {
@@ -7392,165 +8342,39 @@ __export(index_exports, {
7392
8342
  useChat: () => useChat,
7393
8343
  useChatStorage: () => useChatStorage,
7394
8344
  useCredits: () => useCredits,
7395
- useDatabaseManager: () => useDatabaseManager,
7396
- useDropboxAuth: () => useDropboxAuth,
7397
- useDropboxBackup: () => useDropboxBackup,
7398
- useEncryption: () => useEncryption,
7399
- useExportPdf: () => useExportPdf,
7400
- useFiles: () => useFiles,
7401
- useGoogleDriveAuth: () => useGoogleDriveAuth,
7402
- useGoogleDriveBackup: () => useGoogleDriveBackup,
7403
- useICloudAuth: () => useICloudAuth,
7404
- useICloudBackup: () => useICloudBackup,
7405
- useModels: () => useModels,
7406
- useOCR: () => useOCR,
7407
- usePdf: () => usePdf,
7408
- usePhoneCalls: () => usePhoneCalls,
7409
- useProjects: () => useProjects,
7410
- useSettings: () => useSettings,
7411
- useSubscription: () => useSubscription,
7412
- useTools: () => useTools,
7413
- useUIInteraction: () => useUIInteraction,
7414
- useVoice: () => useVoice,
7415
- useWalletBinding: () => useWalletBinding,
7416
- userPreferencesStorageSchema: () => userPreferencesStorageSchema,
7417
- walk: () => walk,
7418
- webPlatformStorage: () => webPlatformStorage,
7419
- writeEncryptedFile: () => writeEncryptedFile
7420
- });
7421
- module.exports = __toCommonJS(index_exports);
7422
-
7423
- // src/lib/chat/resumeStream.ts
7424
- init_clientConfig();
7425
-
7426
- // src/client/core/serverSentEvents.gen.ts
7427
- function createSseClient({
7428
- onRequest,
7429
- onSseError,
7430
- onSseEvent,
7431
- responseTransformer,
7432
- responseValidator,
7433
- sseDefaultRetryDelay,
7434
- sseMaxRetryAttempts,
7435
- sseMaxRetryDelay,
7436
- sseSleepFn,
7437
- url,
7438
- ...options
7439
- }) {
7440
- let lastEventId;
7441
- const sleep4 = sseSleepFn ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
7442
- const createStream = async function* () {
7443
- let retryDelay = sseDefaultRetryDelay ?? 3e3;
7444
- let attempt = 0;
7445
- const signal = options.signal ?? new AbortController().signal;
7446
- while (true) {
7447
- if (signal.aborted) break;
7448
- attempt++;
7449
- const headers = options.headers instanceof Headers ? options.headers : new Headers(options.headers);
7450
- if (lastEventId !== void 0) {
7451
- headers.set("Last-Event-ID", lastEventId);
7452
- }
7453
- try {
7454
- const requestInit = {
7455
- redirect: "follow",
7456
- ...options,
7457
- body: options.serializedBody,
7458
- headers,
7459
- signal
7460
- };
7461
- let request = new Request(url, requestInit);
7462
- if (onRequest) {
7463
- request = await onRequest(url, requestInit);
7464
- }
7465
- const _fetch = options.fetch ?? globalThis.fetch;
7466
- const response = await _fetch(request);
7467
- if (!response.ok) throw new Error(`SSE failed: ${response.status} ${response.statusText}`);
7468
- if (!response.body) throw new Error("No body in SSE response");
7469
- const reader = response.body.pipeThrough(new TextDecoderStream()).getReader();
7470
- let buffer = "";
7471
- const abortHandler = () => {
7472
- try {
7473
- reader.cancel();
7474
- } catch {
7475
- }
7476
- };
7477
- signal.addEventListener("abort", abortHandler);
7478
- try {
7479
- while (true) {
7480
- const { done, value } = await reader.read();
7481
- if (done) break;
7482
- buffer += value;
7483
- buffer = buffer.replace(/\r\n?/g, "\n");
7484
- const chunks = buffer.split("\n\n");
7485
- buffer = chunks.pop() ?? "";
7486
- for (const chunk of chunks) {
7487
- const lines = chunk.split("\n");
7488
- const dataLines = [];
7489
- let eventName;
7490
- for (const line of lines) {
7491
- if (line.startsWith("data:")) {
7492
- dataLines.push(line.replace(/^data:\s*/, ""));
7493
- } else if (line.startsWith("event:")) {
7494
- eventName = line.replace(/^event:\s*/, "");
7495
- } else if (line.startsWith("id:")) {
7496
- lastEventId = line.replace(/^id:\s*/, "");
7497
- } else if (line.startsWith("retry:")) {
7498
- const parsed = Number.parseInt(line.replace(/^retry:\s*/, ""), 10);
7499
- if (!Number.isNaN(parsed)) {
7500
- retryDelay = parsed;
7501
- }
7502
- }
7503
- }
7504
- let data;
7505
- let parsedJson = false;
7506
- if (dataLines.length) {
7507
- const rawData = dataLines.join("\n");
7508
- try {
7509
- data = JSON.parse(rawData);
7510
- parsedJson = true;
7511
- } catch {
7512
- data = rawData;
7513
- }
7514
- }
7515
- if (parsedJson) {
7516
- if (responseValidator) {
7517
- await responseValidator(data);
7518
- }
7519
- if (responseTransformer) {
7520
- data = await responseTransformer(data);
7521
- }
7522
- }
7523
- onSseEvent?.({
7524
- data,
7525
- event: eventName,
7526
- id: lastEventId,
7527
- retry: retryDelay
7528
- });
7529
- if (dataLines.length) {
7530
- yield data;
7531
- }
7532
- }
7533
- }
7534
- } finally {
7535
- signal.removeEventListener("abort", abortHandler);
7536
- reader.releaseLock();
7537
- }
7538
- break;
7539
- } catch (error) {
7540
- onSseError?.(error);
7541
- if (sseMaxRetryAttempts !== void 0 && attempt >= sseMaxRetryAttempts) {
7542
- break;
7543
- }
7544
- const backoff = Math.min(retryDelay * 2 ** (attempt - 1), sseMaxRetryDelay ?? 3e4);
7545
- await sleep4(backoff);
7546
- }
7547
- }
7548
- };
7549
- const stream = createStream();
7550
- return { stream };
7551
- }
8345
+ useDatabaseManager: () => useDatabaseManager,
8346
+ useDropboxAuth: () => useDropboxAuth,
8347
+ useDropboxBackup: () => useDropboxBackup,
8348
+ useEncryption: () => useEncryption,
8349
+ useExportPdf: () => useExportPdf,
8350
+ useFiles: () => useFiles,
8351
+ useGoogleDriveAuth: () => useGoogleDriveAuth,
8352
+ useGoogleDriveBackup: () => useGoogleDriveBackup,
8353
+ useICloudAuth: () => useICloudAuth,
8354
+ useICloudBackup: () => useICloudBackup,
8355
+ useModels: () => useModels,
8356
+ useOCR: () => useOCR,
8357
+ usePdf: () => usePdf,
8358
+ usePhoneCalls: () => usePhoneCalls,
8359
+ useProjects: () => useProjects,
8360
+ useSettings: () => useSettings,
8361
+ useSubscription: () => useSubscription,
8362
+ useTools: () => useTools,
8363
+ useUIInteraction: () => useUIInteraction,
8364
+ useVoice: () => useVoice,
8365
+ useWalletBinding: () => useWalletBinding,
8366
+ userPreferencesStorageSchema: () => userPreferencesStorageSchema,
8367
+ walk: () => walk,
8368
+ webPlatformStorage: () => webPlatformStorage,
8369
+ writeEncryptedFile: () => writeEncryptedFile
8370
+ });
8371
+ module.exports = __toCommonJS(index_exports);
8372
+
8373
+ // src/lib/chat/resumeStream.ts
8374
+ init_clientConfig();
7552
8375
 
7553
8376
  // src/lib/chat/toolLoop.ts
8377
+ init_serverSentEvents_gen();
7554
8378
  init_clientConfig();
7555
8379
  init_embeddings();
7556
8380
  init_redactor();
@@ -24290,1296 +25114,557 @@ async function exportMarkdownToPdf(markdown, options) {
24290
25114
  for (const row of rows) {
24291
25115
  renderRow2(row, "normal");
24292
25116
  }
24293
- cursorY += SPACING.MD;
24294
- break;
24295
- }
24296
- case "space": {
24297
- cursorY += SPACING.MD;
24298
- break;
24299
- }
24300
- default:
24301
- if (token.raw.trim()) {
24302
- renderWrappedText(token.raw.trim(), opts.margins.left, cw, opts.fontSize);
24303
- cursorY += SPACING.SM;
24304
- }
24305
- break;
24306
- }
24307
- }
24308
- if (opts.pageNumbers) {
24309
- addPageNumbers(doc, pageW, pageH);
24310
- }
24311
- opts.onProgress?.({ stage: "complete", percent: 100 });
24312
- return doc.output("blob");
24313
- }
24314
-
24315
- // src/react/useExportPdf.ts
24316
- var import_react10 = require("react");
24317
- var DEFAULT_FILENAME2 = "document.pdf";
24318
- function triggerDownload(blob, filename) {
24319
- const url = URL.createObjectURL(blob);
24320
- const a = document.createElement("a");
24321
- a.href = url;
24322
- a.download = filename;
24323
- document.body.appendChild(a);
24324
- a.click();
24325
- document.body.removeChild(a);
24326
- setTimeout(() => URL.revokeObjectURL(url), 100);
24327
- }
24328
- function toError(err) {
24329
- return err instanceof Error ? err : new Error(String(err));
24330
- }
24331
- function useExportPdf() {
24332
- const [isExporting, setIsExporting] = (0, import_react10.useState)(false);
24333
- const [progress, setProgress] = (0, import_react10.useState)(null);
24334
- const [error, setError] = (0, import_react10.useState)(null);
24335
- const wrappedExportElement = (0, import_react10.useCallback)(
24336
- async (element, options) => {
24337
- setIsExporting(true);
24338
- setError(null);
24339
- setProgress({ stage: "preparing", percent: 0 });
24340
- try {
24341
- return await exportElementToPdf(element, {
24342
- ...options,
24343
- onProgress: setProgress
24344
- });
24345
- } catch (err) {
24346
- const processed = toError(err);
24347
- setError(processed);
24348
- throw processed;
24349
- } finally {
24350
- setIsExporting(false);
24351
- }
24352
- },
24353
- []
24354
- );
24355
- const wrappedExportMarkdown = (0, import_react10.useCallback)(
24356
- async (markdown, options) => {
24357
- setIsExporting(true);
24358
- setError(null);
24359
- setProgress({ stage: "preparing", percent: 0 });
24360
- try {
24361
- return await exportMarkdownToPdf(markdown, {
24362
- ...options,
24363
- onProgress: setProgress
24364
- });
24365
- } catch (err) {
24366
- const processed = toError(err);
24367
- setError(processed);
24368
- throw processed;
24369
- } finally {
24370
- setIsExporting(false);
24371
- }
24372
- },
24373
- []
24374
- );
24375
- const downloadElementAsPdf = (0, import_react10.useCallback)(
24376
- async (element, options) => {
24377
- const blob = await wrappedExportElement(element, options);
24378
- triggerDownload(blob, options?.filename ?? DEFAULT_FILENAME2);
24379
- },
24380
- [wrappedExportElement]
24381
- );
24382
- const downloadMarkdownAsPdf = (0, import_react10.useCallback)(
24383
- async (markdown, options) => {
24384
- const blob = await wrappedExportMarkdown(markdown, options);
24385
- triggerDownload(blob, options?.filename ?? DEFAULT_FILENAME2);
24386
- },
24387
- [wrappedExportMarkdown]
24388
- );
24389
- const wrappedRenderToCanvas = (0, import_react10.useCallback)(
24390
- async (element) => {
24391
- setIsExporting(true);
24392
- setError(null);
24393
- setProgress({ stage: "preparing", percent: 0 });
24394
- try {
24395
- const canvas = await renderElementToCanvas(element, { onProgress: setProgress });
24396
- return canvas;
24397
- } catch (err) {
24398
- const processed = toError(err);
24399
- setError(processed);
24400
- throw processed;
24401
- } finally {
24402
- setIsExporting(false);
24403
- }
24404
- },
24405
- []
24406
- );
24407
- return {
24408
- exportElementToPdf: wrappedExportElement,
24409
- exportMarkdownToPdf: wrappedExportMarkdown,
24410
- downloadElementAsPdf,
24411
- downloadMarkdownAsPdf,
24412
- renderElementToCanvas: wrappedRenderToCanvas,
24413
- isExporting,
24414
- progress,
24415
- error
24416
- };
24417
- }
24418
-
24419
- // src/react/useOCR.ts
24420
- var import_react11 = require("react");
24421
- var import_tesseract = __toESM(require("tesseract.js"));
24422
- init_logger();
24423
- function useOCR() {
24424
- const [isProcessing, setIsProcessing] = (0, import_react11.useState)(false);
24425
- const [error, setError] = (0, import_react11.useState)(null);
24426
- const extractOCRContext = (0, import_react11.useCallback)(async (files) => {
24427
- setIsProcessing(true);
24428
- setError(null);
24429
- try {
24430
- if (files.length === 0) {
24431
- return null;
24432
- }
24433
- const contexts = await Promise.all(
24434
- files.map(async (file) => {
24435
- try {
24436
- let imagesToProcess = [];
24437
- const language = file.language || "eng";
24438
- const filename = file.filename || (file.url instanceof File ? file.url.name : "");
24439
- let isPdf = false;
24440
- if (typeof file.url === "string") {
24441
- isPdf = file.url.toLowerCase().endsWith(".pdf") || (filename?.toLowerCase().endsWith(".pdf") ?? false);
24442
- } else if (file.url instanceof Blob) {
24443
- isPdf = file.url.type === "application/pdf" || (filename?.toLowerCase().endsWith(".pdf") ?? false);
24444
- }
24445
- if (isPdf) {
24446
- let pdfUrl;
24447
- let shouldRevoke = false;
24448
- if (typeof file.url === "string") {
24449
- pdfUrl = file.url;
24450
- } else {
24451
- pdfUrl = URL.createObjectURL(file.url);
24452
- shouldRevoke = true;
24453
- }
24454
- try {
24455
- const pdfImages = await convertPdfToImages(pdfUrl);
24456
- imagesToProcess = pdfImages;
24457
- } catch (e) {
24458
- getLogger().error("Failed to convert PDF to images", e);
24459
- throw e;
24460
- } finally {
24461
- if (shouldRevoke) {
24462
- URL.revokeObjectURL(pdfUrl);
24463
- }
24464
- }
24465
- } else {
24466
- imagesToProcess = [file.url];
24467
- }
24468
- const pageTexts = [];
24469
- for (const image of imagesToProcess) {
24470
- const result = await import_tesseract.default.recognize(image, language);
24471
- pageTexts.push(result.data.text);
24472
- }
24473
- const text12 = pageTexts.join("\n\n");
24474
- if (!text12.trim()) {
24475
- getLogger().warn(`No text found in OCR source ${filename || "unknown"}`);
24476
- return null;
24477
- }
24478
- return `[Context from OCR attachment ${filename || "unknown"}]:
24479
- ${text12}`;
24480
- } catch (err) {
24481
- getLogger().error(`Failed to process OCR for ${file.filename || "unknown"}:`, err);
24482
- return null;
24483
- }
24484
- })
24485
- );
24486
- const mergedContext = contexts.filter(Boolean).join("\n\n");
24487
- return mergedContext || null;
24488
- } catch (err) {
24489
- const processedError = err instanceof Error ? err : new Error(String(err));
24490
- setError(processedError);
24491
- throw processedError;
24492
- } finally {
24493
- setIsProcessing(false);
24494
- }
24495
- }, []);
24496
- return {
24497
- extractOCRContext,
24498
- isProcessing,
24499
- error
24500
- };
24501
- }
24502
-
24503
- // src/react/usePdf.ts
24504
- var import_react12 = require("react");
24505
- init_logger();
24506
- var PDF_MIME_TYPE = "application/pdf";
24507
- function usePdf() {
24508
- const [isProcessing, setIsProcessing] = (0, import_react12.useState)(false);
24509
- const [error, setError] = (0, import_react12.useState)(null);
24510
- const extractPdfContext = (0, import_react12.useCallback)(async (files) => {
24511
- setIsProcessing(true);
24512
- setError(null);
24513
- try {
24514
- const pdfFiles = files.filter(
24515
- (file) => file.mediaType === PDF_MIME_TYPE || file.filename?.toLowerCase().endsWith(".pdf")
24516
- );
24517
- if (pdfFiles.length === 0) {
24518
- return null;
25117
+ cursorY += SPACING.MD;
25118
+ break;
24519
25119
  }
24520
- const contexts = await Promise.all(
24521
- pdfFiles.map(async (file) => {
24522
- try {
24523
- const text12 = await extractTextFromPdf(file.url);
24524
- if (!text12.trim()) {
24525
- getLogger().warn(`No text found in PDF ${file.filename}`);
24526
- return null;
24527
- }
24528
- return `[Context from PDF attachment ${file.filename}]:
24529
- ${text12}`;
24530
- } catch (err) {
24531
- getLogger().error(`Failed to process PDF ${file.filename}:`, err);
24532
- return null;
24533
- }
24534
- })
24535
- );
24536
- const mergedContext = contexts.filter(Boolean).join("\n\n");
24537
- return mergedContext || null;
24538
- } catch (err) {
24539
- const processedError = err instanceof Error ? err : new Error(String(err));
24540
- setError(processedError);
24541
- throw processedError;
24542
- } finally {
24543
- setIsProcessing(false);
25120
+ case "space": {
25121
+ cursorY += SPACING.MD;
25122
+ break;
25123
+ }
25124
+ default:
25125
+ if (token.raw.trim()) {
25126
+ renderWrappedText(token.raw.trim(), opts.margins.left, cw, opts.fontSize);
25127
+ cursorY += SPACING.SM;
25128
+ }
25129
+ break;
24544
25130
  }
24545
- }, []);
24546
- return {
24547
- extractPdfContext,
24548
- isProcessing,
24549
- error
24550
- };
24551
- }
24552
-
24553
- // src/react/useVoice.ts
24554
- var import_react13 = require("react");
24555
- function getOnDeviceSpeechRecognition() {
24556
- if (typeof window === "undefined") return null;
24557
- if (!/iPhone|iPad|iPod/.test(navigator.userAgent)) return null;
24558
- const SR = window.SpeechRecognition ?? window.webkitSpeechRecognition;
24559
- return SR ?? null;
24560
- }
24561
- var SUPPORTED_MIME_TYPES = [
24562
- "audio/webm;codecs=opus",
24563
- "audio/webm",
24564
- "audio/mp4",
24565
- "audio/ogg;codecs=opus",
24566
- "audio/ogg"
24567
- ];
24568
- function getSupportedMimeType() {
24569
- if (typeof MediaRecorder === "undefined") {
24570
- return "audio/webm";
24571
25131
  }
24572
- for (const type of SUPPORTED_MIME_TYPES) {
24573
- if (MediaRecorder.isTypeSupported(type)) {
24574
- return type;
24575
- }
25132
+ if (opts.pageNumbers) {
25133
+ addPageNumbers(doc, pageW, pageH);
24576
25134
  }
24577
- return "audio/webm";
25135
+ opts.onProgress?.({ stage: "complete", percent: 100 });
25136
+ return doc.output("blob");
24578
25137
  }
24579
- var SAMPLE_RATE = 16e3;
24580
- async function audioToFloat32(blob) {
24581
- const arrayBuffer = await blob.arrayBuffer();
24582
- const audioContext = new AudioContext({ sampleRate: SAMPLE_RATE });
24583
- try {
24584
- const audioBuffer = await audioContext.decodeAudioData(arrayBuffer);
24585
- if (audioBuffer.numberOfChannels === 1) {
24586
- return audioBuffer.getChannelData(0);
24587
- }
24588
- const length = audioBuffer.length;
24589
- const mono = new Float32Array(length);
24590
- const channels = audioBuffer.numberOfChannels;
24591
- for (let ch = 0; ch < channels; ch++) {
24592
- const data = audioBuffer.getChannelData(ch);
24593
- for (let i = 0; i < length; i++) {
24594
- mono[i] += data[i];
24595
- }
24596
- }
24597
- for (let i = 0; i < length; i++) {
24598
- mono[i] /= channels;
24599
- }
24600
- return mono;
24601
- } finally {
24602
- await audioContext.close();
24603
- }
25138
+
25139
+ // src/react/useExportPdf.ts
25140
+ var import_react10 = require("react");
25141
+ var DEFAULT_FILENAME2 = "document.pdf";
25142
+ function triggerDownload(blob, filename) {
25143
+ const url = URL.createObjectURL(blob);
25144
+ const a = document.createElement("a");
25145
+ a.href = url;
25146
+ a.download = filename;
25147
+ document.body.appendChild(a);
25148
+ a.click();
25149
+ document.body.removeChild(a);
25150
+ setTimeout(() => URL.revokeObjectURL(url), 100);
24604
25151
  }
24605
- function useVoice(options) {
24606
- const [isRecording, setIsRecording] = (0, import_react13.useState)(false);
24607
- const [isTranscribing, setIsTranscribing] = (0, import_react13.useState)(false);
24608
- const [isModelLoaded, setIsModelLoaded] = (0, import_react13.useState)(false);
24609
- const [isLoadingModel, setIsLoadingModel] = (0, import_react13.useState)(false);
24610
- const [recording, setRecording] = (0, import_react13.useState)(null);
24611
- const [transcription, setTranscription] = (0, import_react13.useState)(null);
24612
- const [error, setError] = (0, import_react13.useState)(null);
24613
- const mediaRecorderRef = (0, import_react13.useRef)(null);
24614
- const mediaStreamRef = (0, import_react13.useRef)(null);
24615
- const chunksRef = (0, import_react13.useRef)([]);
24616
- const startTimeRef = (0, import_react13.useRef)(0);
24617
- const pipelineRef = (0, import_react13.useRef)(null);
24618
- const modelNameRef = (0, import_react13.useRef)(null);
24619
- const getModelName = (0, import_react13.useCallback)(() => {
24620
- const model = options?.model ?? "whisper-tiny";
24621
- return `onnx-community/${model}`;
24622
- }, [options?.model]);
24623
- const loadPipeline = (0, import_react13.useCallback)(async () => {
24624
- const modelName = getModelName();
24625
- if (pipelineRef.current && modelNameRef.current === modelName) {
24626
- return pipelineRef.current;
24627
- }
24628
- setIsLoadingModel(true);
24629
- setError(null);
24630
- try {
24631
- const { pipeline } = await import("@huggingface/transformers");
24632
- const transcriber = await pipeline("automatic-speech-recognition", modelName, {
24633
- dtype: "q4",
24634
- device: "wasm",
24635
- progress_callback: options?.onModelProgress ? (progress) => {
24636
- if (progress.file && progress.progress !== null && progress.progress !== void 0) {
24637
- options.onModelProgress({
24638
- file: progress.file,
24639
- progress: progress.progress / 100,
24640
- loaded: progress.loaded ?? 0,
24641
- total: progress.total ?? 0
24642
- });
24643
- }
24644
- } : void 0
24645
- });
24646
- pipelineRef.current = transcriber;
24647
- modelNameRef.current = modelName;
24648
- setIsModelLoaded(true);
24649
- return pipelineRef.current;
24650
- } catch (err) {
24651
- const processedError = err instanceof Error ? err : new Error("Failed to load Whisper model");
24652
- setError(processedError);
24653
- throw processedError;
24654
- } finally {
24655
- setIsLoadingModel(false);
24656
- }
24657
- }, [getModelName, options?.onModelProgress]);
24658
- const preloadModel = (0, import_react13.useCallback)(async () => {
24659
- await loadPipeline();
24660
- }, [loadPipeline]);
24661
- const disposeModel = (0, import_react13.useCallback)(async () => {
24662
- const pipe = pipelineRef.current;
24663
- if (pipe?.dispose) {
24664
- await pipe.dispose();
24665
- }
24666
- pipelineRef.current = null;
24667
- modelNameRef.current = null;
24668
- setIsModelLoaded(false);
24669
- }, []);
24670
- const startRecording = (0, import_react13.useCallback)(async () => {
24671
- setError(null);
24672
- setRecording(null);
24673
- setTranscription(null);
24674
- try {
24675
- const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
24676
- mediaStreamRef.current = stream;
24677
- const mimeType = getSupportedMimeType();
24678
- const recorder = new MediaRecorder(stream, { mimeType });
24679
- mediaRecorderRef.current = recorder;
24680
- chunksRef.current = [];
24681
- recorder.ondataavailable = (e) => {
24682
- if (e.data.size > 0) {
24683
- chunksRef.current.push(e.data);
24684
- }
24685
- };
24686
- recorder.start();
24687
- startTimeRef.current = Date.now();
24688
- setIsRecording(true);
24689
- } catch (err) {
24690
- const processedError = err instanceof Error ? err : new Error("Failed to start recording");
24691
- setError(processedError);
24692
- throw processedError;
24693
- }
24694
- }, []);
24695
- const stopRecording = (0, import_react13.useCallback)(async () => {
24696
- return new Promise((resolve, reject) => {
24697
- const recorder = mediaRecorderRef.current;
24698
- if (!recorder || recorder.state === "inactive") {
24699
- const err = new Error("No active recording");
24700
- setError(err);
24701
- reject(err);
24702
- return;
24703
- }
24704
- recorder.onstop = () => {
24705
- const mimeType = recorder.mimeType || "audio/webm";
24706
- const blob = new Blob(chunksRef.current, { type: mimeType });
24707
- const duration = Date.now() - startTimeRef.current;
24708
- mediaStreamRef.current?.getTracks().forEach((t) => t.stop());
24709
- mediaStreamRef.current = null;
24710
- mediaRecorderRef.current = null;
24711
- const result = { blob, duration, mimeType };
24712
- setRecording(result);
24713
- setIsRecording(false);
24714
- resolve(result);
24715
- };
24716
- recorder.onerror = () => {
24717
- const err = new Error("Recording failed");
24718
- setError(err);
24719
- setIsRecording(false);
24720
- reject(err);
24721
- };
24722
- recorder.stop();
24723
- });
24724
- }, []);
24725
- const transcribe = (0, import_react13.useCallback)(
24726
- async (rec) => {
24727
- const target = rec ?? recording;
24728
- if (!target) {
24729
- const err = new Error("No recording to transcribe");
24730
- setError(err);
24731
- throw err;
25152
+ function toError(err) {
25153
+ return err instanceof Error ? err : new Error(String(err));
25154
+ }
25155
+ function useExportPdf() {
25156
+ const [isExporting, setIsExporting] = (0, import_react10.useState)(false);
25157
+ const [progress, setProgress] = (0, import_react10.useState)(null);
25158
+ const [error, setError] = (0, import_react10.useState)(null);
25159
+ const wrappedExportElement = (0, import_react10.useCallback)(
25160
+ async (element, options) => {
25161
+ setIsExporting(true);
25162
+ setError(null);
25163
+ setProgress({ stage: "preparing", percent: 0 });
25164
+ try {
25165
+ return await exportElementToPdf(element, {
25166
+ ...options,
25167
+ onProgress: setProgress
25168
+ });
25169
+ } catch (err) {
25170
+ const processed = toError(err);
25171
+ setError(processed);
25172
+ throw processed;
25173
+ } finally {
25174
+ setIsExporting(false);
24732
25175
  }
24733
- setIsTranscribing(true);
25176
+ },
25177
+ []
25178
+ );
25179
+ const wrappedExportMarkdown = (0, import_react10.useCallback)(
25180
+ async (markdown, options) => {
25181
+ setIsExporting(true);
24734
25182
  setError(null);
25183
+ setProgress({ stage: "preparing", percent: 0 });
24735
25184
  try {
24736
- const pipe = await loadPipeline();
24737
- const audio = await audioToFloat32(target.blob);
24738
- const result = await pipe(audio, {
24739
- language: options?.language,
24740
- return_timestamps: true
25185
+ return await exportMarkdownToPdf(markdown, {
25186
+ ...options,
25187
+ onProgress: setProgress
24741
25188
  });
24742
- const transcriptionResult = {
24743
- text: result.text.trim(),
24744
- chunks: result.chunks
24745
- };
24746
- setTranscription(transcriptionResult);
24747
- return transcriptionResult;
24748
25189
  } catch (err) {
24749
- const processedError = err instanceof Error ? err : new Error("Transcription failed");
24750
- setError(processedError);
24751
- throw processedError;
25190
+ const processed = toError(err);
25191
+ setError(processed);
25192
+ throw processed;
24752
25193
  } finally {
24753
- setIsTranscribing(false);
25194
+ setIsExporting(false);
24754
25195
  }
24755
25196
  },
24756
- [recording, loadPipeline, options?.language]
25197
+ []
24757
25198
  );
24758
- const nativeSpeechAvailable = (0, import_react13.useMemo)(() => getOnDeviceSpeechRecognition() !== null, []);
24759
- const [isNativeListening, setIsNativeListening] = (0, import_react13.useState)(false);
24760
- const nativeRecognitionRef = (0, import_react13.useRef)(null);
24761
- const nativeTextRef = (0, import_react13.useRef)("");
24762
- const nativeResolveRef = (0, import_react13.useRef)(null);
24763
- const startNativeTranscription = (0, import_react13.useCallback)(() => {
24764
- const SR = getOnDeviceSpeechRecognition();
24765
- if (!SR) return;
24766
- nativeTextRef.current = "";
24767
- setError(null);
24768
- const recognition = new SR();
24769
- recognition.continuous = true;
24770
- recognition.interimResults = false;
24771
- recognition.lang = options?.language ?? "";
24772
- recognition.onresult = (event) => {
24773
- let text12 = "";
24774
- for (let i = 0; i < event.results.length; i++) {
24775
- const result = event.results[i];
24776
- if (result && result.isFinal && result[0]) {
24777
- text12 += result[0].transcript + " ";
24778
- }
24779
- }
24780
- nativeTextRef.current = text12.trim();
24781
- };
24782
- recognition.onerror = (event) => {
24783
- if (event.error !== "aborted" && event.error !== "no-speech") {
24784
- setError(new Error(`Speech recognition error: ${event.error}`));
24785
- }
24786
- };
24787
- recognition.onend = () => {
24788
- setIsNativeListening(false);
24789
- nativeRecognitionRef.current = null;
24790
- const resolve = nativeResolveRef.current;
24791
- if (resolve) {
24792
- nativeResolveRef.current = null;
24793
- resolve({ text: nativeTextRef.current });
24794
- }
24795
- };
24796
- nativeRecognitionRef.current = recognition;
24797
- recognition.start();
24798
- setIsNativeListening(true);
24799
- }, [options?.language]);
24800
- const stopNativeTranscription = (0, import_react13.useCallback)(() => {
24801
- return new Promise((resolve) => {
24802
- const recognition = nativeRecognitionRef.current;
24803
- if (!recognition) {
24804
- resolve({ text: nativeTextRef.current || "" });
24805
- return;
25199
+ const downloadElementAsPdf = (0, import_react10.useCallback)(
25200
+ async (element, options) => {
25201
+ const blob = await wrappedExportElement(element, options);
25202
+ triggerDownload(blob, options?.filename ?? DEFAULT_FILENAME2);
25203
+ },
25204
+ [wrappedExportElement]
25205
+ );
25206
+ const downloadMarkdownAsPdf = (0, import_react10.useCallback)(
25207
+ async (markdown, options) => {
25208
+ const blob = await wrappedExportMarkdown(markdown, options);
25209
+ triggerDownload(blob, options?.filename ?? DEFAULT_FILENAME2);
25210
+ },
25211
+ [wrappedExportMarkdown]
25212
+ );
25213
+ const wrappedRenderToCanvas = (0, import_react10.useCallback)(
25214
+ async (element) => {
25215
+ setIsExporting(true);
25216
+ setError(null);
25217
+ setProgress({ stage: "preparing", percent: 0 });
25218
+ try {
25219
+ const canvas = await renderElementToCanvas(element, { onProgress: setProgress });
25220
+ return canvas;
25221
+ } catch (err) {
25222
+ const processed = toError(err);
25223
+ setError(processed);
25224
+ throw processed;
25225
+ } finally {
25226
+ setIsExporting(false);
24806
25227
  }
24807
- nativeResolveRef.current = resolve;
24808
- recognition.stop();
24809
- });
24810
- }, []);
24811
- const abortNativeTranscription = (0, import_react13.useCallback)(() => {
24812
- const recognition = nativeRecognitionRef.current;
24813
- if (recognition) {
24814
- nativeResolveRef.current = null;
24815
- recognition.abort();
24816
- nativeRecognitionRef.current = null;
24817
- setIsNativeListening(false);
24818
- }
24819
- }, []);
25228
+ },
25229
+ []
25230
+ );
24820
25231
  return {
24821
- isRecording,
24822
- startRecording,
24823
- stopRecording,
24824
- isTranscribing,
24825
- transcribe,
24826
- preloadModel,
24827
- disposeModel,
24828
- isModelLoaded,
24829
- isLoadingModel,
24830
- recording,
24831
- transcription,
24832
- error,
24833
- nativeSpeechAvailable,
24834
- startNativeTranscription,
24835
- stopNativeTranscription,
24836
- abortNativeTranscription,
24837
- isNativeListening
25232
+ exportElementToPdf: wrappedExportElement,
25233
+ exportMarkdownToPdf: wrappedExportMarkdown,
25234
+ downloadElementAsPdf,
25235
+ downloadMarkdownAsPdf,
25236
+ renderElementToCanvas: wrappedRenderToCanvas,
25237
+ isExporting,
25238
+ progress,
25239
+ error
24838
25240
  };
24839
25241
  }
24840
25242
 
24841
- // src/react/useCredits.ts
24842
- var import_react14 = require("react");
24843
-
24844
- // src/client/core/bodySerializer.gen.ts
24845
- var jsonBodySerializer = {
24846
- bodySerializer: (body) => JSON.stringify(body, (_key, value) => typeof value === "bigint" ? value.toString() : value)
24847
- };
24848
-
24849
- // src/client/core/pathSerializer.gen.ts
24850
- var separatorArrayExplode = (style) => {
24851
- switch (style) {
24852
- case "label":
24853
- return ".";
24854
- case "matrix":
24855
- return ";";
24856
- case "simple":
24857
- return ",";
24858
- default:
24859
- return "&";
24860
- }
24861
- };
24862
- var separatorArrayNoExplode = (style) => {
24863
- switch (style) {
24864
- case "form":
24865
- return ",";
24866
- case "pipeDelimited":
24867
- return "|";
24868
- case "spaceDelimited":
24869
- return "%20";
24870
- default:
24871
- return ",";
24872
- }
24873
- };
24874
- var separatorObjectExplode = (style) => {
24875
- switch (style) {
24876
- case "label":
24877
- return ".";
24878
- case "matrix":
24879
- return ";";
24880
- case "simple":
24881
- return ",";
24882
- default:
24883
- return "&";
24884
- }
24885
- };
24886
- var serializeArrayParam = ({
24887
- allowReserved,
24888
- explode,
24889
- name,
24890
- style,
24891
- value
24892
- }) => {
24893
- if (!explode) {
24894
- const joinedValues2 = (allowReserved ? value : value.map((v) => encodeURIComponent(v))).join(separatorArrayNoExplode(style));
24895
- switch (style) {
24896
- case "label":
24897
- return `.${joinedValues2}`;
24898
- case "matrix":
24899
- return `;${name}=${joinedValues2}`;
24900
- case "simple":
24901
- return joinedValues2;
24902
- default:
24903
- return `${name}=${joinedValues2}`;
24904
- }
24905
- }
24906
- const separator = separatorArrayExplode(style);
24907
- const joinedValues = value.map((v) => {
24908
- if (style === "label" || style === "simple") {
24909
- return allowReserved ? v : encodeURIComponent(v);
24910
- }
24911
- return serializePrimitiveParam({
24912
- allowReserved,
24913
- name,
24914
- value: v
24915
- });
24916
- }).join(separator);
24917
- return style === "label" || style === "matrix" ? separator + joinedValues : joinedValues;
24918
- };
24919
- var serializePrimitiveParam = ({
24920
- allowReserved,
24921
- name,
24922
- value
24923
- }) => {
24924
- if (value === void 0 || value === null) {
24925
- return "";
24926
- }
24927
- if (typeof value === "object") {
24928
- throw new Error(
24929
- "Deeply-nested arrays/objects aren\u2019t supported. Provide your own `querySerializer()` to handle these."
24930
- );
24931
- }
24932
- return `${name}=${allowReserved ? value : encodeURIComponent(value)}`;
24933
- };
24934
- var serializeObjectParam = ({
24935
- allowReserved,
24936
- explode,
24937
- name,
24938
- style,
24939
- value,
24940
- valueOnly
24941
- }) => {
24942
- if (value instanceof Date) {
24943
- return valueOnly ? value.toISOString() : `${name}=${value.toISOString()}`;
24944
- }
24945
- if (style !== "deepObject" && !explode) {
24946
- let values = [];
24947
- Object.entries(value).forEach(([key, v]) => {
24948
- values = [...values, key, allowReserved ? v : encodeURIComponent(v)];
24949
- });
24950
- const joinedValues2 = values.join(",");
24951
- switch (style) {
24952
- case "form":
24953
- return `${name}=${joinedValues2}`;
24954
- case "label":
24955
- return `.${joinedValues2}`;
24956
- case "matrix":
24957
- return `;${name}=${joinedValues2}`;
24958
- default:
24959
- return joinedValues2;
24960
- }
24961
- }
24962
- const separator = separatorObjectExplode(style);
24963
- const joinedValues = Object.entries(value).map(
24964
- ([key, v]) => serializePrimitiveParam({
24965
- allowReserved,
24966
- name: style === "deepObject" ? `${name}[${key}]` : key,
24967
- value: v
24968
- })
24969
- ).join(separator);
24970
- return style === "label" || style === "matrix" ? separator + joinedValues : joinedValues;
24971
- };
24972
-
24973
- // src/client/core/utils.gen.ts
24974
- function getValidRequestBody(options) {
24975
- const hasBody = options.body !== void 0;
24976
- const isSerializedBody = hasBody && options.bodySerializer;
24977
- if (isSerializedBody) {
24978
- if ("serializedBody" in options) {
24979
- const hasSerializedBody = options.serializedBody !== void 0 && options.serializedBody !== "";
24980
- return hasSerializedBody ? options.serializedBody : null;
25243
+ // src/react/useOCR.ts
25244
+ var import_react11 = require("react");
25245
+ var import_tesseract = __toESM(require("tesseract.js"));
25246
+ init_logger();
25247
+ function useOCR() {
25248
+ const [isProcessing, setIsProcessing] = (0, import_react11.useState)(false);
25249
+ const [error, setError] = (0, import_react11.useState)(null);
25250
+ const extractOCRContext = (0, import_react11.useCallback)(async (files) => {
25251
+ setIsProcessing(true);
25252
+ setError(null);
25253
+ try {
25254
+ if (files.length === 0) {
25255
+ return null;
25256
+ }
25257
+ const contexts = await Promise.all(
25258
+ files.map(async (file) => {
25259
+ try {
25260
+ let imagesToProcess = [];
25261
+ const language = file.language || "eng";
25262
+ const filename = file.filename || (file.url instanceof File ? file.url.name : "");
25263
+ let isPdf = false;
25264
+ if (typeof file.url === "string") {
25265
+ isPdf = file.url.toLowerCase().endsWith(".pdf") || (filename?.toLowerCase().endsWith(".pdf") ?? false);
25266
+ } else if (file.url instanceof Blob) {
25267
+ isPdf = file.url.type === "application/pdf" || (filename?.toLowerCase().endsWith(".pdf") ?? false);
25268
+ }
25269
+ if (isPdf) {
25270
+ let pdfUrl;
25271
+ let shouldRevoke = false;
25272
+ if (typeof file.url === "string") {
25273
+ pdfUrl = file.url;
25274
+ } else {
25275
+ pdfUrl = URL.createObjectURL(file.url);
25276
+ shouldRevoke = true;
25277
+ }
25278
+ try {
25279
+ const pdfImages = await convertPdfToImages(pdfUrl);
25280
+ imagesToProcess = pdfImages;
25281
+ } catch (e) {
25282
+ getLogger().error("Failed to convert PDF to images", e);
25283
+ throw e;
25284
+ } finally {
25285
+ if (shouldRevoke) {
25286
+ URL.revokeObjectURL(pdfUrl);
25287
+ }
25288
+ }
25289
+ } else {
25290
+ imagesToProcess = [file.url];
25291
+ }
25292
+ const pageTexts = [];
25293
+ for (const image of imagesToProcess) {
25294
+ const result = await import_tesseract.default.recognize(image, language);
25295
+ pageTexts.push(result.data.text);
25296
+ }
25297
+ const text12 = pageTexts.join("\n\n");
25298
+ if (!text12.trim()) {
25299
+ getLogger().warn(`No text found in OCR source ${filename || "unknown"}`);
25300
+ return null;
25301
+ }
25302
+ return `[Context from OCR attachment ${filename || "unknown"}]:
25303
+ ${text12}`;
25304
+ } catch (err) {
25305
+ getLogger().error(`Failed to process OCR for ${file.filename || "unknown"}:`, err);
25306
+ return null;
25307
+ }
25308
+ })
25309
+ );
25310
+ const mergedContext = contexts.filter(Boolean).join("\n\n");
25311
+ return mergedContext || null;
25312
+ } catch (err) {
25313
+ const processedError = err instanceof Error ? err : new Error(String(err));
25314
+ setError(processedError);
25315
+ throw processedError;
25316
+ } finally {
25317
+ setIsProcessing(false);
24981
25318
  }
24982
- return options.body !== "" ? options.body : null;
24983
- }
24984
- if (hasBody) {
24985
- return options.body;
24986
- }
24987
- return void 0;
25319
+ }, []);
25320
+ return {
25321
+ extractOCRContext,
25322
+ isProcessing,
25323
+ error
25324
+ };
24988
25325
  }
24989
25326
 
24990
- // src/client/core/auth.gen.ts
24991
- var getAuthToken = async (auth, callback) => {
24992
- const token = typeof callback === "function" ? await callback(auth) : callback;
24993
- if (!token) {
24994
- return;
24995
- }
24996
- if (auth.scheme === "bearer") {
24997
- return `Bearer ${token}`;
24998
- }
24999
- if (auth.scheme === "basic") {
25000
- return `Basic ${btoa(token)}`;
25001
- }
25002
- return token;
25003
- };
25004
-
25005
- // src/client/client/utils.gen.ts
25006
- var PATH_PARAM_RE = /\{[^{}]+\}/g;
25007
- var defaultPathSerializer = ({ path, url: _url }) => {
25008
- let url = _url;
25009
- const matches = _url.match(PATH_PARAM_RE);
25010
- if (matches) {
25011
- for (const match of matches) {
25012
- let explode = false;
25013
- let name = match.substring(1, match.length - 1);
25014
- let style = "simple";
25015
- if (name.endsWith("*")) {
25016
- explode = true;
25017
- name = name.substring(0, name.length - 1);
25018
- }
25019
- if (name.startsWith(".")) {
25020
- name = name.substring(1);
25021
- style = "label";
25022
- } else if (name.startsWith(";")) {
25023
- name = name.substring(1);
25024
- style = "matrix";
25025
- }
25026
- const value = path[name];
25027
- if (value === void 0 || value === null) {
25028
- continue;
25029
- }
25030
- if (Array.isArray(value)) {
25031
- url = url.replace(match, serializeArrayParam({ explode, name, style, value }));
25032
- continue;
25033
- }
25034
- if (typeof value === "object") {
25035
- url = url.replace(
25036
- match,
25037
- serializeObjectParam({
25038
- explode,
25039
- name,
25040
- style,
25041
- value,
25042
- valueOnly: true
25043
- })
25044
- );
25045
- continue;
25046
- }
25047
- if (style === "matrix") {
25048
- url = url.replace(
25049
- match,
25050
- `;${serializePrimitiveParam({
25051
- name,
25052
- value
25053
- })}`
25054
- );
25055
- continue;
25056
- }
25057
- const replaceValue = encodeURIComponent(
25058
- style === "label" ? `.${value}` : value
25327
+ // src/react/usePdf.ts
25328
+ var import_react12 = require("react");
25329
+ init_logger();
25330
+ var PDF_MIME_TYPE = "application/pdf";
25331
+ function usePdf() {
25332
+ const [isProcessing, setIsProcessing] = (0, import_react12.useState)(false);
25333
+ const [error, setError] = (0, import_react12.useState)(null);
25334
+ const extractPdfContext = (0, import_react12.useCallback)(async (files) => {
25335
+ setIsProcessing(true);
25336
+ setError(null);
25337
+ try {
25338
+ const pdfFiles = files.filter(
25339
+ (file) => file.mediaType === PDF_MIME_TYPE || file.filename?.toLowerCase().endsWith(".pdf")
25059
25340
  );
25060
- url = url.replace(match, replaceValue);
25061
- }
25062
- }
25063
- return url;
25064
- };
25065
- var createQuerySerializer = ({
25066
- parameters = {},
25067
- ...args
25068
- } = {}) => {
25069
- const querySerializer = (queryParams) => {
25070
- const search = [];
25071
- if (queryParams && typeof queryParams === "object") {
25072
- for (const name in queryParams) {
25073
- const value = queryParams[name];
25074
- if (value === void 0 || value === null) {
25075
- continue;
25076
- }
25077
- const options = parameters[name] || args;
25078
- if (Array.isArray(value)) {
25079
- const serializedArray = serializeArrayParam({
25080
- allowReserved: options.allowReserved,
25081
- explode: true,
25082
- name,
25083
- style: "form",
25084
- value,
25085
- ...options.array
25086
- });
25087
- if (serializedArray) search.push(serializedArray);
25088
- } else if (typeof value === "object") {
25089
- const serializedObject = serializeObjectParam({
25090
- allowReserved: options.allowReserved,
25091
- explode: true,
25092
- name,
25093
- style: "deepObject",
25094
- value,
25095
- ...options.object
25096
- });
25097
- if (serializedObject) search.push(serializedObject);
25098
- } else {
25099
- const serializedPrimitive = serializePrimitiveParam({
25100
- allowReserved: options.allowReserved,
25101
- name,
25102
- value
25103
- });
25104
- if (serializedPrimitive) search.push(serializedPrimitive);
25105
- }
25341
+ if (pdfFiles.length === 0) {
25342
+ return null;
25106
25343
  }
25344
+ const contexts = await Promise.all(
25345
+ pdfFiles.map(async (file) => {
25346
+ try {
25347
+ const text12 = await extractTextFromPdf(file.url);
25348
+ if (!text12.trim()) {
25349
+ getLogger().warn(`No text found in PDF ${file.filename}`);
25350
+ return null;
25351
+ }
25352
+ return `[Context from PDF attachment ${file.filename}]:
25353
+ ${text12}`;
25354
+ } catch (err) {
25355
+ getLogger().error(`Failed to process PDF ${file.filename}:`, err);
25356
+ return null;
25357
+ }
25358
+ })
25359
+ );
25360
+ const mergedContext = contexts.filter(Boolean).join("\n\n");
25361
+ return mergedContext || null;
25362
+ } catch (err) {
25363
+ const processedError = err instanceof Error ? err : new Error(String(err));
25364
+ setError(processedError);
25365
+ throw processedError;
25366
+ } finally {
25367
+ setIsProcessing(false);
25107
25368
  }
25108
- return search.join("&");
25369
+ }, []);
25370
+ return {
25371
+ extractPdfContext,
25372
+ isProcessing,
25373
+ error
25109
25374
  };
25110
- return querySerializer;
25111
- };
25112
- var getParseAs = (contentType) => {
25113
- if (!contentType) {
25114
- return "stream";
25115
- }
25116
- const cleanContent = contentType.split(";")[0]?.trim();
25117
- if (!cleanContent) {
25118
- return;
25119
- }
25120
- if (cleanContent.startsWith("application/json") || cleanContent.endsWith("+json")) {
25121
- return "json";
25122
- }
25123
- if (cleanContent === "multipart/form-data") {
25124
- return "formData";
25125
- }
25126
- if (["application/", "audio/", "image/", "video/"].some((type) => cleanContent.startsWith(type))) {
25127
- return "blob";
25128
- }
25129
- if (cleanContent.startsWith("text/")) {
25130
- return "text";
25131
- }
25132
- return;
25133
- };
25134
- var checkForExistence = (options, name) => {
25135
- if (!name) {
25136
- return false;
25137
- }
25138
- if (options.headers.has(name) || options.query?.[name] || options.headers.get("Cookie")?.includes(`${name}=`)) {
25139
- return true;
25375
+ }
25376
+
25377
+ // src/react/useVoice.ts
25378
+ var import_react13 = require("react");
25379
+ function getOnDeviceSpeechRecognition() {
25380
+ if (typeof window === "undefined") return null;
25381
+ if (!/iPhone|iPad|iPod/.test(navigator.userAgent)) return null;
25382
+ const SR = window.SpeechRecognition ?? window.webkitSpeechRecognition;
25383
+ return SR ?? null;
25384
+ }
25385
+ var SUPPORTED_MIME_TYPES = [
25386
+ "audio/webm;codecs=opus",
25387
+ "audio/webm",
25388
+ "audio/mp4",
25389
+ "audio/ogg;codecs=opus",
25390
+ "audio/ogg"
25391
+ ];
25392
+ function getSupportedMimeType() {
25393
+ if (typeof MediaRecorder === "undefined") {
25394
+ return "audio/webm";
25140
25395
  }
25141
- return false;
25142
- };
25143
- async function setAuthParams(options) {
25144
- for (const auth of options.security ?? []) {
25145
- if (checkForExistence(options, auth.name)) {
25146
- continue;
25147
- }
25148
- const token = await getAuthToken(auth, options.auth);
25149
- if (!token) {
25150
- continue;
25151
- }
25152
- const name = auth.name ?? "Authorization";
25153
- switch (auth.in) {
25154
- case "query":
25155
- if (!options.query) {
25156
- options.query = {};
25157
- }
25158
- options.query[name] = token;
25159
- break;
25160
- case "cookie":
25161
- options.headers.append("Cookie", `${name}=${token}`);
25162
- break;
25163
- case "header":
25164
- default:
25165
- options.headers.set(name, token);
25166
- break;
25396
+ for (const type of SUPPORTED_MIME_TYPES) {
25397
+ if (MediaRecorder.isTypeSupported(type)) {
25398
+ return type;
25167
25399
  }
25168
25400
  }
25401
+ return "audio/webm";
25169
25402
  }
25170
- var buildUrl = (options) => {
25171
- const url = getUrl({
25172
- baseUrl: options.baseUrl,
25173
- path: options.path,
25174
- query: options.query,
25175
- querySerializer: typeof options.querySerializer === "function" ? options.querySerializer : createQuerySerializer(options.querySerializer),
25176
- url: options.url
25177
- });
25178
- return url;
25179
- };
25180
- var getUrl = ({
25181
- baseUrl,
25182
- path,
25183
- query,
25184
- querySerializer,
25185
- url: _url
25186
- }) => {
25187
- const pathUrl = _url.startsWith("/") ? _url : `/${_url}`;
25188
- let url = (baseUrl ?? "") + pathUrl;
25189
- if (path) {
25190
- url = defaultPathSerializer({ path, url });
25191
- }
25192
- let search = query ? querySerializer(query) : "";
25193
- if (search.startsWith("?")) {
25194
- search = search.substring(1);
25195
- }
25196
- if (search) {
25197
- url += `?${search}`;
25198
- }
25199
- return url;
25200
- };
25201
- var mergeConfigs = (a, b) => {
25202
- const config = { ...a, ...b };
25203
- if (config.baseUrl?.endsWith("/")) {
25204
- config.baseUrl = config.baseUrl.substring(0, config.baseUrl.length - 1);
25205
- }
25206
- config.headers = mergeHeaders(a.headers, b.headers);
25207
- return config;
25208
- };
25209
- var headersEntries = (headers) => {
25210
- const entries = [];
25211
- headers.forEach((value, key) => {
25212
- entries.push([key, value]);
25213
- });
25214
- return entries;
25215
- };
25216
- var mergeHeaders = (...headers) => {
25217
- const mergedHeaders = new Headers();
25218
- for (const header of headers) {
25219
- if (!header || typeof header !== "object") {
25220
- continue;
25403
+ var SAMPLE_RATE = 16e3;
25404
+ async function audioToFloat32(blob) {
25405
+ const arrayBuffer = await blob.arrayBuffer();
25406
+ const audioContext = new AudioContext({ sampleRate: SAMPLE_RATE });
25407
+ try {
25408
+ const audioBuffer = await audioContext.decodeAudioData(arrayBuffer);
25409
+ if (audioBuffer.numberOfChannels === 1) {
25410
+ return audioBuffer.getChannelData(0);
25221
25411
  }
25222
- const iterator = header instanceof Headers ? headersEntries(header) : Object.entries(header);
25223
- for (const [key, value] of iterator) {
25224
- if (value === null) {
25225
- mergedHeaders.delete(key);
25226
- } else if (Array.isArray(value)) {
25227
- for (const v of value) {
25228
- mergedHeaders.append(key, v);
25229
- }
25230
- } else if (value !== void 0) {
25231
- mergedHeaders.set(
25232
- key,
25233
- typeof value === "object" ? JSON.stringify(value) : value
25234
- );
25412
+ const length = audioBuffer.length;
25413
+ const mono = new Float32Array(length);
25414
+ const channels = audioBuffer.numberOfChannels;
25415
+ for (let ch = 0; ch < channels; ch++) {
25416
+ const data = audioBuffer.getChannelData(ch);
25417
+ for (let i = 0; i < length; i++) {
25418
+ mono[i] += data[i];
25235
25419
  }
25236
25420
  }
25237
- }
25238
- return mergedHeaders;
25239
- };
25240
- var Interceptors = class {
25241
- constructor() {
25242
- this.fns = [];
25243
- }
25244
- clear() {
25245
- this.fns = [];
25246
- }
25247
- eject(id) {
25248
- const index = this.getInterceptorIndex(id);
25249
- if (this.fns[index]) {
25250
- this.fns[index] = null;
25251
- }
25252
- }
25253
- exists(id) {
25254
- const index = this.getInterceptorIndex(id);
25255
- return Boolean(this.fns[index]);
25256
- }
25257
- getInterceptorIndex(id) {
25258
- if (typeof id === "number") {
25259
- return this.fns[id] ? id : -1;
25260
- }
25261
- return this.fns.indexOf(id);
25262
- }
25263
- update(id, fn) {
25264
- const index = this.getInterceptorIndex(id);
25265
- if (this.fns[index]) {
25266
- this.fns[index] = fn;
25267
- return id;
25421
+ for (let i = 0; i < length; i++) {
25422
+ mono[i] /= channels;
25268
25423
  }
25269
- return false;
25270
- }
25271
- use(fn) {
25272
- this.fns.push(fn);
25273
- return this.fns.length - 1;
25274
- }
25275
- };
25276
- var createInterceptors = () => ({
25277
- error: new Interceptors(),
25278
- request: new Interceptors(),
25279
- response: new Interceptors()
25280
- });
25281
- var defaultQuerySerializer = createQuerySerializer({
25282
- allowReserved: false,
25283
- array: {
25284
- explode: true,
25285
- style: "form"
25286
- },
25287
- object: {
25288
- explode: true,
25289
- style: "deepObject"
25424
+ return mono;
25425
+ } finally {
25426
+ await audioContext.close();
25290
25427
  }
25291
- });
25292
- var defaultHeaders = {
25293
- "Content-Type": "application/json"
25294
- };
25295
- var createConfig = (override = {}) => ({
25296
- ...jsonBodySerializer,
25297
- headers: defaultHeaders,
25298
- parseAs: "auto",
25299
- querySerializer: defaultQuerySerializer,
25300
- ...override
25301
- });
25302
-
25303
- // src/client/client/client.gen.ts
25304
- var createClient = (config = {}) => {
25305
- let _config = mergeConfigs(createConfig(), config);
25306
- const getConfig = () => ({ ..._config });
25307
- const setConfig = (config2) => {
25308
- _config = mergeConfigs(_config, config2);
25309
- return getConfig();
25310
- };
25311
- const interceptors = createInterceptors();
25312
- const beforeRequest = async (options) => {
25313
- const opts = {
25314
- ..._config,
25315
- ...options,
25316
- fetch: options.fetch ?? _config.fetch ?? globalThis.fetch,
25317
- headers: mergeHeaders(_config.headers, options.headers),
25318
- serializedBody: void 0
25319
- };
25320
- if (opts.security) {
25321
- await setAuthParams(opts);
25322
- }
25323
- if (opts.requestValidator) {
25324
- await opts.requestValidator(opts);
25428
+ }
25429
+ function useVoice(options) {
25430
+ const [isRecording, setIsRecording] = (0, import_react13.useState)(false);
25431
+ const [isTranscribing, setIsTranscribing] = (0, import_react13.useState)(false);
25432
+ const [isModelLoaded, setIsModelLoaded] = (0, import_react13.useState)(false);
25433
+ const [isLoadingModel, setIsLoadingModel] = (0, import_react13.useState)(false);
25434
+ const [recording, setRecording] = (0, import_react13.useState)(null);
25435
+ const [transcription, setTranscription] = (0, import_react13.useState)(null);
25436
+ const [error, setError] = (0, import_react13.useState)(null);
25437
+ const mediaRecorderRef = (0, import_react13.useRef)(null);
25438
+ const mediaStreamRef = (0, import_react13.useRef)(null);
25439
+ const chunksRef = (0, import_react13.useRef)([]);
25440
+ const startTimeRef = (0, import_react13.useRef)(0);
25441
+ const pipelineRef = (0, import_react13.useRef)(null);
25442
+ const modelNameRef = (0, import_react13.useRef)(null);
25443
+ const getModelName = (0, import_react13.useCallback)(() => {
25444
+ const model = options?.model ?? "whisper-tiny";
25445
+ return `onnx-community/${model}`;
25446
+ }, [options?.model]);
25447
+ const loadPipeline = (0, import_react13.useCallback)(async () => {
25448
+ const modelName = getModelName();
25449
+ if (pipelineRef.current && modelNameRef.current === modelName) {
25450
+ return pipelineRef.current;
25325
25451
  }
25326
- if (opts.body !== void 0 && opts.bodySerializer) {
25327
- opts.serializedBody = opts.bodySerializer(opts.body);
25452
+ setIsLoadingModel(true);
25453
+ setError(null);
25454
+ try {
25455
+ const { pipeline } = await import("@huggingface/transformers");
25456
+ const transcriber = await pipeline("automatic-speech-recognition", modelName, {
25457
+ dtype: "q4",
25458
+ device: "wasm",
25459
+ progress_callback: options?.onModelProgress ? (progress) => {
25460
+ if (progress.file && progress.progress !== null && progress.progress !== void 0) {
25461
+ options.onModelProgress({
25462
+ file: progress.file,
25463
+ progress: progress.progress / 100,
25464
+ loaded: progress.loaded ?? 0,
25465
+ total: progress.total ?? 0
25466
+ });
25467
+ }
25468
+ } : void 0
25469
+ });
25470
+ pipelineRef.current = transcriber;
25471
+ modelNameRef.current = modelName;
25472
+ setIsModelLoaded(true);
25473
+ return pipelineRef.current;
25474
+ } catch (err) {
25475
+ const processedError = err instanceof Error ? err : new Error("Failed to load Whisper model");
25476
+ setError(processedError);
25477
+ throw processedError;
25478
+ } finally {
25479
+ setIsLoadingModel(false);
25328
25480
  }
25329
- if (opts.body === void 0 || opts.serializedBody === "") {
25330
- opts.headers.delete("Content-Type");
25481
+ }, [getModelName, options?.onModelProgress]);
25482
+ const preloadModel = (0, import_react13.useCallback)(async () => {
25483
+ await loadPipeline();
25484
+ }, [loadPipeline]);
25485
+ const disposeModel = (0, import_react13.useCallback)(async () => {
25486
+ const pipe = pipelineRef.current;
25487
+ if (pipe?.dispose) {
25488
+ await pipe.dispose();
25331
25489
  }
25332
- const resolvedOpts = opts;
25333
- const url = buildUrl(resolvedOpts);
25334
- return { opts: resolvedOpts, url };
25335
- };
25336
- const request = async (options) => {
25337
- const throwOnError = options.throwOnError ?? _config.throwOnError;
25338
- let response;
25490
+ pipelineRef.current = null;
25491
+ modelNameRef.current = null;
25492
+ setIsModelLoaded(false);
25493
+ }, []);
25494
+ const startRecording = (0, import_react13.useCallback)(async () => {
25495
+ setError(null);
25496
+ setRecording(null);
25497
+ setTranscription(null);
25339
25498
  try {
25340
- const { opts, url } = await beforeRequest(options);
25341
- for (const fn of interceptors.request.fns) {
25342
- if (fn) {
25343
- await fn(opts);
25499
+ const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
25500
+ mediaStreamRef.current = stream;
25501
+ const mimeType = getSupportedMimeType();
25502
+ const recorder = new MediaRecorder(stream, { mimeType });
25503
+ mediaRecorderRef.current = recorder;
25504
+ chunksRef.current = [];
25505
+ recorder.ondataavailable = (e) => {
25506
+ if (e.data.size > 0) {
25507
+ chunksRef.current.push(e.data);
25344
25508
  }
25345
- }
25346
- const _fetch = opts.fetch;
25347
- const requestInit = {
25348
- ...opts,
25349
- body: getValidRequestBody(opts)
25350
25509
  };
25351
- response = await _fetch(url, requestInit);
25352
- for (const fn of interceptors.response.fns) {
25353
- if (fn) {
25354
- response = await fn(response, opts);
25355
- }
25510
+ recorder.start();
25511
+ startTimeRef.current = Date.now();
25512
+ setIsRecording(true);
25513
+ } catch (err) {
25514
+ const processedError = err instanceof Error ? err : new Error("Failed to start recording");
25515
+ setError(processedError);
25516
+ throw processedError;
25517
+ }
25518
+ }, []);
25519
+ const stopRecording = (0, import_react13.useCallback)(async () => {
25520
+ return new Promise((resolve, reject) => {
25521
+ const recorder = mediaRecorderRef.current;
25522
+ if (!recorder || recorder.state === "inactive") {
25523
+ const err = new Error("No active recording");
25524
+ setError(err);
25525
+ reject(err);
25526
+ return;
25356
25527
  }
25357
- const result = {
25358
- response
25528
+ recorder.onstop = () => {
25529
+ const mimeType = recorder.mimeType || "audio/webm";
25530
+ const blob = new Blob(chunksRef.current, { type: mimeType });
25531
+ const duration = Date.now() - startTimeRef.current;
25532
+ mediaStreamRef.current?.getTracks().forEach((t) => t.stop());
25533
+ mediaStreamRef.current = null;
25534
+ mediaRecorderRef.current = null;
25535
+ const result = { blob, duration, mimeType };
25536
+ setRecording(result);
25537
+ setIsRecording(false);
25538
+ resolve(result);
25359
25539
  };
25360
- if (response.ok) {
25361
- const parseAs = (opts.parseAs === "auto" ? getParseAs(response.headers.get("Content-Type")) : opts.parseAs) ?? "json";
25362
- if (response.status === 204 || response.headers.get("Content-Length") === "0") {
25363
- let emptyData;
25364
- switch (parseAs) {
25365
- case "arrayBuffer":
25366
- case "blob":
25367
- case "text":
25368
- emptyData = await response[parseAs]();
25369
- break;
25370
- case "formData":
25371
- emptyData = new FormData();
25372
- break;
25373
- case "stream":
25374
- emptyData = response.body;
25375
- break;
25376
- case "json":
25377
- default:
25378
- emptyData = {};
25379
- break;
25380
- }
25381
- return {
25382
- data: emptyData,
25383
- ...result
25384
- };
25385
- }
25386
- let data;
25387
- switch (parseAs) {
25388
- case "arrayBuffer":
25389
- case "blob":
25390
- case "formData":
25391
- case "text":
25392
- data = await response[parseAs]();
25393
- break;
25394
- case "json": {
25395
- const text12 = await response.text();
25396
- data = text12 ? JSON.parse(text12) : {};
25397
- break;
25398
- }
25399
- case "stream":
25400
- return {
25401
- data: response.body,
25402
- ...result
25403
- };
25404
- }
25405
- if (parseAs === "json") {
25406
- if (opts.responseValidator) {
25407
- await opts.responseValidator(data);
25408
- }
25409
- if (opts.responseTransformer) {
25410
- data = await opts.responseTransformer(data);
25411
- }
25412
- }
25413
- return {
25414
- data,
25415
- ...result
25416
- };
25540
+ recorder.onerror = () => {
25541
+ const err = new Error("Recording failed");
25542
+ setError(err);
25543
+ setIsRecording(false);
25544
+ reject(err);
25545
+ };
25546
+ recorder.stop();
25547
+ });
25548
+ }, []);
25549
+ const transcribe = (0, import_react13.useCallback)(
25550
+ async (rec) => {
25551
+ const target = rec ?? recording;
25552
+ if (!target) {
25553
+ const err = new Error("No recording to transcribe");
25554
+ setError(err);
25555
+ throw err;
25417
25556
  }
25418
- const textError = await response.text();
25419
- let jsonError;
25557
+ setIsTranscribing(true);
25558
+ setError(null);
25420
25559
  try {
25421
- jsonError = JSON.parse(textError);
25422
- } catch {
25560
+ const pipe = await loadPipeline();
25561
+ const audio = await audioToFloat32(target.blob);
25562
+ const result = await pipe(audio, {
25563
+ language: options?.language,
25564
+ return_timestamps: true
25565
+ });
25566
+ const transcriptionResult = {
25567
+ text: result.text.trim(),
25568
+ chunks: result.chunks
25569
+ };
25570
+ setTranscription(transcriptionResult);
25571
+ return transcriptionResult;
25572
+ } catch (err) {
25573
+ const processedError = err instanceof Error ? err : new Error("Transcription failed");
25574
+ setError(processedError);
25575
+ throw processedError;
25576
+ } finally {
25577
+ setIsTranscribing(false);
25423
25578
  }
25424
- throw jsonError ?? textError;
25425
- } catch (error) {
25426
- let finalError = error;
25427
- for (const fn of interceptors.error.fns) {
25428
- if (fn) {
25429
- finalError = await fn(finalError, response, options);
25579
+ },
25580
+ [recording, loadPipeline, options?.language]
25581
+ );
25582
+ const nativeSpeechAvailable = (0, import_react13.useMemo)(() => getOnDeviceSpeechRecognition() !== null, []);
25583
+ const [isNativeListening, setIsNativeListening] = (0, import_react13.useState)(false);
25584
+ const nativeRecognitionRef = (0, import_react13.useRef)(null);
25585
+ const nativeTextRef = (0, import_react13.useRef)("");
25586
+ const nativeResolveRef = (0, import_react13.useRef)(null);
25587
+ const startNativeTranscription = (0, import_react13.useCallback)(() => {
25588
+ const SR = getOnDeviceSpeechRecognition();
25589
+ if (!SR) return;
25590
+ nativeTextRef.current = "";
25591
+ setError(null);
25592
+ const recognition = new SR();
25593
+ recognition.continuous = true;
25594
+ recognition.interimResults = false;
25595
+ recognition.lang = options?.language ?? "";
25596
+ recognition.onresult = (event) => {
25597
+ let text12 = "";
25598
+ for (let i = 0; i < event.results.length; i++) {
25599
+ const result = event.results[i];
25600
+ if (result && result.isFinal && result[0]) {
25601
+ text12 += result[0].transcript + " ";
25430
25602
  }
25431
25603
  }
25432
- finalError = finalError || {};
25433
- if (throwOnError) {
25434
- throw finalError;
25604
+ nativeTextRef.current = text12.trim();
25605
+ };
25606
+ recognition.onerror = (event) => {
25607
+ if (event.error !== "aborted" && event.error !== "no-speech") {
25608
+ setError(new Error(`Speech recognition error: ${event.error}`));
25435
25609
  }
25436
- return {
25437
- error: finalError,
25438
- response
25439
- };
25440
- }
25441
- };
25442
- const makeMethodFn = (method) => (options) => request({ ...options, method });
25443
- const makeSseFn = (method) => async (options) => {
25444
- const { opts, url } = await beforeRequest(options);
25445
- return createSseClient({
25446
- ...opts,
25447
- body: opts.body,
25448
- method,
25449
- onRequest: async (url2, init) => {
25450
- let request2 = new Request(url2, init);
25451
- const requestInit = { ...init, url: url2 };
25452
- for (const fn of interceptors.request.fns) {
25453
- if (fn) {
25454
- await fn(requestInit);
25455
- request2 = new Request(requestInit.url, requestInit);
25456
- }
25457
- }
25458
- return request2;
25459
- },
25460
- serializedBody: getValidRequestBody(opts),
25461
- url
25610
+ };
25611
+ recognition.onend = () => {
25612
+ setIsNativeListening(false);
25613
+ nativeRecognitionRef.current = null;
25614
+ const resolve = nativeResolveRef.current;
25615
+ if (resolve) {
25616
+ nativeResolveRef.current = null;
25617
+ resolve({ text: nativeTextRef.current });
25618
+ }
25619
+ };
25620
+ nativeRecognitionRef.current = recognition;
25621
+ recognition.start();
25622
+ setIsNativeListening(true);
25623
+ }, [options?.language]);
25624
+ const stopNativeTranscription = (0, import_react13.useCallback)(() => {
25625
+ return new Promise((resolve) => {
25626
+ const recognition = nativeRecognitionRef.current;
25627
+ if (!recognition) {
25628
+ resolve({ text: nativeTextRef.current || "" });
25629
+ return;
25630
+ }
25631
+ nativeResolveRef.current = resolve;
25632
+ recognition.stop();
25462
25633
  });
25463
- };
25464
- const _buildUrl = (options) => buildUrl({ ..._config, ...options });
25634
+ }, []);
25635
+ const abortNativeTranscription = (0, import_react13.useCallback)(() => {
25636
+ const recognition = nativeRecognitionRef.current;
25637
+ if (recognition) {
25638
+ nativeResolveRef.current = null;
25639
+ recognition.abort();
25640
+ nativeRecognitionRef.current = null;
25641
+ setIsNativeListening(false);
25642
+ }
25643
+ }, []);
25465
25644
  return {
25466
- buildUrl: _buildUrl,
25467
- connect: makeMethodFn("CONNECT"),
25468
- delete: makeMethodFn("DELETE"),
25469
- get: makeMethodFn("GET"),
25470
- getConfig,
25471
- head: makeMethodFn("HEAD"),
25472
- interceptors,
25473
- options: makeMethodFn("OPTIONS"),
25474
- patch: makeMethodFn("PATCH"),
25475
- post: makeMethodFn("POST"),
25476
- put: makeMethodFn("PUT"),
25477
- request,
25478
- setConfig,
25479
- sse: {
25480
- connect: makeSseFn("CONNECT"),
25481
- delete: makeSseFn("DELETE"),
25482
- get: makeSseFn("GET"),
25483
- head: makeSseFn("HEAD"),
25484
- options: makeSseFn("OPTIONS"),
25485
- patch: makeSseFn("PATCH"),
25486
- post: makeSseFn("POST"),
25487
- put: makeSseFn("PUT"),
25488
- trace: makeSseFn("TRACE")
25489
- },
25490
- trace: makeMethodFn("TRACE")
25645
+ isRecording,
25646
+ startRecording,
25647
+ stopRecording,
25648
+ isTranscribing,
25649
+ transcribe,
25650
+ preloadModel,
25651
+ disposeModel,
25652
+ isModelLoaded,
25653
+ isLoadingModel,
25654
+ recording,
25655
+ transcription,
25656
+ error,
25657
+ nativeSpeechAvailable,
25658
+ startNativeTranscription,
25659
+ stopNativeTranscription,
25660
+ abortNativeTranscription,
25661
+ isNativeListening
25491
25662
  };
25492
- };
25493
-
25494
- // src/client/client.gen.ts
25495
- init_clientConfig();
25496
- var client = createClient(createClientConfig(createConfig()));
25497
-
25498
- // src/client/sdk.gen.ts
25499
- var getApiV1Config = (options) => (options?.client ?? client).get({ url: "/api/v1/config", ...options });
25500
- var getApiV1CreditsBalance = (options) => (options?.client ?? client).get({ url: "/api/v1/credits/balance", ...options });
25501
- var getApiV1CreditsPacks = (options) => (options?.client ?? client).get({ url: "/api/v1/credits/packs", ...options });
25502
- var postApiV1CreditsPurchase = (options) => (options.client ?? client).post({
25503
- url: "/api/v1/credits/purchase",
25504
- ...options,
25505
- headers: {
25506
- "Content-Type": "application/json",
25507
- ...options.headers
25508
- }
25509
- });
25510
- var getApiV1Models = (options) => (options?.client ?? client).get({ url: "/api/v1/models", ...options });
25511
- var postApiV1PhoneCalls = (options) => (options.client ?? client).post({
25512
- url: "/api/v1/phone-calls",
25513
- ...options,
25514
- headers: {
25515
- "Content-Type": "application/json",
25516
- ...options.headers
25517
- }
25518
- });
25519
- var getApiV1PhoneCallsByCallId = (options) => (options.client ?? client).get({ url: "/api/v1/phone-calls/{call_id}", ...options });
25520
- var postApiV1SubscriptionsCancel = (options) => (options?.client ?? client).post({
25521
- url: "/api/v1/subscriptions/cancel",
25522
- ...options,
25523
- headers: {
25524
- "Content-Type": "application/json",
25525
- ...options?.headers
25526
- }
25527
- });
25528
- var postApiV1SubscriptionsCreateCheckoutSession = (options) => (options.client ?? client).post({
25529
- url: "/api/v1/subscriptions/create-checkout-session",
25530
- ...options,
25531
- headers: {
25532
- "Content-Type": "application/json",
25533
- ...options.headers
25534
- }
25535
- });
25536
- var postApiV1SubscriptionsCustomerPortal = (options) => (options.client ?? client).post({
25537
- url: "/api/v1/subscriptions/customer-portal",
25538
- ...options,
25539
- headers: {
25540
- "Content-Type": "application/json",
25541
- ...options.headers
25542
- }
25543
- });
25544
- var postApiV1SubscriptionsRenew = (options) => (options?.client ?? client).post({ url: "/api/v1/subscriptions/renew", ...options });
25545
- var getApiV1SubscriptionsStatus = (options) => (options?.client ?? client).get({ url: "/api/v1/subscriptions/status", ...options });
25546
- var getApiV1WalletsBinding = (options) => (options?.client ?? client).get({ url: "/api/v1/wallets/binding", ...options });
25547
- var postApiV1WalletsBinding = (options) => (options.client ?? client).post({
25548
- url: "/api/v1/wallets/binding",
25549
- ...options,
25550
- headers: {
25551
- "Content-Type": "application/json",
25552
- ...options.headers
25553
- }
25554
- });
25555
- var postApiV1WalletsBindingNonce = (options) => (options?.client ?? client).post({ url: "/api/v1/wallets/binding/nonce", ...options });
25556
- var deleteApiV1WalletsBindingByAddress = (options) => (options.client ?? client).delete({ url: "/api/v1/wallets/binding/{address}", ...options });
25557
- var postAuthOauthByProviderExchange = (options) => (options.client ?? client).post({
25558
- url: "/auth/oauth/{provider}/exchange",
25559
- ...options,
25560
- headers: {
25561
- "Content-Type": "application/json",
25562
- ...options.headers
25563
- }
25564
- });
25565
- var postAuthOauthByProviderRefresh = (options) => (options.client ?? client).post({
25566
- url: "/auth/oauth/{provider}/refresh",
25567
- ...options,
25568
- headers: {
25569
- "Content-Type": "application/json",
25570
- ...options.headers
25571
- }
25572
- });
25573
- var postAuthOauthByProviderRevoke = (options) => (options.client ?? client).post({
25574
- url: "/auth/oauth/{provider}/revoke",
25575
- ...options,
25576
- headers: {
25577
- "Content-Type": "application/json",
25578
- ...options.headers
25579
- }
25580
- });
25663
+ }
25581
25664
 
25582
25665
  // src/react/useCredits.ts
25666
+ var import_react14 = require("react");
25667
+ init_sdk_gen();
25583
25668
  init_clientConfig();
25584
25669
  function useCredits(options = {}) {
25585
25670
  const { getToken, baseUrl = BASE_URL, autoFetch = true, onError } = options;
@@ -25738,6 +25823,7 @@ function useCredits(options = {}) {
25738
25823
 
25739
25824
  // src/react/useModels.ts
25740
25825
  var import_react15 = require("react");
25826
+ init_sdk_gen();
25741
25827
  init_clientConfig();
25742
25828
  function useModels(options = {}) {
25743
25829
  const { getToken, baseUrl = BASE_URL, provider, autoFetch = true } = options;
@@ -25843,6 +25929,7 @@ function useModels(options = {}) {
25843
25929
 
25844
25930
  // src/react/usePhoneCalls.ts
25845
25931
  var import_react16 = require("react");
25932
+ init_sdk_gen();
25846
25933
  init_clientConfig();
25847
25934
  var DEFAULT_POLL_INTERVAL_MS = 5e3;
25848
25935
  var DEFAULT_POLL_MAX_ATTEMPTS = 60;
@@ -26142,6 +26229,7 @@ function usePhoneCalls(options = {}) {
26142
26229
 
26143
26230
  // src/react/useSubscription.ts
26144
26231
  var import_react17 = require("react");
26232
+ init_sdk_gen();
26145
26233
  init_clientConfig();
26146
26234
  function useSubscription(options = {}) {
26147
26235
  const { getToken, baseUrl = BASE_URL, autoFetch = true, onError } = options;
@@ -26347,6 +26435,7 @@ function useSubscription(options = {}) {
26347
26435
 
26348
26436
  // src/react/useWalletBinding.ts
26349
26437
  var import_react18 = require("react");
26438
+ init_sdk_gen();
26350
26439
  init_clientConfig();
26351
26440
  function useWalletBinding(options = {}) {
26352
26441
  const { getToken, baseUrl = BASE_URL, autoFetch = true, onError } = options;
@@ -26530,6 +26619,7 @@ function useWalletBinding(options = {}) {
26530
26619
  var import_react19 = require("react");
26531
26620
 
26532
26621
  // src/lib/backup/dropbox/auth.ts
26622
+ init_sdk_gen();
26533
26623
  init_logger();
26534
26624
 
26535
26625
  // src/lib/backup/oauth/storage.ts
@@ -27286,6 +27376,7 @@ function useDropboxBackup(options) {
27286
27376
  var import_react21 = require("react");
27287
27377
 
27288
27378
  // src/lib/backup/google/auth.ts
27379
+ init_sdk_gen();
27289
27380
  init_logger();
27290
27381
  var PROVIDER2 = "google-drive";
27291
27382
  var CODE_STORAGE_KEY = "google_oauth_state";
@@ -29084,6 +29175,7 @@ function useBackup(options) {
29084
29175
  }
29085
29176
 
29086
29177
  // src/lib/auth/google-calendar.ts
29178
+ init_sdk_gen();
29087
29179
  init_useEncryption();
29088
29180
  init_logger();
29089
29181
  var PROVIDER3 = "google-drive";
@@ -29409,6 +29501,7 @@ async function migrateCalendarToken(walletAddress) {
29409
29501
  }
29410
29502
 
29411
29503
  // src/lib/auth/google-drive.ts
29504
+ init_sdk_gen();
29412
29505
  init_useEncryption();
29413
29506
  init_logger();
29414
29507
  var PROVIDER4 = "google-drive";
@@ -30285,6 +30378,7 @@ function getNotionMCPUrl() {
30285
30378
  }
30286
30379
 
30287
30380
  // src/lib/auth/github.ts
30381
+ init_sdk_gen();
30288
30382
  init_useEncryption();
30289
30383
  init_logger();
30290
30384
  var PROVIDER5 = "github";