@persql/sdk 0.1.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.
- package/README.md +146 -0
- package/dist/chunk-CDNTQOBK.js +1737 -0
- package/dist/chunk-CDNTQOBK.js.map +1 -0
- package/dist/cli.cjs +1827 -0
- package/dist/cli.cjs.map +1 -0
- package/dist/cli.js +103 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.cjs +1772 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +926 -0
- package/dist/index.d.ts +926 -0
- package/dist/index.js +25 -0
- package/dist/index.js.map +1 -0
- package/package.json +56 -0
package/README.md
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
# @persql/sdk
|
|
2
|
+
|
|
3
|
+
TypeScript SDK for [PerSQL](https://persql.com) — SQLite databases on the edge, designed for AI agents.
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
npm i @persql/sdk
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## Quick start
|
|
10
|
+
|
|
11
|
+
```ts
|
|
12
|
+
import { PerSQL } from "@persql/sdk";
|
|
13
|
+
|
|
14
|
+
const persql = new PerSQL({ token: process.env.PERSQL_TOKEN! });
|
|
15
|
+
const db = persql.database("acme/orders");
|
|
16
|
+
|
|
17
|
+
// Query — returns rows reshaped as objects.
|
|
18
|
+
const { data } = await db.query<{ id: number; email: string }>(
|
|
19
|
+
"SELECT id, email FROM customers WHERE id = ?",
|
|
20
|
+
[42]
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
// Batch — multiple statements in one round-trip.
|
|
24
|
+
const results = await db.batch([
|
|
25
|
+
{ sql: "INSERT INTO orders (id, total) VALUES (?, ?)", params: ["o-1", 99.5] },
|
|
26
|
+
{ sql: "UPDATE customers SET last_order = ? WHERE id = ?", params: ["o-1", "c-1"] },
|
|
27
|
+
]);
|
|
28
|
+
|
|
29
|
+
// Transaction — same as batch with rollback on error.
|
|
30
|
+
await db.transaction([
|
|
31
|
+
{ sql: "INSERT INTO accounts (id, balance) VALUES (?, ?)", params: ["a-1", 100] },
|
|
32
|
+
{ sql: "INSERT INTO accounts (id, balance) VALUES (?, ?)", params: ["a-2", 0] },
|
|
33
|
+
]);
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Use as a tool with Anthropic / OpenAI
|
|
37
|
+
|
|
38
|
+
```ts
|
|
39
|
+
import Anthropic from "@anthropic-ai/sdk";
|
|
40
|
+
import { PerSQL } from "@persql/sdk";
|
|
41
|
+
|
|
42
|
+
const persql = new PerSQL({ token: process.env.PERSQL_TOKEN! });
|
|
43
|
+
const db = persql.database("acme/orders");
|
|
44
|
+
const tool = db.asTool().anthropic;
|
|
45
|
+
|
|
46
|
+
const anthropic = new Anthropic();
|
|
47
|
+
const response = await anthropic.messages.create({
|
|
48
|
+
model: "claude-opus-4-7",
|
|
49
|
+
max_tokens: 1024,
|
|
50
|
+
tools: [tool],
|
|
51
|
+
messages: [{ role: "user", content: "How many orders did we ship last week?" }],
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
// When the model calls the tool, run it and feed the result back:
|
|
55
|
+
for (const block of response.content) {
|
|
56
|
+
if (block.type === "tool_use" && block.name === tool.name) {
|
|
57
|
+
const result = await db.runTool(block.input as { sql: string; params?: unknown[] });
|
|
58
|
+
// …pass `result` back to the model in the next turn.
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Use with Drizzle
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
npm i drizzle-orm
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
```ts
|
|
70
|
+
import { drizzle } from "drizzle-orm/sqlite-proxy";
|
|
71
|
+
import { PerSQL } from "@persql/sdk";
|
|
72
|
+
import * as schema from "./db/schema";
|
|
73
|
+
|
|
74
|
+
const persql = new PerSQL({ token: process.env.PERSQL_TOKEN! });
|
|
75
|
+
const db = drizzle(persql.database("acme/orders").driver(), { schema });
|
|
76
|
+
|
|
77
|
+
const recent = await db.select().from(schema.orders).limit(10);
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
`db.driver()` returns the callback shape `drizzle-orm/sqlite-proxy`
|
|
81
|
+
expects. Generate the schema file once with the bundled
|
|
82
|
+
`persql-codegen` bin:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
PERSQL_TOKEN=psql_live_… npx persql-codegen --db acme/orders --out src/db/schema.ts
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Local mode (tests)
|
|
89
|
+
|
|
90
|
+
Run the SDK against a local SQLite file (or `:memory:`) so tests
|
|
91
|
+
don't hit your live database:
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
npm i -D better-sqlite3
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
```ts
|
|
98
|
+
import { PerSQL } from "@persql/sdk";
|
|
99
|
+
|
|
100
|
+
const persql = new PerSQL({ local: ":memory:" }); // or "./test.db"
|
|
101
|
+
const db = persql.database("test/db");
|
|
102
|
+
|
|
103
|
+
await db.query("CREATE TABLE customers (id INTEGER, email TEXT)");
|
|
104
|
+
await db.query("INSERT INTO customers VALUES (?, ?)", [1, "a@b.co"]);
|
|
105
|
+
const { data } = await db.query("SELECT * FROM customers");
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
`query / batch / transaction / tables / explain / schema` route
|
|
109
|
+
through `better-sqlite3` (lazy-loaded — never required for live use).
|
|
110
|
+
`vectors`, `blob`, and `subscribe` throw — they have no local
|
|
111
|
+
equivalent. The same `db.driver()` works in local mode, so a
|
|
112
|
+
Drizzle-based data layer needs zero changes between tests and prod.
|
|
113
|
+
|
|
114
|
+
Call `persql.close()` to release the file handle when done.
|
|
115
|
+
|
|
116
|
+
## Idempotency
|
|
117
|
+
|
|
118
|
+
Pass an `Idempotency-Key` to make writes safely retryable:
|
|
119
|
+
|
|
120
|
+
```ts
|
|
121
|
+
await db.query("INSERT INTO events (id, name) VALUES (?, ?)", ["e-1", "click"], {
|
|
122
|
+
idempotencyKey: "evt-e-1-2026-04-29",
|
|
123
|
+
});
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Cached for 24 hours. A retry with the same key returns the cached response.
|
|
127
|
+
|
|
128
|
+
## Errors
|
|
129
|
+
|
|
130
|
+
```ts
|
|
131
|
+
import { PerSQLError, RateLimitError } from "@persql/sdk";
|
|
132
|
+
|
|
133
|
+
try {
|
|
134
|
+
await db.query("SELECT 1");
|
|
135
|
+
} catch (e) {
|
|
136
|
+
if (e instanceof RateLimitError) {
|
|
137
|
+
console.log(`Slow down for ${e.retryAfterSeconds}s`);
|
|
138
|
+
} else if (e instanceof PerSQLError) {
|
|
139
|
+
console.log(`API error ${e.status}: ${e.message}`);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## License
|
|
145
|
+
|
|
146
|
+
MIT
|