Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions components/ExecuteApiExchange.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import styles from './ExecuteApiExchange.module.css'

function CodeLine({ children }) {
return <code className={styles.line}>{children}</code>
}

export default function ExecuteApiExchange() {
return (
<section className={styles.exchange} aria-labelledby="execute-api-exchange-title">
<div className={styles.heading}>
<p className="eyebrow">Asynchronous by design</p>
<h2 id="execute-api-exchange-title">One transaction. A durable terminal receipt.</h2>
<p>Your request gets an immediate acceptance. A signed webhook then delivers the terminal result when the runner has proof or needs reconciliation.</p>
</div>
<ol className={styles.messages}>
<li>
<p className={styles.label}>1 · Submit an authorized transaction</p>
<pre aria-label="Execute API request"><CodeLine><span className={styles.method}>POST</span> /v1/executions</CodeLine><CodeLine>{'{'}</CodeLine><CodeLine>{' "schema_version":'}</CodeLine><CodeLine>{' "openadapt.execute-request/v1",'}</CodeLine><CodeLine>{' "idempotency_key": "txn_…",'}</CodeLine><CodeLine>{' "parameters": { … }'}</CodeLine><CodeLine>{'}'}</CodeLine></pre>
<p className={styles.note}>Your product supplies structured input. The qualified workflow defines the permitted effect.</p>
</li>
<li>
<p className={styles.label}>2 · Keep the transaction identity</p>
<pre aria-label="Execute API accepted response"><CodeLine><span className={styles.status}>202 Accepted</span></CodeLine><CodeLine>{'{'}</CodeLine><CodeLine>{' "schema_version":'}</CodeLine><CodeLine>{' "openadapt.execute-accepted/v1",'}</CodeLine><CodeLine>{' "execution_id": "exec_…",'}</CodeLine><CodeLine>{' "state": "queued"'}</CodeLine><CodeLine>{'}'}</CodeLine></pre>
<p className={styles.note}>Acceptance is not a success claim. Poll this ID if your webhook endpoint is unavailable.</p>
</li>
<li>
<p className={styles.label}>3 · Verify the terminal delivery</p>
<pre aria-label="Signed terminal webhook"><CodeLine><span className={styles.webhook}>POST</span> /hooks/openadapt</CodeLine><CodeLine>{'{'}</CodeLine><CodeLine>{' "schema_version":'}</CodeLine><CodeLine>{' "openadapt.execute-webhook/v1",'}</CodeLine><CodeLine>{' "event_type": "execution.terminal",'}</CodeLine><CodeLine>{' "receipt": {'}</CodeLine><CodeLine>{' "outcome": "verified", …'}</CodeLine><CodeLine>{' },'}</CodeLine><CodeLine>{' "signature": "hmac-sha256:…"'}</CodeLine><CodeLine>{'}'}</CodeLine></pre>
<p className={styles.note}>Verify the signature and store the receipt. The outcome can also require reconciliation instead of a retry.</p>
</li>
</ol>
</section>
)
}
84 changes: 84 additions & 0 deletions components/ExecuteApiExchange.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
.exchange {
padding: clamp(1.25rem, 3vw, 2rem);
border: 1px solid var(--hairline);
border-radius: 1rem;
background: var(--panel);
}

.heading { max-width: 42rem; }

.heading h2 {
margin: 0.4rem 0 0;
color: var(--ink);
font-family: var(--font-display);
font-size: clamp(1.5rem, 3vw, 2rem);
line-height: 1.15;
}

.heading > p:last-child {
margin: 0.75rem 0 0;
color: var(--ink-2);
font-size: 0.95rem;
line-height: 1.55;
}

.messages {
display: grid;
gap: 1rem;
padding: 0;
margin: 1.5rem 0 0;
list-style: none;
}

.messages li {
position: relative;
min-width: 0;
padding: 1rem;
overflow: hidden;
border: 1px solid var(--hairline);
border-radius: 0.75rem;
background: var(--ground);
}

.label {
margin: 0 0 0.65rem;
color: var(--accent);
font-family: var(--font-mono);
font-size: 0.68rem;
font-weight: 700;
letter-spacing: 0.07em;
text-transform: uppercase;
}

.messages pre {
max-width: 100%;
padding: 0.8rem;
margin: 0;
overflow-x: auto;
border-radius: 0.5rem;
background: var(--ink);
color: var(--ground);
font-family: var(--font-mono);
font-size: clamp(0.68rem, 1.8vw, 0.76rem);
line-height: 1.65;
}

.line {
display: block;
overflow-wrap: anywhere;
white-space: pre-wrap;
}
.method { color: #a9d7b5; }
.status { color: #d9d68b; }
.webhook { color: #9bc8d7; }

.note {
margin: 0.7rem 0 0;
color: var(--ink-2);
font-size: 0.78rem;
line-height: 1.45;
}

@media (min-width: 760px) {
.messages { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
86 changes: 86 additions & 0 deletions components/ExecuteBoundaryFlow.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import styles from './ExecuteBoundaryFlow.module.css'

const stages = [
{
title: 'Your product',
detail: 'Authorized structured input',
kind: 'input',
},
{
title: 'OpenAdapt',
detail: 'Qualified contract and authorization',
kind: 'proof',
},
{
title: 'Customer-controlled runner',
detail: 'Local observation and actuation',
kind: 'runner',
},
]

function StageIcon({ kind }) {
if (kind === 'input') {
return (
<svg viewBox="0 0 32 32" aria-hidden="true" focusable="false">
<path d="M7 6h18v20H7zM11 11h10M11 16h10M11 21h6" />
</svg>
)
}

if (kind === 'runner') {
return (
<svg viewBox="0 0 32 32" aria-hidden="true" focusable="false">
<rect x="5" y="6" width="22" height="16" rx="2" />
<path d="M12 27h8M16 22v5M10 14h12M16 10v8" />
</svg>
)
}

return (
<svg viewBox="0 0 32 32" aria-hidden="true" focusable="false">
<path d="M16 4l9 4v7c0 6-3.8 10.4-9 13-5.2-2.6-9-7-9-13V8z" />
<path d="M12 16l2.6 2.6L20.5 12" />
</svg>
)
}

function Connector({ returnPath = false }) {
return (
<div className={`${styles.connector} ${returnPath ? styles.returnPath : ''}`} aria-hidden="true">
<svg viewBox="0 0 80 40" focusable="false">
<path d="M4 20h64m0 0l-9-9m9 9l-9 9" />
</svg>
<span>{returnPath ? 'proof / exception' : 'authorized handoff'}</span>
</div>
)
}

// A static, semantic flow remains available when motion is reduced. The moving
// dash is presentation-only; the text defines the actual execution boundary.
export default function ExecuteBoundaryFlow() {
return (
<figure className={styles.figure} aria-labelledby="execute-boundary-flow-title">
<figcaption id="execute-boundary-flow-title" className={styles.srOnly}>
Your product sends authorized structured input to OpenAdapt. OpenAdapt binds it to a qualified contract and sends it to a customer-controlled runner. The runner acts locally. A signed receipt returns through OpenAdapt.
</figcaption>
<div className={styles.flow}>
{stages.map((stage, index) => (
<div className={styles.part} key={stage.title}>
<article className={styles.stage}>
<span className={styles.icon}><StageIcon kind={stage.kind} /></span>
<span className={styles.stageCopy}>
<strong>{stage.title}</strong>
<span>{stage.detail}</span>
</span>
</article>
{index < stages.length - 1 && <Connector />}
</div>
))}
</div>
<div className={styles.returnLane}>
<Connector returnPath />
<p>A signed receipt returns through OpenAdapt after verification or a governed stop.</p>
</div>
</figure>
)
}
171 changes: 171 additions & 0 deletions components/ExecuteBoundaryFlow.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
.figure {
margin: 0;
padding: 1.25rem;
border: 1px solid var(--hairline);
border-radius: 1rem;
background: var(--ground);
}

.flow {
display: flex;
align-items: stretch;
justify-content: center;
}

.part {
display: flex;
flex: 1 1 0;
align-items: center;
min-width: 0;
}

.stage {
display: flex;
flex: 1 1 auto;
align-items: center;
gap: 0.75rem;
min-width: 0;
padding: 0.9rem;
border: 1px solid var(--hairline);
border-radius: 0.75rem;
background: var(--panel);
}

.icon {
display: grid;
flex: 0 0 auto;
width: 2.25rem;
height: 2.25rem;
place-items: center;
border-radius: 999px;
background: color-mix(in srgb, var(--accent) 12%, transparent);
color: var(--accent);
}

.icon svg {
width: 1.25rem;
height: 1.25rem;
fill: none;
stroke: currentColor;
stroke-linecap: round;
stroke-linejoin: round;
stroke-width: 1.8;
}

.stageCopy {
display: grid;
gap: 0.2rem;
min-width: 0;
}

.stageCopy strong {
color: var(--ink);
font-size: 0.84rem;
line-height: 1.2;
}

.stageCopy span,
.returnLane p {
color: var(--ink-2);
font-size: 0.72rem;
line-height: 1.35;
}

.connector {
display: grid;
flex: 0 1 6.25rem;
justify-items: center;
gap: 0.15rem;
min-width: 3.5rem;
color: var(--accent);
}

.connector svg {
width: 100%;
max-width: 5rem;
height: 1.5rem;
overflow: visible;
}

.connector path {
fill: none;
stroke: currentColor;
stroke-dasharray: 4 4;
stroke-linecap: round;
stroke-linejoin: round;
stroke-width: 1.6;
animation: travel 1.8s linear infinite;
}

.connector span {
max-width: 5.5rem;
color: var(--ink-3);
font-size: 0.62rem;
line-height: 1.15;
text-align: center;
}

.returnLane {
display: grid;
grid-template-columns: minmax(4rem, 14rem) minmax(0, 1fr);
align-items: center;
gap: 0.75rem;
max-width: 26rem;
margin: 1rem auto 0;
}

.returnLane p {
margin: 0;
}

.returnPath svg {
transform: scaleX(-1);
}

.returnPath path {
animation-direction: reverse;
}

.srOnly {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}

@keyframes travel {
to { stroke-dashoffset: -16; }
}

@media (prefers-reduced-motion: reduce) {
.connector path { animation: none; }
}

@media (max-width: 760px) {
.flow,
.part {
flex-direction: column;
}

.part { width: 100%; }

.stage { width: 100%; }

.connector {
flex-basis: auto;
min-height: 3.25rem;
}

.connector svg { transform: rotate(90deg); }

.returnLane {
grid-template-columns: 3.5rem minmax(0, 1fr);
margin-top: 0.5rem;
}

.returnPath svg { transform: rotate(90deg) scaleX(-1); }
}
Loading
Loading