lopata 0.19.2 → 0.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -161,6 +161,10 @@ export function buildWorkerEnv(
161
161
  // SQLITE_BUSY instead of waiting.
162
162
  db.run('PRAGMA busy_timeout=5000')
163
163
  runMigrations(db)
164
+ // Expose this thread's DB handle so the fetch patch (plugin.ts) can serve the
165
+ // intercepted Analytics Engine SQL API from this DO worker's data dir.
166
+ const threadGlobals = globalThis as { __lopata_db?: Database }
167
+ threadGlobals.__lopata_db = db
164
168
 
165
169
  const env: Record<string, unknown> = {}
166
170
 
package/src/plugin.ts CHANGED
@@ -1,4 +1,6 @@
1
1
  import { plugin } from 'bun'
2
+ import type { Database } from 'bun:sqlite'
3
+ import { buildAnalyticsEngineSqlResponse, isAnalyticsEngineSqlUrl, isLocalAnalyticsEngineToken } from './bindings/analytics-engine-sql'
2
4
  import type { ImageTransformOptions, OutputOptions } from './bindings/images'
3
5
  import { setupCloudflareGlobals } from './setup-globals'
4
6
  import { getActiveContext } from './tracing/context'
@@ -158,6 +160,41 @@ async function applyCfImageTransform(response: Response, imageOpts: Record<strin
158
160
 
159
161
  const _originalFetch = globalThis.fetch
160
162
  globalThis.fetch = ((input: any, init?: any): Promise<Response> => {
163
+ // Intercept the Cloudflare Analytics Engine SQL API (no Worker binding exists
164
+ // for reads) and serve it from the local SQLite store — same code runs in dev
165
+ // and prod unchanged.
166
+ const aeMethod = String(init?.method ?? (input instanceof Request ? input.method : 'GET')).toUpperCase()
167
+ const aeUrl = typeof input === 'string'
168
+ ? input
169
+ : input instanceof URL
170
+ ? input.href
171
+ : input instanceof Request
172
+ ? input.url
173
+ : undefined
174
+ // Gate on the bearer token: missing or `Bearer local` is served locally; a real
175
+ // token falls through to the actual Cloudflare API (prod).
176
+ const aeAuth = new Headers(init?.headers ?? (input instanceof Request ? input.headers : undefined)).get('authorization')
177
+ if (aeMethod === 'POST' && typeof aeUrl === 'string' && isAnalyticsEngineSqlUrl(aeUrl) && isLocalAnalyticsEngineToken(aeAuth)) {
178
+ // Set per worker-thread by buildThreadEnv / buildDoWorkerEnv before user code
179
+ // runs. Fail loudly rather than fall back to a possibly-wrong data dir, which
180
+ // would return plausible but incorrect numbers.
181
+ const db = (globalThis as { __lopata_db?: Database }).__lopata_db
182
+ if (!db) throw new Error('Analytics Engine SQL API was intercepted before the worker-thread database was wired')
183
+ const aeReq = new Request(input, init)
184
+ if (!getActiveContext()) return aeReq.text().then(sql => buildAnalyticsEngineSqlResponse(db, sql))
185
+ return startSpan({
186
+ name: 'analytics_engine sql',
187
+ kind: 'client',
188
+ attributes: { 'http.method': 'POST', 'http.url': aeUrl },
189
+ }, async () => {
190
+ const sql = (await aeReq.text()).trim()
191
+ if (sql) setSpanAttribute('db.statement', sql)
192
+ const res = buildAnalyticsEngineSqlResponse(db, sql)
193
+ setSpanAttribute('http.status_code', res.status)
194
+ return res
195
+ })
196
+ }
197
+
161
198
  const ctx = getActiveContext()
162
199
  if (ctx) {
163
200
  ctx.fetchStack.current = new Error()
@@ -67,6 +67,10 @@ export function buildThreadEnv({ config, baseDir, dataDir, rpc, envWsBridge, bro
67
67
  db.run('PRAGMA journal_mode=WAL')
68
68
  db.run('PRAGMA busy_timeout=5000')
69
69
  runMigrations(db)
70
+ // Expose this thread's DB handle so the fetch patch (plugin.ts) can serve the
71
+ // intercepted Analytics Engine SQL API from the right data dir in multi-worker setups.
72
+ const threadGlobals = globalThis as { __lopata_db?: Database }
73
+ threadGlobals.__lopata_db = db
70
74
 
71
75
  const env: Record<string, unknown> = {}
72
76