@databob/sdk 0.0.0-stage → 0.0.2
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/LICENSE +202 -0
- package/README.md +180 -2
- package/dist/api.d.ts +17 -0
- package/dist/api.js +13 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +302 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +7 -0
- package/dist/mcp.d.ts +163 -0
- package/dist/mcp.js +307 -0
- package/dist/ops.d.ts +33 -0
- package/dist/ops.js +102 -0
- package/dist/project.d.ts +31 -0
- package/dist/project.js +283 -0
- package/dist/react.d.ts +27 -0
- package/dist/react.js +133 -0
- package/dist/server.d.ts +63 -0
- package/dist/server.js +130 -0
- package/package.json +52 -4
package/dist/cli.js
ADDED
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// databob CLI. Every command prints JSON or plain lines, so agents can drive it.
|
|
3
|
+
import { watch } from "node:fs";
|
|
4
|
+
import { createServer } from "node:http";
|
|
5
|
+
import { relative } from "node:path";
|
|
6
|
+
import { Engine, EngineError, createHandler } from "@databob/engine";
|
|
7
|
+
import { LocalTenants, StaticProjects, toNodeListener } from "@databob/engine/node";
|
|
8
|
+
import { ProjectLoadError, codegen, devState, loadProject, paths, projectConfig, scaffold, writeEnv, } from "./project.js";
|
|
9
|
+
import { cloudSettings, deployProject, openLocal, trackLocal } from "./ops.js";
|
|
10
|
+
import { serveMcp } from "./mcp.js";
|
|
11
|
+
const HELP = `databob: typed analytics you define in code
|
|
12
|
+
|
|
13
|
+
Usage: databob <command> [options]
|
|
14
|
+
|
|
15
|
+
init Create databob/schema.ts and databob/metrics.ts
|
|
16
|
+
dev [--port 4100] Run the local API, watch databob/, regenerate types
|
|
17
|
+
start [--port 4100] Self-host in production. Needs DATABOB_SECRET_KEY,
|
|
18
|
+
DATABOB_SIGNING_KEY, DATABOB_USER_KEY (32+ chars each)
|
|
19
|
+
check Validate the schema and every metric (exit 1 on problems)
|
|
20
|
+
deploy [--url URL] Ship databob/ to databob cloud. Needs DATABOB_URL and
|
|
21
|
+
DATABOB_DEPLOY_KEY (environment or .env.local)
|
|
22
|
+
codegen Write databob/_generated
|
|
23
|
+
describe Print the schema and metrics as JSON
|
|
24
|
+
query <metric> [options] Run a metric on local data and print JSON
|
|
25
|
+
--args '{"range":"7d"}' --tenant <id> --tz <IANA zone> --compare
|
|
26
|
+
track <event> [options] Record one event locally
|
|
27
|
+
--props '{"plan":"pro"}' --tenant <id> --user <id>
|
|
28
|
+
mcp Run the MCP server on stdio, for coding agents:
|
|
29
|
+
claude mcp add databob -- npx databob mcp
|
|
30
|
+
|
|
31
|
+
Data lives in .databob/ (git-ignored). Requires Node 22.13+.`;
|
|
32
|
+
function parse(argv) {
|
|
33
|
+
const flags = { _: [] };
|
|
34
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
35
|
+
const arg = argv[index];
|
|
36
|
+
if (!arg.startsWith("--")) {
|
|
37
|
+
flags._.push(arg);
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
const [name, inline] = arg.slice(2).split("=", 2);
|
|
41
|
+
if (inline !== undefined)
|
|
42
|
+
flags[name] = inline;
|
|
43
|
+
else if (argv[index + 1] !== undefined && !argv[index + 1].startsWith("--"))
|
|
44
|
+
flags[name] = argv[++index];
|
|
45
|
+
else
|
|
46
|
+
flags[name] = true;
|
|
47
|
+
}
|
|
48
|
+
return flags;
|
|
49
|
+
}
|
|
50
|
+
function str(flags, name) {
|
|
51
|
+
const value = flags[name];
|
|
52
|
+
return typeof value === "string" ? value : undefined;
|
|
53
|
+
}
|
|
54
|
+
function jsonFlag(flags, name) {
|
|
55
|
+
const value = str(flags, name);
|
|
56
|
+
if (value === undefined)
|
|
57
|
+
return undefined;
|
|
58
|
+
try {
|
|
59
|
+
return JSON.parse(value);
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
throw new Error(`--${name} must be JSON, for example --${name} '{"range":"7d"}'`);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
function print(value) {
|
|
66
|
+
process.stdout.write(`${JSON.stringify(value, null, 2)}\n`);
|
|
67
|
+
}
|
|
68
|
+
async function loadOrExit(p) {
|
|
69
|
+
const loaded = await loadProject(p);
|
|
70
|
+
if (loaded.problems.length > 0) {
|
|
71
|
+
for (const problem of loaded.problems)
|
|
72
|
+
console.error(`✗ ${problem}`);
|
|
73
|
+
process.exit(1);
|
|
74
|
+
}
|
|
75
|
+
return loaded;
|
|
76
|
+
}
|
|
77
|
+
const MIN_KEY_LENGTH = 32;
|
|
78
|
+
function requiredSecret(name) {
|
|
79
|
+
const value = process.env[name] ?? "";
|
|
80
|
+
if (value.length < MIN_KEY_LENGTH) {
|
|
81
|
+
console.error(`✗ Set ${name} to a random value of at least ${MIN_KEY_LENGTH} characters.`);
|
|
82
|
+
process.exit(1);
|
|
83
|
+
}
|
|
84
|
+
return value;
|
|
85
|
+
}
|
|
86
|
+
// Production self-hosting: no file watching, no generated keys, no .env writes.
|
|
87
|
+
async function start(p, flags) {
|
|
88
|
+
const port = Number(str(flags, "port") ?? process.env.PORT ?? process.env.DATABOB_PORT ?? 4100);
|
|
89
|
+
const host = str(flags, "host") ?? process.env.DATABOB_HOST ?? "0.0.0.0";
|
|
90
|
+
const secretKey = requiredSecret("DATABOB_SECRET_KEY");
|
|
91
|
+
if (!secretKey.startsWith("dbsk_")) {
|
|
92
|
+
console.error("✗ DATABOB_SECRET_KEY must start with dbsk_");
|
|
93
|
+
process.exit(1);
|
|
94
|
+
}
|
|
95
|
+
const loaded = await loadOrExit(p);
|
|
96
|
+
const config = {
|
|
97
|
+
id: process.env.DATABOB_PROJECT_ID ?? "default",
|
|
98
|
+
schema: loaded.schema,
|
|
99
|
+
metrics: loaded.metrics,
|
|
100
|
+
signingKey: requiredSecret("DATABOB_SIGNING_KEY"),
|
|
101
|
+
userKey: requiredSecret("DATABOB_USER_KEY"),
|
|
102
|
+
};
|
|
103
|
+
const tenants = new LocalTenants({ dir: process.env.DATABOB_DATA_DIR ?? p.data });
|
|
104
|
+
const handler = createHandler({ projects: new StaticProjects([{ secretKey, config }]), engine: new Engine(tenants) });
|
|
105
|
+
const server = createServer(toNodeListener(handler));
|
|
106
|
+
server.listen(port, host, () => {
|
|
107
|
+
console.log(`databob listening on http://${host}:${port} (${Object.keys(config.metrics).length} metrics)`);
|
|
108
|
+
});
|
|
109
|
+
const stop = () => {
|
|
110
|
+
server.close(() => {
|
|
111
|
+
tenants.close();
|
|
112
|
+
process.exit(0);
|
|
113
|
+
});
|
|
114
|
+
};
|
|
115
|
+
process.on("SIGINT", stop);
|
|
116
|
+
process.on("SIGTERM", stop);
|
|
117
|
+
}
|
|
118
|
+
async function deploy(p, flags) {
|
|
119
|
+
const cloud = cloudSettings(p.root, str(flags, "url"));
|
|
120
|
+
const loaded = await loadOrExit(p);
|
|
121
|
+
const result = await deployProject(loaded, cloud);
|
|
122
|
+
if (!result.ok) {
|
|
123
|
+
console.error(`✗ ${result.status ? `Deploy failed (${result.status}): ` : ""}${result.message}`);
|
|
124
|
+
for (const problem of result.problems ?? [])
|
|
125
|
+
console.error(` ✗ ${problem}`);
|
|
126
|
+
process.exit(1);
|
|
127
|
+
}
|
|
128
|
+
console.log(`✓ Deployed version ${result.version}: ${result.events} event(s), ${result.metrics} metric(s) to ${result.url}`);
|
|
129
|
+
}
|
|
130
|
+
async function dev(p, flags) {
|
|
131
|
+
const port = Number(str(flags, "port") ?? process.env.DATABOB_PORT ?? 4100);
|
|
132
|
+
const host = str(flags, "host") ?? "127.0.0.1";
|
|
133
|
+
if (scaffold(p).length > 0)
|
|
134
|
+
console.log(`Created ${relative(process.cwd(), p.source)}/ with a starter schema and metrics.`);
|
|
135
|
+
const state = devState(p);
|
|
136
|
+
let loaded;
|
|
137
|
+
try {
|
|
138
|
+
loaded = await loadProject(p);
|
|
139
|
+
}
|
|
140
|
+
catch (error) {
|
|
141
|
+
console.error(error instanceof Error ? error.message : error);
|
|
142
|
+
process.exit(1);
|
|
143
|
+
}
|
|
144
|
+
for (const problem of loaded.problems)
|
|
145
|
+
console.error(`✗ ${problem}`);
|
|
146
|
+
const projects = new StaticProjects([{ secretKey: state.secretKey, config: projectConfig(state, loaded) }]);
|
|
147
|
+
const tenants = new LocalTenants({ dir: p.data });
|
|
148
|
+
const handler = createHandler({ projects, engine: new Engine(tenants) });
|
|
149
|
+
const server = createServer(toNodeListener(async (request) => {
|
|
150
|
+
const url = new URL(request.url);
|
|
151
|
+
if (url.pathname === "/") {
|
|
152
|
+
const config = await projects.byId(state.projectId);
|
|
153
|
+
return Response.json({
|
|
154
|
+
name: "databob dev",
|
|
155
|
+
project: state.projectId,
|
|
156
|
+
events: Object.keys(config?.schema.events ?? {}),
|
|
157
|
+
metrics: Object.keys(config?.metrics ?? {}),
|
|
158
|
+
routes: ["POST /v1/track", "POST /v1/metrics/:name", "GET /v1/metrics/:name/live", "POST /v1/query", "POST /v1/tokens", "GET /v1/describe"],
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
return handler(request);
|
|
162
|
+
}));
|
|
163
|
+
server.on("error", (error) => {
|
|
164
|
+
console.error(error.code === "EADDRINUSE" ? `Port ${port} is in use. Try --port ${port + 1}.` : error.message);
|
|
165
|
+
process.exit(1);
|
|
166
|
+
});
|
|
167
|
+
server.listen(port, host, () => {
|
|
168
|
+
const url = `http://${host}:${port}`;
|
|
169
|
+
const added = writeEnv(p, url, state.secretKey);
|
|
170
|
+
const events = Object.keys(loaded.schema.events).length;
|
|
171
|
+
const metrics = Object.keys(loaded.metrics).length;
|
|
172
|
+
console.log(`databob dev ${url}`);
|
|
173
|
+
console.log(` project ${state.projectId}: ${events} event(s), ${metrics} metric(s)${loaded.schema.tenants ? ", tenants on" : ""}`);
|
|
174
|
+
console.log(` data ${relative(process.cwd(), p.data) || "."}`);
|
|
175
|
+
console.log(` secret ${state.secretKey}`);
|
|
176
|
+
if (added.length > 0)
|
|
177
|
+
console.log(` env added ${added.join(", ")} to .env.local`);
|
|
178
|
+
console.log(`Watching ${relative(process.cwd(), p.source)}/ for changes.`);
|
|
179
|
+
});
|
|
180
|
+
let timer = null;
|
|
181
|
+
const reload = async () => {
|
|
182
|
+
try {
|
|
183
|
+
const next = await loadProject(p);
|
|
184
|
+
if (next.problems.length > 0) {
|
|
185
|
+
for (const problem of next.problems)
|
|
186
|
+
console.error(`✗ ${problem}`);
|
|
187
|
+
console.error("Keeping the previous schema and metrics until these are fixed.");
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
projects.replace([{ secretKey: state.secretKey, config: projectConfig(state, next) }]);
|
|
191
|
+
loaded = next;
|
|
192
|
+
console.log(`✓ Reloaded: ${Object.keys(next.schema.events).length} event(s), ${Object.keys(next.metrics).length} metric(s)`);
|
|
193
|
+
}
|
|
194
|
+
catch (error) {
|
|
195
|
+
console.error(`✗ ${error instanceof Error ? error.message : error}`);
|
|
196
|
+
console.error("Keeping the previous schema and metrics until this is fixed.");
|
|
197
|
+
}
|
|
198
|
+
};
|
|
199
|
+
watch(p.source, { recursive: true }, (_event, file) => {
|
|
200
|
+
if (!file || String(file).includes("_generated"))
|
|
201
|
+
return;
|
|
202
|
+
if (timer)
|
|
203
|
+
clearTimeout(timer);
|
|
204
|
+
timer = setTimeout(() => void reload(), 100);
|
|
205
|
+
});
|
|
206
|
+
const stop = () => {
|
|
207
|
+
tenants.close();
|
|
208
|
+
server.close();
|
|
209
|
+
process.exit(0);
|
|
210
|
+
};
|
|
211
|
+
process.on("SIGINT", stop);
|
|
212
|
+
process.on("SIGTERM", stop);
|
|
213
|
+
}
|
|
214
|
+
async function main() {
|
|
215
|
+
const flags = parse(process.argv.slice(2));
|
|
216
|
+
const command = flags._[0] ?? "help";
|
|
217
|
+
const p = paths(process.cwd());
|
|
218
|
+
switch (command) {
|
|
219
|
+
case "init": {
|
|
220
|
+
const created = scaffold(p);
|
|
221
|
+
console.log(created.length > 0 ? `Created ${created.join(", ")}` : "databob/ already exists. Nothing to create.");
|
|
222
|
+
console.log("Next: npx databob dev");
|
|
223
|
+
console.log("Agents: claude mcp add databob -- npx databob mcp");
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
case "dev":
|
|
227
|
+
return dev(p, flags);
|
|
228
|
+
case "start":
|
|
229
|
+
return start(p, flags);
|
|
230
|
+
case "deploy":
|
|
231
|
+
return deploy(p, flags);
|
|
232
|
+
case "mcp":
|
|
233
|
+
return serveMcp({ root: process.cwd() });
|
|
234
|
+
case "codegen": {
|
|
235
|
+
const written = codegen(p);
|
|
236
|
+
console.log(written.length > 0 ? `Wrote ${written.join(", ")}` : "Generated files are up to date.");
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
case "check": {
|
|
240
|
+
const loaded = await loadOrExit(p);
|
|
241
|
+
console.log(`✓ ${Object.keys(loaded.schema.events).length} event(s) and ${Object.keys(loaded.metrics).length} metric(s) are valid`);
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
case "describe": {
|
|
245
|
+
const loaded = await loadOrExit(p);
|
|
246
|
+
print({ schema: loaded.schema, metrics: loaded.metrics });
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
case "query": {
|
|
250
|
+
const name = flags._[1];
|
|
251
|
+
if (!name)
|
|
252
|
+
throw new Error("Usage: databob query <metric> [--args JSON] [--tenant id]");
|
|
253
|
+
const { engine, project, tenants } = openLocal(p, await loadOrExit(p));
|
|
254
|
+
const options = {};
|
|
255
|
+
const tenant = str(flags, "tenant");
|
|
256
|
+
if (tenant)
|
|
257
|
+
options.tenant = tenant;
|
|
258
|
+
const tz = str(flags, "tz");
|
|
259
|
+
if (tz)
|
|
260
|
+
options.timeZone = tz;
|
|
261
|
+
if (flags.compare)
|
|
262
|
+
options.compare = "previous";
|
|
263
|
+
print(await engine.metric(project, name, jsonFlag(flags, "args") ?? {}, options));
|
|
264
|
+
tenants.close();
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
case "track": {
|
|
268
|
+
const name = flags._[1];
|
|
269
|
+
if (!name)
|
|
270
|
+
throw new Error("Usage: databob track <event> [--props JSON] [--tenant id] [--user id]");
|
|
271
|
+
const event = { name, props: jsonFlag(flags, "props") ?? {} };
|
|
272
|
+
const tenant = str(flags, "tenant");
|
|
273
|
+
if (tenant)
|
|
274
|
+
event.tenant = tenant;
|
|
275
|
+
const user = str(flags, "user");
|
|
276
|
+
if (user)
|
|
277
|
+
event.user = user;
|
|
278
|
+
const port = str(flags, "port");
|
|
279
|
+
const result = await trackLocal(p, await loadOrExit(p), [event], port ? Number(port) : undefined);
|
|
280
|
+
print(result);
|
|
281
|
+
if (result.rejected.length > 0)
|
|
282
|
+
process.exit(1);
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
case "help":
|
|
286
|
+
case "--help":
|
|
287
|
+
case "-h":
|
|
288
|
+
console.log(HELP);
|
|
289
|
+
return;
|
|
290
|
+
default:
|
|
291
|
+
console.error(`Unknown command "${command}".\n`);
|
|
292
|
+
console.log(HELP);
|
|
293
|
+
process.exit(1);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
main().catch((error) => {
|
|
297
|
+
if (error instanceof EngineError || error instanceof ProjectLoadError)
|
|
298
|
+
console.error(`✗ ${error.message}`);
|
|
299
|
+
else
|
|
300
|
+
console.error(error instanceof Error ? error.message : error);
|
|
301
|
+
process.exit(1);
|
|
302
|
+
});
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export { v, defineSchema, event, metricFactory, queryRoot, type AggregateResult, type AnySchema, type Cell, type EventNames, type EventProps, type FunnelResult, type FunnelStep, type Infer, type MetricDef, type QueryAst, type QueryResult, type RangeValue, type Schema, } from "@databob/engine";
|
|
2
|
+
export { makeApi, ref, type ApiFromModule, type MetricRef, type RefArgs, type RefResult } from "./api.js";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
// databob: typed product analytics you define in code.
|
|
2
|
+
//
|
|
3
|
+
// databob/schema.ts events and their properties
|
|
4
|
+
// databob/metrics.ts named queries your app and your users read
|
|
5
|
+
// databob/_generated written by `databob dev`; commit it
|
|
6
|
+
export { v, defineSchema, event, metricFactory, queryRoot, } from "@databob/engine";
|
|
7
|
+
export { makeApi, ref } from "./api.js";
|
package/dist/mcp.d.ts
ADDED
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
export declare const PROTOCOL_VERSIONS: readonly ["2025-06-18", "2025-03-26", "2024-11-05"];
|
|
2
|
+
type Json = Record<string, unknown>;
|
|
3
|
+
export type McpOptions = {
|
|
4
|
+
root: string;
|
|
5
|
+
fetch?: typeof fetch;
|
|
6
|
+
};
|
|
7
|
+
export declare const TOOLS: readonly [{
|
|
8
|
+
readonly name: "describe";
|
|
9
|
+
readonly title: "Describe the analytics project";
|
|
10
|
+
readonly description: "The events, properties, and metrics defined in databob/, whether a cloud app is configured, and a reference for the JSON query language. Call this first.";
|
|
11
|
+
readonly inputSchema: {
|
|
12
|
+
readonly type: "object";
|
|
13
|
+
readonly properties: {};
|
|
14
|
+
readonly additionalProperties: false;
|
|
15
|
+
};
|
|
16
|
+
readonly annotations: {
|
|
17
|
+
readonly readOnlyHint: true;
|
|
18
|
+
readonly openWorldHint: false;
|
|
19
|
+
};
|
|
20
|
+
}, {
|
|
21
|
+
readonly name: "check";
|
|
22
|
+
readonly title: "Check the schema and metrics";
|
|
23
|
+
readonly description: "Validate databob/schema.ts and databob/metrics.ts. Returns every problem, or ok. Run it after editing either file.";
|
|
24
|
+
readonly inputSchema: {
|
|
25
|
+
readonly type: "object";
|
|
26
|
+
readonly properties: {};
|
|
27
|
+
readonly additionalProperties: false;
|
|
28
|
+
};
|
|
29
|
+
readonly annotations: {
|
|
30
|
+
readonly readOnlyHint: true;
|
|
31
|
+
readonly openWorldHint: false;
|
|
32
|
+
};
|
|
33
|
+
}, {
|
|
34
|
+
readonly name: "query_metric";
|
|
35
|
+
readonly title: "Run a named metric";
|
|
36
|
+
readonly description: "Run a metric defined in databob/metrics.ts and return its rows (or funnel steps).";
|
|
37
|
+
readonly inputSchema: {
|
|
38
|
+
readonly type: "object";
|
|
39
|
+
readonly properties: {
|
|
40
|
+
readonly tenant: {
|
|
41
|
+
readonly type: "string";
|
|
42
|
+
readonly description: "Tenant id. Required when the schema has tenants.";
|
|
43
|
+
};
|
|
44
|
+
readonly timeZone: {
|
|
45
|
+
readonly type: "string";
|
|
46
|
+
readonly description: "IANA time zone for time buckets, e.g. \"America/New_York\". Default UTC.";
|
|
47
|
+
};
|
|
48
|
+
readonly compare: {
|
|
49
|
+
readonly type: "boolean";
|
|
50
|
+
readonly description: "Also return the same-length period just before.";
|
|
51
|
+
};
|
|
52
|
+
readonly target: {
|
|
53
|
+
readonly type: "string";
|
|
54
|
+
readonly enum: readonly ["local", "cloud"];
|
|
55
|
+
readonly description: "local: data recorded by `databob dev` in .databob/. cloud: the deployed app at DATABOB_URL. Default \"local\".";
|
|
56
|
+
};
|
|
57
|
+
readonly metric: {
|
|
58
|
+
readonly type: "string";
|
|
59
|
+
readonly description: "The metric's export name.";
|
|
60
|
+
};
|
|
61
|
+
readonly args: {
|
|
62
|
+
readonly type: "object";
|
|
63
|
+
readonly description: "The metric's arguments, e.g. { \"range\": \"7d\" }.";
|
|
64
|
+
};
|
|
65
|
+
};
|
|
66
|
+
readonly required: readonly ["metric"];
|
|
67
|
+
readonly additionalProperties: false;
|
|
68
|
+
};
|
|
69
|
+
readonly annotations: {
|
|
70
|
+
readonly readOnlyHint: true;
|
|
71
|
+
readonly openWorldHint: true;
|
|
72
|
+
};
|
|
73
|
+
}, {
|
|
74
|
+
readonly name: "query";
|
|
75
|
+
readonly title: "Run an ad hoc query";
|
|
76
|
+
readonly description: "Run a JSON query that is not a saved metric. describe returns the query language. Use it to explore data or to try a metric before adding it to metrics.ts.";
|
|
77
|
+
readonly inputSchema: {
|
|
78
|
+
readonly type: "object";
|
|
79
|
+
readonly properties: {
|
|
80
|
+
readonly tenant: {
|
|
81
|
+
readonly type: "string";
|
|
82
|
+
readonly description: "Tenant id. Required when the schema has tenants.";
|
|
83
|
+
};
|
|
84
|
+
readonly timeZone: {
|
|
85
|
+
readonly type: "string";
|
|
86
|
+
readonly description: "IANA time zone for time buckets, e.g. \"America/New_York\". Default UTC.";
|
|
87
|
+
};
|
|
88
|
+
readonly compare: {
|
|
89
|
+
readonly type: "boolean";
|
|
90
|
+
readonly description: "Also return the same-length period just before.";
|
|
91
|
+
};
|
|
92
|
+
readonly target: {
|
|
93
|
+
readonly type: "string";
|
|
94
|
+
readonly enum: readonly ["local", "cloud"];
|
|
95
|
+
readonly description: "local: data recorded by `databob dev` in .databob/. cloud: the deployed app at DATABOB_URL. Default \"local\".";
|
|
96
|
+
};
|
|
97
|
+
readonly query: {
|
|
98
|
+
readonly type: "object";
|
|
99
|
+
readonly description: "A query with kind \"aggregate\" or \"funnel\".";
|
|
100
|
+
};
|
|
101
|
+
};
|
|
102
|
+
readonly required: readonly ["query"];
|
|
103
|
+
readonly additionalProperties: false;
|
|
104
|
+
};
|
|
105
|
+
readonly annotations: {
|
|
106
|
+
readonly readOnlyHint: true;
|
|
107
|
+
readonly openWorldHint: true;
|
|
108
|
+
};
|
|
109
|
+
}, {
|
|
110
|
+
readonly name: "track_test_event";
|
|
111
|
+
readonly title: "Record a test event locally";
|
|
112
|
+
readonly description: "Record one event in local dev data (never the cloud), to check instrumentation or to give a new metric something to show. Refused events come back with the reason.";
|
|
113
|
+
readonly inputSchema: {
|
|
114
|
+
readonly type: "object";
|
|
115
|
+
readonly properties: {
|
|
116
|
+
readonly name: {
|
|
117
|
+
readonly type: "string";
|
|
118
|
+
readonly description: "Event name from the schema.";
|
|
119
|
+
};
|
|
120
|
+
readonly props: {
|
|
121
|
+
readonly type: "object";
|
|
122
|
+
readonly description: "Event properties.";
|
|
123
|
+
};
|
|
124
|
+
readonly tenant: {
|
|
125
|
+
readonly type: "string";
|
|
126
|
+
};
|
|
127
|
+
readonly user: {
|
|
128
|
+
readonly type: "string";
|
|
129
|
+
readonly description: "A user id. Stored as a keyed hash.";
|
|
130
|
+
};
|
|
131
|
+
readonly ts: {
|
|
132
|
+
readonly type: "string";
|
|
133
|
+
readonly description: "ISO time. Default now.";
|
|
134
|
+
};
|
|
135
|
+
};
|
|
136
|
+
readonly required: readonly ["name"];
|
|
137
|
+
readonly additionalProperties: false;
|
|
138
|
+
};
|
|
139
|
+
readonly annotations: {
|
|
140
|
+
readonly readOnlyHint: false;
|
|
141
|
+
readonly destructiveHint: false;
|
|
142
|
+
readonly idempotentHint: false;
|
|
143
|
+
readonly openWorldHint: false;
|
|
144
|
+
};
|
|
145
|
+
}, {
|
|
146
|
+
readonly name: "deploy";
|
|
147
|
+
readonly title: "Deploy to databob cloud";
|
|
148
|
+
readonly description: "Ship databob/schema.ts and databob/metrics.ts to the cloud app at DATABOB_URL with DATABOB_DEPLOY_KEY. Events not in the new schema are refused from then on. Only deploy when the user asks.";
|
|
149
|
+
readonly inputSchema: {
|
|
150
|
+
readonly type: "object";
|
|
151
|
+
readonly properties: {};
|
|
152
|
+
readonly additionalProperties: false;
|
|
153
|
+
};
|
|
154
|
+
readonly annotations: {
|
|
155
|
+
readonly readOnlyHint: false;
|
|
156
|
+
readonly destructiveHint: true;
|
|
157
|
+
readonly idempotentHint: true;
|
|
158
|
+
readonly openWorldHint: true;
|
|
159
|
+
};
|
|
160
|
+
}];
|
|
161
|
+
export declare function createMcpHandler(options: McpOptions): (message: unknown) => Promise<Json | null>;
|
|
162
|
+
export declare function serveMcp(options: McpOptions, input?: NodeJS.ReadableStream, output?: NodeJS.WritableStream): Promise<void>;
|
|
163
|
+
export {};
|