sermon-js 0.1.0 → 0.2.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.
@@ -150,6 +150,21 @@ type RedisPingOptions = PresetOptions & {
150
150
  declare const redis: {
151
151
  ping: (options: RedisPingOptions) => ServiceDefinition;
152
152
  };
153
+ type PostgresPingOptions = PresetOptions & {
154
+ /**
155
+ * Runs one statement with the driver you already use (pg, postgres.js, Neon…). When
156
+ * undefined the service is "not configured".
157
+ */
158
+ query: ((sql: string) => Promise<unknown>) | undefined;
159
+ /** Optional: the connection string, only so it is redacted from public errors */
160
+ secrets?: {
161
+ url?: string;
162
+ };
163
+ };
164
+ /** Presets for PostgreSQL servers reached with a client library */
165
+ declare const postgres: {
166
+ ping: (options: PostgresPingOptions) => ServiceDefinition;
167
+ };
153
168
 
154
169
  type ApiKey = {
155
170
  secrets: {
@@ -200,6 +215,24 @@ declare const anthropic: (options: CommonOptions & ApiKey) => ServiceDefinition;
200
215
  declare const gemini: (options: CommonOptions & ApiKey) => ServiceDefinition;
201
216
  /** CAMB.AI. Lists source languages. */
202
217
  declare const cambai: (options: CommonOptions & ApiKey) => ServiceDefinition;
218
+ type ElevenLabsOptions = PresetOptions & ApiKey & {
219
+ track?: {
220
+ /** Warn when less than this share of the period's credits is left (default 10) */
221
+ quota?: {
222
+ warnBelowPct?: number;
223
+ };
224
+ };
225
+ };
226
+ /**
227
+ * ElevenLabs. Reads the subscription, which validates the API key.
228
+ * - up: the key works. A key without the user scope is refused with `missing_permissions`,
229
+ * which still proves it is valid.
230
+ * - degraded: less than `track.quota.warnBelowPct` of the credits left
231
+ * - down: the API rejects the key or errors
232
+ *
233
+ * Reports a `usage` bar (credits used this period, with the reset time) and `metrics.tier`.
234
+ */
235
+ declare const elevenlabs: (options: ElevenLabsOptions) => ServiceDefinition;
203
236
 
204
237
  type DeepLOptions = PresetOptions & {
205
238
  secrets: {
@@ -377,6 +410,40 @@ type StatuspageOptions = PresetOptions & {
377
410
  * The provider's own description becomes the error text.
378
411
  */
379
412
  declare const statuspage: (options: StatuspageOptions) => ServiceDefinition;
413
+ type ResendOptions = PresetOptions & {
414
+ secrets: {
415
+ apiKey: string | undefined;
416
+ };
417
+ };
418
+ /**
419
+ * Resend. Lists domains, which validates the API key.
420
+ * - up: the key works. A sending-only key is refused with `restricted_api_key`, which still
421
+ * proves it is valid.
422
+ * - degraded: domains exist, but none is verified
423
+ * - down: the API rejects the key or errors
424
+ *
425
+ * Reports `metrics.domains` and `metrics.verified` for full-access keys.
426
+ */
427
+ declare const resend: (options: ResendOptions) => ServiceDefinition;
428
+ type MeilisearchOptions = PresetOptions & {
429
+ /** The server, e.g. "https://search.example.com" */
430
+ host: string | undefined;
431
+ /** Also require this index, and report its document count */
432
+ index?: string;
433
+ secrets: {
434
+ apiKey: string | undefined;
435
+ };
436
+ };
437
+ /**
438
+ * Meilisearch. Reads `/health`, then the index (or the list of indexes), which validates the key.
439
+ * - up: the server is available and the key works
440
+ * - degraded: the index does not exist
441
+ * - down: the server is unavailable, or rejects the key
442
+ *
443
+ * Reports `metrics.documents`, and `metrics.indexing` while a batch is running, when the key
444
+ * may read statistics; scoped keys often may not, and that is not held against them.
445
+ */
446
+ declare const meilisearch: (options: MeilisearchOptions) => ServiceDefinition;
380
447
 
381
448
  type PusherOptions = PresetOptions & {
382
449
  appId: string | undefined;
@@ -424,4 +491,26 @@ declare function signPusherRequest({ appId, key, secret, path, params, timestamp
424
491
  */
425
492
  declare const pusher: (options: PusherOptions) => ServiceDefinition;
426
493
 
427
- export { type AttendeeOptions, type AwsCredentialsOptions, type AxiomOptions, type AzureTranslatorOptions, type CloudflareStreamOptions, type DeepLOptions, type DeepgramOptions, type FlyAppOptions, type GcpInstanceOptions, type GitHubOptions, type GoogleServiceAccount, type GoogleTranslateOptions, type MailerSendOptions, type MongoPingOptions, type MuxOptions, type OpenAIOptions, type PusherOptions, type RedisPingOptions, type RevolutOptions, type S3BucketOptions, type SpeechmaticsOptions, type StatuspageOptions, type UpstashRedisOptions, anthropic, attendee, aws, axiom, azureTranslator, cambai, clearGoogleTokens, cloudflareStream, crashReason, deepgram, deepl, fly, gcp, gemini, github, gladia, googleServiceAccountToken, googleTranslate, mailersend, mongodb, mux, openai, parseServiceAccount, pusher, redis, revolut, signGoogleAssertion, signPusherRequest, speechmatics, statuspage, upstashRedis };
494
+ type VercelAiGatewayOptions = PresetOptions & {
495
+ secrets: {
496
+ apiKey: string | undefined;
497
+ };
498
+ track?: {
499
+ /** Warn when the credit balance drops below this amount in USD (default 5). `false` skips the balance. */
500
+ credits?: {
501
+ warnBelow?: number;
502
+ } | false;
503
+ };
504
+ };
505
+ type VercelBlobOptions = PresetOptions & {
506
+ secrets: {
507
+ token: string | undefined;
508
+ };
509
+ };
510
+ /** Presets for Vercel products */
511
+ declare const vercel: {
512
+ aiGateway: (options: VercelAiGatewayOptions) => ServiceDefinition;
513
+ blob: (options: VercelBlobOptions) => ServiceDefinition;
514
+ };
515
+
516
+ export { type AttendeeOptions, type AwsCredentialsOptions, type AxiomOptions, type AzureTranslatorOptions, type CloudflareStreamOptions, type DeepLOptions, type DeepgramOptions, type ElevenLabsOptions, type FlyAppOptions, type GcpInstanceOptions, type GitHubOptions, type GoogleServiceAccount, type GoogleTranslateOptions, type MailerSendOptions, type MeilisearchOptions, type MongoPingOptions, type MuxOptions, type OpenAIOptions, type PostgresPingOptions, type PusherOptions, type RedisPingOptions, type ResendOptions, type RevolutOptions, type S3BucketOptions, type SpeechmaticsOptions, type StatuspageOptions, type UpstashRedisOptions, type VercelAiGatewayOptions, type VercelBlobOptions, anthropic, attendee, aws, axiom, azureTranslator, cambai, clearGoogleTokens, cloudflareStream, crashReason, deepgram, deepl, elevenlabs, fly, gcp, gemini, github, gladia, googleServiceAccountToken, googleTranslate, mailersend, meilisearch, mongodb, mux, openai, parseServiceAccount, postgres, pusher, redis, resend, revolut, signGoogleAssertion, signPusherRequest, speechmatics, statuspage, upstashRedis, vercel };
@@ -150,6 +150,21 @@ type RedisPingOptions = PresetOptions & {
150
150
  declare const redis: {
151
151
  ping: (options: RedisPingOptions) => ServiceDefinition;
152
152
  };
153
+ type PostgresPingOptions = PresetOptions & {
154
+ /**
155
+ * Runs one statement with the driver you already use (pg, postgres.js, Neon…). When
156
+ * undefined the service is "not configured".
157
+ */
158
+ query: ((sql: string) => Promise<unknown>) | undefined;
159
+ /** Optional: the connection string, only so it is redacted from public errors */
160
+ secrets?: {
161
+ url?: string;
162
+ };
163
+ };
164
+ /** Presets for PostgreSQL servers reached with a client library */
165
+ declare const postgres: {
166
+ ping: (options: PostgresPingOptions) => ServiceDefinition;
167
+ };
153
168
 
154
169
  type ApiKey = {
155
170
  secrets: {
@@ -200,6 +215,24 @@ declare const anthropic: (options: CommonOptions & ApiKey) => ServiceDefinition;
200
215
  declare const gemini: (options: CommonOptions & ApiKey) => ServiceDefinition;
201
216
  /** CAMB.AI. Lists source languages. */
202
217
  declare const cambai: (options: CommonOptions & ApiKey) => ServiceDefinition;
218
+ type ElevenLabsOptions = PresetOptions & ApiKey & {
219
+ track?: {
220
+ /** Warn when less than this share of the period's credits is left (default 10) */
221
+ quota?: {
222
+ warnBelowPct?: number;
223
+ };
224
+ };
225
+ };
226
+ /**
227
+ * ElevenLabs. Reads the subscription, which validates the API key.
228
+ * - up: the key works. A key without the user scope is refused with `missing_permissions`,
229
+ * which still proves it is valid.
230
+ * - degraded: less than `track.quota.warnBelowPct` of the credits left
231
+ * - down: the API rejects the key or errors
232
+ *
233
+ * Reports a `usage` bar (credits used this period, with the reset time) and `metrics.tier`.
234
+ */
235
+ declare const elevenlabs: (options: ElevenLabsOptions) => ServiceDefinition;
203
236
 
204
237
  type DeepLOptions = PresetOptions & {
205
238
  secrets: {
@@ -377,6 +410,40 @@ type StatuspageOptions = PresetOptions & {
377
410
  * The provider's own description becomes the error text.
378
411
  */
379
412
  declare const statuspage: (options: StatuspageOptions) => ServiceDefinition;
413
+ type ResendOptions = PresetOptions & {
414
+ secrets: {
415
+ apiKey: string | undefined;
416
+ };
417
+ };
418
+ /**
419
+ * Resend. Lists domains, which validates the API key.
420
+ * - up: the key works. A sending-only key is refused with `restricted_api_key`, which still
421
+ * proves it is valid.
422
+ * - degraded: domains exist, but none is verified
423
+ * - down: the API rejects the key or errors
424
+ *
425
+ * Reports `metrics.domains` and `metrics.verified` for full-access keys.
426
+ */
427
+ declare const resend: (options: ResendOptions) => ServiceDefinition;
428
+ type MeilisearchOptions = PresetOptions & {
429
+ /** The server, e.g. "https://search.example.com" */
430
+ host: string | undefined;
431
+ /** Also require this index, and report its document count */
432
+ index?: string;
433
+ secrets: {
434
+ apiKey: string | undefined;
435
+ };
436
+ };
437
+ /**
438
+ * Meilisearch. Reads `/health`, then the index (or the list of indexes), which validates the key.
439
+ * - up: the server is available and the key works
440
+ * - degraded: the index does not exist
441
+ * - down: the server is unavailable, or rejects the key
442
+ *
443
+ * Reports `metrics.documents`, and `metrics.indexing` while a batch is running, when the key
444
+ * may read statistics; scoped keys often may not, and that is not held against them.
445
+ */
446
+ declare const meilisearch: (options: MeilisearchOptions) => ServiceDefinition;
380
447
 
381
448
  type PusherOptions = PresetOptions & {
382
449
  appId: string | undefined;
@@ -424,4 +491,26 @@ declare function signPusherRequest({ appId, key, secret, path, params, timestamp
424
491
  */
425
492
  declare const pusher: (options: PusherOptions) => ServiceDefinition;
426
493
 
427
- export { type AttendeeOptions, type AwsCredentialsOptions, type AxiomOptions, type AzureTranslatorOptions, type CloudflareStreamOptions, type DeepLOptions, type DeepgramOptions, type FlyAppOptions, type GcpInstanceOptions, type GitHubOptions, type GoogleServiceAccount, type GoogleTranslateOptions, type MailerSendOptions, type MongoPingOptions, type MuxOptions, type OpenAIOptions, type PusherOptions, type RedisPingOptions, type RevolutOptions, type S3BucketOptions, type SpeechmaticsOptions, type StatuspageOptions, type UpstashRedisOptions, anthropic, attendee, aws, axiom, azureTranslator, cambai, clearGoogleTokens, cloudflareStream, crashReason, deepgram, deepl, fly, gcp, gemini, github, gladia, googleServiceAccountToken, googleTranslate, mailersend, mongodb, mux, openai, parseServiceAccount, pusher, redis, revolut, signGoogleAssertion, signPusherRequest, speechmatics, statuspage, upstashRedis };
494
+ type VercelAiGatewayOptions = PresetOptions & {
495
+ secrets: {
496
+ apiKey: string | undefined;
497
+ };
498
+ track?: {
499
+ /** Warn when the credit balance drops below this amount in USD (default 5). `false` skips the balance. */
500
+ credits?: {
501
+ warnBelow?: number;
502
+ } | false;
503
+ };
504
+ };
505
+ type VercelBlobOptions = PresetOptions & {
506
+ secrets: {
507
+ token: string | undefined;
508
+ };
509
+ };
510
+ /** Presets for Vercel products */
511
+ declare const vercel: {
512
+ aiGateway: (options: VercelAiGatewayOptions) => ServiceDefinition;
513
+ blob: (options: VercelBlobOptions) => ServiceDefinition;
514
+ };
515
+
516
+ export { type AttendeeOptions, type AwsCredentialsOptions, type AxiomOptions, type AzureTranslatorOptions, type CloudflareStreamOptions, type DeepLOptions, type DeepgramOptions, type ElevenLabsOptions, type FlyAppOptions, type GcpInstanceOptions, type GitHubOptions, type GoogleServiceAccount, type GoogleTranslateOptions, type MailerSendOptions, type MeilisearchOptions, type MongoPingOptions, type MuxOptions, type OpenAIOptions, type PostgresPingOptions, type PusherOptions, type RedisPingOptions, type ResendOptions, type RevolutOptions, type S3BucketOptions, type SpeechmaticsOptions, type StatuspageOptions, type UpstashRedisOptions, type VercelAiGatewayOptions, type VercelBlobOptions, anthropic, attendee, aws, axiom, azureTranslator, cambai, clearGoogleTokens, cloudflareStream, crashReason, deepgram, deepl, elevenlabs, fly, gcp, gemini, github, gladia, googleServiceAccountToken, googleTranslate, mailersend, meilisearch, mongodb, mux, openai, parseServiceAccount, postgres, pusher, redis, resend, revolut, signGoogleAssertion, signPusherRequest, speechmatics, statuspage, upstashRedis, vercel };
@@ -346,6 +346,16 @@ var redisPing = definePreset()({
346
346
  })
347
347
  });
348
348
  var redis = { ping: redisPing };
349
+ var postgresPing = definePreset()({
350
+ kind: "postgres.ping",
351
+ requiredFields: ["query"],
352
+ defaults: { slowMs: 1e3 },
353
+ derive: () => ({ name: "PostgreSQL", description: "Runs `select 1`" }),
354
+ check: ({ options, measure }) => measure(async () => {
355
+ await options.query("select 1");
356
+ })
357
+ });
358
+ var postgres = { ping: postgresPing };
349
359
 
350
360
  // src/presets/providers/shared.ts
351
361
  var bearer = (token) => ({ Authorization: `Bearer ${token}` });
@@ -464,6 +474,38 @@ var cambai = definePreset()({
464
474
  derive: () => ({ name: "CAMB.AI", identity: "cambai", description: "Lists source languages" }),
465
475
  check: ({ secrets, http }) => call(http, "https://client.camb.ai/apis/source-languages", { headers: { "x-api-key": secrets.apiKey } })
466
476
  });
477
+ var elevenlabs = definePreset()({
478
+ kind: "elevenlabs",
479
+ requiredSecrets: ["apiKey"],
480
+ derive: () => ({ name: "ElevenLabs", identity: "elevenlabs", description: "Reads the subscription" }),
481
+ check: async ({ options, secrets, http }) => {
482
+ const res = await http("https://api.elevenlabs.io/v1/user/subscription", {
483
+ headers: { "xi-api-key": secrets.apiKey }
484
+ });
485
+ const body = res.json ?? {};
486
+ if (res.status === 401 && body.detail?.status === "missing_permissions") {
487
+ return { status: "up", latencyMs: res.latencyMs, httpStatus: 401, metrics: { key: "restricted" } };
488
+ }
489
+ if (!res.ok) return res.outcome;
490
+ const metrics = body.tier ? { tier: body.tier } : void 0;
491
+ const { character_count: used, character_limit: limit } = body;
492
+ if (typeof used !== "number" || !limit) return { ...res.outcome, metrics };
493
+ return {
494
+ ...res.outcome,
495
+ ...quota({
496
+ label: "Credits",
497
+ used,
498
+ limit,
499
+ unit: "credits",
500
+ // ElevenLabs gives the reset as epoch seconds
501
+ resetsAt: body.next_character_count_reset_unix ? body.next_character_count_reset_unix * 1e3 : void 0,
502
+ warnAbovePct: 100 - (options.track?.quota?.warnBelowPct ?? 10),
503
+ warning: "Credits almost exhausted"
504
+ }),
505
+ metrics
506
+ };
507
+ }
508
+ });
467
509
 
468
510
  // src/presets/providers/translation.ts
469
511
  var deepl = definePreset()({
@@ -695,6 +737,64 @@ var statuspage = definePreset()({
695
737
  return { status, error: status === "up" ? void 0 : description };
696
738
  })
697
739
  });
740
+ var resend = definePreset()({
741
+ kind: "resend",
742
+ requiredSecrets: ["apiKey"],
743
+ derive: () => ({ name: "Resend", identity: "resend", description: "Lists domains" }),
744
+ check: async ({ secrets, http }) => {
745
+ const res = await http("https://api.resend.com/domains", { headers: bearer(secrets.apiKey) });
746
+ const body = res.json ?? {};
747
+ if (res.status === 401 && body.name === "restricted_api_key") {
748
+ return { status: "up", latencyMs: res.latencyMs, httpStatus: 401, metrics: { key: "sending only" } };
749
+ }
750
+ if (!res.ok || !Array.isArray(body.data)) return res.outcome;
751
+ const verified = body.data.filter((domain) => domain.status === "verified").length;
752
+ const unverified = body.data.length > 0 && verified === 0;
753
+ return {
754
+ ...res.outcome,
755
+ status: unverified ? "degraded" : "up",
756
+ error: unverified ? "No verified domain" : void 0,
757
+ metrics: { domains: body.data.length, verified }
758
+ };
759
+ }
760
+ });
761
+ var meilisearch = definePreset()({
762
+ kind: "meilisearch",
763
+ requiredFields: ["host"],
764
+ requiredSecrets: ["apiKey"],
765
+ derive: (options) => ({
766
+ name: "Meilisearch",
767
+ identity: options.index ? `meilisearch:${options.index}` : "meilisearch",
768
+ description: options.index ? `Reads the health and the ${options.index} index` : "Reads the health and lists indexes"
769
+ }),
770
+ check: async ({ options, secrets, http, combine }) => {
771
+ const host = options.host.replace(/\/+$/, "");
772
+ const headers = bearer(secrets.apiKey);
773
+ const index = options.index ? `/indexes/${encodeURIComponent(options.index)}` : void 0;
774
+ const health = call(
775
+ http,
776
+ `${host}/health`,
777
+ void 0,
778
+ (res2) => res2.json?.status === "available" ? void 0 : { status: "down", error: "Not available" }
779
+ );
780
+ const access = http(`${host}${index ?? "/indexes?limit=1"}`, { headers }).then((res2) => {
781
+ if (res2.status !== 404 || !options.index) return res2.outcome;
782
+ return {
783
+ status: "degraded",
784
+ latencyMs: res2.latencyMs,
785
+ httpStatus: 404,
786
+ error: `Index ${options.index} not found`
787
+ };
788
+ });
789
+ const stats = http(`${host}${index ?? ""}/stats`, { headers });
790
+ const outcome = combine(await Promise.all([health, access]));
791
+ const res = await stats;
792
+ if (!res.ok) return outcome;
793
+ const body = res.json ?? {};
794
+ const documents = body.numberOfDocuments ?? Object.values(body.indexes ?? {}).reduce((sum, entry) => sum + (entry.numberOfDocuments ?? 0), 0);
795
+ return { ...outcome, metrics: { ...outcome.metrics, documents, ...body.isIndexing ? { indexing: "yes" } : {} } };
796
+ }
797
+ });
698
798
 
699
799
  // src/presets/providers/pusher.ts
700
800
  var MAX_CHANNELS = 500;
@@ -826,6 +926,46 @@ var pusher = definePreset()({
826
926
  }
827
927
  });
828
928
 
829
- export { anthropic, attendee, aws, axiom, azureTranslator, cambai, clearGoogleTokens, cloudflareStream, crashReason, deepgram, deepl, fly, gcp, gemini, github, gladia, googleServiceAccountToken, googleTranslate, mailersend, mongodb, mux, openai, parseServiceAccount, pusher, redis, revolut, signGoogleAssertion, signPusherRequest, speechmatics, statuspage, upstashRedis };
929
+ // src/presets/providers/vercel.ts
930
+ var aiGateway = definePreset()({
931
+ kind: "vercel.aiGateway",
932
+ requiredSecrets: ["apiKey"],
933
+ derive: (options) => ({
934
+ name: "Vercel AI Gateway",
935
+ identity: "vercel.aiGateway",
936
+ description: options.track?.credits === false ? "Lists models" : "Reads the credit balance"
937
+ }),
938
+ check: ({ options, secrets, http }) => {
939
+ const headers = bearer(secrets.apiKey);
940
+ if (options.track?.credits === false) return call(http, "https://ai-gateway.vercel.sh/v1/models", { headers });
941
+ const warnBelow = options.track?.credits?.warnBelow ?? 5;
942
+ return call(http, "https://ai-gateway.vercel.sh/v1/credits", { headers }, (res) => {
943
+ const body = res.json ?? {};
944
+ const balance = Number(body.balance);
945
+ if (body.balance === void 0 || !Number.isFinite(balance)) return void 0;
946
+ const used = Number(body.total_used);
947
+ const low = balance < warnBelow;
948
+ return {
949
+ status: low ? "degraded" : "up",
950
+ error: low ? "Low credit balance" : void 0,
951
+ metrics: {
952
+ balance: `${round(balance, 2)} USD`,
953
+ ...body.total_used !== void 0 && Number.isFinite(used) ? { used: `${round(used, 2)} USD` } : {}
954
+ }
955
+ };
956
+ });
957
+ }
958
+ });
959
+ var blob = definePreset()({
960
+ kind: "vercel.blob",
961
+ requiredSecrets: ["token"],
962
+ derive: () => ({ name: "Vercel Blob", identity: "vercel.blob", description: "Lists one blob of the store" }),
963
+ check: ({ secrets, http }) => call(http, "https://vercel.com/api/blob?limit=1", {
964
+ headers: { ...bearer(secrets.token), "x-api-version": "12" }
965
+ })
966
+ });
967
+ var vercel = { aiGateway, blob };
968
+
969
+ export { anthropic, attendee, aws, axiom, azureTranslator, cambai, clearGoogleTokens, cloudflareStream, crashReason, deepgram, deepl, elevenlabs, fly, gcp, gemini, github, gladia, googleServiceAccountToken, googleTranslate, mailersend, meilisearch, mongodb, mux, openai, parseServiceAccount, postgres, pusher, redis, resend, revolut, signGoogleAssertion, signPusherRequest, speechmatics, statuspage, upstashRedis, vercel };
830
970
  //# sourceMappingURL=index.js.map
831
971
  //# sourceMappingURL=index.js.map