lopata 0.19.2 → 0.20.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/types/bindings/ai-search.d.ts +44 -0
- package/dist/types/bindings/analytics-engine-sql.d.ts +107 -0
- package/dist/types/bindings/artifacts-git-http.d.ts +19 -0
- package/dist/types/bindings/artifacts.d.ts +108 -0
- package/dist/types/bindings/flagship.d.ts +37 -0
- package/dist/types/bindings/vpc-network.d.ts +22 -0
- package/dist/types/bindings/worker-loader-entry.d.ts +71 -0
- package/dist/types/bindings/worker-loader.d.ts +81 -0
- package/dist/types/config.d.ts +23 -0
- package/dist/types/env.d.ts +3 -1
- package/dist/types/generation-manager.d.ts +6 -0
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/dist/types/vite-plugin/dev-server-plugin.d.ts +8 -0
- package/dist/types/worker-thread/executor.d.ts +2 -0
- package/dist/types/worker-thread/protocol.d.ts +2 -0
- package/dist/types/worker-thread/thread-env.d.ts +3 -1
- package/package.json +1 -1
- package/src/bindings/ai-search.ts +185 -0
- package/src/bindings/analytics-engine-sql.ts +1138 -0
- package/src/bindings/artifacts-git-http.ts +249 -0
- package/src/bindings/artifacts.ts +453 -0
- package/src/bindings/do-worker-env.ts +4 -0
- package/src/bindings/flagship.ts +117 -0
- package/src/bindings/vpc-network.ts +40 -0
- package/src/bindings/worker-loader-entry.ts +143 -0
- package/src/bindings/worker-loader.ts +325 -0
- package/src/cli/dev.ts +25 -3
- package/src/config.ts +20 -0
- package/src/db.ts +54 -0
- package/src/env.ts +71 -0
- package/src/generation-manager.ts +5 -1
- package/src/generation.ts +20 -3
- package/src/plugin.ts +37 -0
- package/src/vite-plugin/dev-server-plugin.ts +18 -2
- package/src/worker-thread/entry.ts +1 -0
- package/src/worker-thread/executor.ts +3 -0
- package/src/worker-thread/protocol.ts +2 -0
- package/src/worker-thread/thread-env.ts +72 -1
|
@@ -28,4 +28,12 @@ interface DevServerPluginOptions {
|
|
|
28
28
|
* via link:), so dynamic imports here run through Bun's native loader.
|
|
29
29
|
*/
|
|
30
30
|
export declare function devServerPlugin(options: DevServerPluginOptions): Plugin;
|
|
31
|
+
/**
|
|
32
|
+
* Convert Response headers to a node writeHead record. `set-cookie` must go
|
|
33
|
+
* through `getSetCookie()`: Headers iteration yields it once per cookie (and a
|
|
34
|
+
* keyed record would keep only the last one), so a multi-cookie response —
|
|
35
|
+
* e.g. better-auth's session_token + session_data — would silently lose
|
|
36
|
+
* cookies. Exported for tests.
|
|
37
|
+
*/
|
|
38
|
+
export declare function buildNodeHeaders(response: Response): Record<string, string | string[]>;
|
|
31
39
|
export {};
|
|
@@ -24,6 +24,8 @@ export interface WorkerThreadExecutorOptions {
|
|
|
24
24
|
executablePath?: string;
|
|
25
25
|
headless?: boolean;
|
|
26
26
|
};
|
|
27
|
+
/** Base URL for the Artifacts git remote (main's `/__artifacts/git` endpoint). */
|
|
28
|
+
artifactsBaseUrl?: string;
|
|
27
29
|
/** Main-thread env holding the stateful binding instances the worker calls into via RPC. */
|
|
28
30
|
mainEnv: Record<string, unknown>;
|
|
29
31
|
}
|
|
@@ -92,6 +92,8 @@ export interface WorkerInitConfig {
|
|
|
92
92
|
executablePath?: string;
|
|
93
93
|
headless?: boolean;
|
|
94
94
|
};
|
|
95
|
+
/** Base URL for the Artifacts git remote (main's `/__artifacts/git` endpoint). */
|
|
96
|
+
artifactsBaseUrl?: string;
|
|
95
97
|
}
|
|
96
98
|
/** Names of the worker handlers we know how to invoke via RPC. */
|
|
97
99
|
export type WorkerHandlerName = 'fetch' | 'scheduled' | 'email' | 'queue';
|
|
@@ -26,6 +26,8 @@ export interface ThreadEnvOptions {
|
|
|
26
26
|
executablePath?: string;
|
|
27
27
|
headless?: boolean;
|
|
28
28
|
};
|
|
29
|
+
/** Base URL for the Artifacts git remote (main's `/__artifacts/git` endpoint). */
|
|
30
|
+
artifactsBaseUrl?: string;
|
|
29
31
|
}
|
|
30
32
|
export interface ThreadEnvBuilt {
|
|
31
33
|
env: Record<string, unknown>;
|
|
@@ -39,4 +41,4 @@ export interface ThreadEnvBuilt {
|
|
|
39
41
|
binding: SqliteWorkflowBinding;
|
|
40
42
|
}[];
|
|
41
43
|
}
|
|
42
|
-
export declare function buildThreadEnv({ config, baseDir, dataDir, rpc, envWsBridge, browserConfig }: ThreadEnvOptions): ThreadEnvBuilt;
|
|
44
|
+
export declare function buildThreadEnv({ config, baseDir, dataDir, rpc, envWsBridge, browserConfig, artifactsBaseUrl }: ThreadEnvOptions): ThreadEnvBuilt;
|
package/package.json
CHANGED
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Local implementation of the Cloudflare AI Search namespace binding
|
|
3
|
+
* (`ai_search_namespaces`).
|
|
4
|
+
*
|
|
5
|
+
* Running vector search + RAG locally is impractical, so this binding
|
|
6
|
+
* proxies to the real Cloudflare AI Search REST API — same strategy as
|
|
7
|
+
* `AiBinding`. Every proxied call is logged to SQLite for the dashboard.
|
|
8
|
+
*
|
|
9
|
+
* Requires `CLOUDFLARE_ACCOUNT_ID` and `CLOUDFLARE_API_TOKEN` in `.dev.vars`
|
|
10
|
+
* or the environment.
|
|
11
|
+
*/
|
|
12
|
+
import { randomUUIDv7 } from 'bun'
|
|
13
|
+
import type { Database } from 'bun:sqlite'
|
|
14
|
+
|
|
15
|
+
const MAX_LOG_SIZE = 1024
|
|
16
|
+
|
|
17
|
+
function truncate(value: unknown): string {
|
|
18
|
+
const str = typeof value === 'string' ? value : JSON.stringify(value)
|
|
19
|
+
if (!str) return ''
|
|
20
|
+
return str.length > MAX_LOG_SIZE ? str.slice(0, MAX_LOG_SIZE) + '…' : str
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
interface CreateInstanceOptions {
|
|
24
|
+
id: string
|
|
25
|
+
type?: string
|
|
26
|
+
source?: unknown
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
interface SearchOptions {
|
|
30
|
+
messages: { role: string; content: string }[]
|
|
31
|
+
ai_search_options?: {
|
|
32
|
+
instance_ids?: string[]
|
|
33
|
+
[key: string]: unknown
|
|
34
|
+
}
|
|
35
|
+
stream?: boolean
|
|
36
|
+
[key: string]: unknown
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export class AiSearchInstance {
|
|
40
|
+
private readonly binding: AiSearchNamespaceBinding
|
|
41
|
+
readonly id: string
|
|
42
|
+
readonly metadata: Record<string, unknown>
|
|
43
|
+
|
|
44
|
+
constructor(binding: AiSearchNamespaceBinding, id: string, metadata: Record<string, unknown> = {}) {
|
|
45
|
+
this.binding = binding
|
|
46
|
+
this.id = id
|
|
47
|
+
this.metadata = metadata
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
async search(options: SearchOptions): Promise<unknown> {
|
|
51
|
+
return this.binding._proxyInstance('search', this.id, options)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
async chatCompletions(options: SearchOptions): Promise<unknown> {
|
|
55
|
+
return this.binding._proxyInstance('chatCompletions', this.id, options)
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export class AiSearchNamespaceBinding {
|
|
60
|
+
private readonly db: Database
|
|
61
|
+
private readonly namespace: string
|
|
62
|
+
private readonly accountId?: string
|
|
63
|
+
private readonly apiToken?: string
|
|
64
|
+
|
|
65
|
+
constructor(db: Database, namespace: string, accountId?: string, apiToken?: string) {
|
|
66
|
+
this.db = db
|
|
67
|
+
this.namespace = namespace
|
|
68
|
+
this.accountId = accountId
|
|
69
|
+
this.apiToken = apiToken
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
private ensureCredentials(): { accountId: string; apiToken: string } {
|
|
73
|
+
if (!this.accountId || !this.apiToken) {
|
|
74
|
+
throw new Error(
|
|
75
|
+
'AI Search requires CLOUDFLARE_ACCOUNT_ID and CLOUDFLARE_API_TOKEN in .dev.vars',
|
|
76
|
+
)
|
|
77
|
+
}
|
|
78
|
+
return { accountId: this.accountId, apiToken: this.apiToken }
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
async create(opts: CreateInstanceOptions): Promise<AiSearchInstance> {
|
|
82
|
+
const body = await this.proxy('POST', '/ai-search/instances', opts, 'create')
|
|
83
|
+
const result = (body as { result?: Record<string, unknown> }).result ?? {}
|
|
84
|
+
return new AiSearchInstance(this, opts.id, result)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
async get(id: string): Promise<AiSearchInstance> {
|
|
88
|
+
const body = await this.proxy('GET', `/ai-search/instances/${encodeURIComponent(id)}`, undefined, 'get')
|
|
89
|
+
const result = (body as { result?: Record<string, unknown> }).result ?? {}
|
|
90
|
+
return new AiSearchInstance(this, id, result)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
async list(opts?: Record<string, string>): Promise<unknown> {
|
|
94
|
+
const query = opts ? '?' + new URLSearchParams(opts).toString() : ''
|
|
95
|
+
return this.proxy('GET', `/ai-search/instances${query}`, undefined, 'list')
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
async delete(id: string): Promise<boolean> {
|
|
99
|
+
await this.proxy('DELETE', `/ai-search/instances/${encodeURIComponent(id)}`, undefined, 'delete')
|
|
100
|
+
return true
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
async search(options: SearchOptions): Promise<unknown> {
|
|
104
|
+
return this.proxy('POST', `/ai-search/namespaces/${encodeURIComponent(this.namespace)}/search`, options, 'search')
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
async chatCompletions(options: SearchOptions): Promise<unknown> {
|
|
108
|
+
return this.proxy(
|
|
109
|
+
'POST',
|
|
110
|
+
`/ai-search/namespaces/${encodeURIComponent(this.namespace)}/chat/completions`,
|
|
111
|
+
options,
|
|
112
|
+
'chatCompletions',
|
|
113
|
+
)
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/** @internal — called by AiSearchInstance */
|
|
117
|
+
async _proxyInstance(method: 'search' | 'chatCompletions', instanceId: string, options: SearchOptions): Promise<unknown> {
|
|
118
|
+
const path = method === 'search'
|
|
119
|
+
? `/ai-search/instances/${encodeURIComponent(instanceId)}/search`
|
|
120
|
+
: `/ai-search/instances/${encodeURIComponent(instanceId)}/chat/completions`
|
|
121
|
+
return this.proxy('POST', path, options, `instance.${method}`)
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
private async proxy(
|
|
125
|
+
httpMethod: string,
|
|
126
|
+
apiPath: string,
|
|
127
|
+
body: unknown,
|
|
128
|
+
operation: string,
|
|
129
|
+
): Promise<unknown> {
|
|
130
|
+
const { accountId, apiToken } = this.ensureCredentials()
|
|
131
|
+
const id = randomUUIDv7()
|
|
132
|
+
const start = Date.now()
|
|
133
|
+
let status = 'ok'
|
|
134
|
+
let error: string | undefined
|
|
135
|
+
let outputSummary = ''
|
|
136
|
+
|
|
137
|
+
try {
|
|
138
|
+
const url = `https://api.cloudflare.com/client/v4/accounts/${accountId}${apiPath}`
|
|
139
|
+
const response = await fetch(url, {
|
|
140
|
+
method: httpMethod,
|
|
141
|
+
headers: {
|
|
142
|
+
Authorization: `Bearer ${apiToken}`,
|
|
143
|
+
'Content-Type': 'application/json',
|
|
144
|
+
},
|
|
145
|
+
body: body === undefined ? undefined : JSON.stringify(body),
|
|
146
|
+
})
|
|
147
|
+
|
|
148
|
+
if (!response.ok) {
|
|
149
|
+
const text = await response.text()
|
|
150
|
+
status = 'error'
|
|
151
|
+
error = `HTTP ${response.status}: ${text}`
|
|
152
|
+
throw new Error(error)
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if ((body as SearchOptions | undefined)?.stream) {
|
|
156
|
+
outputSummary = '<streaming>'
|
|
157
|
+
return response.body
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const ct = response.headers.get('content-type') ?? ''
|
|
161
|
+
if (ct.includes('application/json')) {
|
|
162
|
+
const json = await response.json()
|
|
163
|
+
outputSummary = truncate(json)
|
|
164
|
+
return json
|
|
165
|
+
}
|
|
166
|
+
const text = await response.text()
|
|
167
|
+
outputSummary = truncate(text)
|
|
168
|
+
return text
|
|
169
|
+
} catch (err) {
|
|
170
|
+
if (status !== 'error') {
|
|
171
|
+
status = 'error'
|
|
172
|
+
error = err instanceof Error ? err.message : String(err)
|
|
173
|
+
}
|
|
174
|
+
throw err
|
|
175
|
+
} finally {
|
|
176
|
+
const duration = Date.now() - start
|
|
177
|
+
this.db
|
|
178
|
+
.prepare(
|
|
179
|
+
`INSERT INTO ai_search_requests (id, namespace, operation, input_summary, output_summary, duration_ms, status, error, created_at)
|
|
180
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
181
|
+
)
|
|
182
|
+
.run(id, this.namespace, operation, truncate(body), outputSummary, duration, status, error ?? null, start)
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|