sermon-js 0.1.0 → 0.3.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.
Files changed (52) hide show
  1. package/README.md +2 -1
  2. package/dist/api/index.d.cts +4 -4
  3. package/dist/api/index.d.ts +4 -4
  4. package/dist/{chunk-PARE6EUZ.cjs → chunk-NZTKXXW2.cjs} +7 -3
  5. package/dist/chunk-NZTKXXW2.cjs.map +1 -0
  6. package/dist/{chunk-2M4UBCDM.js → chunk-R7BDAQOM.js} +7 -3
  7. package/dist/chunk-R7BDAQOM.js.map +1 -0
  8. package/dist/{config-BEbP-uLf.d.cts → config-gro29syt.d.cts} +1 -1
  9. package/dist/{config-w1tm1bdu.d.ts → config-iY18j9IA.d.ts} +1 -1
  10. package/dist/{generic-lmrGxMDC.d.cts → generic-BUiaKpNp.d.cts} +2 -2
  11. package/dist/{generic-BJmlgtUM.d.ts → generic-CV2O4aNH.d.ts} +2 -2
  12. package/dist/index.cjs +6 -6
  13. package/dist/index.d.cts +8 -8
  14. package/dist/index.d.ts +8 -8
  15. package/dist/index.js +2 -2
  16. package/dist/presets/index.cjs +552 -47
  17. package/dist/presets/index.cjs.map +1 -1
  18. package/dist/presets/index.d.cts +261 -13
  19. package/dist/presets/index.d.ts +261 -13
  20. package/dist/presets/index.js +542 -48
  21. package/dist/presets/index.js.map +1 -1
  22. package/dist/react/heroui/index.cjs +27 -18
  23. package/dist/react/heroui/index.cjs.map +1 -1
  24. package/dist/react/heroui/index.d.cts +7 -2
  25. package/dist/react/heroui/index.d.ts +7 -2
  26. package/dist/react/heroui/index.js +13 -4
  27. package/dist/react/heroui/index.js.map +1 -1
  28. package/dist/react/index.d.cts +2 -2
  29. package/dist/react/index.d.ts +2 -2
  30. package/dist/{status-DsWzgb9Q.d.cts → status-BExBb08T.d.cts} +3 -3
  31. package/dist/{status-zd04ZQ98.d.ts → status-DmRhwvVC.d.ts} +3 -3
  32. package/dist/{store-_GuzSP0z.d.ts → store-BfKP7CjW.d.ts} +1 -1
  33. package/dist/{store-DybhDphS.d.cts → store-CAIB7Esp.d.cts} +1 -1
  34. package/dist/stores/mongodb.d.cts +2 -2
  35. package/dist/stores/mongodb.d.ts +2 -2
  36. package/dist/stores/redis.d.cts +2 -2
  37. package/dist/stores/redis.d.ts +2 -2
  38. package/dist/stores/sql.d.cts +2 -2
  39. package/dist/stores/sql.d.ts +2 -2
  40. package/dist/stores/upstash.d.cts +2 -2
  41. package/dist/stores/upstash.d.ts +2 -2
  42. package/dist/testing/index.cjs +3 -3
  43. package/dist/testing/index.d.cts +3 -3
  44. package/dist/testing/index.d.ts +3 -3
  45. package/dist/testing/index.js +1 -1
  46. package/dist/{tree-BXbXfjF1.d.cts → tree-J3riUyI9.d.cts} +9 -0
  47. package/dist/{tree-BXbXfjF1.d.ts → tree-J3riUyI9.d.ts} +9 -0
  48. package/dist/{types-CctvUAs2.d.cts → types-BVa6vIKk.d.cts} +9 -0
  49. package/dist/{types-CctvUAs2.d.ts → types-BVa6vIKk.d.ts} +9 -0
  50. package/package.json +1 -1
  51. package/dist/chunk-2M4UBCDM.js.map +0 -1
  52. package/dist/chunk-PARE6EUZ.cjs.map +0 -1
@@ -19,9 +19,9 @@ function withKeys(machines) {
19
19
  const seen = /* @__PURE__ */ new Map();
20
20
  return [...machines].sort((a, b) => (a.region ?? "").localeCompare(b.region ?? "") || a.id.localeCompare(b.id)).map((machine) => {
21
21
  const region = machine.region ?? "unknown";
22
- const count = (seen.get(region) ?? 0) + 1;
23
- seen.set(region, count);
24
- return { machine, region, key: count === 1 ? region : `${region}#${count}` };
22
+ const count2 = (seen.get(region) ?? 0) + 1;
23
+ seen.set(region, count2);
24
+ return { machine, region, key: count2 === 1 ? region : `${region}#${count2}` };
25
25
  });
26
26
  }
27
27
  function median(values) {
@@ -223,8 +223,8 @@ var instance = chunkXHXEKB3Q_cjs.definePreset()({
223
223
  }),
224
224
  check: async ({ options, secrets, http, now }) => {
225
225
  const account = parseServiceAccount(secrets.serviceAccount);
226
- const project = options.project ?? account?.project_id;
227
- if (!account || !project) {
226
+ const project2 = options.project ?? account?.project_id;
227
+ if (!account || !project2) {
228
228
  return { status: "down", probed: false, error: "The service account secret is not a service-account JSON key" };
229
229
  }
230
230
  let token;
@@ -239,7 +239,7 @@ var instance = chunkXHXEKB3Q_cjs.definePreset()({
239
239
  return { status: "down", probed: false, error: error instanceof Error ? error.message : String(error) };
240
240
  }
241
241
  const info = await http(
242
- `https://compute.googleapis.com/compute/v1/projects/${project}/zones/${options.zone}/instances/${options.instance}`,
242
+ `https://compute.googleapis.com/compute/v1/projects/${project2}/zones/${options.zone}/instances/${options.instance}`,
243
243
  { headers: { Authorization: `Bearer ${token}` } }
244
244
  );
245
245
  const state = info.json?.status;
@@ -262,6 +262,68 @@ var instance = chunkXHXEKB3Q_cjs.definePreset()({
262
262
  }
263
263
  });
264
264
  var gcp = { instance };
265
+
266
+ // src/presets/providers/shared.ts
267
+ var bearer = (token) => ({ Authorization: `Bearer ${token}` });
268
+ var round = (value, digits = 1) => Math.round(value * 10 ** digits) / 10 ** digits;
269
+ function base64(text) {
270
+ const bytes = new TextEncoder().encode(text);
271
+ let binary = "";
272
+ for (const byte of bytes) binary += String.fromCharCode(byte);
273
+ return btoa(binary);
274
+ }
275
+ async function call(http, url, init, refine) {
276
+ const response = await http(url, init);
277
+ if (!response.ok || !refine) return response.outcome;
278
+ return { ...response.outcome, ...chunkXHXEKB3Q_cjs.normalizeReturn(refine(response)) };
279
+ }
280
+ function quota({
281
+ label,
282
+ used,
283
+ limit,
284
+ unit,
285
+ resetsAt,
286
+ warnAbovePct,
287
+ warning
288
+ }) {
289
+ const pct = limit > 0 ? used / limit * 100 : 0;
290
+ const over = pct >= warnAbovePct;
291
+ return {
292
+ status: over ? "degraded" : "up",
293
+ error: over ? warning : void 0,
294
+ usage: [{ label, used, limit, unit, resetsAt }]
295
+ };
296
+ }
297
+ function summarize(instances, noun) {
298
+ const down = instances.filter((instance2) => instance2.status === "down");
299
+ const degraded = instances.filter((instance2) => instance2.status === "degraded");
300
+ const awake = instances.filter((instance2) => instance2.status === "up" || instance2.status === "degraded");
301
+ const keysOf = (items) => items.map((instance2) => instance2.key).join(", ");
302
+ const latencies = instances.map((instance2) => instance2.latencyMs).filter((l) => l !== void 0);
303
+ const latencyMs = latencies.length ? Math.max(...latencies) : void 0;
304
+ if (instances.length > 0 && down.length === instances.length) {
305
+ return { status: "down", latencyMs, error: `All ${instances.length} ${noun}(s) failing` };
306
+ }
307
+ if (down.length > 0) {
308
+ return { status: "degraded", latencyMs, error: `${down.length}/${instances.length} ${noun}(s) failing: ${keysOf(down)}` };
309
+ }
310
+ if (degraded.length > 0) return { status: "degraded", latencyMs, error: `Degraded: ${keysOf(degraded)}` };
311
+ return { status: awake.length || instances.length === 0 ? "up" : "sleeping", latencyMs };
312
+ }
313
+ function keyAccepted(res) {
314
+ if (res.status === 400 || res.status === 422) return { status: "up", latencyMs: res.latencyMs, httpStatus: res.status };
315
+ if (res.status === 402) {
316
+ return { status: "degraded", latencyMs: res.latencyMs, httpStatus: 402, error: "Out of credits, or payment required" };
317
+ }
318
+ return res.outcome;
319
+ }
320
+ var emptyPost = (headers) => ({
321
+ method: "POST",
322
+ headers: { "content-type": "application/json", ...headers },
323
+ body: "{}"
324
+ });
325
+
326
+ // src/presets/aws.ts
265
327
  async function signedCall({
266
328
  http,
267
329
  secrets,
@@ -321,7 +383,170 @@ var s3Bucket = chunkXHXEKB3Q_cjs.definePreset()({
321
383
  return response.outcome;
322
384
  }
323
385
  });
324
- var aws = { credentials, s3Bucket };
386
+ function pingBody(model) {
387
+ if (/(^|\.)cohere\.embed/.test(model)) return { texts: ["ping"], input_type: "search_query" };
388
+ return { anthropic_version: "bedrock-2023-05-31", max_tokens: 1, messages: [{ role: "user", content: "ping" }] };
389
+ }
390
+ var bedrockPreset = chunkXHXEKB3Q_cjs.definePreset()({
391
+ kind: "aws.bedrock",
392
+ requiredFields: ["region"],
393
+ requiredSecrets: "all",
394
+ defaults: { slowMs: 5e3, timeoutMs: 2e4 },
395
+ derive: () => ({
396
+ name: "Amazon Bedrock",
397
+ identity: "aws.bedrock",
398
+ description: "Invokes each monitored model with one token"
399
+ }),
400
+ check: async ({ options, secrets, http }) => {
401
+ const signer = secrets.accessKeyId && secrets.secretAccessKey ? new aws4fetch.AwsClient({
402
+ accessKeyId: secrets.accessKeyId,
403
+ secretAccessKey: secrets.secretAccessKey,
404
+ service: "bedrock",
405
+ region: options.region
406
+ }) : void 0;
407
+ const invoke = async (model) => {
408
+ const url = `https://bedrock-runtime.${options.region}.amazonaws.com/model/${encodeURIComponent(model)}/invoke`;
409
+ const init = {
410
+ method: "POST",
411
+ headers: { "content-type": "application/json", accept: "application/json" },
412
+ body: JSON.stringify(pingBody(model))
413
+ };
414
+ if (!signer) return http(url, { ...init, headers: { ...init.headers, ...bearer(secrets.bearerToken ?? "") } });
415
+ const signed = await signer.sign(url, init);
416
+ return http(signed.url, { ...init, headers: Object.fromEntries(signed.headers.entries()) });
417
+ };
418
+ const instances = await Promise.all(
419
+ [...new Set(options.models)].map(async (model) => {
420
+ const res = await invoke(model);
421
+ return {
422
+ key: model,
423
+ status: res.outcome.status,
424
+ latencyMs: res.status === void 0 ? void 0 : res.latencyMs,
425
+ httpStatus: res.status,
426
+ error: res.outcome.error
427
+ };
428
+ })
429
+ );
430
+ return { ...summarize(instances, "model"), instances, instanceLabels: { key: "Model" } };
431
+ }
432
+ });
433
+ function bedrock(options) {
434
+ const { bearerToken, accessKeyId, secretAccessKey } = options.secrets;
435
+ return bedrockPreset({ ...options, secrets: bearerToken ? { bearerToken } : { accessKeyId, secretAccessKey } });
436
+ }
437
+ var aws = { credentials, s3Bucket, bedrock };
438
+
439
+ // src/presets/neon.ts
440
+ var API = "https://console.neon.tech/api/v2";
441
+ var GB = 1024 ** 3;
442
+ function withKeys2(endpoints, branches) {
443
+ const seen = /* @__PURE__ */ new Map();
444
+ return endpoints.map((endpoint) => {
445
+ const name = branches.get(endpoint.branch_id)?.name ?? endpoint.branch_id;
446
+ const count2 = (seen.get(name) ?? 0) + 1;
447
+ seen.set(name, count2);
448
+ return { endpoint, key: count2 === 1 ? name : `${name}#${count2}` };
449
+ });
450
+ }
451
+ var project = chunkXHXEKB3Q_cjs.definePreset()({
452
+ kind: "neon.project",
453
+ requiredFields: ["projectId"],
454
+ requiredSecrets: ["apiKey"],
455
+ defaults: { slowMs: 1e3 },
456
+ derive: (options) => ({
457
+ name: "Neon",
458
+ identity: `neon.project:${options.projectId ?? ""}`,
459
+ description: "Compute states from the Neon API, then `select 1` on an active compute only"
460
+ }),
461
+ check: async ({ options, secrets, http, measure }) => {
462
+ const base = `${API}/projects/${encodeURIComponent(options.projectId)}`;
463
+ const headers = { ...bearer(secrets.apiKey), accept: "application/json" };
464
+ const [list, info, branchList] = await Promise.all([
465
+ http(`${base}/endpoints`, { headers }),
466
+ http(base, { headers }),
467
+ http(`${base}/branches`, { headers })
468
+ ]);
469
+ if (list.status === 404) {
470
+ return { status: "down", probed: false, httpStatus: 404, error: `Project "${options.projectId}" not found on Neon` };
471
+ }
472
+ const endpoints = list.json?.endpoints;
473
+ if (!list.ok || !Array.isArray(endpoints)) {
474
+ return {
475
+ status: "degraded",
476
+ probed: false,
477
+ httpStatus: list.status,
478
+ error: list.status ? `Neon API HTTP ${list.status}` : `Neon API unreachable: ${list.outcome.error ?? "no response"}`
479
+ };
480
+ }
481
+ if (endpoints.length === 0) return { status: "down", probed: false, error: "No compute: nothing can connect" };
482
+ const branches = branchList.json?.branches ?? [];
483
+ const details = info.json?.project;
484
+ const byId = new Map(branches.map((branch) => [branch.id, branch]));
485
+ const defaultBranch = branches.find((branch) => branch.default)?.id;
486
+ const keyed = withKeys2(endpoints, byId);
487
+ const target = keyed.find(({ endpoint }) => endpoint.id === options.endpoint) ?? (options.endpoint ? void 0 : keyed.find(({ endpoint }) => endpoint.type === "read_write" && endpoint.branch_id === defaultBranch) ?? keyed.find(({ endpoint }) => endpoint.type === "read_write"));
488
+ const ping = options.query && target?.endpoint.current_state === "active" && !target.endpoint.disabled ? await measure(async () => void await options.query("select 1")) : void 0;
489
+ const instances = keyed.map(({ endpoint, key }) => {
490
+ const row = { key, region: endpoint.region_id, id: endpoint.id };
491
+ if (endpoint.disabled) return { ...row, state: "disabled", status: "sleeping" };
492
+ if (endpoint.current_state === "idle") return { ...row, state: "idle", status: "sleeping" };
493
+ if (endpoint.current_state !== "active") return { ...row, state: endpoint.current_state, status: "degraded" };
494
+ if (ping && endpoint.id === target?.endpoint.id) {
495
+ return { ...row, state: "active", status: ping.status, latencyMs: ping.latencyMs, error: ping.error };
496
+ }
497
+ return { ...row, state: "active", status: "up" };
498
+ });
499
+ const usage = [];
500
+ const warnings = [];
501
+ const bar = (entry, warnAbovePct = 90) => {
502
+ usage.push(entry);
503
+ if (entry.limit > 0 && entry.used / entry.limit * 100 >= warnAbovePct) warnings.push(`${entry.label} close to the plan limit`);
504
+ };
505
+ const compute = options.track?.compute;
506
+ if (compute && typeof details?.compute_time_seconds === "number") {
507
+ bar(
508
+ {
509
+ label: "Compute this period",
510
+ used: round(details.compute_time_seconds / 3600),
511
+ limit: compute.maxHours,
512
+ unit: "CU-hours",
513
+ resetsAt: details.consumption_period_end ? Date.parse(details.consumption_period_end) || void 0 : void 0
514
+ },
515
+ compute.warnAbovePct
516
+ );
517
+ }
518
+ const storage = options.track?.storage;
519
+ if (storage && branches.length > 0) {
520
+ const bytes = branches.reduce((sum, branch) => sum + (branch.logical_size ?? 0), 0);
521
+ bar({ label: "Storage", used: round(bytes / GB, 2), limit: storage.maxGb, unit: "GB" }, storage.warnAbovePct);
522
+ }
523
+ const main = instances.find((instance2) => instance2.id === target?.endpoint.id) ?? instances[0];
524
+ const active = instances.filter((instance2) => instance2.state === "active").length;
525
+ let status = main.status;
526
+ let error = main.error;
527
+ if (status === "degraded" && !error) error = `Compute is ${main.state}`;
528
+ if ((status === "up" || status === "sleeping") && warnings.length) {
529
+ status = "degraded";
530
+ error = warnings.join("; ");
531
+ }
532
+ return {
533
+ status,
534
+ probed: !!ping,
535
+ latencyMs: ping?.latencyMs ?? list.latencyMs,
536
+ error,
537
+ metrics: {
538
+ ...details?.pg_version ? { postgres: details.pg_version } : {},
539
+ ...details?.region_id ? { region: details.region_id } : {},
540
+ ...branches.length ? { branches: branches.length } : {},
541
+ computes: `${active}/${instances.length} active`
542
+ },
543
+ usage: usage.length ? usage : void 0,
544
+ instances,
545
+ instanceLabels: { key: "Compute", detail: "Endpoint" }
546
+ };
547
+ }
548
+ });
549
+ var neon = { project };
325
550
 
326
551
  // src/presets/databases.ts
327
552
  var mongoPing = chunkXHXEKB3Q_cjs.definePreset()({
@@ -348,38 +573,16 @@ var redisPing = chunkXHXEKB3Q_cjs.definePreset()({
348
573
  })
349
574
  });
350
575
  var redis = { ping: redisPing };
351
-
352
- // src/presets/providers/shared.ts
353
- var bearer = (token) => ({ Authorization: `Bearer ${token}` });
354
- var round = (value, digits = 1) => Math.round(value * 10 ** digits) / 10 ** digits;
355
- function base64(text) {
356
- const bytes = new TextEncoder().encode(text);
357
- let binary = "";
358
- for (const byte of bytes) binary += String.fromCharCode(byte);
359
- return btoa(binary);
360
- }
361
- async function call(http, url, init, refine) {
362
- const response = await http(url, init);
363
- if (!response.ok || !refine) return response.outcome;
364
- return { ...response.outcome, ...chunkXHXEKB3Q_cjs.normalizeReturn(refine(response)) };
365
- }
366
- function quota({
367
- label,
368
- used,
369
- limit,
370
- unit,
371
- resetsAt,
372
- warnAbovePct,
373
- warning
374
- }) {
375
- const pct = limit > 0 ? used / limit * 100 : 0;
376
- const over = pct >= warnAbovePct;
377
- return {
378
- status: over ? "degraded" : "up",
379
- error: over ? warning : void 0,
380
- usage: [{ label, used, limit, unit, resetsAt }]
381
- };
382
- }
576
+ var postgresPing = chunkXHXEKB3Q_cjs.definePreset()({
577
+ kind: "postgres.ping",
578
+ requiredFields: ["query"],
579
+ defaults: { slowMs: 1e3 },
580
+ derive: () => ({ name: "PostgreSQL", description: "Runs `select 1`" }),
581
+ check: ({ options, measure }) => measure(async () => {
582
+ await options.query("select 1");
583
+ })
584
+ });
585
+ var postgres = { ping: postgresPing };
383
586
 
384
587
  // src/presets/providers/ai.ts
385
588
  var deepgram = chunkXHXEKB3Q_cjs.definePreset()({
@@ -444,13 +647,33 @@ var openai = chunkXHXEKB3Q_cjs.definePreset()({
444
647
  }
445
648
  )
446
649
  });
650
+ var API2 = "https://api.anthropic.com/v1/models";
447
651
  var anthropic = chunkXHXEKB3Q_cjs.definePreset()({
448
652
  kind: "anthropic",
449
653
  requiredSecrets: ["apiKey"],
450
- derive: () => ({ name: "Anthropic", identity: "anthropic", description: "Lists models" }),
451
- check: ({ secrets, http }) => call(http, "https://api.anthropic.com/v1/models?limit=1", {
452
- headers: { "x-api-key": secrets.apiKey, "anthropic-version": "2023-06-01" }
453
- })
654
+ derive: (options) => ({
655
+ name: "Anthropic",
656
+ identity: "anthropic",
657
+ description: options.track?.models?.length ? "Reads each monitored model" : "Lists models"
658
+ }),
659
+ check: async ({ options, secrets, http }) => {
660
+ const headers = { "x-api-key": secrets.apiKey, "anthropic-version": "2023-06-01" };
661
+ const models = [...new Set(options.track?.models ?? [])];
662
+ if (models.length === 0) return (await http(`${API2}?limit=1`, { headers })).outcome;
663
+ const responses = await Promise.all(
664
+ models.map(async (model) => ({ model, res: await http(`${API2}/${encodeURIComponent(model)}`, { headers }) }))
665
+ );
666
+ const rejected = responses.find(({ res }) => res.status === 401 || res.status === 403);
667
+ if (rejected) return rejected.res.outcome;
668
+ const instances = responses.map(({ model, res }) => {
669
+ const base = { key: model, latencyMs: res.status === void 0 ? void 0 : res.latencyMs, httpStatus: res.status };
670
+ if (res.ok) return { ...base, status: "up" };
671
+ if (res.status === 404) return { ...base, status: "down", error: "Model not found: retired, or not available to this key" };
672
+ if (res.status === 529) return { ...base, status: "degraded", error: "Overloaded" };
673
+ return { ...base, status: res.outcome.status, error: res.outcome.error };
674
+ });
675
+ return { ...summarize(instances, "model"), instances, instanceLabels: { key: "Model" } };
676
+ }
454
677
  });
455
678
  var gemini = chunkXHXEKB3Q_cjs.definePreset()({
456
679
  kind: "gemini",
@@ -466,6 +689,38 @@ var cambai = chunkXHXEKB3Q_cjs.definePreset()({
466
689
  derive: () => ({ name: "CAMB.AI", identity: "cambai", description: "Lists source languages" }),
467
690
  check: ({ secrets, http }) => call(http, "https://client.camb.ai/apis/source-languages", { headers: { "x-api-key": secrets.apiKey } })
468
691
  });
692
+ var elevenlabs = chunkXHXEKB3Q_cjs.definePreset()({
693
+ kind: "elevenlabs",
694
+ requiredSecrets: ["apiKey"],
695
+ derive: () => ({ name: "ElevenLabs", identity: "elevenlabs", description: "Reads the subscription" }),
696
+ check: async ({ options, secrets, http }) => {
697
+ const res = await http("https://api.elevenlabs.io/v1/user/subscription", {
698
+ headers: { "xi-api-key": secrets.apiKey }
699
+ });
700
+ const body = res.json ?? {};
701
+ if (res.status === 401 && body.detail?.status === "missing_permissions") {
702
+ return { status: "up", latencyMs: res.latencyMs, httpStatus: 401, metrics: { key: "restricted" } };
703
+ }
704
+ if (!res.ok) return res.outcome;
705
+ const metrics = body.tier ? { tier: body.tier } : void 0;
706
+ const { character_count: used, character_limit: limit } = body;
707
+ if (typeof used !== "number" || !limit) return { ...res.outcome, metrics };
708
+ return {
709
+ ...res.outcome,
710
+ ...quota({
711
+ label: "Credits",
712
+ used,
713
+ limit,
714
+ unit: "credits",
715
+ // ElevenLabs gives the reset as epoch seconds
716
+ resetsAt: body.next_character_count_reset_unix ? body.next_character_count_reset_unix * 1e3 : void 0,
717
+ warnAbovePct: 100 - (options.track?.quota?.warnBelowPct ?? 10),
718
+ warning: "Credits almost exhausted"
719
+ }),
720
+ metrics
721
+ };
722
+ }
723
+ });
469
724
 
470
725
  // src/presets/providers/translation.ts
471
726
  var deepl = chunkXHXEKB3Q_cjs.definePreset()({
@@ -697,6 +952,64 @@ var statuspage = chunkXHXEKB3Q_cjs.definePreset()({
697
952
  return { status, error: status === "up" ? void 0 : description };
698
953
  })
699
954
  });
955
+ var resend = chunkXHXEKB3Q_cjs.definePreset()({
956
+ kind: "resend",
957
+ requiredSecrets: ["apiKey"],
958
+ derive: () => ({ name: "Resend", identity: "resend", description: "Lists domains" }),
959
+ check: async ({ secrets, http }) => {
960
+ const res = await http("https://api.resend.com/domains", { headers: bearer(secrets.apiKey) });
961
+ const body = res.json ?? {};
962
+ if (res.status === 401 && body.name === "restricted_api_key") {
963
+ return { status: "up", latencyMs: res.latencyMs, httpStatus: 401, metrics: { key: "sending only" } };
964
+ }
965
+ if (!res.ok || !Array.isArray(body.data)) return res.outcome;
966
+ const verified = body.data.filter((domain) => domain.status === "verified").length;
967
+ const unverified = body.data.length > 0 && verified === 0;
968
+ return {
969
+ ...res.outcome,
970
+ status: unverified ? "degraded" : "up",
971
+ error: unverified ? "No verified domain" : void 0,
972
+ metrics: { domains: body.data.length, verified }
973
+ };
974
+ }
975
+ });
976
+ var meilisearch = chunkXHXEKB3Q_cjs.definePreset()({
977
+ kind: "meilisearch",
978
+ requiredFields: ["host"],
979
+ requiredSecrets: ["apiKey"],
980
+ derive: (options) => ({
981
+ name: "Meilisearch",
982
+ identity: options.index ? `meilisearch:${options.index}` : "meilisearch",
983
+ description: options.index ? `Reads the health and the ${options.index} index` : "Reads the health and lists indexes"
984
+ }),
985
+ check: async ({ options, secrets, http, combine }) => {
986
+ const host = options.host.replace(/\/+$/, "");
987
+ const headers = bearer(secrets.apiKey);
988
+ const index = options.index ? `/indexes/${encodeURIComponent(options.index)}` : void 0;
989
+ const health = call(
990
+ http,
991
+ `${host}/health`,
992
+ void 0,
993
+ (res2) => res2.json?.status === "available" ? void 0 : { status: "down", error: "Not available" }
994
+ );
995
+ const access = http(`${host}${index ?? "/indexes?limit=1"}`, { headers }).then((res2) => {
996
+ if (res2.status !== 404 || !options.index) return res2.outcome;
997
+ return {
998
+ status: "degraded",
999
+ latencyMs: res2.latencyMs,
1000
+ httpStatus: 404,
1001
+ error: `Index ${options.index} not found`
1002
+ };
1003
+ });
1004
+ const stats = http(`${host}${index ?? ""}/stats`, { headers });
1005
+ const outcome = combine(await Promise.all([health, access]));
1006
+ const res = await stats;
1007
+ if (!res.ok) return outcome;
1008
+ const body = res.json ?? {};
1009
+ const documents = body.numberOfDocuments ?? Object.values(body.indexes ?? {}).reduce((sum, entry) => sum + (entry.numberOfDocuments ?? 0), 0);
1010
+ return { ...outcome, metrics: { ...outcome.metrics, documents, ...body.isIndexing ? { indexing: "yes" } : {} } };
1011
+ }
1012
+ });
700
1013
 
701
1014
  // src/presets/providers/pusher.ts
702
1015
  var MAX_CHANNELS = 500;
@@ -780,12 +1093,12 @@ var pusher = chunkXHXEKB3Q_cjs.definePreset()({
780
1093
  let countingDisabled = false;
781
1094
  const counts = await mapLimit(queried, CONCURRENCY, async (name) => {
782
1095
  const res = await get(`/channels/${encodeURIComponent(name)}`, { info: "subscription_count" });
783
- const count = res.json?.subscription_count;
1096
+ const count2 = res.json?.subscription_count;
784
1097
  if (!res.ok) failed += 1;
785
- else if (typeof count !== "number") countingDisabled = true;
786
- return typeof count === "number" ? count : 0;
1098
+ else if (typeof count2 !== "number") countingDisabled = true;
1099
+ return typeof count2 === "number" ? count2 : 0;
787
1100
  });
788
- const connections = counts.reduce((sum, count) => sum + count, 0);
1101
+ const connections = counts.reduce((sum, count2) => sum + count2, 0);
789
1102
  const signedInUsers = queried.reduce(
790
1103
  (sum, name, index) => name.startsWith("#server-to-user-") ? sum + (counts[index] ?? 0) : sum,
791
1104
  0
@@ -828,6 +1141,187 @@ var pusher = chunkXHXEKB3Q_cjs.definePreset()({
828
1141
  }
829
1142
  });
830
1143
 
1144
+ // src/presets/providers/vercel.ts
1145
+ var aiGateway = chunkXHXEKB3Q_cjs.definePreset()({
1146
+ kind: "vercel.aiGateway",
1147
+ requiredSecrets: ["apiKey"],
1148
+ derive: (options) => ({
1149
+ name: "Vercel AI Gateway",
1150
+ identity: "vercel.aiGateway",
1151
+ description: options.track?.credits === false ? "Lists models" : "Reads the credit balance"
1152
+ }),
1153
+ check: ({ options, secrets, http }) => {
1154
+ const headers = bearer(secrets.apiKey);
1155
+ if (options.track?.credits === false) return call(http, "https://ai-gateway.vercel.sh/v1/models", { headers });
1156
+ const warnBelow = options.track?.credits?.warnBelow ?? 5;
1157
+ return call(http, "https://ai-gateway.vercel.sh/v1/credits", { headers }, (res) => {
1158
+ const body = res.json ?? {};
1159
+ const balance = Number(body.balance);
1160
+ if (body.balance === void 0 || !Number.isFinite(balance)) return void 0;
1161
+ const used = Number(body.total_used);
1162
+ const low = balance < warnBelow;
1163
+ return {
1164
+ status: low ? "degraded" : "up",
1165
+ error: low ? "Low credit balance" : void 0,
1166
+ metrics: {
1167
+ balance: `${round(balance, 2)} USD`,
1168
+ ...body.total_used !== void 0 && Number.isFinite(used) ? { used: `${round(used, 2)} USD` } : {}
1169
+ }
1170
+ };
1171
+ });
1172
+ }
1173
+ });
1174
+ var blob = chunkXHXEKB3Q_cjs.definePreset()({
1175
+ kind: "vercel.blob",
1176
+ requiredSecrets: ["token"],
1177
+ derive: () => ({ name: "Vercel Blob", identity: "vercel.blob", description: "Lists one blob of the store" }),
1178
+ check: ({ secrets, http }) => call(http, "https://vercel.com/api/blob?limit=1", {
1179
+ headers: { ...bearer(secrets.token), "x-api-version": "12" }
1180
+ })
1181
+ });
1182
+ var vercel = { aiGateway, blob };
1183
+
1184
+ // src/presets/providers/stripe.ts
1185
+ var API3 = "https://api.stripe.com/v1";
1186
+ var DAY_S = 24 * 60 * 60;
1187
+ var ZERO_DECIMAL = /* @__PURE__ */ new Set(["bif", "clp", "djf", "gnf", "jpy", "kmf", "krw", "mga", "pyg", "rwf", "ugx", "vnd", "vuv", "xaf", "xof", "xpf"]);
1188
+ function money(amounts) {
1189
+ return (amounts ?? []).slice(0, 3).map(({ amount, currency }) => {
1190
+ const value = ZERO_DECIMAL.has(currency) ? String(amount) : (amount / 100).toFixed(2);
1191
+ return `${value} ${currency.toUpperCase()}`;
1192
+ }).join(", ");
1193
+ }
1194
+ function endpointKey(url) {
1195
+ try {
1196
+ const { host, pathname } = new URL(url);
1197
+ return `${host}${pathname}`;
1198
+ } catch {
1199
+ return "endpoint";
1200
+ }
1201
+ }
1202
+ var count = (list) => `${list.data?.length ?? 0}${list.has_more ? "+" : ""}`;
1203
+ var stripe = chunkXHXEKB3Q_cjs.definePreset()({
1204
+ kind: "stripe",
1205
+ requiredSecrets: ["apiKey"],
1206
+ derive: () => ({ name: "Stripe", identity: "stripe", description: "Reads the balance, account and webhook endpoints" }),
1207
+ check: async ({ options, secrets, http, now }) => {
1208
+ const { account = true, webhooks = true, disputes = true } = options.track ?? {};
1209
+ const get = (path) => http(`${API3}${path}`, { headers: bearer(secrets.apiKey) });
1210
+ const skip = Promise.resolve(void 0);
1211
+ const [balance, accountRes, endpoints, undelivered, disputeList] = await Promise.all([
1212
+ get("/balance"),
1213
+ account ? get("/account") : skip,
1214
+ webhooks ? get("/webhook_endpoints?limit=100") : skip,
1215
+ webhooks ? get(`/events?delivery_success=false&limit=100&created[gte]=${Math.floor(now / 1e3) - DAY_S}`) : skip,
1216
+ disputes ? get("/disputes?limit=100") : skip
1217
+ ]);
1218
+ if (!balance.ok && balance.status !== 403) return balance.outcome;
1219
+ const metrics = {};
1220
+ const warnings = [];
1221
+ const funds = balance.ok ? balance.json : void 0;
1222
+ if (funds) {
1223
+ metrics.mode = funds.livemode ? "live" : "test";
1224
+ if (funds.available?.length) metrics.available = money(funds.available);
1225
+ if (funds.pending?.length) metrics.pending = money(funds.pending);
1226
+ } else {
1227
+ metrics.key = "restricted";
1228
+ }
1229
+ if (accountRes?.ok && funds?.livemode) {
1230
+ const body = accountRes.json;
1231
+ if (body.charges_enabled === false) warnings.push("Charges are disabled");
1232
+ if (body.payouts_enabled === false) warnings.push("Payouts are disabled");
1233
+ const overdue = body.requirements?.past_due?.length ?? 0;
1234
+ if (overdue > 0) warnings.push(`${overdue} account requirement(s) past due`);
1235
+ }
1236
+ let instances;
1237
+ if (endpoints?.ok) {
1238
+ const list = endpoints.json.data ?? [];
1239
+ const seen = /* @__PURE__ */ new Set();
1240
+ instances = list.map((endpoint) => {
1241
+ let key = endpointKey(endpoint.url);
1242
+ for (let n = 2; seen.has(key); n++) key = `${endpointKey(endpoint.url)}#${n}`;
1243
+ seen.add(key);
1244
+ const enabled = endpoint.status === "enabled";
1245
+ return { key, id: endpoint.id, state: endpoint.status, status: enabled ? "up" : "down", error: enabled ? void 0 : "Endpoint disabled" };
1246
+ });
1247
+ metrics.webhookEndpoints = list.length;
1248
+ const disabled = instances.filter((instance2) => instance2.status === "down").length;
1249
+ if (disabled > 0) warnings.push(`${disabled} webhook endpoint(s) disabled`);
1250
+ }
1251
+ if (undelivered?.ok) {
1252
+ const list = undelivered.json;
1253
+ metrics.undelivered24h = count(list);
1254
+ if (list.data?.length) warnings.push(`${count(list)} event(s) not delivered in the last 24 h`);
1255
+ }
1256
+ if (disputeList?.ok) {
1257
+ const open = (disputeList.json.data ?? []).filter(
1258
+ (dispute) => dispute.status.endsWith("needs_response")
1259
+ );
1260
+ metrics.openDisputes = open.length;
1261
+ }
1262
+ return {
1263
+ status: warnings.length ? "degraded" : "up",
1264
+ latencyMs: balance.latencyMs,
1265
+ httpStatus: balance.status,
1266
+ error: warnings.join("; ") || void 0,
1267
+ metrics,
1268
+ instances: instances?.length ? instances : void 0,
1269
+ instanceLabels: { key: "Webhook endpoint", detail: "ID" }
1270
+ };
1271
+ }
1272
+ });
1273
+
1274
+ // src/presets/providers/search.ts
1275
+ var exa = chunkXHXEKB3Q_cjs.definePreset()({
1276
+ kind: "exa",
1277
+ requiredSecrets: ["apiKey"],
1278
+ derive: () => ({ name: "Exa", identity: "exa", description: "Validates the API key (no search is run)" }),
1279
+ check: async ({ secrets, http }) => keyAccepted(await http("https://api.exa.ai/search", emptyPost({ "x-api-key": secrets.apiKey })))
1280
+ });
1281
+ var nimble = chunkXHXEKB3Q_cjs.definePreset()({
1282
+ kind: "nimble",
1283
+ requiredSecrets: ["apiKey"],
1284
+ derive: () => ({ name: "Nimble", identity: "nimble", description: "Validates the API key (no search is run)" }),
1285
+ check: async ({ secrets, http }) => keyAccepted(await http("https://sdk.nimbleway.com/v1/search", emptyPost(bearer(secrets.apiKey))))
1286
+ });
1287
+ var tavily = chunkXHXEKB3Q_cjs.definePreset()({
1288
+ kind: "tavily",
1289
+ requiredSecrets: ["apiKey"],
1290
+ derive: () => ({ name: "Tavily", identity: "tavily", description: "Reads the credits used this period" }),
1291
+ check: async ({ options, secrets, http }) => {
1292
+ const res = await http("https://api.tavily.com/usage", { headers: bearer(secrets.apiKey) });
1293
+ if (!res.ok) return res.outcome;
1294
+ const { key, account } = res.json ?? {};
1295
+ const metrics = account?.current_plan ? { plan: account.current_plan } : void 0;
1296
+ const [used, limit] = key?.limit ? [key.usage, key.limit] : [account?.plan_usage, account?.plan_limit];
1297
+ if (typeof used !== "number" || !limit) return { ...res.outcome, metrics };
1298
+ return {
1299
+ ...res.outcome,
1300
+ ...quota({
1301
+ label: "Credits",
1302
+ used,
1303
+ limit,
1304
+ unit: "credits",
1305
+ warnAbovePct: options.track?.quota?.warnAbovePct ?? 90,
1306
+ warning: "Credits almost exhausted"
1307
+ }),
1308
+ metrics
1309
+ };
1310
+ }
1311
+ });
1312
+ var emelia = chunkXHXEKB3Q_cjs.definePreset()({
1313
+ kind: "emelia",
1314
+ requiredSecrets: ["apiKey"],
1315
+ derive: () => ({ name: "Emelia", identity: "emelia", description: "Validates the API key (no lookup is run)" }),
1316
+ check: async ({ options, secrets, http }) => keyAccepted(
1317
+ await http(
1318
+ `${(options.baseUrl ?? "https://api.emelia.io").replace(/\/+$/, "")}/tools/find/email`,
1319
+ // Emelia takes the bare key, without a scheme
1320
+ emptyPost({ Authorization: secrets.apiKey })
1321
+ )
1322
+ )
1323
+ });
1324
+
831
1325
  Object.defineProperty(exports, "generic", {
832
1326
  enumerable: true,
833
1327
  get: function () { return chunkELV4ZU6G_cjs.generic; }
@@ -843,6 +1337,9 @@ exports.cloudflareStream = cloudflareStream;
843
1337
  exports.crashReason = crashReason;
844
1338
  exports.deepgram = deepgram;
845
1339
  exports.deepl = deepl;
1340
+ exports.elevenlabs = elevenlabs;
1341
+ exports.emelia = emelia;
1342
+ exports.exa = exa;
846
1343
  exports.fly = fly;
847
1344
  exports.gcp = gcp;
848
1345
  exports.gemini = gemini;
@@ -851,17 +1348,25 @@ exports.gladia = gladia;
851
1348
  exports.googleServiceAccountToken = googleServiceAccountToken;
852
1349
  exports.googleTranslate = googleTranslate;
853
1350
  exports.mailersend = mailersend;
1351
+ exports.meilisearch = meilisearch;
854
1352
  exports.mongodb = mongodb;
855
1353
  exports.mux = mux;
1354
+ exports.neon = neon;
1355
+ exports.nimble = nimble;
856
1356
  exports.openai = openai;
857
1357
  exports.parseServiceAccount = parseServiceAccount;
1358
+ exports.postgres = postgres;
858
1359
  exports.pusher = pusher;
859
1360
  exports.redis = redis;
1361
+ exports.resend = resend;
860
1362
  exports.revolut = revolut;
861
1363
  exports.signGoogleAssertion = signGoogleAssertion;
862
1364
  exports.signPusherRequest = signPusherRequest;
863
1365
  exports.speechmatics = speechmatics;
864
1366
  exports.statuspage = statuspage;
1367
+ exports.stripe = stripe;
1368
+ exports.tavily = tavily;
865
1369
  exports.upstashRedis = upstashRedis;
1370
+ exports.vercel = vercel;
866
1371
  //# sourceMappingURL=index.cjs.map
867
1372
  //# sourceMappingURL=index.cjs.map