@persql/sdk 0.1.0 → 1.0.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/dist/cli.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  PerSQL
4
- } from "./chunk-CDNTQOBK.js";
4
+ } from "./chunk-ZRZANHPI.js";
5
5
 
6
6
  // src/cli.ts
7
7
  import { writeFile } from "fs/promises";
package/dist/index.cjs CHANGED
@@ -22,18 +22,40 @@ var index_exports = {};
22
22
  __export(index_exports, {
23
23
  ApprovalRequiredError: () => ApprovalRequiredError,
24
24
  PerSQL: () => PerSQL,
25
+ PerSQLApprovalRules: () => PerSQLApprovalRules,
25
26
  PerSQLApprovals: () => PerSQLApprovals,
26
- PerSQLBlob: () => PerSQLBlob,
27
27
  PerSQLBranches: () => PerSQLBranches,
28
28
  PerSQLDatabase: () => PerSQLDatabase,
29
29
  PerSQLError: () => PerSQLError,
30
30
  PerSQLProposals: () => PerSQLProposals,
31
- PerSQLVectors: () => PerSQLVectors,
32
- RateLimitError: () => RateLimitError
31
+ RateLimitError: () => RateLimitError,
32
+ SupportClient: () => SupportClient
33
33
  });
34
34
  module.exports = __toCommonJS(index_exports);
35
35
 
36
36
  // src/local.ts
37
+ function checkLocalExpect(e, r) {
38
+ const rows = r.rows.length;
39
+ if (e.rows != null && rows !== e.rows) {
40
+ return `expected rows=${e.rows}, got ${rows}`;
41
+ }
42
+ if (e.rowsAtLeast != null && rows < e.rowsAtLeast) {
43
+ return `expected rows>=${e.rowsAtLeast}, got ${rows}`;
44
+ }
45
+ if (e.rowsAtMost != null && rows > e.rowsAtMost) {
46
+ return `expected rows<=${e.rowsAtMost}, got ${rows}`;
47
+ }
48
+ if (e.rowsWritten != null && r.rowsWritten !== e.rowsWritten) {
49
+ return `expected rowsWritten=${e.rowsWritten}, got ${r.rowsWritten}`;
50
+ }
51
+ if (e.rowsWrittenAtLeast != null && r.rowsWritten < e.rowsWrittenAtLeast) {
52
+ return `expected rowsWritten>=${e.rowsWrittenAtLeast}, got ${r.rowsWritten}`;
53
+ }
54
+ if (e.rowsWrittenAtMost != null && r.rowsWritten > e.rowsWrittenAtMost) {
55
+ return `expected rowsWritten<=${e.rowsWrittenAtMost}, got ${r.rowsWritten}`;
56
+ }
57
+ return null;
58
+ }
37
59
  var PROPOSAL_TTL_DEFAULT_SEC = 600;
38
60
  var PROPOSAL_TTL_MAX_SEC = 3600;
39
61
  function newLocalProposalId() {
@@ -72,7 +94,16 @@ var LocalDriver = class {
72
94
  }
73
95
  async batch(statements, transaction) {
74
96
  const db = await this.open();
75
- const exec = () => statements.map((s) => runOne(db, s.sql, s.params ?? []));
97
+ const exec = () => statements.map((s, i) => {
98
+ const r = runOne(db, s.sql, s.params ?? []);
99
+ if (s.expect) {
100
+ const violation = checkLocalExpect(s.expect, r);
101
+ if (violation) {
102
+ throw new Error(`Assertion failed on statement ${i}: ${violation}`);
103
+ }
104
+ }
105
+ return r;
106
+ });
76
107
  if (transaction) return db.transaction(exec)();
77
108
  return exec();
78
109
  }
@@ -234,6 +265,19 @@ var PerSQL = class _PerSQL {
234
265
  close() {
235
266
  this.local?.close();
236
267
  }
268
+ /**
269
+ * Resolve the bearer token's namespace + live usage. Use this once
270
+ * per agent run so you know the slug to put in URLs and how much
271
+ * monthly budget / prepaid balance remains before a 402.
272
+ *
273
+ * Throws in local mode — no server, nothing to ask.
274
+ */
275
+ async me() {
276
+ if (this.local) {
277
+ throw new Error("PerSQL: me() is not available in local mode.");
278
+ }
279
+ return this.request("GET", "/v1/me");
280
+ }
237
281
  /**
238
282
  * Redeem a handoff token (`phand_…`) for a regular PerSQL client
239
283
  * scoped to the handed-off (database, branch, role). Single use:
@@ -307,40 +351,74 @@ var PerSQL = class _PerSQL {
307
351
  }
308
352
  return envelope.data;
309
353
  }
310
- /** @internal — raw upload (e.g. blob PUT) returning the ApiResponse data. */
311
- async requestRaw(method, path, body, contentType) {
312
- const res = await this._fetch(`${this.baseURL}${path}`, {
313
- method,
314
- headers: {
315
- Authorization: `Bearer ${this.token}`,
316
- "Content-Type": contentType ?? "application/octet-stream"
317
- },
318
- body,
319
- // @ts-expect-error — duplex is required by Node fetch for streaming bodies
320
- duplex: "half"
321
- });
322
- if (res.status === 429) {
323
- const retryAfter = Number(res.headers.get("retry-after") ?? "60");
324
- throw new RateLimitError(retryAfter);
325
- }
326
- let envelope = null;
327
- try {
328
- envelope = await res.json();
329
- } catch {
330
- }
331
- if (!res.ok || !envelope?.success) {
332
- const message = envelope?.error ?? `Request failed (${res.status})`;
333
- throw new PerSQLError(res.status, message, envelope?.errorDetail);
334
- }
335
- return envelope.data;
336
- }
337
- /** @internal — raw fetch returning the underlying Response (used by blob GET). */
354
+ /** @internal — raw fetch returning the underlying Response. */
338
355
  fetchRaw(method, path) {
339
356
  return this._fetch(`${this.baseURL}${path}`, {
340
357
  method,
341
358
  headers: { Authorization: `Bearer ${this.token}` }
342
359
  });
343
360
  }
361
+ /**
362
+ * File a support ticket directly from your SDK code. Tickets land in
363
+ * the customer console at `/support`; staff reply from the admin
364
+ * app. Useful for agents and background jobs that hit a PerSQL
365
+ * error and want a human to see it.
366
+ *
367
+ * ```ts
368
+ * try {
369
+ * await db.query("UPDATE ...");
370
+ * } catch (err) {
371
+ * await persql.support.createTicket({
372
+ * subject: "Branch merge keeps 500ing",
373
+ * body: "Repro: ...",
374
+ * error: err,
375
+ * });
376
+ * }
377
+ * ```
378
+ */
379
+ get support() {
380
+ return new SupportClient(this);
381
+ }
382
+ };
383
+ function errorContextFor(err) {
384
+ if (err instanceof PerSQLError) {
385
+ return {
386
+ errorName: err.name,
387
+ errorMessage: err.message,
388
+ status: err.status,
389
+ detail: err.detail ?? null
390
+ };
391
+ }
392
+ if (err instanceof Error) {
393
+ return { errorName: err.name, errorMessage: err.message };
394
+ }
395
+ if (err !== void 0 && err !== null) {
396
+ return { errorMessage: String(err) };
397
+ }
398
+ return {};
399
+ }
400
+ var SupportClient = class {
401
+ constructor(client) {
402
+ this.client = client;
403
+ }
404
+ async createTicket(opts) {
405
+ if (this.client.local) {
406
+ throw new Error("support.createTicket is not supported in local mode");
407
+ }
408
+ const errorContext = {
409
+ ...errorContextFor(opts.error),
410
+ ...opts.errorContext ?? {}
411
+ };
412
+ return this.client.request(
413
+ "POST",
414
+ "/v1/support/tickets",
415
+ {
416
+ subject: opts.subject,
417
+ body: opts.body,
418
+ errorContext: Object.keys(errorContext).length > 0 ? errorContext : void 0
419
+ }
420
+ );
421
+ }
344
422
  };
345
423
  var PerSQLDatabase = class {
346
424
  constructor(client, namespace, slug) {
@@ -394,6 +472,25 @@ var PerSQLDatabase = class {
394
472
  transaction(statements, options = {}) {
395
473
  return this.batch(statements, { ...options, transaction: true });
396
474
  }
475
+ /**
476
+ * Mint a short-lived session JWT for an end user. The server (which
477
+ * holds the bearer token) calls this and hands the resulting token
478
+ * to an untrusted client (browser, mobile app, agent run). The
479
+ * client uses the JWT to call this database's published `/p/*`
480
+ * endpoints on behalf of `userId`. TTL defaults to 1 hour; max 24h.
481
+ */
482
+ async createSession(opts) {
483
+ if (this.client.local) {
484
+ throw new Error("createSession is not supported in local mode");
485
+ }
486
+ return this.client.request("POST", "/v1/sessions", {
487
+ namespaceSlug: this.namespace,
488
+ databaseSlug: this.slug,
489
+ userId: opts.userId,
490
+ email: opts.email,
491
+ expiresIn: opts.expiresIn
492
+ });
493
+ }
397
494
  /**
398
495
  * Engine telemetry — recent /v1/query and /v1/batch calls issued
399
496
  * against this database. Backed by the in-DO `_persql_meta_query_log`
@@ -515,6 +612,61 @@ var PerSQLDatabase = class {
515
612
  if (this.client.local) return this.client.local.explain(sql, params);
516
613
  return this.client.request("POST", `/v1/db/${this.namespace}/${this.slug}/explain`, { sql, params });
517
614
  }
615
+ /**
616
+ * Parse + bind-check a SQL statement without executing it. Faster
617
+ * and cheaper than running the query just to catch unknown columns
618
+ * or wrong param counts.
619
+ *
620
+ * Returns `{ ok: true }` on success or `{ ok: false, error, errorDetail }`
621
+ * with the same `errorDetail` envelope as `PerSQLError.detail`.
622
+ */
623
+ async validate(sql, params = []) {
624
+ if (this.client.local) {
625
+ throw new Error("PerSQL: validate is not available in local mode.");
626
+ }
627
+ const data = await this.client.request(
628
+ "POST",
629
+ `/v1/db/${this.namespace}/${this.slug}/validate`,
630
+ { sql, params }
631
+ );
632
+ return data;
633
+ }
634
+ /**
635
+ * Compact text rendering of the database's schema — one line per
636
+ * table with columns, types, PKs, and FK arrows inlined. Designed
637
+ * to stuff into an LLM prompt with minimum token overhead. See
638
+ * `db.describe()` for the structured form.
639
+ */
640
+ async describeCompact() {
641
+ if (this.client.local) {
642
+ throw new Error("PerSQL: describeCompact is not available in local mode.");
643
+ }
644
+ const data = await this.client.request(
645
+ "GET",
646
+ `/v1/db/${this.namespace}/${this.slug}/describe?format=compact`
647
+ );
648
+ return data.text;
649
+ }
650
+ /**
651
+ * First N rows of a table plus per-column stats (null count,
652
+ * distinct count, min, max). One call to size up an unfamiliar
653
+ * table — replaces a hand-rolled `SELECT *`, `COUNT(*)`, and
654
+ * `PRAGMA table_info` sequence.
655
+ *
656
+ * `n` defaults to 10 and is capped at 100.
657
+ */
658
+ async sampleTable(table, opts = {}) {
659
+ if (this.client.local) {
660
+ throw new Error("PerSQL: sampleTable is not available in local mode.");
661
+ }
662
+ const qs = opts.n ? `?n=${Math.max(1, Math.min(100, opts.n | 0))}` : "";
663
+ return this.client.request(
664
+ "GET",
665
+ `/v1/db/${this.namespace}/${this.slug}/tables/${encodeURIComponent(
666
+ table
667
+ )}/sample${qs}`
668
+ );
669
+ }
518
670
  /**
519
671
  * Introspect the database schema. Returns one entry per user table
520
672
  * with column definitions, suitable for codegen tools (the
@@ -538,20 +690,6 @@ var PerSQLDatabase = class {
538
690
  }
539
691
  return out;
540
692
  }
541
- /**
542
- * Per-database semantic search via Cloudflare Vectorize. Use
543
- * `vectors.upsert` to embed and store rows; `vectors.query` to
544
- * retrieve the most similar by free text. Embeddings are computed
545
- * server-side using bge-base-en-v1.5 (768 dim, cosine distance).
546
- */
547
- get vectors() {
548
- if (this.client.local) {
549
- throw new Error(
550
- "PerSQL: vectors require Cloudflare Vectorize and Workers AI \u2014 not available in local mode. Use a server-mode token (psql_live_/psql_test_) to call vectors.upsert/query/delete."
551
- );
552
- }
553
- return new PerSQLVectors(this.client, this.namespace, this.slug);
554
- }
555
693
  /**
556
694
  * Manage preview/PR-style branches of this database. Each branch is
557
695
  * its own DO with its own SQLite file; create-or-reset by ref is
@@ -580,6 +718,19 @@ var PerSQLDatabase = class {
580
718
  }
581
719
  return new PerSQLApprovals(this.client, this.namespace, this.slug);
582
720
  }
721
+ /**
722
+ * Manage the require_approval / deny rules for this database. Reads
723
+ * are open to any bearer with read access; create + delete require
724
+ * an admin-role bearer token.
725
+ */
726
+ get approvalRules() {
727
+ if (this.client.local) {
728
+ throw new Error(
729
+ "PerSQL: approval rules live on the server; local mode does not enforce them."
730
+ );
731
+ }
732
+ return new PerSQLApprovalRules(this.client, this.namespace, this.slug);
733
+ }
583
734
  /**
584
735
  * Pre-flight a write before running it. `propose()` validates the
585
736
  * SQL via EXPLAIN, estimates affected rows, and returns a single-use
@@ -591,20 +742,6 @@ var PerSQLDatabase = class {
591
742
  get proposals() {
592
743
  return new PerSQLProposals(this.client, this.namespace, this.slug);
593
744
  }
594
- /**
595
- * Per-database BLOB storage backed by R2. Use this for anything
596
- * larger than a SQLite cell (images, PDFs, model weights). Each
597
- * database has its own private namespace; keys may be hierarchical
598
- * (`avatars/2025/foo.jpg`) but never start with `/`.
599
- */
600
- get blob() {
601
- if (this.client.local) {
602
- throw new Error(
603
- "PerSQL: blob storage is backed by R2 \u2014 not available in local mode. Use a server-mode token, or store blobs in your test fixtures directly."
604
- );
605
- }
606
- return new PerSQLBlob(this.client, this.namespace, this.slug);
607
- }
608
745
  /**
609
746
  * Subscribe to row-changes via WebSocket — the SQL equivalent of
610
747
  * Postgres `LISTEN`. The callback fires once per write that
@@ -692,42 +829,61 @@ var PerSQLDatabase = class {
692
829
  return callback;
693
830
  }
694
831
  /**
695
- * Returns a tool definition for use with Anthropic / OpenAI / function-calling
696
- * agents. Pair it with `runTool` to execute the call.
832
+ * Returns a single SQL-query tool definition in every shape PerSQL
833
+ * supports (Anthropic, OpenAI Chat, Vercel AI SDK, Mastra, LangChain,
834
+ * OpenAI Agents SDK). Same input contract as `asTools()` — the only
835
+ * difference is one fat `query` tool instead of typed-per-table tools.
836
+ *
837
+ * Pair the format-specific fields with `runTool` (or use the bundled
838
+ * `execute`/`invoke` callbacks, which call `runTool` internally).
697
839
  */
698
840
  asTool(name = "persql_query") {
699
- return {
700
- anthropic: {
701
- name,
702
- description: `Run a SQL query against the PerSQL database "${this.namespace}/${this.slug}". Returns up to 1000 rows. Use parameter binding (?) to avoid injection.`,
703
- input_schema: {
704
- type: "object",
705
- properties: {
706
- sql: { type: "string", description: "SQLite SQL statement" },
707
- params: {
708
- type: "array",
709
- items: {},
710
- description: "Positional parameters for the SQL statement"
711
- }
712
- },
713
- required: ["sql"]
841
+ const description = `Run a SQL query against the PerSQL database "${this.namespace}/${this.slug}". Returns up to 1000 rows. Use parameter binding (?) to avoid injection.`;
842
+ const inputSchema = {
843
+ type: "object",
844
+ properties: {
845
+ sql: { type: "string", description: "SQLite SQL statement" },
846
+ params: {
847
+ type: "array",
848
+ items: {},
849
+ description: "Positional parameters for the SQL statement"
714
850
  }
715
851
  },
852
+ required: ["sql"]
853
+ };
854
+ const execute = (input) => this.runTool({
855
+ sql: String(input.sql ?? ""),
856
+ params: Array.isArray(input.params) ? input.params : []
857
+ });
858
+ return {
859
+ anthropic: { name, description, input_schema: inputSchema },
716
860
  openai: {
717
861
  type: "function",
718
- function: {
862
+ function: { name, description, parameters: inputSchema }
863
+ },
864
+ aiSdk: () => ({
865
+ [name]: { description, inputSchema, execute }
866
+ }),
867
+ mastra: () => ({
868
+ [name]: {
869
+ id: name,
870
+ description,
871
+ inputSchema,
872
+ execute: ({ context }) => execute(context)
873
+ }
874
+ }),
875
+ langchain: () => [
876
+ { name, description, schema: inputSchema, invoke: execute }
877
+ ],
878
+ openaiAgents: () => [
879
+ {
880
+ type: "function",
719
881
  name,
720
- description: `Run a SQL query against the PerSQL database "${this.namespace}/${this.slug}".`,
721
- parameters: {
722
- type: "object",
723
- properties: {
724
- sql: { type: "string" },
725
- params: { type: "array", items: {} }
726
- },
727
- required: ["sql"]
728
- }
882
+ description,
883
+ parameters: inputSchema,
884
+ invoke: execute
729
885
  }
730
- }
886
+ ]
731
887
  };
732
888
  }
733
889
  /**
@@ -1499,106 +1655,148 @@ function sanitizeToolPart(s) {
1499
1655
  function quoteIdent(s) {
1500
1656
  return `"${s.replace(/"/g, '""')}"`;
1501
1657
  }
1502
- var PerSQLBlob = class {
1658
+ var PerSQLApprovals = class {
1503
1659
  constructor(client, namespace, slug) {
1504
1660
  this.client = client;
1505
1661
  this.namespace = namespace;
1506
1662
  this.slug = slug;
1507
1663
  }
1508
- /** Upload a blob. Body can be ArrayBuffer, Blob, ReadableStream, or string. */
1509
- async put(key, body, opts = {}) {
1510
- const path = `/v1/db/${this.namespace}/${this.slug}/blobs/${encodeBlobKey(key)}`;
1511
- return this.client.requestRaw(
1512
- "PUT",
1513
- path,
1514
- body,
1515
- opts.contentType
1664
+ // Tokens this client has seen via subscribe used to dedupe poll
1665
+ // results so onApprovalRequired fires once per token regardless of
1666
+ // how many subscribe ticks observe it.
1667
+ seen = /* @__PURE__ */ new Map();
1668
+ /**
1669
+ * Look up the status of an approval token without consuming it. The
1670
+ * bearer must match the one that minted the original 403; cross-bearer
1671
+ * lookup returns 403.
1672
+ */
1673
+ async get(approvalToken) {
1674
+ return this.client.request(
1675
+ "GET",
1676
+ `/v1/db/${this.namespace}/${this.slug}/approval/${encodeURIComponent(
1677
+ approvalToken
1678
+ )}`
1516
1679
  );
1517
1680
  }
1518
- /** Fetch a blob. Returns null if missing. */
1519
- async get(key) {
1520
- const path = `/v1/db/${this.namespace}/${this.slug}/blobs/${encodeBlobKey(key)}`;
1521
- const res = await this.client.fetchRaw("GET", path);
1522
- if (res.status === 404) return null;
1523
- if (!res.ok) {
1524
- throw new PerSQLError(res.status, `Blob fetch failed (${res.status})`);
1681
+ /**
1682
+ * Poll until a reviewer decides (or the token expires). Resolves with
1683
+ * the final status — `approved` is your green light for `redeem()`.
1684
+ */
1685
+ async poll(approvalToken, opts = {}) {
1686
+ const intervalMs = Math.max(250, opts.intervalMs ?? 2e3);
1687
+ const deadline = Date.now() + (opts.timeoutMs ?? 10 * 60 * 1e3);
1688
+ while (true) {
1689
+ if (opts.signal?.aborted) {
1690
+ throw new Error("approval poll aborted");
1691
+ }
1692
+ const status = await this.get(approvalToken);
1693
+ if (status.status !== "pending") return status;
1694
+ if (Date.now() > deadline) return status;
1695
+ await new Promise((r) => setTimeout(r, intervalMs));
1525
1696
  }
1526
- return res;
1527
1697
  }
1528
- /** Delete a blob. */
1529
- async delete(key) {
1530
- const path = `/v1/db/${this.namespace}/${this.slug}/blobs/${encodeBlobKey(key)}`;
1531
- await this.client.request("DELETE", path);
1698
+ /**
1699
+ * Long-running poll subscription for new approval events on this
1700
+ * database. Returns a `stop()` handle. Webhook delivery is the push
1701
+ * path (events `approval_required` / `approval_resolved`); subscribe
1702
+ * is the pull fallback for clients that can't host a webhook.
1703
+ *
1704
+ * Today this iterates over a known set of tokens supplied by the
1705
+ * caller; an SDK-only client that wants discovery should pair this
1706
+ * with the webhook path. Pass tokens you already hold (e.g. from a
1707
+ * prior `ApprovalRequiredError`).
1708
+ */
1709
+ subscribe(tokens, opts) {
1710
+ const intervalMs = Math.max(1e3, opts.intervalMs ?? 5e3);
1711
+ let cancelled = false;
1712
+ const onAbort = () => {
1713
+ cancelled = true;
1714
+ };
1715
+ opts.signal?.addEventListener("abort", onAbort);
1716
+ const tick = async () => {
1717
+ for (const token of tokens) {
1718
+ if (cancelled) return;
1719
+ try {
1720
+ const status = await this.get(token);
1721
+ const prev = this.seen.get(token);
1722
+ if (status.status !== prev) {
1723
+ this.seen.set(token, status.status);
1724
+ const event = {
1725
+ approvalToken: token,
1726
+ status: status.status,
1727
+ hits: status.hits
1728
+ };
1729
+ if (status.status === "pending") {
1730
+ opts.onApprovalRequired?.(event);
1731
+ } else {
1732
+ opts.onApprovalResolved?.(event);
1733
+ }
1734
+ }
1735
+ } catch (e) {
1736
+ opts.onError?.(e instanceof Error ? e : new Error(String(e)));
1737
+ }
1738
+ }
1739
+ };
1740
+ const id = setInterval(() => {
1741
+ void tick();
1742
+ }, intervalMs);
1743
+ void tick();
1744
+ return {
1745
+ stop: () => {
1746
+ cancelled = true;
1747
+ clearInterval(id);
1748
+ opts.signal?.removeEventListener("abort", onAbort);
1749
+ }
1750
+ };
1532
1751
  }
1533
- /** List blobs by prefix. */
1534
- async list(opts = {}) {
1535
- const params = new URLSearchParams();
1536
- if (opts.prefix) params.set("prefix", opts.prefix);
1537
- if (opts.cursor) params.set("cursor", opts.cursor);
1538
- if (opts.limit) params.set("limit", String(opts.limit));
1539
- const qs = params.toString();
1540
- const path = `/v1/db/${this.namespace}/${this.slug}/blobs` + (qs ? `?${qs}` : "");
1541
- return this.client.request("GET", path);
1752
+ /**
1753
+ * Redeem an approved approvalToken. The bearer must be the same one
1754
+ * that minted it, and the request must target the same database.
1755
+ * Returns the result of the originally-blocked query or batch.
1756
+ */
1757
+ async redeem(approvalToken) {
1758
+ const raw = await this.client.request("POST", `/v1/db/${this.namespace}/${this.slug}/redeem_approval`, {
1759
+ approvalToken
1760
+ });
1761
+ if (Array.isArray(raw)) {
1762
+ return raw.map((r) => ({
1763
+ ...r,
1764
+ data: rowsToObjects(r.columns, r.rows)
1765
+ }));
1766
+ }
1767
+ return { ...raw, data: rowsToObjects(raw.columns, raw.rows) };
1542
1768
  }
1543
1769
  };
1544
- function encodeBlobKey(key) {
1545
- return key.split("/").map(encodeURIComponent).join("/");
1546
- }
1547
- var PerSQLVectors = class {
1770
+ var PerSQLApprovalRules = class {
1548
1771
  constructor(client, namespace, slug) {
1549
1772
  this.client = client;
1550
1773
  this.namespace = namespace;
1551
1774
  this.slug = slug;
1552
1775
  }
1553
- /** Embed and upsert up to 100 items in one call. */
1554
- async upsert(items) {
1776
+ async list() {
1555
1777
  return this.client.request(
1556
- "POST",
1557
- `/v1/db/${this.namespace}/${this.slug}/vectors`,
1558
- { items }
1778
+ "GET",
1779
+ `/v1/db/${this.namespace}/${this.slug}/approval-rules`
1559
1780
  );
1560
1781
  }
1561
- /** Top-K nearest neighbours by free-text query. */
1562
- async query(text, opts = {}) {
1782
+ /** Requires an admin-role bearer token. */
1783
+ async create(input) {
1563
1784
  return this.client.request(
1564
1785
  "POST",
1565
- `/v1/db/${this.namespace}/${this.slug}/vectors/query`,
1566
- { query: text, topK: opts.topK, filter: opts.filter }
1786
+ `/v1/db/${this.namespace}/${this.slug}/approval-rules`,
1787
+ input
1567
1788
  );
1568
1789
  }
1569
- /** Delete vectors by id. Up to 1000 ids per call. */
1570
- async delete(ids) {
1790
+ /** Requires an admin-role bearer token. */
1791
+ async delete(ruleId) {
1571
1792
  return this.client.request(
1572
1793
  "DELETE",
1573
- `/v1/db/${this.namespace}/${this.slug}/vectors`,
1574
- { ids }
1794
+ `/v1/db/${this.namespace}/${this.slug}/approval-rules/${encodeURIComponent(
1795
+ ruleId
1796
+ )}`
1575
1797
  );
1576
1798
  }
1577
1799
  };
1578
- var PerSQLApprovals = class {
1579
- constructor(client, namespace, slug) {
1580
- this.client = client;
1581
- this.namespace = namespace;
1582
- this.slug = slug;
1583
- }
1584
- /**
1585
- * Redeem an approved approvalToken. The bearer must be the same one
1586
- * that minted it, and the request must target the same database.
1587
- * Returns the result of the originally-blocked query or batch.
1588
- */
1589
- async redeem(approvalToken) {
1590
- const raw = await this.client.request("POST", `/v1/db/${this.namespace}/${this.slug}/redeem_approval`, {
1591
- approvalToken
1592
- });
1593
- if (Array.isArray(raw)) {
1594
- return raw.map((r) => ({
1595
- ...r,
1596
- data: rowsToObjects(r.columns, r.rows)
1597
- }));
1598
- }
1599
- return { ...raw, data: rowsToObjects(raw.columns, raw.rows) };
1600
- }
1601
- };
1602
1800
  var PerSQLProposals = class {
1603
1801
  constructor(client, namespace, slug) {
1604
1802
  this.client = client;
@@ -1760,13 +1958,13 @@ function rowsToObjects(columns, rows) {
1760
1958
  0 && (module.exports = {
1761
1959
  ApprovalRequiredError,
1762
1960
  PerSQL,
1961
+ PerSQLApprovalRules,
1763
1962
  PerSQLApprovals,
1764
- PerSQLBlob,
1765
1963
  PerSQLBranches,
1766
1964
  PerSQLDatabase,
1767
1965
  PerSQLError,
1768
1966
  PerSQLProposals,
1769
- PerSQLVectors,
1770
- RateLimitError
1967
+ RateLimitError,
1968
+ SupportClient
1771
1969
  });
1772
1970
  //# sourceMappingURL=index.cjs.map