@bunbase-ae/js 3.0.1-next.403.265841b → 3.0.1-next.407.08bf4a7

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/admin.ts +138 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bunbase-ae/js",
3
- "version": "3.0.1-next.403.265841b",
3
+ "version": "3.0.1-next.407.08bf4a7",
4
4
  "type": "module",
5
5
  "description": "TypeScript/JavaScript SDK for BunBase",
6
6
  "license": "UNLICENSED",
package/src/admin.ts CHANGED
@@ -1307,6 +1307,40 @@ export interface CreateNamedQueryInput {
1307
1307
 
1308
1308
  export type UpdateNamedQueryInput = Partial<Omit<CreateNamedQueryInput, "name">>;
1309
1309
 
1310
+ // ─── Query Advisor (#481) ──────────────────────────────────────────────────────
1311
+
1312
+ export interface QueryAdvisorCandidate {
1313
+ /** Normalized RPC + filter/sort shape — never raw values. */
1314
+ signature: string;
1315
+ tenant_id: string | null;
1316
+ call_count: number;
1317
+ total_duration_ms: number;
1318
+ avg_duration_ms: number;
1319
+ p50_ms: number;
1320
+ p99_ms: number;
1321
+ last_seen: number;
1322
+ cache_hit_estimate: number;
1323
+ projected_savings_ms: number;
1324
+ }
1325
+
1326
+ export interface AdvisorListResult {
1327
+ /** False when the advisor is disabled — render the "Enable" CTA. */
1328
+ enabled: boolean;
1329
+ candidates: QueryAdvisorCandidate[];
1330
+ settings: { enabled: boolean; sampleRate: number; retentionDays: number; topK: number };
1331
+ }
1332
+
1333
+ export interface PromoteAdvisorInput {
1334
+ name: string;
1335
+ description?: string | null;
1336
+ sql: string;
1337
+ params?: Record<string, NamedQueryParamDef>;
1338
+ access?: NamedQueryAccessRule;
1339
+ result_cache_ttl_s?: number;
1340
+ /** The originating advisor signature. Stamped so the suggestion disappears. */
1341
+ signature: string;
1342
+ }
1343
+
1310
1344
  class AdminNamedQueriesClient {
1311
1345
  constructor(private readonly http: HttpClient) {}
1312
1346
 
@@ -1375,6 +1409,37 @@ class AdminNamedQueriesClient {
1375
1409
  "/api/v1/admin/queries/install-starter",
1376
1410
  );
1377
1411
  }
1412
+
1413
+ // ─── Query Advisor (#481) ────────────────────────────────────────────────────
1414
+
1415
+ /**
1416
+ * List the top hot read-pattern candidates the advisor suggests promoting
1417
+ * into named queries, ranked by projected savings. `enabled` is false (with
1418
+ * an empty list) when the advisor is turned off — surface the "Enable" CTA.
1419
+ */
1420
+ async advisorList(opts: { tenantId?: string | null } = {}): Promise<AdvisorListResult> {
1421
+ const qs =
1422
+ opts.tenantId !== undefined && opts.tenantId !== null
1423
+ ? `?tenant_id=${encodeURIComponent(opts.tenantId)}`
1424
+ : "";
1425
+ return this.http.request<AdvisorListResult>("GET", `/api/v1/admin/queries/advisor${qs}`);
1426
+ }
1427
+
1428
+ /** Enable the Query Advisor at runtime (existing-deployment opt-in). */
1429
+ async advisorEnable(): Promise<{ enabled: boolean }> {
1430
+ return this.http.request<{ enabled: boolean }>("POST", "/api/v1/admin/queries/advisor/enable");
1431
+ }
1432
+
1433
+ /**
1434
+ * Promote a captured signature into a named query. SQL/params are best-effort
1435
+ * pre-filled by the caller (Studio derives them from the signature). Once
1436
+ * promoted, the advisor stops suggesting that signature.
1437
+ */
1438
+ async advisorPromote(input: PromoteAdvisorInput): Promise<NamedQuery> {
1439
+ return this.http.request<NamedQuery>("POST", "/api/v1/admin/queries/advisor/promote", {
1440
+ body: input,
1441
+ });
1442
+ }
1378
1443
  }
1379
1444
 
1380
1445
  // ─── Write hooks ──────────────────────────────────────────────────────────────
@@ -1387,6 +1452,21 @@ export type HookEvent =
1387
1452
  | "beforeDelete"
1388
1453
  | "afterDelete";
1389
1454
 
1455
+ /**
1456
+ * Per-hook delivery options (issue #682). `mode: "durable"` persists each
1457
+ * after-hook delivery before its first attempt and retries with backoff until
1458
+ * acked or dead-lettered, surviving restarts. Default is fire-and-forget.
1459
+ */
1460
+ export interface HookDeliveryConfig {
1461
+ mode?: "fire_and_forget" | "durable";
1462
+ /** Max attempts before dead-lettering (durable mode). Default 10. */
1463
+ max_retries?: number;
1464
+ /** Per-attempt request timeout in ms. Default 10000. */
1465
+ timeout_ms?: number;
1466
+ /** Park exhausted deliveries in the dead-letter store for replay. Default true. */
1467
+ dead_letter?: boolean;
1468
+ }
1469
+
1390
1470
  export interface HookConfig {
1391
1471
  id: string;
1392
1472
  collection: string;
@@ -1397,6 +1477,8 @@ export interface HookConfig {
1397
1477
  timeout_ms: number;
1398
1478
  enabled: boolean;
1399
1479
  sort_order: number;
1480
+ /** Durable-delivery options, or null for legacy fire-and-forget (#682). */
1481
+ delivery?: HookDeliveryConfig | null;
1400
1482
  created_at: number;
1401
1483
  }
1402
1484
 
@@ -1412,10 +1494,35 @@ export interface CreateHookInput {
1412
1494
  enabled?: boolean;
1413
1495
  /** Ascending order for hooks sharing the same (collection, event). Default 0. */
1414
1496
  sort_order?: number;
1497
+ /** Durable, at-least-once delivery options (after-hooks only). (#682) */
1498
+ delivery?: HookDeliveryConfig | null;
1415
1499
  }
1416
1500
 
1417
1501
  export type UpdateHookInput = Partial<Omit<CreateHookInput, "collection" | "event">>;
1418
1502
 
1503
+ /** Status of a durable delivery as surfaced to the admin replay API (#682). */
1504
+ export type WebhookDeliveryStatus = "pending" | "in_flight" | "delivered" | "dead_letter";
1505
+
1506
+ /** Admin-facing view of a durable delivery. The signing secret is never included. */
1507
+ export interface WebhookDeliverySummary {
1508
+ id: string;
1509
+ idempotency_key: string;
1510
+ hook_id: string | null;
1511
+ collection: string;
1512
+ event: string;
1513
+ url: string;
1514
+ has_secret: boolean;
1515
+ status: WebhookDeliveryStatus;
1516
+ attempts: number;
1517
+ max_attempts: number;
1518
+ timeout_ms: number;
1519
+ next_attempt_at: number;
1520
+ last_error: string | null;
1521
+ last_status: number | null;
1522
+ created_at: number;
1523
+ updated_at: number;
1524
+ }
1525
+
1419
1526
  class AdminHooksClient {
1420
1527
  constructor(private readonly http: HttpClient) {}
1421
1528
 
@@ -1453,6 +1560,37 @@ class AdminHooksClient {
1453
1560
  async delete(id: string): Promise<void> {
1454
1561
  await this.http.request("DELETE", `/api/v1/admin/hooks/${encodeURIComponent(id)}`);
1455
1562
  }
1563
+
1564
+ /**
1565
+ * List durable deliveries (issue #682). `status: "pending"` returns rows
1566
+ * still in the live queue; `status: "dead_letter"` returns exhausted
1567
+ * deliveries parked for inspection/replay. Secrets are never returned.
1568
+ */
1569
+ async deliveries(opts?: {
1570
+ status?: "pending" | "dead_letter";
1571
+ limit?: number;
1572
+ }): Promise<WebhookDeliverySummary[]> {
1573
+ const query: Record<string, string> = {};
1574
+ if (opts?.status) query.status = opts.status;
1575
+ if (opts?.limit != null) query.limit = String(opts.limit);
1576
+ const res = await this.http.request<{ items: WebhookDeliverySummary[] }>(
1577
+ "GET",
1578
+ "/api/v1/admin/hooks/deliveries",
1579
+ { query },
1580
+ );
1581
+ return res.items;
1582
+ }
1583
+
1584
+ /**
1585
+ * Replay a durable delivery (issue #682) — re-arm a queue row or re-enqueue
1586
+ * a dead-letter row back to pending. Returns the (possibly new) queue id.
1587
+ */
1588
+ async replayDelivery(id: string): Promise<{ id: string; source: "queue" | "dead_letter" }> {
1589
+ return this.http.request<{ id: string; source: "queue" | "dead_letter" }>(
1590
+ "POST",
1591
+ `/api/v1/admin/hooks/deliveries/${encodeURIComponent(id)}/replay`,
1592
+ );
1593
+ }
1456
1594
  }
1457
1595
 
1458
1596
  // Tenant membership management — surfaces the /api/v1/admin/tenants/* endpoints