@llmops/sdk 1.0.0-beta.2 → 1.0.0-beta.22
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/agents.cjs +1 -1
- package/dist/agents.d.cts +1 -1
- package/dist/agents.d.mts +1 -1
- package/dist/agents.mjs +1 -1
- package/dist/chunk-CxwUPGYo.mjs +21 -0
- package/dist/constants--ywcWP7q.cjs +18 -0
- package/dist/constants-BvnYU_pl.mjs +12 -0
- package/dist/eval.cjs +367 -0
- package/dist/eval.d.cts +200 -0
- package/dist/eval.d.mts +200 -0
- package/dist/eval.mjs +364 -0
- package/dist/express.cjs +29 -2
- package/dist/express.d.cts +7 -3
- package/dist/express.d.mts +7 -3
- package/dist/express.mjs +28 -1
- package/dist/hono.d.cts +2 -2
- package/dist/hono.d.mts +2 -2
- package/dist/{index-05byZKeu.d.mts → index-BZLzywwb.d.mts} +1 -1
- package/dist/{index-Beb26ZNG.d.cts → index-lgspeSNr.d.cts} +1 -1
- package/dist/index.cjs +3 -3
- package/dist/index.d.cts +4 -4
- package/dist/index.d.mts +4 -4
- package/dist/index.mjs +3 -3
- package/dist/interface-BbAwy96d.d.cts +223 -0
- package/dist/interface-Dz7B6QN1.d.mts +223 -0
- package/dist/nextjs.d.cts +2 -2
- package/dist/nextjs.d.mts +2 -2
- package/dist/store/d1.cjs +512 -0
- package/dist/store/d1.d.cts +60 -0
- package/dist/store/d1.d.mts +60 -0
- package/dist/store/d1.mjs +511 -0
- package/dist/store/pg.cjs +13634 -6
- package/dist/store/pg.d.cts +38 -2
- package/dist/store/pg.d.mts +38 -2
- package/dist/store/pg.mjs +13618 -2
- package/dist/store/sqlite.cjs +541 -0
- package/dist/store/sqlite.d.cts +50 -0
- package/dist/store/sqlite.d.mts +50 -0
- package/dist/store/sqlite.mjs +541 -0
- package/dist/types.d.cts +2 -2
- package/dist/types.d.mts +2 -2
- package/package.json +48 -3
- package/dist/express-B-wbCza5.cjs +0 -35
- package/dist/express-DMtc0d_Y.mjs +0 -30
- package/dist/index-DnWGper4.d.cts +0 -7
- package/dist/index-Dvz-L2Hf.d.mts +0 -7
- /package/dist/{agents-exporter-vcpgCF69.mjs → agents-exporter-CGxTzDeQ.mjs} +0 -0
- /package/dist/{agents-exporter-BZHCcFSd.d.mts → agents-exporter-CehKIArI.d.mts} +0 -0
- /package/dist/{agents-exporter-BuTq2n2y.cjs → agents-exporter-DizRE7CQ.cjs} +0 -0
- /package/dist/{agents-exporter-uzN3bkth.d.cts → agents-exporter-DkqkCcIx.d.cts} +0 -0
|
@@ -0,0 +1,541 @@
|
|
|
1
|
+
let node_crypto = require("node:crypto");
|
|
2
|
+
|
|
3
|
+
//#region src/store/sqlite/sqlite-store.ts
|
|
4
|
+
const JSON_COLUMNS = new Set([
|
|
5
|
+
"tags",
|
|
6
|
+
"metadata",
|
|
7
|
+
"attributes",
|
|
8
|
+
"guardrailResults",
|
|
9
|
+
"input",
|
|
10
|
+
"output"
|
|
11
|
+
]);
|
|
12
|
+
function parseJsonColumns(row) {
|
|
13
|
+
if (!row || typeof row !== "object") return row;
|
|
14
|
+
const parsed = { ...row };
|
|
15
|
+
for (const key of Object.keys(parsed)) if (JSON_COLUMNS.has(key) && typeof parsed[key] === "string") try {
|
|
16
|
+
parsed[key] = JSON.parse(parsed[key]);
|
|
17
|
+
} catch {}
|
|
18
|
+
return parsed;
|
|
19
|
+
}
|
|
20
|
+
function parseJsonRows(rows) {
|
|
21
|
+
return rows.map(parseJsonColumns);
|
|
22
|
+
}
|
|
23
|
+
function buildTagFilters(tags) {
|
|
24
|
+
const conditions = [];
|
|
25
|
+
const params = [];
|
|
26
|
+
if (!tags) return {
|
|
27
|
+
conditions,
|
|
28
|
+
params
|
|
29
|
+
};
|
|
30
|
+
for (const [key, values] of Object.entries(tags)) {
|
|
31
|
+
if (values.length === 0) continue;
|
|
32
|
+
if (values.length === 1) {
|
|
33
|
+
conditions.push(`json_extract("tags", '$.' || ?) = ?`);
|
|
34
|
+
params.push(key, values[0]);
|
|
35
|
+
} else {
|
|
36
|
+
const placeholders = values.map(() => "?").join(", ");
|
|
37
|
+
conditions.push(`json_extract("tags", '$.' || ?) IN (${placeholders})`);
|
|
38
|
+
params.push(key, ...values);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return {
|
|
42
|
+
conditions,
|
|
43
|
+
params
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
function createSQLiteLLMRequestsStore(db) {
|
|
47
|
+
const insertStmt = `
|
|
48
|
+
INSERT INTO "llm_requests" (
|
|
49
|
+
"id","requestId","configId","variantId","environmentId",
|
|
50
|
+
"providerConfigId","provider","model","promptTokens",
|
|
51
|
+
"completionTokens","totalTokens","cachedTokens",
|
|
52
|
+
"cacheCreationTokens","cost","cacheSavings","inputCost",
|
|
53
|
+
"outputCost","endpoint","statusCode","latencyMs","isStreaming",
|
|
54
|
+
"userId","tags","guardrailResults","traceId","spanId",
|
|
55
|
+
"parentSpanId","sessionId","createdAt","updatedAt"
|
|
56
|
+
) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
|
|
57
|
+
`;
|
|
58
|
+
function bindRequest(req, now) {
|
|
59
|
+
return [
|
|
60
|
+
(0, node_crypto.randomUUID)(),
|
|
61
|
+
req.requestId,
|
|
62
|
+
req.configId ?? null,
|
|
63
|
+
req.variantId ?? null,
|
|
64
|
+
req.environmentId ?? null,
|
|
65
|
+
req.providerConfigId ?? null,
|
|
66
|
+
req.provider,
|
|
67
|
+
req.model,
|
|
68
|
+
req.promptTokens ?? 0,
|
|
69
|
+
req.completionTokens ?? 0,
|
|
70
|
+
req.totalTokens ?? 0,
|
|
71
|
+
req.cachedTokens ?? 0,
|
|
72
|
+
req.cacheCreationTokens ?? 0,
|
|
73
|
+
req.cost ?? 0,
|
|
74
|
+
req.cacheSavings ?? 0,
|
|
75
|
+
req.inputCost ?? 0,
|
|
76
|
+
req.outputCost ?? 0,
|
|
77
|
+
req.endpoint,
|
|
78
|
+
req.statusCode,
|
|
79
|
+
req.latencyMs ?? 0,
|
|
80
|
+
req.isStreaming ? 1 : 0,
|
|
81
|
+
req.userId ?? null,
|
|
82
|
+
JSON.stringify(req.tags ?? {}),
|
|
83
|
+
req.guardrailResults ? JSON.stringify(req.guardrailResults) : null,
|
|
84
|
+
req.traceId ?? null,
|
|
85
|
+
req.spanId ?? null,
|
|
86
|
+
req.parentSpanId ?? null,
|
|
87
|
+
req.sessionId ?? null,
|
|
88
|
+
now,
|
|
89
|
+
now
|
|
90
|
+
];
|
|
91
|
+
}
|
|
92
|
+
return {
|
|
93
|
+
batchInsertRequests: async (requests) => {
|
|
94
|
+
if (requests.length === 0) return { count: 0 };
|
|
95
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
96
|
+
const stmt = db.prepare(insertStmt);
|
|
97
|
+
for (const req of requests) stmt.run(...bindRequest(req, now));
|
|
98
|
+
return { count: requests.length };
|
|
99
|
+
},
|
|
100
|
+
insertRequest: async (req) => {
|
|
101
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
102
|
+
db.prepare(insertStmt).run(...bindRequest(req, now));
|
|
103
|
+
const row = db.prepare(`SELECT * FROM "llm_requests" WHERE "requestId" = ?`).get(req.requestId);
|
|
104
|
+
return row ? parseJsonColumns(row) : null;
|
|
105
|
+
},
|
|
106
|
+
listRequests: async (params) => {
|
|
107
|
+
const { limit = 100, offset = 0, configId, variantId, environmentId, providerConfigId, provider, model, startDate, endDate, tags } = params ?? {};
|
|
108
|
+
const conditions = ["1=1"];
|
|
109
|
+
const queryParams = [];
|
|
110
|
+
if (configId) {
|
|
111
|
+
conditions.push(`"configId" = ?`);
|
|
112
|
+
queryParams.push(configId);
|
|
113
|
+
}
|
|
114
|
+
if (variantId) {
|
|
115
|
+
conditions.push(`"variantId" = ?`);
|
|
116
|
+
queryParams.push(variantId);
|
|
117
|
+
}
|
|
118
|
+
if (environmentId) {
|
|
119
|
+
conditions.push(`"environmentId" = ?`);
|
|
120
|
+
queryParams.push(environmentId);
|
|
121
|
+
}
|
|
122
|
+
if (providerConfigId) {
|
|
123
|
+
conditions.push(`"providerConfigId" = ?`);
|
|
124
|
+
queryParams.push(providerConfigId);
|
|
125
|
+
}
|
|
126
|
+
if (provider) {
|
|
127
|
+
conditions.push(`"provider" = ?`);
|
|
128
|
+
queryParams.push(provider);
|
|
129
|
+
}
|
|
130
|
+
if (model) {
|
|
131
|
+
conditions.push(`"model" = ?`);
|
|
132
|
+
queryParams.push(model);
|
|
133
|
+
}
|
|
134
|
+
if (startDate) {
|
|
135
|
+
conditions.push(`"createdAt" >= ?`);
|
|
136
|
+
queryParams.push(startDate.toISOString());
|
|
137
|
+
}
|
|
138
|
+
if (endDate) {
|
|
139
|
+
conditions.push(`"createdAt" <= ?`);
|
|
140
|
+
queryParams.push(endDate.toISOString());
|
|
141
|
+
}
|
|
142
|
+
const tagFilter = buildTagFilters(tags);
|
|
143
|
+
conditions.push(...tagFilter.conditions);
|
|
144
|
+
queryParams.push(...tagFilter.params);
|
|
145
|
+
const where = conditions.join(" AND ");
|
|
146
|
+
const total = db.prepare(`SELECT COUNT(*) AS "total" FROM "llm_requests" WHERE ${where}`).get(...queryParams)?.total ?? 0;
|
|
147
|
+
return {
|
|
148
|
+
data: parseJsonRows(db.prepare(`SELECT * FROM "llm_requests" WHERE ${where} ORDER BY "createdAt" DESC LIMIT ? OFFSET ?`).all(...queryParams, limit, offset)),
|
|
149
|
+
total,
|
|
150
|
+
limit,
|
|
151
|
+
offset
|
|
152
|
+
};
|
|
153
|
+
},
|
|
154
|
+
getRequestByRequestId: async (requestId) => {
|
|
155
|
+
const row = db.prepare(`SELECT * FROM "llm_requests" WHERE "requestId" = ?`).get(requestId);
|
|
156
|
+
return row ? parseJsonColumns(row) : void 0;
|
|
157
|
+
},
|
|
158
|
+
getTotalCost: async (params) => {
|
|
159
|
+
const conditions = [`"createdAt" >= ?`, `"createdAt" <= ?`];
|
|
160
|
+
const queryParams = [params.startDate.toISOString(), params.endDate.toISOString()];
|
|
161
|
+
if (params.configId) {
|
|
162
|
+
conditions.push(`"configId" = ?`);
|
|
163
|
+
queryParams.push(params.configId);
|
|
164
|
+
}
|
|
165
|
+
if (params.variantId) {
|
|
166
|
+
conditions.push(`"variantId" = ?`);
|
|
167
|
+
queryParams.push(params.variantId);
|
|
168
|
+
}
|
|
169
|
+
if (params.environmentId) {
|
|
170
|
+
conditions.push(`"environmentId" = ?`);
|
|
171
|
+
queryParams.push(params.environmentId);
|
|
172
|
+
}
|
|
173
|
+
const tagFilter = buildTagFilters(params.tags);
|
|
174
|
+
conditions.push(...tagFilter.conditions);
|
|
175
|
+
queryParams.push(...tagFilter.params);
|
|
176
|
+
const where = conditions.join(" AND ");
|
|
177
|
+
return db.prepare(`
|
|
178
|
+
SELECT
|
|
179
|
+
COALESCE(SUM("cost"), 0) AS "totalCost",
|
|
180
|
+
COALESCE(SUM("inputCost"), 0) AS "totalInputCost",
|
|
181
|
+
COALESCE(SUM("outputCost"), 0) AS "totalOutputCost",
|
|
182
|
+
COALESCE(SUM("promptTokens"), 0) AS "totalPromptTokens",
|
|
183
|
+
COALESCE(SUM("completionTokens"), 0) AS "totalCompletionTokens",
|
|
184
|
+
COALESCE(SUM("totalTokens"), 0) AS "totalTokens",
|
|
185
|
+
COALESCE(SUM("cachedTokens"), 0) AS "totalCachedTokens",
|
|
186
|
+
COALESCE(SUM("cacheSavings"), 0) AS "totalCacheSavings",
|
|
187
|
+
COUNT(*) AS "requestCount"
|
|
188
|
+
FROM "llm_requests" WHERE ${where}
|
|
189
|
+
`).get(...queryParams);
|
|
190
|
+
},
|
|
191
|
+
getCostByModel: async (params) => {
|
|
192
|
+
return db.prepare(`
|
|
193
|
+
SELECT "provider", "model",
|
|
194
|
+
COALESCE(SUM("cost"), 0) AS "totalCost",
|
|
195
|
+
COALESCE(SUM("inputCost"), 0) AS "totalInputCost",
|
|
196
|
+
COALESCE(SUM("outputCost"), 0) AS "totalOutputCost",
|
|
197
|
+
COALESCE(SUM("totalTokens"), 0) AS "totalTokens",
|
|
198
|
+
COUNT(*) AS "requestCount",
|
|
199
|
+
AVG("latencyMs") AS "avgLatencyMs"
|
|
200
|
+
FROM "llm_requests"
|
|
201
|
+
WHERE "createdAt" >= ? AND "createdAt" <= ?
|
|
202
|
+
GROUP BY "provider", "model"
|
|
203
|
+
ORDER BY SUM("cost") DESC
|
|
204
|
+
`).all(params.startDate.toISOString(), params.endDate.toISOString());
|
|
205
|
+
},
|
|
206
|
+
getCostByProvider: async (params) => {
|
|
207
|
+
return db.prepare(`
|
|
208
|
+
SELECT "provider",
|
|
209
|
+
COALESCE(SUM("cost"), 0) AS "totalCost",
|
|
210
|
+
COALESCE(SUM("inputCost"), 0) AS "totalInputCost",
|
|
211
|
+
COALESCE(SUM("outputCost"), 0) AS "totalOutputCost",
|
|
212
|
+
COALESCE(SUM("totalTokens"), 0) AS "totalTokens",
|
|
213
|
+
COUNT(*) AS "requestCount",
|
|
214
|
+
AVG("latencyMs") AS "avgLatencyMs"
|
|
215
|
+
FROM "llm_requests"
|
|
216
|
+
WHERE "createdAt" >= ? AND "createdAt" <= ?
|
|
217
|
+
GROUP BY "provider"
|
|
218
|
+
ORDER BY SUM("cost") DESC
|
|
219
|
+
`).all(params.startDate.toISOString(), params.endDate.toISOString());
|
|
220
|
+
},
|
|
221
|
+
getDailyCosts: async (params) => {
|
|
222
|
+
return db.prepare(`
|
|
223
|
+
SELECT date("createdAt") AS "date",
|
|
224
|
+
COALESCE(SUM("cost"), 0) AS "totalCost",
|
|
225
|
+
COALESCE(SUM("inputCost"), 0) AS "totalInputCost",
|
|
226
|
+
COALESCE(SUM("outputCost"), 0) AS "totalOutputCost",
|
|
227
|
+
COALESCE(SUM("totalTokens"), 0) AS "totalTokens",
|
|
228
|
+
COUNT(*) AS "requestCount"
|
|
229
|
+
FROM "llm_requests"
|
|
230
|
+
WHERE "createdAt" >= ? AND "createdAt" <= ?
|
|
231
|
+
GROUP BY date("createdAt")
|
|
232
|
+
ORDER BY date("createdAt") ASC
|
|
233
|
+
`).all(params.startDate.toISOString(), params.endDate.toISOString());
|
|
234
|
+
},
|
|
235
|
+
getCostSummary: async (params) => {
|
|
236
|
+
const { startDate, endDate, groupBy, configId, variantId, environmentId, tags, tagKeys } = params;
|
|
237
|
+
const conditions = [`"createdAt" >= ?`, `"createdAt" <= ?`];
|
|
238
|
+
const queryParams = [startDate.toISOString(), endDate.toISOString()];
|
|
239
|
+
if (configId) {
|
|
240
|
+
conditions.push(`"configId" = ?`);
|
|
241
|
+
queryParams.push(configId);
|
|
242
|
+
}
|
|
243
|
+
if (variantId) {
|
|
244
|
+
conditions.push(`"variantId" = ?`);
|
|
245
|
+
queryParams.push(variantId);
|
|
246
|
+
}
|
|
247
|
+
if (environmentId) {
|
|
248
|
+
conditions.push(`"environmentId" = ?`);
|
|
249
|
+
queryParams.push(environmentId);
|
|
250
|
+
}
|
|
251
|
+
const tagFilter = buildTagFilters(tags);
|
|
252
|
+
conditions.push(...tagFilter.conditions);
|
|
253
|
+
queryParams.push(...tagFilter.params);
|
|
254
|
+
const where = conditions.join(" AND ");
|
|
255
|
+
if (groupBy === "tags") {
|
|
256
|
+
const tagConditions = [...conditions];
|
|
257
|
+
const tagParams = [...queryParams];
|
|
258
|
+
if (tagKeys && tagKeys.length > 0) {
|
|
259
|
+
tagConditions.push(`json_each.key IN (${tagKeys.map(() => "?").join(",")})`);
|
|
260
|
+
tagParams.push(...tagKeys);
|
|
261
|
+
}
|
|
262
|
+
const tagWhere = tagConditions.join(" AND ");
|
|
263
|
+
return db.prepare(`
|
|
264
|
+
SELECT json_each.key || ':' || json_each.value AS "groupKey",
|
|
265
|
+
COALESCE(SUM("cost"), 0) AS "totalCost",
|
|
266
|
+
COUNT(*) AS "requestCount"
|
|
267
|
+
FROM "llm_requests", json_each("tags")
|
|
268
|
+
WHERE ${tagWhere}
|
|
269
|
+
GROUP BY json_each.key, json_each.value
|
|
270
|
+
ORDER BY SUM("cost") DESC
|
|
271
|
+
`).all(...tagParams);
|
|
272
|
+
}
|
|
273
|
+
const sqlMap = {
|
|
274
|
+
day: `SELECT date("createdAt") AS "groupKey", COALESCE(SUM("cost"),0) AS "totalCost", COUNT(*) AS "requestCount", COALESCE(SUM("totalTokens"),0) AS "totalTokens" FROM "llm_requests" WHERE ${where} GROUP BY date("createdAt") ORDER BY date("createdAt") ASC`,
|
|
275
|
+
hour: `SELECT strftime('%Y-%m-%d %H:00:00',"createdAt") AS "groupKey", COALESCE(SUM("cost"),0) AS "totalCost", COUNT(*) AS "requestCount", COALESCE(SUM("totalTokens"),0) AS "totalTokens" FROM "llm_requests" WHERE ${where} GROUP BY strftime('%Y-%m-%d %H:00:00',"createdAt") ORDER BY strftime('%Y-%m-%d %H:00:00',"createdAt") ASC`,
|
|
276
|
+
model: `SELECT "provider"||'/'||"model" AS "groupKey", COALESCE(SUM("cost"),0) AS "totalCost", COUNT(*) AS "requestCount" FROM "llm_requests" WHERE ${where} GROUP BY "provider","model" ORDER BY SUM("cost") DESC`,
|
|
277
|
+
provider: `SELECT "provider" AS "groupKey", COALESCE(SUM("cost"),0) AS "totalCost", COUNT(*) AS "requestCount" FROM "llm_requests" WHERE ${where} GROUP BY "provider" ORDER BY SUM("cost") DESC`,
|
|
278
|
+
endpoint: `SELECT COALESCE("endpoint",'unknown') AS "groupKey", COALESCE(SUM("cost"),0) AS "totalCost", COUNT(*) AS "requestCount" FROM "llm_requests" WHERE ${where} GROUP BY "endpoint" ORDER BY SUM("cost") DESC`
|
|
279
|
+
};
|
|
280
|
+
const totalSql = `SELECT 'total' AS "groupKey", COALESCE(SUM("cost"),0) AS "totalCost", COUNT(*) AS "requestCount" FROM "llm_requests" WHERE ${where}`;
|
|
281
|
+
const sql = groupBy ? sqlMap[groupBy] ?? totalSql : totalSql;
|
|
282
|
+
return db.prepare(sql).all(...queryParams);
|
|
283
|
+
},
|
|
284
|
+
getRequestStats: async (params) => {
|
|
285
|
+
const conditions = [`"createdAt" >= ?`, `"createdAt" <= ?`];
|
|
286
|
+
const queryParams = [params.startDate.toISOString(), params.endDate.toISOString()];
|
|
287
|
+
if (params.configId) {
|
|
288
|
+
conditions.push(`"configId" = ?`);
|
|
289
|
+
queryParams.push(params.configId);
|
|
290
|
+
}
|
|
291
|
+
if (params.variantId) {
|
|
292
|
+
conditions.push(`"variantId" = ?`);
|
|
293
|
+
queryParams.push(params.variantId);
|
|
294
|
+
}
|
|
295
|
+
if (params.environmentId) {
|
|
296
|
+
conditions.push(`"environmentId" = ?`);
|
|
297
|
+
queryParams.push(params.environmentId);
|
|
298
|
+
}
|
|
299
|
+
const tagFilter = buildTagFilters(params.tags);
|
|
300
|
+
conditions.push(...tagFilter.conditions);
|
|
301
|
+
queryParams.push(...tagFilter.params);
|
|
302
|
+
const where = conditions.join(" AND ");
|
|
303
|
+
return db.prepare(`
|
|
304
|
+
SELECT
|
|
305
|
+
COUNT(*) AS "totalRequests",
|
|
306
|
+
COUNT(CASE WHEN "statusCode">=200 AND "statusCode"<300 THEN 1 END) AS "successfulRequests",
|
|
307
|
+
COUNT(CASE WHEN "statusCode">=400 THEN 1 END) AS "failedRequests",
|
|
308
|
+
COUNT(CASE WHEN "isStreaming"=1 THEN 1 END) AS "streamingRequests",
|
|
309
|
+
AVG("latencyMs") AS "avgLatencyMs",
|
|
310
|
+
MAX("latencyMs") AS "maxLatencyMs",
|
|
311
|
+
MIN("latencyMs") AS "minLatencyMs"
|
|
312
|
+
FROM "llm_requests" WHERE ${where}
|
|
313
|
+
`).get(...queryParams);
|
|
314
|
+
},
|
|
315
|
+
getDistinctTags: async () => {
|
|
316
|
+
return db.prepare(`
|
|
317
|
+
SELECT DISTINCT json_each.key AS key, json_each.value AS value
|
|
318
|
+
FROM "llm_requests", json_each("tags")
|
|
319
|
+
WHERE "tags" != '{}'
|
|
320
|
+
ORDER BY json_each.key, json_each.value
|
|
321
|
+
`).all();
|
|
322
|
+
}
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
function createSQLiteTracesStore(db) {
|
|
326
|
+
return {
|
|
327
|
+
upsertTrace: async (data) => {
|
|
328
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
329
|
+
db.prepare(`
|
|
330
|
+
INSERT INTO "traces" (
|
|
331
|
+
"id","traceId","name","sessionId","userId","status",
|
|
332
|
+
"startTime","endTime","durationMs","spanCount",
|
|
333
|
+
"totalInputTokens","totalOutputTokens","totalTokens","totalCost",
|
|
334
|
+
"tags","metadata","createdAt","updatedAt"
|
|
335
|
+
) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
|
|
336
|
+
ON CONFLICT ("traceId") DO UPDATE SET
|
|
337
|
+
"name" = COALESCE(EXCLUDED."name", "traces"."name"),
|
|
338
|
+
"sessionId" = COALESCE(EXCLUDED."sessionId", "traces"."sessionId"),
|
|
339
|
+
"userId" = COALESCE(EXCLUDED."userId", "traces"."userId"),
|
|
340
|
+
"status" = CASE
|
|
341
|
+
WHEN EXCLUDED."status" = 'error' THEN 'error'
|
|
342
|
+
WHEN EXCLUDED."status" = 'ok' AND "traces"."status" != 'error' THEN 'ok'
|
|
343
|
+
ELSE "traces"."status"
|
|
344
|
+
END,
|
|
345
|
+
"startTime" = MIN("traces"."startTime", EXCLUDED."startTime"),
|
|
346
|
+
"endTime" = MAX(
|
|
347
|
+
COALESCE("traces"."endTime", EXCLUDED."endTime"),
|
|
348
|
+
COALESCE(EXCLUDED."endTime", "traces"."endTime")
|
|
349
|
+
),
|
|
350
|
+
"durationMs" = CAST(
|
|
351
|
+
(julianday(MAX(
|
|
352
|
+
COALESCE("traces"."endTime", EXCLUDED."endTime"),
|
|
353
|
+
COALESCE(EXCLUDED."endTime", "traces"."endTime")
|
|
354
|
+
)) - julianday(MIN("traces"."startTime", EXCLUDED."startTime")))
|
|
355
|
+
* 86400000 AS INTEGER
|
|
356
|
+
),
|
|
357
|
+
"spanCount" = "traces"."spanCount" + EXCLUDED."spanCount",
|
|
358
|
+
"totalInputTokens" = "traces"."totalInputTokens" + EXCLUDED."totalInputTokens",
|
|
359
|
+
"totalOutputTokens" = "traces"."totalOutputTokens" + EXCLUDED."totalOutputTokens",
|
|
360
|
+
"totalTokens" = "traces"."totalTokens" + EXCLUDED."totalTokens",
|
|
361
|
+
"totalCost" = "traces"."totalCost" + EXCLUDED."totalCost",
|
|
362
|
+
"tags" = json_patch("traces"."tags", EXCLUDED."tags"),
|
|
363
|
+
"metadata" = json_patch("traces"."metadata", EXCLUDED."metadata"),
|
|
364
|
+
"updatedAt" = ?
|
|
365
|
+
`).run((0, node_crypto.randomUUID)(), data.traceId, data.name ?? null, data.sessionId ?? null, data.userId ?? null, data.status ?? "unset", data.startTime.toISOString(), data.endTime?.toISOString() ?? null, data.durationMs ?? null, data.spanCount ?? 1, data.totalInputTokens ?? 0, data.totalOutputTokens ?? 0, data.totalTokens ?? 0, data.totalCost ?? 0, JSON.stringify(data.tags ?? {}), JSON.stringify(data.metadata ?? {}), now, now, now);
|
|
366
|
+
},
|
|
367
|
+
batchInsertSpans: async (spans) => {
|
|
368
|
+
if (spans.length === 0) return { count: 0 };
|
|
369
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
370
|
+
const stmt = db.prepare(`
|
|
371
|
+
INSERT OR IGNORE INTO "spans" (
|
|
372
|
+
"id","traceId","spanId","parentSpanId","name","kind",
|
|
373
|
+
"status","statusMessage","startTime","endTime","durationMs",
|
|
374
|
+
"provider","model","promptTokens","completionTokens",
|
|
375
|
+
"totalTokens","cost","configId","variantId","environmentId",
|
|
376
|
+
"providerConfigId","requestId","source","input","output",
|
|
377
|
+
"attributes","createdAt","updatedAt"
|
|
378
|
+
) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
|
|
379
|
+
`);
|
|
380
|
+
for (const s of spans) stmt.run((0, node_crypto.randomUUID)(), s.traceId, s.spanId, s.parentSpanId ?? null, s.name, s.kind ?? 1, s.status ?? 0, s.statusMessage ?? null, s.startTime.toISOString(), s.endTime?.toISOString() ?? null, s.durationMs ?? null, s.provider ?? null, s.model ?? null, s.promptTokens ?? 0, s.completionTokens ?? 0, s.totalTokens ?? 0, s.cost ?? 0, s.configId ?? null, s.variantId ?? null, s.environmentId ?? null, s.providerConfigId ?? null, s.requestId ?? null, s.source ?? "gateway", s.input != null ? JSON.stringify(s.input) : null, s.output != null ? JSON.stringify(s.output) : null, JSON.stringify(s.attributes ?? {}), now, now);
|
|
381
|
+
return { count: spans.length };
|
|
382
|
+
},
|
|
383
|
+
batchInsertSpanEvents: async (events) => {
|
|
384
|
+
if (events.length === 0) return { count: 0 };
|
|
385
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
386
|
+
const stmt = db.prepare(`
|
|
387
|
+
INSERT INTO "span_events" (
|
|
388
|
+
"id","traceId","spanId","name","timestamp","attributes","createdAt"
|
|
389
|
+
) VALUES (?,?,?,?,?,?,?)
|
|
390
|
+
`);
|
|
391
|
+
for (const e of events) stmt.run((0, node_crypto.randomUUID)(), e.traceId, e.spanId, e.name, e.timestamp.toISOString(), JSON.stringify(e.attributes ?? {}), now);
|
|
392
|
+
return { count: events.length };
|
|
393
|
+
},
|
|
394
|
+
listTraces: async (params) => {
|
|
395
|
+
const { limit = 50, offset = 0, sessionId, userId, status, name, startDate, endDate, tags } = params ?? {};
|
|
396
|
+
const conditions = ["1=1"];
|
|
397
|
+
const queryParams = [];
|
|
398
|
+
if (sessionId) {
|
|
399
|
+
conditions.push(`"sessionId" = ?`);
|
|
400
|
+
queryParams.push(sessionId);
|
|
401
|
+
}
|
|
402
|
+
if (userId) {
|
|
403
|
+
conditions.push(`"userId" = ?`);
|
|
404
|
+
queryParams.push(userId);
|
|
405
|
+
}
|
|
406
|
+
if (status) {
|
|
407
|
+
conditions.push(`"status" = ?`);
|
|
408
|
+
queryParams.push(status);
|
|
409
|
+
}
|
|
410
|
+
if (name) {
|
|
411
|
+
conditions.push(`"name" LIKE ?`);
|
|
412
|
+
queryParams.push(`%${name}%`);
|
|
413
|
+
}
|
|
414
|
+
if (startDate) {
|
|
415
|
+
conditions.push(`"startTime" >= ?`);
|
|
416
|
+
queryParams.push(startDate.toISOString());
|
|
417
|
+
}
|
|
418
|
+
if (endDate) {
|
|
419
|
+
conditions.push(`"startTime" <= ?`);
|
|
420
|
+
queryParams.push(endDate.toISOString());
|
|
421
|
+
}
|
|
422
|
+
const tagFilter = buildTagFilters(tags);
|
|
423
|
+
conditions.push(...tagFilter.conditions);
|
|
424
|
+
queryParams.push(...tagFilter.params);
|
|
425
|
+
const where = conditions.join(" AND ");
|
|
426
|
+
const total = db.prepare(`SELECT COUNT(*) AS "total" FROM "traces" WHERE ${where}`).get(...queryParams)?.total ?? 0;
|
|
427
|
+
return {
|
|
428
|
+
data: parseJsonRows(db.prepare(`SELECT * FROM "traces" WHERE ${where} ORDER BY "startTime" DESC LIMIT ? OFFSET ?`).all(...queryParams, limit, offset)),
|
|
429
|
+
total,
|
|
430
|
+
limit,
|
|
431
|
+
offset
|
|
432
|
+
};
|
|
433
|
+
},
|
|
434
|
+
getTraceWithSpans: async (traceId) => {
|
|
435
|
+
const trace = db.prepare(`SELECT * FROM "traces" WHERE "traceId" = ?`).get(traceId);
|
|
436
|
+
if (!trace) return void 0;
|
|
437
|
+
const spans = db.prepare(`SELECT * FROM "spans" WHERE "traceId" = ? ORDER BY "startTime" ASC`).all(traceId);
|
|
438
|
+
const events = db.prepare(`SELECT * FROM "span_events" WHERE "traceId" = ? ORDER BY "timestamp" ASC`).all(traceId);
|
|
439
|
+
return {
|
|
440
|
+
trace: parseJsonColumns(trace),
|
|
441
|
+
spans: parseJsonRows(spans),
|
|
442
|
+
events: parseJsonRows(events)
|
|
443
|
+
};
|
|
444
|
+
},
|
|
445
|
+
getTraceStats: async (params) => {
|
|
446
|
+
const conditions = [`"startTime" >= ?`, `"startTime" <= ?`];
|
|
447
|
+
const queryParams = [params.startDate.toISOString(), params.endDate.toISOString()];
|
|
448
|
+
if (params.sessionId) {
|
|
449
|
+
conditions.push(`"sessionId" = ?`);
|
|
450
|
+
queryParams.push(params.sessionId);
|
|
451
|
+
}
|
|
452
|
+
if (params.userId) {
|
|
453
|
+
conditions.push(`"userId" = ?`);
|
|
454
|
+
queryParams.push(params.userId);
|
|
455
|
+
}
|
|
456
|
+
const where = conditions.join(" AND ");
|
|
457
|
+
return db.prepare(`
|
|
458
|
+
SELECT
|
|
459
|
+
COUNT(*) AS "totalTraces",
|
|
460
|
+
COALESCE(AVG("durationMs"), 0) AS "avgDurationMs",
|
|
461
|
+
COUNT(CASE WHEN "status" = 'error' THEN 1 END) AS "errorCount",
|
|
462
|
+
COALESCE(SUM("totalCost"), 0) AS "totalCost",
|
|
463
|
+
COALESCE(SUM("totalTokens"), 0) AS "totalTokens",
|
|
464
|
+
COALESCE(SUM("spanCount"), 0) AS "totalSpans"
|
|
465
|
+
FROM "traces" WHERE ${where}
|
|
466
|
+
`).get(...queryParams);
|
|
467
|
+
}
|
|
468
|
+
};
|
|
469
|
+
}
|
|
470
|
+
/**
|
|
471
|
+
* Open a SQLite database, trying better-sqlite3 first, then node:sqlite.
|
|
472
|
+
*/
|
|
473
|
+
function openDatabase(path) {
|
|
474
|
+
try {
|
|
475
|
+
return new (require("better-sqlite3"))(path);
|
|
476
|
+
} catch {}
|
|
477
|
+
try {
|
|
478
|
+
const { DatabaseSync } = require("node:sqlite");
|
|
479
|
+
return new DatabaseSync(path);
|
|
480
|
+
} catch {}
|
|
481
|
+
throw new Error("sqliteStore requires either \"better-sqlite3\" or Node.js 22+ (for node:sqlite). Install better-sqlite3 with: pnpm add better-sqlite3");
|
|
482
|
+
}
|
|
483
|
+
/**
|
|
484
|
+
* Create a SQLite-backed telemetry store.
|
|
485
|
+
*
|
|
486
|
+
* Uses better-sqlite3 if available, falls back to node:sqlite (Node 22+).
|
|
487
|
+
*
|
|
488
|
+
* Usage:
|
|
489
|
+
* ```ts
|
|
490
|
+
* import { sqliteStore } from '@llmops/sdk/store/sqlite'
|
|
491
|
+
*
|
|
492
|
+
* const ops = llmops({
|
|
493
|
+
* telemetry: sqliteStore('./llmops.db'),
|
|
494
|
+
* })
|
|
495
|
+
* ```
|
|
496
|
+
*/
|
|
497
|
+
function createSQLiteStore(path) {
|
|
498
|
+
const db = openDatabase(path);
|
|
499
|
+
db.exec("PRAGMA journal_mode = WAL");
|
|
500
|
+
return {
|
|
501
|
+
...createSQLiteLLMRequestsStore(db),
|
|
502
|
+
...createSQLiteTracesStore(db),
|
|
503
|
+
_db: db
|
|
504
|
+
};
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
//#endregion
|
|
508
|
+
//#region src/store/sqlite/migrations/000001_e44e1c4f.sql
|
|
509
|
+
var _000001_e44e1c4f_default = "CREATE TABLE IF NOT EXISTS llm_requests (\n id TEXT PRIMARY KEY,\n \"requestId\" TEXT NOT NULL,\n \"configId\" TEXT,\n \"variantId\" TEXT,\n \"environmentId\" TEXT,\n \"providerConfigId\" TEXT,\n provider TEXT NOT NULL,\n model TEXT NOT NULL,\n \"promptTokens\" INTEGER NOT NULL DEFAULT 0,\n \"completionTokens\" INTEGER NOT NULL DEFAULT 0,\n \"totalTokens\" INTEGER NOT NULL DEFAULT 0,\n \"cachedTokens\" INTEGER NOT NULL DEFAULT 0,\n \"cacheCreationTokens\" INTEGER NOT NULL DEFAULT 0,\n cost INTEGER NOT NULL DEFAULT 0,\n \"cacheSavings\" INTEGER NOT NULL DEFAULT 0,\n \"inputCost\" INTEGER NOT NULL DEFAULT 0,\n \"outputCost\" INTEGER NOT NULL DEFAULT 0,\n endpoint TEXT NOT NULL,\n \"statusCode\" INTEGER NOT NULL,\n \"latencyMs\" INTEGER NOT NULL DEFAULT 0,\n \"isStreaming\" INTEGER NOT NULL DEFAULT 0,\n \"userId\" TEXT,\n tags TEXT NOT NULL DEFAULT '{}',\n \"guardrailResults\" TEXT,\n \"traceId\" TEXT,\n \"spanId\" TEXT,\n \"parentSpanId\" TEXT,\n \"sessionId\" TEXT,\n \"createdAt\" TEXT NOT NULL DEFAULT (datetime('now')),\n \"updatedAt\" TEXT NOT NULL DEFAULT (datetime('now'))\n);\n\nCREATE TABLE IF NOT EXISTS span_events (\n id TEXT PRIMARY KEY,\n \"traceId\" TEXT NOT NULL,\n \"spanId\" TEXT NOT NULL,\n name TEXT NOT NULL,\n timestamp TEXT NOT NULL,\n attributes TEXT NOT NULL DEFAULT '{}',\n \"createdAt\" TEXT NOT NULL DEFAULT (datetime('now'))\n);\n\nCREATE TABLE IF NOT EXISTS spans (\n id TEXT PRIMARY KEY,\n \"traceId\" TEXT NOT NULL,\n \"spanId\" TEXT NOT NULL UNIQUE,\n \"parentSpanId\" TEXT,\n name TEXT NOT NULL,\n kind INTEGER NOT NULL DEFAULT 1,\n status INTEGER NOT NULL DEFAULT 0,\n \"statusMessage\" TEXT,\n \"startTime\" TEXT NOT NULL,\n \"endTime\" TEXT,\n \"durationMs\" INTEGER,\n provider TEXT,\n model TEXT,\n \"promptTokens\" INTEGER NOT NULL DEFAULT 0,\n \"completionTokens\" INTEGER NOT NULL DEFAULT 0,\n \"totalTokens\" INTEGER NOT NULL DEFAULT 0,\n cost INTEGER NOT NULL DEFAULT 0,\n \"configId\" TEXT,\n \"variantId\" TEXT,\n \"environmentId\" TEXT,\n \"providerConfigId\" TEXT,\n \"requestId\" TEXT,\n source TEXT NOT NULL DEFAULT 'gateway',\n input TEXT,\n output TEXT,\n attributes TEXT NOT NULL DEFAULT '{}',\n \"createdAt\" TEXT NOT NULL DEFAULT (datetime('now')),\n \"updatedAt\" TEXT NOT NULL DEFAULT (datetime('now'))\n);\n\nCREATE TABLE IF NOT EXISTS traces (\n id TEXT PRIMARY KEY,\n \"traceId\" TEXT NOT NULL UNIQUE,\n name TEXT,\n \"sessionId\" TEXT,\n \"userId\" TEXT,\n status TEXT NOT NULL DEFAULT 'unset',\n \"startTime\" TEXT NOT NULL,\n \"endTime\" TEXT,\n \"durationMs\" INTEGER,\n \"spanCount\" INTEGER NOT NULL DEFAULT 0,\n \"totalInputTokens\" INTEGER NOT NULL DEFAULT 0,\n \"totalOutputTokens\" INTEGER NOT NULL DEFAULT 0,\n \"totalTokens\" INTEGER NOT NULL DEFAULT 0,\n \"totalCost\" INTEGER NOT NULL DEFAULT 0,\n tags TEXT NOT NULL DEFAULT '{}',\n metadata TEXT NOT NULL DEFAULT '{}',\n \"createdAt\" TEXT NOT NULL DEFAULT (datetime('now')),\n \"updatedAt\" TEXT NOT NULL DEFAULT (datetime('now'))\n);\n";
|
|
510
|
+
|
|
511
|
+
//#endregion
|
|
512
|
+
//#region src/store/sqlite/migrations/index.ts
|
|
513
|
+
const migrations = [["000001_e44e1c4f", _000001_e44e1c4f_default]];
|
|
514
|
+
|
|
515
|
+
//#endregion
|
|
516
|
+
//#region src/store/sqlite/migrate.ts
|
|
517
|
+
/**
|
|
518
|
+
* Run pending migrations against a SQLite database.
|
|
519
|
+
*/
|
|
520
|
+
function runSQLiteMigrations(db) {
|
|
521
|
+
db.exec(`
|
|
522
|
+
CREATE TABLE IF NOT EXISTS _llmops_migrations (
|
|
523
|
+
name TEXT PRIMARY KEY,
|
|
524
|
+
applied_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
525
|
+
)
|
|
526
|
+
`);
|
|
527
|
+
const rows = db.prepare("SELECT name FROM _llmops_migrations ORDER BY name").all();
|
|
528
|
+
const applied = new Set(rows.map((r) => r.name));
|
|
529
|
+
const newlyApplied = [];
|
|
530
|
+
for (const [name, sql] of migrations) {
|
|
531
|
+
if (applied.has(name)) continue;
|
|
532
|
+
db.exec(sql);
|
|
533
|
+
db.prepare("INSERT INTO _llmops_migrations (name) VALUES (?)").run(name);
|
|
534
|
+
newlyApplied.push(name);
|
|
535
|
+
}
|
|
536
|
+
return { applied: newlyApplied };
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
//#endregion
|
|
540
|
+
exports.runSQLiteMigrations = runSQLiteMigrations;
|
|
541
|
+
exports.sqliteStore = createSQLiteStore;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { t as TelemetryStore } from "../interface-BbAwy96d.cjs";
|
|
2
|
+
|
|
3
|
+
//#region src/store/sqlite/types.d.ts
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Minimal SQLite database interface.
|
|
7
|
+
* Satisfied by both better-sqlite3 and node:sqlite (DatabaseSync).
|
|
8
|
+
*/
|
|
9
|
+
interface SQLiteDatabase {
|
|
10
|
+
prepare(sql: string): SQLiteStatement;
|
|
11
|
+
exec(sql: string): void;
|
|
12
|
+
close(): void;
|
|
13
|
+
}
|
|
14
|
+
interface SQLiteStatement {
|
|
15
|
+
run(...params: unknown[]): {
|
|
16
|
+
changes: number;
|
|
17
|
+
};
|
|
18
|
+
get(...params: unknown[]): unknown;
|
|
19
|
+
all(...params: unknown[]): unknown[];
|
|
20
|
+
}
|
|
21
|
+
//#endregion
|
|
22
|
+
//#region src/store/sqlite/sqlite-store.d.ts
|
|
23
|
+
type SQLiteStore = TelemetryStore & {
|
|
24
|
+
_db: SQLiteDatabase;
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Create a SQLite-backed telemetry store.
|
|
28
|
+
*
|
|
29
|
+
* Uses better-sqlite3 if available, falls back to node:sqlite (Node 22+).
|
|
30
|
+
*
|
|
31
|
+
* Usage:
|
|
32
|
+
* ```ts
|
|
33
|
+
* import { sqliteStore } from '@llmops/sdk/store/sqlite'
|
|
34
|
+
*
|
|
35
|
+
* const ops = llmops({
|
|
36
|
+
* telemetry: sqliteStore('./llmops.db'),
|
|
37
|
+
* })
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
declare function createSQLiteStore(path: string): SQLiteStore;
|
|
41
|
+
//#endregion
|
|
42
|
+
//#region src/store/sqlite/migrate.d.ts
|
|
43
|
+
/**
|
|
44
|
+
* Run pending migrations against a SQLite database.
|
|
45
|
+
*/
|
|
46
|
+
declare function runSQLiteMigrations(db: SQLiteDatabase): {
|
|
47
|
+
applied: string[];
|
|
48
|
+
};
|
|
49
|
+
//#endregion
|
|
50
|
+
export { type SQLiteDatabase, type SQLiteStore, runSQLiteMigrations, createSQLiteStore as sqliteStore };
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { t as TelemetryStore } from "../interface-Dz7B6QN1.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/store/sqlite/types.d.ts
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Minimal SQLite database interface.
|
|
7
|
+
* Satisfied by both better-sqlite3 and node:sqlite (DatabaseSync).
|
|
8
|
+
*/
|
|
9
|
+
interface SQLiteDatabase {
|
|
10
|
+
prepare(sql: string): SQLiteStatement;
|
|
11
|
+
exec(sql: string): void;
|
|
12
|
+
close(): void;
|
|
13
|
+
}
|
|
14
|
+
interface SQLiteStatement {
|
|
15
|
+
run(...params: unknown[]): {
|
|
16
|
+
changes: number;
|
|
17
|
+
};
|
|
18
|
+
get(...params: unknown[]): unknown;
|
|
19
|
+
all(...params: unknown[]): unknown[];
|
|
20
|
+
}
|
|
21
|
+
//#endregion
|
|
22
|
+
//#region src/store/sqlite/sqlite-store.d.ts
|
|
23
|
+
type SQLiteStore = TelemetryStore & {
|
|
24
|
+
_db: SQLiteDatabase;
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Create a SQLite-backed telemetry store.
|
|
28
|
+
*
|
|
29
|
+
* Uses better-sqlite3 if available, falls back to node:sqlite (Node 22+).
|
|
30
|
+
*
|
|
31
|
+
* Usage:
|
|
32
|
+
* ```ts
|
|
33
|
+
* import { sqliteStore } from '@llmops/sdk/store/sqlite'
|
|
34
|
+
*
|
|
35
|
+
* const ops = llmops({
|
|
36
|
+
* telemetry: sqliteStore('./llmops.db'),
|
|
37
|
+
* })
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
declare function createSQLiteStore(path: string): SQLiteStore;
|
|
41
|
+
//#endregion
|
|
42
|
+
//#region src/store/sqlite/migrate.d.ts
|
|
43
|
+
/**
|
|
44
|
+
* Run pending migrations against a SQLite database.
|
|
45
|
+
*/
|
|
46
|
+
declare function runSQLiteMigrations(db: SQLiteDatabase): {
|
|
47
|
+
applied: string[];
|
|
48
|
+
};
|
|
49
|
+
//#endregion
|
|
50
|
+
export { type SQLiteDatabase, type SQLiteStore, runSQLiteMigrations, createSQLiteStore as sqliteStore };
|