@contractspec/bundle.library 3.10.0 → 3.10.2
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/.turbo/turbo-build.log +212 -206
- package/CHANGELOG.md +43 -0
- package/dist/components/docs/DocsIndexPage.js +2 -2
- package/dist/components/docs/docsManifest.js +1 -1
- package/dist/components/docs/guides/GuideProviderBackedKnowledgePage.d.ts +1 -0
- package/dist/components/docs/guides/GuideProviderBackedKnowledgePage.js +73 -0
- package/dist/components/docs/guides/GuidesIndexPage.js +1 -1
- package/dist/components/docs/guides/guides.docblocks.js +10 -1
- package/dist/components/docs/guides/index.d.ts +1 -0
- package/dist/components/docs/guides/index.js +132 -52
- package/dist/components/docs/index.js +414 -284
- package/dist/components/docs/integrations/IntegrationsGmailPage.js +3 -3
- package/dist/components/docs/integrations/IntegrationsGoogleCalendarPage.js +1 -1
- package/dist/components/docs/integrations/IntegrationsGoogleDrivePage.d.ts +1 -0
- package/dist/components/docs/integrations/IntegrationsGoogleDrivePage.js +22 -0
- package/dist/components/docs/integrations/IntegrationsOverviewPage.js +1 -1
- package/dist/components/docs/integrations/index.d.ts +1 -0
- package/dist/components/docs/integrations/index.js +65 -45
- package/dist/components/docs/knowledge/KnowledgeGovernancePage.d.ts +1 -0
- package/dist/components/docs/knowledge/KnowledgeGovernancePage.js +23 -0
- package/dist/components/docs/knowledge/KnowledgeOverviewPage.js +1 -1
- package/dist/components/docs/knowledge/KnowledgeSourcesPage.js +11 -2
- package/dist/components/docs/knowledge/index.d.ts +1 -0
- package/dist/components/docs/knowledge/index.js +49 -19
- package/dist/index.js +430 -300
- package/dist/node/components/docs/DocsIndexPage.js +2 -2
- package/dist/node/components/docs/docsManifest.js +1 -1
- package/dist/node/components/docs/guides/GuideProviderBackedKnowledgePage.js +72 -0
- package/dist/node/components/docs/guides/GuidesIndexPage.js +1 -1
- package/dist/node/components/docs/guides/guides.docblocks.js +10 -1
- package/dist/node/components/docs/guides/index.js +132 -52
- package/dist/node/components/docs/index.js +414 -284
- package/dist/node/components/docs/integrations/IntegrationsGmailPage.js +3 -3
- package/dist/node/components/docs/integrations/IntegrationsGoogleCalendarPage.js +1 -1
- package/dist/node/components/docs/integrations/IntegrationsGoogleDrivePage.js +21 -0
- package/dist/node/components/docs/integrations/IntegrationsOverviewPage.js +1 -1
- package/dist/node/components/docs/integrations/index.js +65 -45
- package/dist/node/components/docs/knowledge/KnowledgeGovernancePage.js +22 -0
- package/dist/node/components/docs/knowledge/KnowledgeOverviewPage.js +1 -1
- package/dist/node/components/docs/knowledge/KnowledgeSourcesPage.js +11 -2
- package/dist/node/components/docs/knowledge/index.js +49 -19
- package/dist/node/index.js +430 -300
- package/package.json +59 -23
- package/src/components/docs/docsManifest.ts +62 -0
- package/src/components/docs/generated/docs-index._common.json +32 -0
- package/src/components/docs/generated/docs-index.manifest.json +2 -2
- package/src/components/docs/generated/docs-index.notifications.json +7 -7
- package/src/components/docs/guides/GuideProviderBackedKnowledgePage.tsx +191 -0
- package/src/components/docs/guides/GuidesIndexPage.tsx +7 -0
- package/src/components/docs/guides/guides.docblocks.ts +20 -0
- package/src/components/docs/guides/index.ts +1 -0
- package/src/components/docs/integrations/IntegrationsGmailPage.tsx +23 -2
- package/src/components/docs/integrations/IntegrationsGoogleCalendarPage.tsx +2 -2
- package/src/components/docs/integrations/IntegrationsGoogleDrivePage.tsx +88 -0
- package/src/components/docs/integrations/IntegrationsOverviewPage.tsx +1 -0
- package/src/components/docs/integrations/index.ts +1 -0
- package/src/components/docs/knowledge/KnowledgeGovernancePage.tsx +94 -0
- package/src/components/docs/knowledge/KnowledgeOverviewPage.tsx +10 -0
- package/src/components/docs/knowledge/KnowledgeSourcesPage.tsx +45 -0
- package/src/components/docs/knowledge/index.ts +1 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
var
|
|
1
|
+
var ge=Object.defineProperty;var ue=(P)=>P;function fe(P,T){this[P]=ue.bind(null,T)}var et=(P,T)=>{for(var F in T)ge(P,F,{get:T[F],enumerable:!0,configurable:!0,set:fe.bind(T,F)})};var tt=(P,T)=>()=>(P&&(T=P(P=0)),T);import{jsx as q,jsxs as V}from"react/jsx-runtime";function he(){return V("div",{className:"space-y-8",children:[V("div",{className:"space-y-4",children:[q("h1",{className:"font-bold text-4xl",children:"Integration Circuit Breakers"}),q("p",{className:"text-lg text-muted-foreground",children:"External APIs are the most common source of instability. Wrap every integration call in a circuit breaker to protect your system."})]}),V("div",{className:"space-y-4",children:[q("h2",{className:"font-bold text-2xl",children:"Pattern"}),q("p",{children:"Create a dedicated circuit breaker instance for each external service. This ensures that a failure in Stripe doesn't trigger the circuit breaker for Twilio."}),q("pre",{className:"rounded-lg border bg-muted p-4 text-sm",children:`// integrations/stripe.ts
|
|
2
2
|
import { CircuitBreaker } from '@contractspec/lib.resilience/circuit-breaker';
|
|
3
3
|
|
|
4
4
|
const stripeBreaker = new CircuitBreaker({
|
|
@@ -8,8 +8,8 @@ const stripeBreaker = new CircuitBreaker({
|
|
|
8
8
|
|
|
9
9
|
export async function createCharge(amount: number) {
|
|
10
10
|
return stripeBreaker.execute(() => stripe.charges.create({ amount }));
|
|
11
|
-
}`})]})]})}import
|
|
12
|
-
ELEVENLABS_API_KEY=...`})})]}),
|
|
11
|
+
}`})]})]})}import Y from"@contractspec/lib.ui-link";import{ChevronRight as ve}from"lucide-react";import{jsx as w,jsxs as R}from"react/jsx-runtime";function be(){return R("div",{className:"space-y-8",children:[R("div",{className:"space-y-4",children:[w("h1",{className:"font-bold text-4xl",children:"ElevenLabs"}),w("p",{className:"text-muted-foreground",children:"ElevenLabs provides state-of-the-art text-to-speech and voice cloning technology. Create natural-sounding voiceovers, audiobooks, and voice assistants."})]}),R("div",{className:"space-y-4",children:[w("h2",{className:"font-bold text-2xl",children:"Setup"}),w("div",{className:"overflow-x-auto rounded-lg border border-border bg-background/50 p-4 font-mono text-muted-foreground text-sm",children:w("pre",{children:`# .env
|
|
12
|
+
ELEVENLABS_API_KEY=...`})})]}),R("div",{className:"space-y-4",children:[w("h2",{className:"font-bold text-2xl",children:"Text-to-Speech"}),w("div",{className:"overflow-x-auto rounded-lg border border-border bg-background/50 p-4 font-mono text-muted-foreground text-sm",children:w("pre",{children:`capabilityId: elevenlabs-tts
|
|
13
13
|
provider:
|
|
14
14
|
type: elevenlabs
|
|
15
15
|
operation: textToSpeech
|
|
@@ -28,7 +28,7 @@ outputs:
|
|
|
28
28
|
audioUrl:
|
|
29
29
|
type: string
|
|
30
30
|
audioData:
|
|
31
|
-
type: buffer`})})]}),
|
|
31
|
+
type: buffer`})})]}),R("div",{className:"space-y-4",children:[w("h2",{className:"font-bold text-2xl",children:"Use cases"}),R("ul",{className:"list-inside list-disc space-y-2 text-muted-foreground",children:[w("li",{children:"Generate voiceovers for videos"}),w("li",{children:"Create audio versions of articles"}),w("li",{children:"Build voice assistants"}),w("li",{children:"Produce audiobooks"})]})]}),R("div",{className:"flex items-center gap-4 pt-4",children:[w(Y,{href:"/docs/integrations/mistral",className:"btn-ghost",children:"Previous: Mistral"}),R(Y,{href:"/docs/integrations/qdrant",className:"btn-primary",children:["Next: Qdrant ",w(ve,{size:16})]})]})]})}import Z from"@contractspec/lib.ui-link";import{ChevronRight as Ne}from"lucide-react";import{jsx as f,jsxs as _}from"react/jsx-runtime";function ye(){return _("div",{className:"space-y-8",children:[_("div",{className:"space-y-4",children:[f("h1",{className:"font-bold text-4xl",children:"GitHub Messaging"}),f("p",{className:"text-muted-foreground",children:"Use GitHub issue and pull request comments as an AI-native messaging channel with webhook verification, policy checks, and reliable outbound dispatch."})]}),_("div",{className:"space-y-4",children:[f("h2",{className:"font-bold text-2xl",children:"Required secrets and config"}),f("div",{className:"overflow-x-auto rounded-lg border border-border bg-background/50 p-4 font-mono text-muted-foreground text-sm",children:f("pre",{children:`// secret payload
|
|
32
32
|
{
|
|
33
33
|
"token": "ghp_...",
|
|
34
34
|
"webhookSecret": "..."
|
|
@@ -39,13 +39,13 @@ outputs:
|
|
|
39
39
|
"defaultOwner": "lssm-tech",
|
|
40
40
|
"defaultRepo": "contractspec",
|
|
41
41
|
"apiBaseUrl": "https://api.github.com"
|
|
42
|
-
}`})})]}),
|
|
42
|
+
}`})})]}),_("div",{className:"space-y-4",children:[f("h2",{className:"font-bold text-2xl",children:"Webhook ingress"}),_("ul",{className:"list-inside list-disc space-y-2 text-muted-foreground",children:[_("li",{children:["Inbound GitHub events are accepted on"," ",f("code",{className:"rounded bg-background/50 px-2 py-1",children:"/webhooks/github/events"}),"."]}),_("li",{children:["Signatures are checked using"," ",f("code",{className:"rounded bg-background/50 px-2 py-1",children:"x-hub-signature-256"})," ","and the configured webhook secret."]}),f("li",{children:"Current normalization focuses on issue comment workflows and durable comment dispatch."})]})]}),_("div",{className:"space-y-4",children:[f("h2",{className:"font-bold text-2xl",children:"Workspace mapping"}),f("div",{className:"overflow-x-auto rounded-lg border border-border bg-background/50 p-4 font-mono text-muted-foreground text-sm",children:f("pre",{children:`CHANNEL_WORKSPACE_MAP_GITHUB={"lssm-tech/contractspec":"workspace-acme"}
|
|
43
43
|
|
|
44
44
|
# Optional dev fallback (off by default)
|
|
45
|
-
CHANNEL_ALLOW_UNMAPPED_WORKSPACE=0`})})]}),
|
|
45
|
+
CHANNEL_ALLOW_UNMAPPED_WORKSPACE=0`})})]}),_("div",{className:"space-y-4",children:[f("h2",{className:"font-bold text-2xl",children:"Best practices"}),_("ul",{className:"list-inside list-disc space-y-2 text-muted-foreground",children:[f("li",{children:"Use a least-privileged token scoped for comment operations."}),f("li",{children:"Route repositories explicitly with workspace maps in multi-tenant environments."}),f("li",{children:"Keep dispatch endpoints protected with token or bearer auth."})]})]}),_("div",{className:"flex items-center gap-4 pt-4",children:[f(Z,{href:"/docs/integrations/slack",className:"btn-ghost",children:"Previous: Slack Messaging"}),_(Z,{href:"/docs/integrations/whatsapp-meta",className:"btn-primary",children:["Next: WhatsApp Meta ",f(Ne,{size:16})]})]})]})}import z from"@contractspec/lib.ui-link";import{ChevronRight as ke}from"lucide-react";import{jsx as c,jsxs as S}from"react/jsx-runtime";function we(){return S("div",{className:"space-y-8",children:[S("div",{className:"space-y-4",children:[c("h1",{className:"font-bold text-4xl",children:"Gmail API"}),c("p",{className:"text-muted-foreground",children:"The Gmail API integration allows you to read inbound emails, manage threads, and build email-based workflows. Perfect for support tickets, email parsing, and automated responses."})]}),S("div",{className:"space-y-4",children:[c("h2",{className:"font-bold text-2xl",children:"Setup"}),c("p",{className:"text-muted-foreground",children:"Configure OAuth 2.0 credentials in Google Cloud Console:"}),c("div",{className:"overflow-x-auto rounded-lg border border-border bg-background/50 p-4 font-mono text-muted-foreground text-sm",children:c("pre",{children:`# .env
|
|
46
46
|
GOOGLE_CLIENT_ID=...
|
|
47
47
|
GOOGLE_CLIENT_SECRET=...
|
|
48
|
-
GOOGLE_REDIRECT_URI=https://your-app.com/auth/google/callback`})})]}),
|
|
48
|
+
GOOGLE_REDIRECT_URI=https://your-app.com/auth/google/callback`})})]}),S("div",{className:"space-y-4",children:[c("h2",{className:"font-bold text-2xl",children:"Reading emails"}),c("div",{className:"overflow-x-auto rounded-lg border border-border bg-background/50 p-4 font-mono text-muted-foreground text-sm",children:c("pre",{children:`capabilityId: gmail-list-messages
|
|
49
49
|
provider:
|
|
50
50
|
type: gmail
|
|
51
51
|
operation: listMessages
|
|
@@ -66,10 +66,10 @@ outputs:
|
|
|
66
66
|
properties:
|
|
67
67
|
id: string
|
|
68
68
|
threadId: string
|
|
69
|
-
snippet: string`})})]}),
|
|
69
|
+
snippet: string`})})]}),S("div",{className:"space-y-4",children:[c("h2",{className:"font-bold text-2xl",children:"Use cases"}),S("ul",{className:"list-inside list-disc space-y-2 text-muted-foreground",children:[c("li",{children:"Parse support emails and create tickets"}),c("li",{children:"Extract attachments and process them"}),c("li",{children:"Build email-to-task workflows"}),c("li",{children:"Monitor specific email threads"}),c("li",{children:"Sync threads into governed knowledge spaces with checkpointed deltas"})]})]}),S("div",{className:"space-y-4",children:[c("h2",{className:"font-bold text-2xl",children:"Knowledge sync and mutation gates"}),S("p",{className:"text-muted-foreground",children:["Gmail supports the shared ",c("code",{children:"provider.delta.watch"})," ","capability. Knowledge runtimes should persist provider cursor, watermark, dedupe, idempotency, replay, and tombstone state before acknowledging sync work. Outbound email sends should pass through knowledge mutation governance so dry-runs, approvals, audit evidence, and outbound-send gates are recorded."]}),S("div",{className:"flex flex-wrap gap-3",children:[c(z,{href:"/docs/guides/provider-backed-knowledge",className:"btn-ghost",children:"Provider-backed knowledge guide"}),c(z,{href:"/docs/knowledge/governance",className:"btn-ghost",children:"Mutation governance"})]})]}),S("div",{className:"flex items-center gap-4 pt-4",children:[c(z,{href:"/docs/integrations/resend",className:"btn-ghost",children:"Previous: Resend"}),S(z,{href:"/docs/integrations/google-drive",className:"btn-primary",children:["Next: Google Drive ",c(ke,{size:16})]})]})]})}import J from"@contractspec/lib.ui-link";import{ChevronRight as se}from"lucide-react";import{jsx as H,jsxs as K}from"react/jsx-runtime";function Ae(){return K("div",{className:"space-y-8",children:[K("div",{className:"space-y-4",children:[H("h1",{className:"font-bold text-4xl",children:"Google Calendar"}),H("p",{className:"text-muted-foreground",children:"Integrate Google Calendar to schedule appointments, manage availability, and sync events with your application."})]}),K("div",{className:"space-y-4",children:[H("h2",{className:"font-bold text-2xl",children:"Setup"}),H("div",{className:"overflow-x-auto rounded-lg border border-border bg-background/50 p-4 font-mono text-muted-foreground text-sm",children:H("pre",{children:`# .env
|
|
70
70
|
GOOGLE_CLIENT_ID=...
|
|
71
71
|
GOOGLE_CLIENT_SECRET=...
|
|
72
|
-
GOOGLE_CALENDAR_ID=primary`})})]}),
|
|
72
|
+
GOOGLE_CALENDAR_ID=primary`})})]}),K("div",{className:"space-y-4",children:[H("h2",{className:"font-bold text-2xl",children:"Creating events"}),H("div",{className:"overflow-x-auto rounded-lg border border-border bg-background/50 p-4 font-mono text-muted-foreground text-sm",children:H("pre",{children:`capabilityId: calendar-create-event
|
|
73
73
|
provider:
|
|
74
74
|
type: google-calendar
|
|
75
75
|
operation: createEvent
|
|
@@ -93,7 +93,27 @@ outputs:
|
|
|
93
93
|
eventId:
|
|
94
94
|
type: string
|
|
95
95
|
htmlLink:
|
|
96
|
-
type: string`})})]}),
|
|
96
|
+
type: string`})})]}),K("div",{className:"flex items-center gap-4 pt-4",children:[H(J,{href:"/docs/integrations/google-drive",className:"btn-ghost",children:"Previous: Google Drive"}),K(J,{href:"/docs/integrations/openai",className:"btn-primary",children:["Next: OpenAI ",H(se,{size:16})]})]})]})}import{CodeBlock as X}from"@contractspec/lib.design-system";import $ from"@contractspec/lib.ui-link";import{ChevronRight as Pe}from"lucide-react";import{jsx as b,jsxs as E}from"react/jsx-runtime";function Ie(){return E("div",{className:"space-y-8",children:[E("div",{className:"space-y-4",children:[b("h1",{className:"font-bold text-4xl",children:"Google Drive"}),b("p",{className:"text-muted-foreground",children:"Google Drive is modeled as a storage and knowledge-ingestion provider with explicit delta watch state. The contract covers file listing, file retrieval, Drive watches, channel/resource expiry, replay checkpoints, dedupe, idempotency, and tombstones."})]}),E("div",{className:"space-y-4",children:[b("h2",{className:"font-bold text-2xl",children:"Provider contract"}),b(X,{language:"typescript",filename:"google-drive-provider.ts",code:`interface GoogleDriveProvider {
|
|
97
|
+
listFiles(query?: GoogleDriveListFilesQuery): Promise<GoogleDriveListFilesResult>;
|
|
98
|
+
getFile(fileId: string): Promise<GoogleDriveFile | null>;
|
|
99
|
+
watchChanges?(input: GoogleDriveWatchInput): Promise<GoogleDriveWatchResult>;
|
|
100
|
+
}`}),E("p",{className:"text-muted-foreground text-sm",children:["The provider advertises ",b("code",{children:"storage.objects"}),","," ",b("code",{children:"knowledge.ingestion.drive"}),", and"," ",b("code",{children:"provider.delta.watch"}),". Runtime implementations should persist returned deltas before acknowledging sync work."]})]}),E("div",{className:"space-y-4",children:[b("h2",{className:"font-bold text-2xl",children:"Delta-aware ingestion"}),b(X,{language:"typescript",filename:"drive-sync.ts",code:`await knowledge.syncDriveFiles(
|
|
101
|
+
{
|
|
102
|
+
query: "mimeType = 'text/plain' and trashed = false",
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
sourceId: "src_drive_support",
|
|
106
|
+
evidenceRef: "audit://sync/drive/support",
|
|
107
|
+
},
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
await knowledge.watchDriveChanges(
|
|
111
|
+
{
|
|
112
|
+
channelId: "drive-support-watch",
|
|
113
|
+
webhookUrl: "https://app.example.com/webhooks/google-drive",
|
|
114
|
+
},
|
|
115
|
+
{ sourceId: "src_drive_support" },
|
|
116
|
+
);`})]}),E("div",{className:"space-y-4",children:[b("h2",{className:"font-bold text-2xl",children:"Production checklist"}),E("ul",{className:"list-inside list-disc space-y-2 text-muted-foreground",children:[b("li",{children:"Persist `ProviderDeltaSyncState` per Drive source."}),b("li",{children:"Renew webhook channels before `webhookChannel.expiresAt`."}),b("li",{children:"Skip tombstoned files before indexing or mutating them."}),b("li",{children:"Record replay checkpoint and idempotency evidence for retries."}),b("li",{children:"Use mutation governance before changing permissions or sending outbound notifications."})]})]}),E("div",{className:"flex items-center gap-4 pt-4",children:[b($,{href:"/docs/integrations/gmail",className:"btn-ghost",children:"Previous: Gmail API"}),E($,{href:"/docs/knowledge/governance",className:"btn-primary",children:["Knowledge governance ",b(Pe,{size:16})]})]})]})}import x from"@contractspec/lib.ui-link";import{jsx as m,jsxs as W}from"react/jsx-runtime";function Te(){return W("div",{className:"space-y-8",children:[W("div",{className:"space-y-4",children:[m("h1",{className:"font-bold text-4xl",children:"Health Routing Strategy"}),m("p",{className:"text-muted-foreground",children:"Health integrations resolve providers through deterministic transport strategy order with explicit capability gating and unofficial-route controls."})]}),W("div",{className:"space-y-4",children:[m("h2",{className:"font-bold text-2xl",children:"Connection config fields"}),m("div",{className:"overflow-x-auto rounded-lg border border-border bg-background/50 p-4 font-mono text-muted-foreground text-sm",children:m("pre",{children:`{
|
|
97
117
|
"defaultTransport": "official-api",
|
|
98
118
|
"strategyOrder": [
|
|
99
119
|
"official-api",
|
|
@@ -107,7 +127,7 @@ outputs:
|
|
|
107
127
|
"apiBaseUrl": "https://api.provider.example",
|
|
108
128
|
"mcpUrl": "https://mcp.provider.example",
|
|
109
129
|
"oauthTokenUrl": "https://api.provider.example/oauth/token"
|
|
110
|
-
}`})})]}),
|
|
130
|
+
}`})})]}),W("div",{className:"space-y-4",children:[m("h2",{className:"font-bold text-2xl",children:"Secret payload fields"}),m("div",{className:"overflow-x-auto rounded-lg border border-border bg-background/50 p-4 font-mono text-muted-foreground text-sm",children:m("pre",{children:`{
|
|
111
131
|
"apiKey": "...",
|
|
112
132
|
"accessToken": "...",
|
|
113
133
|
"refreshToken": "...",
|
|
@@ -116,8 +136,8 @@ outputs:
|
|
|
116
136
|
"tokenExpiresAt": "2026-02-01T00:00:00.000Z",
|
|
117
137
|
"mcpAccessToken": "...",
|
|
118
138
|
"webhookSecret": "..."
|
|
119
|
-
}`})})]}),
|
|
120
|
-
MISTRAL_API_KEY=...`})})]}),
|
|
139
|
+
}`})})]}),W("div",{className:"space-y-4",children:[m("h2",{className:"font-bold text-2xl",children:"Routing behavior"}),W("ul",{className:"list-inside list-disc space-y-2 text-muted-foreground",children:[m("li",{children:"Unsupported strategies are skipped per provider capability matrix."}),m("li",{children:"Missing credentials fail closed and fall through only when a later strategy is valid."}),W("li",{children:["Unofficial routes are disabled unless",m("code",{className:"ml-1 rounded bg-background/50 px-2 py-1",children:"allowUnofficial"}),"is true."]}),W("li",{children:["When",m("code",{className:"ml-1 rounded bg-background/50 px-2 py-1",children:"unofficialAllowList"}),"is set, only listed provider keys can route unofficially."]}),W("li",{children:["OAuth refresh uses",m("code",{className:"ml-1 rounded bg-background/50 px-2 py-1",children:"oauthTokenUrl"}),"with refresh/client credentials when APIs return 401."]})]})]}),W("div",{className:"space-y-4",children:[m("h2",{className:"font-bold text-2xl",children:"Provider guidance"}),W("ul",{className:"list-inside list-disc space-y-2 text-muted-foreground",children:[m("li",{children:"Use official APIs when available (Whoop, Oura, Strava, Fitbit)."}),m("li",{children:"Use aggregator routing for providers without stable official APIs (Garmin, MyFitnessPal, Eight Sleep, Peloton)."}),m("li",{children:"Keep unofficial automation opt-in and auditable for production."})]})]}),W("div",{className:"flex items-center gap-4 pt-4",children:[m(x,{href:"/docs/integrations/whatsapp-twilio",className:"btn-ghost",children:"Previous: WhatsApp Twilio"}),m(x,{href:"/docs/integrations",className:"btn-primary",children:"Back to Integrations"})]})]})}import j from"@contractspec/lib.ui-link";import{ChevronRight as _e}from"lucide-react";import{jsx as r,jsxs as C}from"react/jsx-runtime";function We(){return C("div",{className:"space-y-8",children:[C("div",{className:"space-y-4",children:[r("h1",{className:"font-bold text-4xl",children:"Mistral"}),r("p",{className:"text-muted-foreground",children:"Integrate Mistral models for chat, reasoning, embeddings, speech-to-text, and conversational voice workflows. ContractSpec ships first-class Mistral support across contracts, provider runtime wiring, and CLI provider selection."})]}),C("div",{className:"space-y-4",children:[r("h2",{className:"font-bold text-2xl",children:"Setup"}),r("div",{className:"overflow-x-auto rounded-lg border border-border bg-background/50 p-4 font-mono text-muted-foreground text-sm",children:r("pre",{children:`# .env
|
|
140
|
+
MISTRAL_API_KEY=...`})})]}),C("div",{className:"space-y-4",children:[r("h2",{className:"font-bold text-2xl",children:"Chat and reasoning"}),r("div",{className:"overflow-x-auto rounded-lg border border-border bg-background/50 p-4 font-mono text-muted-foreground text-sm",children:r("pre",{children:`capabilityId: mistral-chat
|
|
121
141
|
provider:
|
|
122
142
|
type: mistral
|
|
123
143
|
operation: chatCompletion
|
|
@@ -136,7 +156,7 @@ outputs:
|
|
|
136
156
|
content:
|
|
137
157
|
type: string
|
|
138
158
|
usage:
|
|
139
|
-
type: object`})})]}),
|
|
159
|
+
type: object`})})]}),C("div",{className:"space-y-4",children:[r("h2",{className:"font-bold text-2xl",children:"Embeddings"}),r("div",{className:"overflow-x-auto rounded-lg border border-border bg-background/50 p-4 font-mono text-muted-foreground text-sm",children:r("pre",{children:`capabilityId: mistral-embeddings
|
|
140
160
|
provider:
|
|
141
161
|
type: mistral
|
|
142
162
|
operation: createEmbedding
|
|
@@ -152,7 +172,7 @@ outputs:
|
|
|
152
172
|
embedding:
|
|
153
173
|
type: array
|
|
154
174
|
items:
|
|
155
|
-
type: number`})})]}),
|
|
175
|
+
type: number`})})]}),C("div",{className:"space-y-4",children:[r("h2",{className:"font-bold text-2xl",children:"Speech-to-Text (Voxtral)"}),r("div",{className:"overflow-x-auto rounded-lg border border-border bg-background/50 p-4 font-mono text-muted-foreground text-sm",children:r("pre",{children:`capabilityId: mistral-stt
|
|
156
176
|
provider:
|
|
157
177
|
type: mistral
|
|
158
178
|
operation: transcribe
|
|
@@ -172,9 +192,9 @@ outputs:
|
|
|
172
192
|
segments:
|
|
173
193
|
type: array
|
|
174
194
|
language:
|
|
175
|
-
type: string`})})]}),
|
|
195
|
+
type: string`})})]}),C("div",{className:"space-y-4",children:[r("h2",{className:"font-bold text-2xl",children:"Conversational voice sessions"}),r("p",{className:"text-muted-foreground",children:"Use the conversational provider for session-based realtime voice flows (turn handling, events, and interruption-safe streaming)."})]}),C("div",{className:"space-y-4",children:[r("h2",{className:"font-bold text-2xl",children:"Best practices"}),C("ul",{className:"list-inside list-disc space-y-2 text-muted-foreground",children:[r("li",{children:"Choose model families by workload: coding, reasoning, or speech"}),r("li",{children:"Persist session IDs for conversational continuity across turns"}),r("li",{children:"Capture token and latency telemetry for provider-level tuning"}),r("li",{children:"Set explicit fallbacks for network and rate-limit failures"})]})]}),C("div",{className:"flex items-center gap-4 pt-4",children:[r(j,{href:"/docs/integrations/openai",className:"btn-ghost",children:"Previous: OpenAI"}),C(j,{href:"/docs/integrations/elevenlabs",className:"btn-primary",children:["Next: ElevenLabs ",r(_e,{size:16})]})]})]})}import ee from"@contractspec/lib.ui-link";import{ChevronRight as Me}from"lucide-react";import{jsx as l,jsxs as D}from"react/jsx-runtime";function Se(){return D("div",{className:"space-y-8",children:[D("div",{className:"space-y-4",children:[l("h1",{className:"font-bold text-4xl",children:"OpenAI"}),l("p",{className:"text-muted-foreground",children:"Integrate OpenAI's powerful AI models for chat completion, embeddings, and speech-to-text. Build intelligent features with GPT-4, generate embeddings for semantic search, and transcribe audio with Whisper."})]}),D("div",{className:"space-y-4",children:[l("h2",{className:"font-bold text-2xl",children:"Setup"}),l("div",{className:"overflow-x-auto rounded-lg border border-border bg-background/50 p-4 font-mono text-muted-foreground text-sm",children:l("pre",{children:`# .env
|
|
176
196
|
OPENAI_API_KEY=sk-...
|
|
177
|
-
OPENAI_ORGANIZATION=org-...`})})]}),
|
|
197
|
+
OPENAI_ORGANIZATION=org-...`})})]}),D("div",{className:"space-y-4",children:[l("h2",{className:"font-bold text-2xl",children:"Chat completions"}),l("div",{className:"overflow-x-auto rounded-lg border border-border bg-background/50 p-4 font-mono text-muted-foreground text-sm",children:l("pre",{children:`capabilityId: openai-chat
|
|
178
198
|
provider:
|
|
179
199
|
type: openai
|
|
180
200
|
operation: chatCompletion
|
|
@@ -199,7 +219,7 @@ outputs:
|
|
|
199
219
|
content:
|
|
200
220
|
type: string
|
|
201
221
|
usage:
|
|
202
|
-
type: object`})})]}),
|
|
222
|
+
type: object`})})]}),D("div",{className:"space-y-4",children:[l("h2",{className:"font-bold text-2xl",children:"Embeddings"}),l("div",{className:"overflow-x-auto rounded-lg border border-border bg-background/50 p-4 font-mono text-muted-foreground text-sm",children:l("pre",{children:`capabilityId: openai-embeddings
|
|
203
223
|
provider:
|
|
204
224
|
type: openai
|
|
205
225
|
operation: createEmbedding
|
|
@@ -215,7 +235,7 @@ outputs:
|
|
|
215
235
|
embedding:
|
|
216
236
|
type: array
|
|
217
237
|
items:
|
|
218
|
-
type: number`})})]}),
|
|
238
|
+
type: number`})})]}),D("div",{className:"space-y-4",children:[l("h2",{className:"font-bold text-2xl",children:"Whisper (Speech-to-Text)"}),l("div",{className:"overflow-x-auto rounded-lg border border-border bg-background/50 p-4 font-mono text-muted-foreground text-sm",children:l("pre",{children:`capabilityId: openai-transcribe
|
|
219
239
|
provider:
|
|
220
240
|
type: openai
|
|
221
241
|
operation: transcribe
|
|
@@ -231,10 +251,10 @@ outputs:
|
|
|
231
251
|
text:
|
|
232
252
|
type: string
|
|
233
253
|
language:
|
|
234
|
-
type: string`})})]}),
|
|
254
|
+
type: string`})})]}),D("div",{className:"space-y-4",children:[l("h2",{className:"font-bold text-2xl",children:"Best practices"}),D("ul",{className:"list-inside list-disc space-y-2 text-muted-foreground",children:[l("li",{children:"Use streaming for real-time chat responses"}),l("li",{children:"Cache embeddings to reduce API costs"}),l("li",{children:"Implement rate limiting to avoid quota issues"}),l("li",{children:"Store conversation history for context"}),l("li",{children:"Monitor token usage and costs"})]})]}),D("div",{className:"flex items-center gap-4 pt-4",children:[l(ee,{href:"/docs/integrations/google-calendar",className:"btn-ghost",children:"Previous: Google Calendar"}),D(ee,{href:"/docs/integrations/mistral",className:"btn-primary",children:["Next: Mistral ",l(Me,{size:16})]})]})]})}import Q from"@contractspec/lib.ui-link";import{jsx as y,jsxs as U}from"react/jsx-runtime";var Ce=[{title:"Models and voice",items:[{title:"OpenAI",href:"/docs/integrations/openai"},{title:"Mistral",href:"/docs/integrations/mistral"},{title:"ElevenLabs",href:"/docs/integrations/elevenlabs"}]},{title:"Messaging and product operations",items:[{title:"GitHub",href:"/docs/integrations/github"},{title:"Slack",href:"/docs/integrations/slack"},{title:"Twilio",href:"/docs/integrations/twilio"},{title:"Postmark",href:"/docs/integrations/postmark"}]},{title:"Data, storage, and retrieval",items:[{title:"Qdrant",href:"/docs/integrations/qdrant"},{title:"S3 storage",href:"/docs/integrations/s3"},{title:"Gmail",href:"/docs/integrations/gmail"},{title:"Google Drive",href:"/docs/integrations/google-drive"},{title:"Google Calendar",href:"/docs/integrations/google-calendar"}]},{title:"Payments and external workflows",items:[{title:"Stripe",href:"/docs/integrations/stripe"},{title:"Powens",href:"/docs/integrations/powens"},{title:"Circuit breakers",href:"/docs/integrations/circuit-breakers"},{title:"Health routing",href:"/docs/integrations/health-routing"}]}];function He(){return U("div",{className:"space-y-10",children:[U("div",{className:"space-y-3",children:[y("p",{className:"editorial-kicker",children:"Integrations"}),y("h1",{className:"font-serif text-4xl tracking-[-0.04em] md:text-5xl",children:"Integrations stay explicit: spec what a provider offers, then bind it per tenant and per app."}),y("p",{className:"max-w-3xl text-lg text-muted-foreground leading-8",children:"The integration model keeps provider behavior out of ad hoc glue code. Define the capability contract first, configure the provider connection explicitly, then bind the integration into app workflows and runtime surfaces with clear ownership."})]}),U("div",{className:"editorial-proof-strip",children:[U("div",{className:"editorial-stat",children:[y("span",{className:"editorial-label",children:"Binding model"}),y("span",{className:"editorial-stat-value",children:"Integration spec → tenant connection → app binding"})]}),y("p",{className:"max-w-2xl text-muted-foreground text-sm leading-7",children:"That separation is what makes reuse, tenant isolation, and provider swaps practical without rewriting every surface."})]}),y("section",{className:"editorial-panel space-y-5",children:U("div",{className:"space-y-2",children:[y("h2",{className:"font-serif text-3xl tracking-[-0.03em]",children:"Start with the model, then pick a provider"}),U("div",{className:"grid gap-4 md:grid-cols-2",children:[U(Q,{href:"/docs/integrations/spec-model",className:"docs-footer-link",children:[y("h3",{className:"font-semibold text-lg",children:"Integration spec model"}),y("p",{className:"text-muted-foreground text-sm leading-7",children:"Define what the provider offers, what configuration it needs, and how the runtime should treat it."})]}),U(Q,{href:"/docs/architecture/integration-binding",className:"docs-footer-link",children:[y("h3",{className:"font-semibold text-lg",children:"Integration binding"}),y("p",{className:"text-muted-foreground text-sm leading-7",children:"Understand how tenant connections get mapped into concrete app surfaces and workflows."})]})]})]})}),y("div",{className:"grid gap-5 md:grid-cols-2",children:Ce.map((P)=>U("section",{className:"editorial-panel space-y-4",children:[y("h2",{className:"font-serif text-2xl tracking-[-0.03em]",children:P.title}),y("div",{className:"space-y-3",children:P.items.map((T)=>y(Q,{href:T.href,className:"docs-chip-link",children:T.title},T.href))})]},P.title))})]})}import te from"@contractspec/lib.ui-link";import{ChevronRight as De}from"lucide-react";import{jsx as o,jsxs as N}from"react/jsx-runtime";function Ee(){return N("div",{className:"space-y-8",children:[N("div",{className:"space-y-4",children:[o("h1",{className:"font-bold text-4xl",children:"Postmark"}),o("p",{className:"text-muted-foreground",children:"Postmark is a transactional email service with industry-leading deliverability. Use it to send order confirmations, password resets, notifications, and other critical emails."})]}),N("div",{className:"space-y-4",children:[o("h2",{className:"font-bold text-2xl",children:"Setup"}),o("p",{className:"text-muted-foreground",children:"Add your Postmark credentials to your environment variables:"}),o("div",{className:"overflow-x-auto rounded-lg border border-border bg-background/50 p-4 font-mono text-muted-foreground text-sm",children:o("pre",{children:`# .env
|
|
235
255
|
POSTMARK_API_TOKEN=...
|
|
236
256
|
POSTMARK_FROM_EMAIL=noreply@example.com
|
|
237
|
-
POSTMARK_FROM_NAME="Your App Name"`})}),
|
|
257
|
+
POSTMARK_FROM_NAME="Your App Name"`})}),N("p",{className:"text-muted-foreground text-sm",children:["Get your API token from the"," ",o("a",{href:"https://account.postmarkapp.com/servers",target:"_blank",rel:"noopener noreferrer",className:"text-violet-400 hover:text-violet-300",children:"Postmark Dashboard"}),"."]})]}),N("div",{className:"space-y-4",children:[o("h2",{className:"font-bold text-2xl",children:"Sending emails"}),o("div",{className:"overflow-x-auto rounded-lg border border-border bg-background/50 p-4 font-mono text-muted-foreground text-sm",children:o("pre",{children:`capabilityId: send-email
|
|
238
258
|
provider:
|
|
239
259
|
type: postmark
|
|
240
260
|
operation: sendEmail
|
|
@@ -262,7 +282,7 @@ outputs:
|
|
|
262
282
|
messageId:
|
|
263
283
|
type: string
|
|
264
284
|
submittedAt:
|
|
265
|
-
type: timestamp`})})]}),
|
|
285
|
+
type: timestamp`})})]}),N("div",{className:"space-y-4",children:[o("h2",{className:"font-bold text-2xl",children:"Using templates"}),o("p",{className:"text-muted-foreground",children:"Postmark templates allow you to design emails in their dashboard and populate them with data:"}),o("div",{className:"overflow-x-auto rounded-lg border border-border bg-background/50 p-4 font-mono text-muted-foreground text-sm",children:o("pre",{children:`capabilityId: send-welcome-email
|
|
266
286
|
provider:
|
|
267
287
|
type: postmark
|
|
268
288
|
operation: sendEmail
|
|
@@ -277,7 +297,7 @@ config:
|
|
|
277
297
|
templateId: "welcome-email"
|
|
278
298
|
templateData:
|
|
279
299
|
user_name: \${input.userName}
|
|
280
|
-
login_url: "https://app.example.com/login"`})})]}),
|
|
300
|
+
login_url: "https://app.example.com/login"`})})]}),N("div",{className:"space-y-4",children:[o("h2",{className:"font-bold text-2xl",children:"Webhooks"}),o("p",{className:"text-muted-foreground",children:"Postmark can notify your app about delivery, bounces, and opens:"}),o("div",{className:"overflow-x-auto rounded-lg border border-border bg-background/50 p-4 font-mono text-muted-foreground text-sm",children:o("pre",{children:"https://your-app.com/api/webhooks/postmark"})}),o("p",{className:"text-muted-foreground",children:"ContractSpec automatically processes these webhook events:"}),N("ul",{className:"list-inside list-disc space-y-2 text-muted-foreground",children:[N("li",{children:[o("strong",{children:"Delivery"})," – Email was successfully delivered"]}),N("li",{children:[o("strong",{children:"Bounce"})," – Email bounced (hard or soft)"]}),N("li",{children:[o("strong",{children:"SpamComplaint"})," – Recipient marked email as spam"]}),N("li",{children:[o("strong",{children:"Open"})," – Recipient opened the email"]}),N("li",{children:[o("strong",{children:"Click"})," – Recipient clicked a link"]})]})]}),N("div",{className:"space-y-4",children:[o("h2",{className:"font-bold text-2xl",children:"Best practices"}),N("ul",{className:"list-inside list-disc space-y-2 text-muted-foreground",children:[o("li",{children:"Use templates for consistent branding"}),o("li",{children:"Always provide both HTML and plain text versions"}),o("li",{children:"Monitor bounce rates and remove invalid addresses"}),o("li",{children:"Use message streams to separate different email types"}),o("li",{children:"Test emails in the Postmark sandbox before going live"}),o("li",{children:"Set up DKIM and SPF records for your domain"})]})]}),N("div",{className:"flex items-center gap-4 pt-4",children:[o(te,{href:"/docs/integrations/stripe",className:"btn-ghost",children:"Previous: Stripe"}),N(te,{href:"/docs/integrations/resend",className:"btn-primary",children:["Next: Resend ",o(De,{size:16})]})]})]})}import ae from"@contractspec/lib.ui-link";import{ChevronRight as Ue}from"lucide-react";import{jsx as a,jsxs as i}from"react/jsx-runtime";function Le(){return i("div",{className:"space-y-8",children:[i("div",{className:"space-y-4",children:[a("h1",{className:"font-bold text-4xl",children:"Powens Open Banking"}),a("p",{className:"text-muted-foreground",children:"Powens provides read-only open banking connectivity for ContractSpec applications. The reference integration powers Pocket Family Office by synchronising household bank accounts, transactions, and balances while keeping all raw PII protected."})]}),i("div",{className:"space-y-4",children:[a("h2",{className:"font-bold text-2xl",children:"Setup"}),a("p",{className:"text-muted-foreground",children:"Create a Powens BYOK project, then store the credentials in your secret manager. The ContractSpec integration expects the following fields:"}),a("div",{className:"overflow-x-auto rounded-lg border border-border bg-background/50 p-4 font-mono text-muted-foreground text-sm",children:a("pre",{children:`{
|
|
281
301
|
"clientId": "powens-client-id",
|
|
282
302
|
"clientSecret": "powens-client-secret",
|
|
283
303
|
"apiKey": "optional-api-key",
|
|
@@ -332,10 +352,10 @@ inputs:
|
|
|
332
352
|
outputs:
|
|
333
353
|
balances:
|
|
334
354
|
type: AccountBalanceRecord[]
|
|
335
|
-
description: "Current/available balances with timestamps"`})})]}),i("div",{className:"space-y-4",children:[a("h2",{className:"font-bold text-2xl",children:"Primary workflows"}),i("div",{className:"space-y-3",children:[a("h3",{className:"font-semibold text-lg",children:"Account sync"}),i("p",{className:"text-muted-foreground",children:["The workflow"," ",a("code",{className:"rounded bg-background/50 px-2 py-1",children:"pfo.workflow.sync-openbanking-accounts"})," ","refreshes account metadata, then surfaces canonical records to other automations."]})]}),i("div",{className:"space-y-3",children:[a("h3",{className:"font-semibold text-lg",children:"Transaction sync"}),i("p",{className:"text-muted-foreground",children:[a("code",{className:"rounded bg-background/50 px-2 py-1",children:"pfo.workflow.sync-openbanking-transactions"})," ","ingests incremental transactions for each linked account and stores them in the canonical ledger."]})]}),i("div",{className:"space-y-3",children:[a("h3",{className:"font-semibold text-lg",children:"Balance refresh"}),i("p",{className:"text-muted-foreground",children:[a("code",{className:"rounded bg-background/50 px-2 py-1",children:"pfo.workflow.refresh-openbanking-balances"})," ","retrieves current and available balances to power dashboards and anomaly detection."]})]}),i("div",{className:"space-y-3",children:[a("h3",{className:"font-semibold text-lg",children:"Derived financial overview"}),i("p",{className:"text-muted-foreground",children:[a("code",{className:"rounded bg-background/50 px-2 py-1",children:"pfo.workflow.generate-openbanking-overview"})," ","aggregates balances, category breakdowns, and cashflow trends into the ",a("code",{children:"knowledge.financial-overview"})," space. Only derived summaries are exposed to LLMs."]})]})]}),i("div",{className:"space-y-4",children:[a("h2",{className:"font-bold text-2xl",children:"Telemetry & guardrails"}),i("ul",{className:"list-inside list-disc space-y-2 text-muted-foreground",children:[i("li",{children:["Telemetry events such as"," ",a("code",{className:"rounded bg-background/50 px-2 py-1",children:"openbanking.accounts.synced"})," ","and"," ",a("code",{className:"rounded bg-background/50 px-2 py-1",children:"openbanking.transactions.synced"})," ","are emitted automatically with tenant, slot, and config metadata."]}),i("li",{children:["Guard helpers ensure the"," ",a("code",{className:"rounded bg-background/50 px-2 py-1",children:"primaryOpenBanking"})," ","slot is bound and healthy before workflows execute."]}),i("li",{children:["PII fields (IBAN, counterparty names, descriptions) are redacted via"," ",a("code",{className:"rounded bg-background/50 px-2 py-1",children:"redactOpenBankingTelemetryPayload"})," ","before logging or sending telemetry."]})]})]}),i("div",{className:"space-y-4",children:[a("h2",{className:"font-bold text-2xl",children:"Best practices"}),i("ul",{className:"list-inside list-disc space-y-2 text-muted-foreground",children:[a("li",{children:"Use BYOK credentials per tenant to avoid cross-tenant exposure."}),a("li",{children:"Store only canonical entities (BankAccountRecord, BankTransactionRecord). Never persist raw Powens payloads or customer PII in logs."}),a("li",{children:"Run the transaction sync on a schedule appropriate for banking SLAs (e.g. every 15 minutes for cashflow dashboards)."}),a("li",{children:"Pair ledger updates with derived summaries to feed the knowledge layer instead of exposing raw transactions to agents."}),i("li",{children:["Monitor telemetry for"," ",a("code",{className:"rounded bg-background/50 px-2 py-1",children:"openbanking.*.sync_failed"})," ","events to detect credential issues early."]})]})]}),i("div",{className:"flex items-center gap-4 pt-4",children:[a(
|
|
355
|
+
description: "Current/available balances with timestamps"`})})]}),i("div",{className:"space-y-4",children:[a("h2",{className:"font-bold text-2xl",children:"Primary workflows"}),i("div",{className:"space-y-3",children:[a("h3",{className:"font-semibold text-lg",children:"Account sync"}),i("p",{className:"text-muted-foreground",children:["The workflow"," ",a("code",{className:"rounded bg-background/50 px-2 py-1",children:"pfo.workflow.sync-openbanking-accounts"})," ","refreshes account metadata, then surfaces canonical records to other automations."]})]}),i("div",{className:"space-y-3",children:[a("h3",{className:"font-semibold text-lg",children:"Transaction sync"}),i("p",{className:"text-muted-foreground",children:[a("code",{className:"rounded bg-background/50 px-2 py-1",children:"pfo.workflow.sync-openbanking-transactions"})," ","ingests incremental transactions for each linked account and stores them in the canonical ledger."]})]}),i("div",{className:"space-y-3",children:[a("h3",{className:"font-semibold text-lg",children:"Balance refresh"}),i("p",{className:"text-muted-foreground",children:[a("code",{className:"rounded bg-background/50 px-2 py-1",children:"pfo.workflow.refresh-openbanking-balances"})," ","retrieves current and available balances to power dashboards and anomaly detection."]})]}),i("div",{className:"space-y-3",children:[a("h3",{className:"font-semibold text-lg",children:"Derived financial overview"}),i("p",{className:"text-muted-foreground",children:[a("code",{className:"rounded bg-background/50 px-2 py-1",children:"pfo.workflow.generate-openbanking-overview"})," ","aggregates balances, category breakdowns, and cashflow trends into the ",a("code",{children:"knowledge.financial-overview"})," space. Only derived summaries are exposed to LLMs."]})]})]}),i("div",{className:"space-y-4",children:[a("h2",{className:"font-bold text-2xl",children:"Telemetry & guardrails"}),i("ul",{className:"list-inside list-disc space-y-2 text-muted-foreground",children:[i("li",{children:["Telemetry events such as"," ",a("code",{className:"rounded bg-background/50 px-2 py-1",children:"openbanking.accounts.synced"})," ","and"," ",a("code",{className:"rounded bg-background/50 px-2 py-1",children:"openbanking.transactions.synced"})," ","are emitted automatically with tenant, slot, and config metadata."]}),i("li",{children:["Guard helpers ensure the"," ",a("code",{className:"rounded bg-background/50 px-2 py-1",children:"primaryOpenBanking"})," ","slot is bound and healthy before workflows execute."]}),i("li",{children:["PII fields (IBAN, counterparty names, descriptions) are redacted via"," ",a("code",{className:"rounded bg-background/50 px-2 py-1",children:"redactOpenBankingTelemetryPayload"})," ","before logging or sending telemetry."]})]})]}),i("div",{className:"space-y-4",children:[a("h2",{className:"font-bold text-2xl",children:"Best practices"}),i("ul",{className:"list-inside list-disc space-y-2 text-muted-foreground",children:[a("li",{children:"Use BYOK credentials per tenant to avoid cross-tenant exposure."}),a("li",{children:"Store only canonical entities (BankAccountRecord, BankTransactionRecord). Never persist raw Powens payloads or customer PII in logs."}),a("li",{children:"Run the transaction sync on a schedule appropriate for banking SLAs (e.g. every 15 minutes for cashflow dashboards)."}),a("li",{children:"Pair ledger updates with derived summaries to feed the knowledge layer instead of exposing raw transactions to agents."}),i("li",{children:["Monitor telemetry for"," ",a("code",{className:"rounded bg-background/50 px-2 py-1",children:"openbanking.*.sync_failed"})," ","events to detect credential issues early."]})]})]}),i("div",{className:"flex items-center gap-4 pt-4",children:[a(ae,{href:"/docs/integrations",className:"btn-ghost",children:"Back to Integrations"}),i(ae,{href:"/docs/integrations/stripe",className:"btn-primary",children:["Next: Stripe ",a(Ue,{size:16})]})]})]})}import oe from"@contractspec/lib.ui-link";import{ChevronRight as Oe}from"lucide-react";import{jsx as k,jsxs as B}from"react/jsx-runtime";function Re(){return B("div",{className:"space-y-8",children:[B("div",{className:"space-y-4",children:[k("h1",{className:"font-bold text-4xl",children:"Qdrant"}),k("p",{className:"text-muted-foreground",children:"Qdrant is a high-performance vector database for semantic search, recommendations, and RAG (Retrieval-Augmented Generation) applications."})]}),B("div",{className:"space-y-4",children:[k("h2",{className:"font-bold text-2xl",children:"Setup"}),k("div",{className:"overflow-x-auto rounded-lg border border-border bg-background/50 p-4 font-mono text-muted-foreground text-sm",children:k("pre",{children:`# .env
|
|
336
356
|
QDRANT_URL=https://...
|
|
337
357
|
QDRANT_API_KEY=...
|
|
338
|
-
QDRANT_COLLECTION=documents`})})]}),
|
|
358
|
+
QDRANT_COLLECTION=documents`})})]}),B("div",{className:"space-y-4",children:[k("h2",{className:"font-bold text-2xl",children:"Storing vectors"}),k("div",{className:"overflow-x-auto rounded-lg border border-border bg-background/50 p-4 font-mono text-muted-foreground text-sm",children:k("pre",{children:`capabilityId: qdrant-upsert
|
|
339
359
|
provider:
|
|
340
360
|
type: qdrant
|
|
341
361
|
operation: upsert
|
|
@@ -354,7 +374,7 @@ inputs:
|
|
|
354
374
|
|
|
355
375
|
outputs:
|
|
356
376
|
status:
|
|
357
|
-
type: string`})})]}),
|
|
377
|
+
type: string`})})]}),B("div",{className:"space-y-4",children:[k("h2",{className:"font-bold text-2xl",children:"Semantic search"}),k("div",{className:"overflow-x-auto rounded-lg border border-border bg-background/50 p-4 font-mono text-muted-foreground text-sm",children:k("pre",{children:`capabilityId: qdrant-search
|
|
358
378
|
provider:
|
|
359
379
|
type: qdrant
|
|
360
380
|
operation: search
|
|
@@ -378,7 +398,7 @@ outputs:
|
|
|
378
398
|
properties:
|
|
379
399
|
id: string
|
|
380
400
|
score: number
|
|
381
|
-
payload: object`})})]}),
|
|
401
|
+
payload: object`})})]}),B("div",{className:"space-y-4",children:[k("h2",{className:"font-bold text-2xl",children:"RAG workflow example"}),k("div",{className:"overflow-x-auto rounded-lg border border-border bg-background/50 p-4 font-mono text-muted-foreground text-sm",children:k("pre",{children:`workflowId: rag-query
|
|
382
402
|
version: '1.0.0'.0.0
|
|
383
403
|
|
|
384
404
|
steps:
|
|
@@ -403,9 +423,9 @@ steps:
|
|
|
403
423
|
- role: "user"
|
|
404
424
|
content: |
|
|
405
425
|
Context: \${steps.search-documents.output.results}
|
|
406
|
-
Question: \${input.query}`})})]}),
|
|
426
|
+
Question: \${input.query}`})})]}),B("div",{className:"flex items-center gap-4 pt-4",children:[k(oe,{href:"/docs/integrations/elevenlabs",className:"btn-ghost",children:"Previous: ElevenLabs"}),B(oe,{href:"/docs/integrations/s3",className:"btn-primary",children:["Next: S3 Storage ",k(Oe,{size:16})]})]})]})}import ie from"@contractspec/lib.ui-link";import{ChevronRight as Be}from"lucide-react";import{jsx as s,jsxs as G}from"react/jsx-runtime";function Ge(){return G("div",{className:"space-y-8",children:[G("div",{className:"space-y-4",children:[s("h1",{className:"font-bold text-4xl",children:"Resend"}),s("p",{className:"text-muted-foreground",children:"Resend is a modern email API built for developers. It provides a simple, reliable way to send transactional emails with React Email templates."})]}),G("div",{className:"space-y-4",children:[s("h2",{className:"font-bold text-2xl",children:"Setup"}),s("div",{className:"overflow-x-auto rounded-lg border border-border bg-background/50 p-4 font-mono text-muted-foreground text-sm",children:s("pre",{children:`# .env
|
|
407
427
|
RESEND_API_KEY=re_...
|
|
408
|
-
RESEND_FROM_EMAIL=onboarding@resend.dev`})})]}),
|
|
428
|
+
RESEND_FROM_EMAIL=onboarding@resend.dev`})})]}),G("div",{className:"space-y-4",children:[s("h2",{className:"font-bold text-2xl",children:"Sending emails"}),s("div",{className:"overflow-x-auto rounded-lg border border-border bg-background/50 p-4 font-mono text-muted-foreground text-sm",children:s("pre",{children:`capabilityId: resend-send-email
|
|
409
429
|
provider:
|
|
410
430
|
type: resend
|
|
411
431
|
operation: sendEmail
|
|
@@ -426,12 +446,12 @@ inputs:
|
|
|
426
446
|
|
|
427
447
|
outputs:
|
|
428
448
|
id:
|
|
429
|
-
type: string`})})]}),
|
|
449
|
+
type: string`})})]}),G("div",{className:"space-y-4",children:[s("h2",{className:"font-bold text-2xl",children:"Best practices"}),G("ul",{className:"list-inside list-disc space-y-2 text-muted-foreground",children:[s("li",{children:"Use React Email for type-safe templates"}),s("li",{children:"Verify your domain for better deliverability"}),s("li",{children:"Monitor email analytics in the Resend dashboard"})]})]}),G("div",{className:"flex items-center gap-4 pt-4",children:[s(ie,{href:"/docs/integrations/postmark",className:"btn-ghost",children:"Previous: Postmark"}),G(ie,{href:"/docs/integrations/gmail",className:"btn-primary",children:["Next: Gmail API ",s(Be,{size:16})]})]})]})}import re from"@contractspec/lib.ui-link";import{ChevronRight as Ke}from"lucide-react";import{jsx as g,jsxs as L}from"react/jsx-runtime";function qe(){return L("div",{className:"space-y-8",children:[L("div",{className:"space-y-4",children:[g("h1",{className:"font-bold text-4xl",children:"S3-Compatible Storage"}),g("p",{className:"text-muted-foreground",children:"Store files, images, and documents using any S3-compatible object storage service including AWS S3, Scaleway Object Storage, MinIO, DigitalOcean Spaces, and more."})]}),L("div",{className:"space-y-4",children:[g("h2",{className:"font-bold text-2xl",children:"Setup"}),g("div",{className:"overflow-x-auto rounded-lg border border-border bg-background/50 p-4 font-mono text-muted-foreground text-sm",children:g("pre",{children:`# .env
|
|
430
450
|
S3_ENDPOINT=https://s3.fr-par.scw.cloud
|
|
431
451
|
S3_ACCESS_KEY_ID=...
|
|
432
452
|
S3_SECRET_ACCESS_KEY=...
|
|
433
453
|
S3_BUCKET=my-bucket
|
|
434
|
-
S3_REGION=fr-par`})})]}),
|
|
454
|
+
S3_REGION=fr-par`})})]}),L("div",{className:"space-y-4",children:[g("h2",{className:"font-bold text-2xl",children:"Uploading files"}),g("div",{className:"overflow-x-auto rounded-lg border border-border bg-background/50 p-4 font-mono text-muted-foreground text-sm",children:g("pre",{children:`capabilityId: s3-upload
|
|
435
455
|
provider:
|
|
436
456
|
type: s3
|
|
437
457
|
operation: upload
|
|
@@ -453,7 +473,7 @@ outputs:
|
|
|
453
473
|
url:
|
|
454
474
|
type: string
|
|
455
475
|
etag:
|
|
456
|
-
type: string`})})]}),
|
|
476
|
+
type: string`})})]}),L("div",{className:"space-y-4",children:[g("h2",{className:"font-bold text-2xl",children:"Generating presigned URLs"}),g("div",{className:"overflow-x-auto rounded-lg border border-border bg-background/50 p-4 font-mono text-muted-foreground text-sm",children:g("pre",{children:`capabilityId: s3-presigned-url
|
|
457
477
|
provider:
|
|
458
478
|
type: s3
|
|
459
479
|
operation: getPresignedUrl
|
|
@@ -468,7 +488,7 @@ inputs:
|
|
|
468
488
|
|
|
469
489
|
outputs:
|
|
470
490
|
url:
|
|
471
|
-
type: string`})})]}),
|
|
491
|
+
type: string`})})]}),L("div",{className:"space-y-4",children:[g("h2",{className:"font-bold text-2xl",children:"Best practices"}),L("ul",{className:"list-inside list-disc space-y-2 text-muted-foreground",children:[g("li",{children:"Use presigned URLs for secure, temporary access"}),g("li",{children:"Set appropriate CORS policies for browser uploads"}),g("li",{children:"Enable versioning for important files"}),g("li",{children:"Use lifecycle policies to archive old files"}),g("li",{children:"Organize files with a clear key structure"})]})]}),L("div",{className:"flex items-center gap-4 pt-4",children:[g(re,{href:"/docs/integrations/qdrant",className:"btn-ghost",children:"Previous: Qdrant"}),L(re,{href:"/docs/integrations/twilio",className:"btn-primary",children:["Next: Twilio ",g(Ke,{size:16})]})]})]})}import le from"@contractspec/lib.ui-link";import{ChevronRight as ze}from"lucide-react";import{jsx as u,jsxs as M}from"react/jsx-runtime";function Fe(){return M("div",{className:"space-y-8",children:[M("div",{className:"space-y-4",children:[u("h1",{className:"font-bold text-4xl",children:"Slack Messaging"}),u("p",{className:"text-muted-foreground",children:"ContractSpec supports signed Slack event ingestion and outbox-backed outbound replies through the channel runtime."})]}),M("div",{className:"space-y-4",children:[u("h2",{className:"font-bold text-2xl",children:"Required secrets and config"}),u("div",{className:"overflow-x-auto rounded-lg border border-border bg-background/50 p-4 font-mono text-muted-foreground text-sm",children:u("pre",{children:`// secret payload
|
|
472
492
|
{
|
|
473
493
|
"botToken": "xoxb-...",
|
|
474
494
|
"signingSecret": "..."
|
|
@@ -486,7 +506,7 @@ CHANNEL_DISPATCH_TOKEN=...
|
|
|
486
506
|
|
|
487
507
|
# Optional scheduler
|
|
488
508
|
CHANNEL_DISPATCH_INTERVAL_MS=120000
|
|
489
|
-
CHANNEL_DISPATCH_RUN_ON_START=1`})})]}),M("div",{className:"space-y-4",children:[u("h2",{className:"font-bold text-2xl",children:"Best practices"}),M("ul",{className:"list-inside list-disc space-y-2 text-muted-foreground",children:[u("li",{children:"Keep bot tokens and signing secrets in a managed secret provider."}),u("li",{children:"Use workspace mapping to prevent cross-tenant event leakage."}),u("li",{children:"Keep dispatch asynchronous so webhook handlers stay fast and reliable."}),u("li",{children:"Monitor telemetry for ingest, decision, outbox, and dispatch stages."})]})]}),M("div",{className:"flex items-center gap-4 pt-4",children:[u(
|
|
509
|
+
CHANNEL_DISPATCH_RUN_ON_START=1`})})]}),M("div",{className:"space-y-4",children:[u("h2",{className:"font-bold text-2xl",children:"Best practices"}),M("ul",{className:"list-inside list-disc space-y-2 text-muted-foreground",children:[u("li",{children:"Keep bot tokens and signing secrets in a managed secret provider."}),u("li",{children:"Use workspace mapping to prevent cross-tenant event leakage."}),u("li",{children:"Keep dispatch asynchronous so webhook handlers stay fast and reliable."}),u("li",{children:"Monitor telemetry for ingest, decision, outbox, and dispatch stages."})]})]}),M("div",{className:"flex items-center gap-4 pt-4",children:[u(le,{href:"/docs/integrations/twilio",className:"btn-ghost",children:"Previous: Twilio SMS"}),M(le,{href:"/docs/integrations/github",className:"btn-primary",children:["Next: GitHub Messaging ",u(ze,{size:16})]})]})]})}import de from"@contractspec/lib.ui-link";import{ChevronRight as Ve}from"lucide-react";import{jsx as t,jsxs as d}from"react/jsx-runtime";function Qe(){return d("div",{className:"space-y-8",children:[d("div",{className:"space-y-4",children:[t("h1",{className:"font-bold text-4xl",children:"Integration Spec Model"}),t("p",{className:"text-muted-foreground",children:"Integrations in ContractSpec are defined through typed specifications that declare capabilities, configuration requirements, and connection details. This page covers IntegrationSpec and IntegrationConnection."})]}),d("div",{className:"space-y-4",children:[t("h2",{className:"font-bold text-2xl",children:"IntegrationSpec"}),d("p",{className:"text-muted-foreground",children:["The ",t("strong",{children:"IntegrationSpec"})," is a global definition of an integration provider. It declares what the integration provides and what it requires."]}),t("div",{className:"overflow-x-auto rounded-lg border border-border bg-background/50 p-4 font-mono text-muted-foreground text-sm",children:t("pre",{children:`type IntegrationSpec = {
|
|
490
510
|
id: string;
|
|
491
511
|
label: string;
|
|
492
512
|
description: string;
|
|
@@ -539,7 +559,7 @@ CHANNEL_DISPATCH_RUN_ON_START=1`})})]}),M("div",{className:"space-y-4",children:
|
|
|
539
559
|
version: string;
|
|
540
560
|
createdAt: string;
|
|
541
561
|
updatedAt: string;
|
|
542
|
-
};`})})]}),
|
|
562
|
+
};`})})]}),d("div",{className:"space-y-4",children:[t("h2",{className:"font-bold text-2xl",children:"Example: Stripe IntegrationSpec"}),t("div",{className:"overflow-x-auto rounded-lg border border-border bg-background/50 p-4 font-mono text-muted-foreground text-sm",children:t("pre",{children:`{
|
|
543
563
|
id: "stripe",
|
|
544
564
|
label: "Stripe",
|
|
545
565
|
description: "Payment processing and subscription management",
|
|
@@ -604,7 +624,7 @@ CHANNEL_DISPATCH_RUN_ON_START=1`})})]}),M("div",{className:"space-y-4",children:
|
|
|
604
624
|
docsUrl: "https://docs.contractspec.com/integrations/stripe",
|
|
605
625
|
setupGuideUrl: "https://stripe.com/docs/keys",
|
|
606
626
|
version: "1.0.0"
|
|
607
|
-
}`})})]}),
|
|
627
|
+
}`})})]}),d("div",{className:"space-y-4",children:[t("h2",{className:"font-bold text-2xl",children:"IntegrationConnection"}),d("p",{className:"text-muted-foreground",children:["An ",t("strong",{children:"IntegrationConnection"})," is a per-tenant instance of an integration with configured credentials and environment settings."]}),t("div",{className:"overflow-x-auto rounded-lg border border-border bg-background/50 p-4 font-mono text-muted-foreground text-sm",children:t("pre",{children:`type IntegrationConnection = {
|
|
608
628
|
id: string;
|
|
609
629
|
tenantId: string;
|
|
610
630
|
integrationId: string;
|
|
@@ -628,7 +648,7 @@ CHANNEL_DISPATCH_RUN_ON_START=1`})})]}),M("div",{className:"space-y-4",children:
|
|
|
628
648
|
createdAt: string;
|
|
629
649
|
updatedAt: string;
|
|
630
650
|
createdBy: string;
|
|
631
|
-
};`})})]}),
|
|
651
|
+
};`})})]}),d("div",{className:"space-y-4",children:[t("h2",{className:"font-bold text-2xl",children:"Example: Stripe IntegrationConnection"}),t("div",{className:"overflow-x-auto rounded-lg border border-border bg-background/50 p-4 font-mono text-muted-foreground text-sm",children:t("pre",{children:`// Production connection
|
|
632
652
|
{
|
|
633
653
|
id: "conn_stripe_acme_prod",
|
|
634
654
|
tenantId: "acme-corp",
|
|
@@ -662,7 +682,7 @@ CHANNEL_DISPATCH_RUN_ON_START=1`})})]}),M("div",{className:"space-y-4",children:
|
|
|
662
682
|
createdAt: "2025-01-01T00:00:00Z",
|
|
663
683
|
updatedAt: "2025-01-15T10:25:00Z",
|
|
664
684
|
createdBy: "dev@acme.com"
|
|
665
|
-
}`})})]}),
|
|
685
|
+
}`})})]}),d("div",{className:"space-y-4",children:[t("h2",{className:"font-bold text-2xl",children:"Example: Messaging IntegrationConnection"}),t("p",{className:"text-muted-foreground",children:"Messaging providers use the same spec + connection model, then route inbound events through the channel runtime for signature validation, idempotent ingestion, policy decisions, and outbox-backed dispatch."}),t("div",{className:"overflow-x-auto rounded-lg border border-border bg-background/50 p-4 font-mono text-muted-foreground text-sm",children:t("pre",{children:`{
|
|
666
686
|
id: "conn_slack_acme_prod",
|
|
667
687
|
tenantId: "acme-corp",
|
|
668
688
|
integrationId: "messaging.slack",
|
|
@@ -679,7 +699,7 @@ CHANNEL_DISPATCH_RUN_ON_START=1`})})]}),M("div",{className:"space-y-4",children:
|
|
|
679
699
|
{
|
|
680
700
|
"botToken": "xoxb-...",
|
|
681
701
|
"signingSecret": "..."
|
|
682
|
-
}`})})]}),
|
|
702
|
+
}`})})]}),d("div",{className:"space-y-4",children:[t("h2",{className:"font-bold text-2xl",children:"Health transport strategy config"}),t("p",{className:"text-muted-foreground",children:"Health providers support deterministic transport routing and explicit unofficial gating in connection config."}),t("div",{className:"overflow-x-auto rounded-lg border border-border bg-background/50 p-4 font-mono text-muted-foreground text-sm",children:t("pre",{children:`{
|
|
683
703
|
"defaultTransport": "official-api",
|
|
684
704
|
"strategyOrder": ["official-api", "aggregator-api", "unofficial"],
|
|
685
705
|
"allowUnofficial": false,
|
|
@@ -696,7 +716,7 @@ CHANNEL_DISPATCH_RUN_ON_START=1`})})]}),M("div",{className:"space-y-4",children:
|
|
|
696
716
|
"clientSecret": "...",
|
|
697
717
|
"tokenExpiresAt": "2026-02-01T00:00:00.000Z",
|
|
698
718
|
"mcpAccessToken": "..."
|
|
699
|
-
}`})})]}),
|
|
719
|
+
}`})})]}),d("div",{className:"space-y-4",children:[t("h2",{className:"font-bold text-2xl",children:"Health checks"}),t("p",{className:"text-muted-foreground",children:"IntegrationConnections are periodically health-checked to ensure they remain valid:"}),d("ul",{className:"list-inside list-disc space-y-2 text-muted-foreground",children:[d("li",{children:[t("strong",{children:"API key validation"})," - Test that credentials are still valid"]}),d("li",{children:[t("strong",{children:"Connectivity check"})," - Verify network access to the provider"]}),d("li",{children:[t("strong",{children:"Permission verification"})," - Ensure required scopes are granted"]}),d("li",{children:[t("strong",{children:"Webhook validation"})," - Test webhook endpoint reachability"]})]}),t("p",{className:"text-muted-foreground",children:'Failed health checks update the connection status to "error" and trigger alerts.'})]}),d("div",{className:"space-y-4",children:[t("h2",{className:"font-bold text-2xl",children:"Secret management"}),t("p",{className:"text-muted-foreground",children:"Secrets (API keys, tokens) are never stored in plaintext:"}),d("ol",{className:"list-inside list-decimal space-y-2 text-muted-foreground",children:[t("li",{children:"User provides secrets through secure UI or API"}),t("li",{children:"Secrets are encrypted using tenant-specific keys"}),t("li",{children:"Encrypted secrets are stored in secure vault (e.g., AWS Secrets Manager)"}),t("li",{children:"IntegrationConnection stores only a reference (secretRef)"}),t("li",{children:"At runtime, secrets are decrypted on-demand and never logged"})]})]}),d("div",{className:"space-y-4",children:[t("h2",{className:"font-bold text-2xl",children:"Best practices"}),d("ul",{className:"list-inside list-disc space-y-2 text-muted-foreground",children:[t("li",{children:"Always maintain separate sandbox and production connections"}),t("li",{children:"Use descriptive connection IDs that include tenant and environment"}),t("li",{children:"Monitor health check status and set up alerts for failures"}),t("li",{children:"Rotate secrets regularly and update secretRef accordingly"}),t("li",{children:"Document the purpose and ownership of each connection"}),t("li",{children:"Test connections in sandbox before enabling in production"})]})]}),d("div",{className:"flex items-center gap-4 pt-4",children:[t(de,{href:"/docs/integrations",className:"btn-ghost",children:"Back to Integrations"}),d(de,{href:"/docs/architecture/integration-binding",className:"btn-primary",children:["Integration Binding ",t(Ve,{size:16})]})]})]})}import ne from"@contractspec/lib.ui-link";import{ChevronRight as Ye}from"lucide-react";import{jsx as e,jsxs as n}from"react/jsx-runtime";function Ze(){return n("div",{className:"space-y-8",children:[n("div",{className:"space-y-4",children:[e("h1",{className:"font-bold text-4xl",children:"Stripe"}),e("p",{className:"text-muted-foreground",children:"The Stripe integration enables payment processing, subscription management, and invoicing in your ContractSpec applications. All Stripe operations are type-safe, policy-enforced, and automatically logged."})]}),n("div",{className:"space-y-4",children:[e("h2",{className:"font-bold text-2xl",children:"Setup"}),e("p",{className:"text-muted-foreground",children:"Add your Stripe credentials to your environment variables:"}),e("div",{className:"overflow-x-auto rounded-lg border border-border bg-background/50 p-4 font-mono text-muted-foreground text-sm",children:e("pre",{children:`# .env
|
|
700
720
|
STRIPE_SECRET_KEY=sk_test_...
|
|
701
721
|
STRIPE_PUBLISHABLE_KEY=pk_test_...
|
|
702
722
|
STRIPE_WEBHOOK_SECRET=whsec_...`})}),n("p",{className:"text-muted-foreground text-sm",children:["Get your API keys from the"," ",e("a",{href:"https://dashboard.stripe.com/apikeys",target:"_blank",rel:"noopener noreferrer",className:"text-violet-400 hover:text-violet-300",children:"Stripe Dashboard"}),"."]})]}),n("div",{className:"space-y-4",children:[e("h2",{className:"font-bold text-2xl",children:"Available capabilities"}),n("div",{className:"space-y-3",children:[e("h3",{className:"font-semibold text-lg",children:"Payment Intents"}),e("div",{className:"overflow-x-auto rounded-lg border border-border bg-background/50 p-4 font-mono text-muted-foreground text-sm",children:e("pre",{children:`capabilityId: stripe-create-payment-intent
|
|
@@ -799,10 +819,10 @@ steps:
|
|
|
799
819
|
to: "admin@example.com"
|
|
800
820
|
template: "payment-error"
|
|
801
821
|
data:
|
|
802
|
-
error: \${error.message}`})})]}),n("div",{className:"space-y-4",children:[e("h2",{className:"font-bold text-2xl",children:"Testing"}),e("p",{className:"text-muted-foreground",children:"Use Stripe's test cards for development:"}),e("div",{className:"overflow-x-auto rounded-lg border border-border/50",children:n("table",{className:"w-full text-left text-sm",children:[e("thead",{className:"bg-card/50",children:n("tr",{className:"border-border/50 border-b",children:[e("th",{className:"px-4 py-3 font-semibold",children:"Card Number"}),e("th",{className:"px-4 py-3 font-semibold",children:"Scenario"})]})}),n("tbody",{className:"divide-y divide-border/50",children:[n("tr",{children:[e("td",{className:"px-4 py-3 font-mono",children:"4242 4242 4242 4242"}),e("td",{className:"px-4 py-3",children:"Successful payment"})]}),n("tr",{children:[e("td",{className:"px-4 py-3 font-mono",children:"4000 0000 0000 9995"}),e("td",{className:"px-4 py-3",children:"Insufficient funds"})]}),n("tr",{children:[e("td",{className:"px-4 py-3 font-mono",children:"4000 0000 0000 0002"}),e("td",{className:"px-4 py-3",children:"Card declined"})]})]})]})})]}),n("div",{className:"space-y-4",children:[e("h2",{className:"font-bold text-2xl",children:"Best practices"}),n("ul",{className:"list-inside list-disc space-y-2 text-muted-foreground",children:[e("li",{children:"Always use test mode during development"}),e("li",{children:"Verify webhook signatures to prevent fraud"}),e("li",{children:"Handle idempotency for payment operations"}),e("li",{children:"Store customer IDs for recurring payments"}),e("li",{children:"Use metadata to link Stripe objects to your application records"}),e("li",{children:"Monitor failed payments and retry logic"})]})]}),n("div",{className:"flex items-center gap-4 pt-4",children:[e(
|
|
822
|
+
error: \${error.message}`})})]}),n("div",{className:"space-y-4",children:[e("h2",{className:"font-bold text-2xl",children:"Testing"}),e("p",{className:"text-muted-foreground",children:"Use Stripe's test cards for development:"}),e("div",{className:"overflow-x-auto rounded-lg border border-border/50",children:n("table",{className:"w-full text-left text-sm",children:[e("thead",{className:"bg-card/50",children:n("tr",{className:"border-border/50 border-b",children:[e("th",{className:"px-4 py-3 font-semibold",children:"Card Number"}),e("th",{className:"px-4 py-3 font-semibold",children:"Scenario"})]})}),n("tbody",{className:"divide-y divide-border/50",children:[n("tr",{children:[e("td",{className:"px-4 py-3 font-mono",children:"4242 4242 4242 4242"}),e("td",{className:"px-4 py-3",children:"Successful payment"})]}),n("tr",{children:[e("td",{className:"px-4 py-3 font-mono",children:"4000 0000 0000 9995"}),e("td",{className:"px-4 py-3",children:"Insufficient funds"})]}),n("tr",{children:[e("td",{className:"px-4 py-3 font-mono",children:"4000 0000 0000 0002"}),e("td",{className:"px-4 py-3",children:"Card declined"})]})]})]})})]}),n("div",{className:"space-y-4",children:[e("h2",{className:"font-bold text-2xl",children:"Best practices"}),n("ul",{className:"list-inside list-disc space-y-2 text-muted-foreground",children:[e("li",{children:"Always use test mode during development"}),e("li",{children:"Verify webhook signatures to prevent fraud"}),e("li",{children:"Handle idempotency for payment operations"}),e("li",{children:"Store customer IDs for recurring payments"}),e("li",{children:"Use metadata to link Stripe objects to your application records"}),e("li",{children:"Monitor failed payments and retry logic"})]})]}),n("div",{className:"flex items-center gap-4 pt-4",children:[e(ne,{href:"/docs/integrations",className:"btn-ghost",children:"Back to Integrations"}),n(ne,{href:"/docs/integrations/postmark",className:"btn-primary",children:["Next: Postmark ",e(Ye,{size:16})]})]})]})}import ce from"@contractspec/lib.ui-link";import{jsx as p,jsxs as O}from"react/jsx-runtime";function Je(){return O("div",{className:"space-y-8",children:[O("div",{className:"space-y-4",children:[p("h1",{className:"font-bold text-4xl",children:"Twilio"}),p("p",{className:"text-muted-foreground",children:"Send SMS notifications, alerts, and two-factor authentication codes using Twilio's reliable messaging platform."})]}),O("div",{className:"space-y-4",children:[p("h2",{className:"font-bold text-2xl",children:"Setup"}),p("div",{className:"overflow-x-auto rounded-lg border border-border bg-background/50 p-4 font-mono text-muted-foreground text-sm",children:p("pre",{children:`# .env
|
|
803
823
|
TWILIO_ACCOUNT_SID=...
|
|
804
824
|
TWILIO_AUTH_TOKEN=...
|
|
805
|
-
TWILIO_PHONE_NUMBER=+1234567890`})})]}),O("div",{className:"space-y-4",children:[
|
|
825
|
+
TWILIO_PHONE_NUMBER=+1234567890`})})]}),O("div",{className:"space-y-4",children:[p("h2",{className:"font-bold text-2xl",children:"Sending SMS"}),p("div",{className:"overflow-x-auto rounded-lg border border-border bg-background/50 p-4 font-mono text-muted-foreground text-sm",children:p("pre",{children:`capabilityId: twilio-send-sms
|
|
806
826
|
provider:
|
|
807
827
|
type: twilio
|
|
808
828
|
operation: sendSMS
|
|
@@ -819,7 +839,7 @@ outputs:
|
|
|
819
839
|
messageSid:
|
|
820
840
|
type: string
|
|
821
841
|
status:
|
|
822
|
-
type: string`})})]}),O("div",{className:"space-y-4",children:[
|
|
842
|
+
type: string`})})]}),O("div",{className:"space-y-4",children:[p("h2",{className:"font-bold text-2xl",children:"Use cases"}),O("ul",{className:"list-inside list-disc space-y-2 text-muted-foreground",children:[p("li",{children:"Order confirmations and shipping updates"}),p("li",{children:"Two-factor authentication codes"}),p("li",{children:"Appointment reminders"}),p("li",{children:"Alert notifications"})]})]}),O("div",{className:"space-y-4",children:[p("h2",{className:"font-bold text-2xl",children:"Best practices"}),O("ul",{className:"list-inside list-disc space-y-2 text-muted-foreground",children:[p("li",{children:"Always use E.164 format for phone numbers (+1234567890)"}),p("li",{children:"Keep messages under 160 characters to avoid splitting"}),p("li",{children:"Implement rate limiting to prevent spam"}),p("li",{children:"Handle delivery failures gracefully"}),p("li",{children:"Respect opt-out requests"})]})]}),O("div",{className:"flex items-center gap-4 pt-4",children:[p(ce,{href:"/docs/integrations/s3",className:"btn-ghost",children:"Previous: S3 Storage"}),p(ce,{href:"/docs/integrations/slack",className:"btn-primary",children:"Next: Slack Messaging"})]})]})}import pe from"@contractspec/lib.ui-link";import{ChevronRight as Xe}from"lucide-react";import{jsx as h,jsxs as I}from"react/jsx-runtime";function $e(){return I("div",{className:"space-y-8",children:[I("div",{className:"space-y-4",children:[h("h1",{className:"font-bold text-4xl",children:"WhatsApp Meta"}),h("p",{className:"text-muted-foreground",children:"Meta WhatsApp is the primary WhatsApp channel for ContractSpec's messaging runtime, with signed webhook verification and reliable outbound delivery."})]}),I("div",{className:"space-y-4",children:[h("h2",{className:"font-bold text-2xl",children:"Required secrets and config"}),h("div",{className:"overflow-x-auto rounded-lg border border-border bg-background/50 p-4 font-mono text-muted-foreground text-sm",children:h("pre",{children:`// secret payload
|
|
823
843
|
{
|
|
824
844
|
"accessToken": "...",
|
|
825
845
|
"appSecret": "...",
|
|
@@ -830,7 +850,7 @@ outputs:
|
|
|
830
850
|
{
|
|
831
851
|
"phoneNumberId": "120000000001",
|
|
832
852
|
"apiVersion": "v22.0"
|
|
833
|
-
}`})})]}),I("div",{className:"space-y-4",children:[
|
|
853
|
+
}`})})]}),I("div",{className:"space-y-4",children:[h("h2",{className:"font-bold text-2xl",children:"Webhook endpoints"}),I("ul",{className:"list-inside list-disc space-y-2 text-muted-foreground",children:[I("li",{children:["Verification challenge:"," ",h("code",{className:"rounded bg-background/50 px-2 py-1",children:"GET /webhooks/whatsapp/meta"})]}),I("li",{children:["Inbound messages:"," ",h("code",{className:"rounded bg-background/50 px-2 py-1",children:"POST /webhooks/whatsapp/meta"})]}),I("li",{children:["Signatures are validated with"," ",h("code",{className:"rounded bg-background/50 px-2 py-1",children:"x-hub-signature-256"}),"."]})]})]}),I("div",{className:"space-y-4",children:[h("h2",{className:"font-bold text-2xl",children:"Workspace mapping"}),h("div",{className:"overflow-x-auto rounded-lg border border-border bg-background/50 p-4 font-mono text-muted-foreground text-sm",children:h("pre",{children:'CHANNEL_WORKSPACE_MAP_WHATSAPP_META={"120000000001":"workspace-acme"}'})})]}),I("div",{className:"space-y-4",children:[h("h2",{className:"font-bold text-2xl",children:"Best practices"}),I("ul",{className:"list-inside list-disc space-y-2 text-muted-foreground",children:[h("li",{children:"Keep verify and app secrets separate from access tokens."}),h("li",{children:"Map each phone number ID to a workspace for strict tenant routing."}),h("li",{children:"Use Twilio WhatsApp only as fallback when you need active-passive routing."})]})]}),I("div",{className:"flex items-center gap-4 pt-4",children:[h(pe,{href:"/docs/integrations/github",className:"btn-ghost",children:"Previous: GitHub Messaging"}),I(pe,{href:"/docs/integrations/whatsapp-twilio",className:"btn-primary",children:["Next: WhatsApp Twilio ",h(Xe,{size:16})]})]})]})}import me from"@contractspec/lib.ui-link";import{ChevronRight as xe}from"lucide-react";import{jsx as v,jsxs as A}from"react/jsx-runtime";function je(){return A("div",{className:"space-y-8",children:[A("div",{className:"space-y-4",children:[v("h1",{className:"font-bold text-4xl",children:"WhatsApp Twilio"}),v("p",{className:"text-muted-foreground",children:"Twilio WhatsApp support provides a durable fallback channel with signature verification and outbox-backed outbound dispatch."})]}),A("div",{className:"space-y-4",children:[v("h2",{className:"font-bold text-2xl",children:"Required secrets and config"}),v("div",{className:"overflow-x-auto rounded-lg border border-border bg-background/50 p-4 font-mono text-muted-foreground text-sm",children:v("pre",{children:`// secret payload
|
|
834
854
|
{
|
|
835
855
|
"accountSid": "AC123",
|
|
836
856
|
"authToken": "..."
|
|
@@ -839,4 +859,4 @@ outputs:
|
|
|
839
859
|
// optional connection config
|
|
840
860
|
{
|
|
841
861
|
"fromNumber": "whatsapp:+15550002"
|
|
842
|
-
}`})})]}),A("div",{className:"space-y-4",children:[
|
|
862
|
+
}`})})]}),A("div",{className:"space-y-4",children:[v("h2",{className:"font-bold text-2xl",children:"Webhook ingress"}),A("ul",{className:"list-inside list-disc space-y-2 text-muted-foreground",children:[A("li",{children:["Inbound Twilio form payloads are accepted on"," ",v("code",{className:"rounded bg-background/50 px-2 py-1",children:"/webhooks/whatsapp/twilio"}),"."]}),A("li",{children:["Signatures are validated with"," ",v("code",{className:"rounded bg-background/50 px-2 py-1",children:"x-twilio-signature"})," ","and the configured auth token."]}),A("li",{children:["For deterministic verification, set the exact public webhook URL in"," ",v("code",{className:"rounded bg-background/50 px-2 py-1",children:"WHATSAPP_TWILIO_WEBHOOK_URL"}),"."]})]})]}),A("div",{className:"space-y-4",children:[v("h2",{className:"font-bold text-2xl",children:"Workspace mapping"}),v("div",{className:"overflow-x-auto rounded-lg border border-border bg-background/50 p-4 font-mono text-muted-foreground text-sm",children:v("pre",{children:'CHANNEL_WORKSPACE_MAP_WHATSAPP_TWILIO={"AC123":"workspace-acme"}'})})]}),A("div",{className:"space-y-4",children:[v("h2",{className:"font-bold text-2xl",children:"Best practices"}),A("ul",{className:"list-inside list-disc space-y-2 text-muted-foreground",children:[v("li",{children:"Use Twilio as fallback when Meta WhatsApp is your primary route."}),v("li",{children:"Keep account SID mapping explicit to avoid tenant misrouting."}),A("li",{children:["Protect internal dispatch endpoints with",v("code",{className:"ml-1 rounded bg-background/50 px-2 py-1",children:"CHANNEL_DISPATCH_TOKEN"}),"."]})]})]}),A("div",{className:"flex items-center gap-4 pt-4",children:[v(me,{href:"/docs/integrations/whatsapp-meta",className:"btn-ghost",children:"Previous: WhatsApp Meta"}),A(me,{href:"/docs/integrations/health-routing",className:"btn-primary",children:["Next: Health Routing ",v(xe,{size:16})]})]})]})}export{je as IntegrationsWhatsappTwilioPage,$e as IntegrationsWhatsappMetaPage,Je as IntegrationsTwilioPage,Ze as IntegrationsStripePage,Qe as IntegrationsSpecModelPage,Fe as IntegrationsSlackPage,qe as IntegrationsS3Page,Ge as IntegrationsResendPage,Re as IntegrationsQdrantPage,Le as IntegrationsPowensPage,Ee as IntegrationsPostmarkPage,He as IntegrationsOverviewPage,Se as IntegrationsOpenAIPage,We as IntegrationsMistralPage,Te as IntegrationsHealthRoutingPage,Ie as IntegrationsGoogleDrivePage,Ae as IntegrationsGoogleCalendarPage,we as IntegrationsGmailPage,ye as IntegrationsGithubPage,be as IntegrationsElevenLabsPage,he as IntegrationsCircuitBreakersPage};
|