Orchestrator boundaries
Everything between Nwire and the outside world. Five first-class primitives so Studio sees every boundary as a sticky on the EventStorming canvas.
defineExternalCall — HTTP / RPC outbound
const chargeStripe = defineExternalCall({
name: "stripe.create-payment-intent",
target: { provider: "stripe", endpoint: "/v1/payment_intents" },
request: ChargePaymentIntentSchema,
response: PaymentIntentSchema,
idempotencyKey: (req) => `charge-${req.orderId}-${req.amount}`,
slo: { p95LatencyMs: 600, successRate: 0.995 },
retry: { max: 3, backoff: "exponential" },
});
// Bind a transport at boot (HTTP client / Stripe SDK / test mock):
app.runtime.registerExternalCallExecutor(chargeStripe, async (req, meta) => {
return await stripe.paymentIntents.create({
amount: req.amount,
idempotency_key: meta.idempotencyKey,
});
});
// Call it from a handler:
defineHandler(chargeOrder, async (input, ctx) => {
const intent = await ctx.externalCall(chargeStripe, { amount: input.amount, orderId: input.id });
return OrderCharged({ orderId: input.id, intentId: intent.id });
});Runtime: retries automatically with backoff, threads idempotency key, emits external.call.started/.completed/.failed telemetry per attempt.
defineInboundWebhook — HTTP callbacks IN
const stripeWebhook = defineInboundWebhook({
name: "stripe.payment-events",
source: "stripe",
path: "/webhooks/stripe",
verifySignature: stripeSignatureVerifier,
dedupe: { window: "24h", keyFrom: (msg) => msg.id },
schema: StripeWebhookSchema,
discriminator: "type",
routes: {
"payment_intent.succeeded": confirmPayment,
"payment_intent.payment_failed": markPaymentFailed,
},
});The HTTP wire mounts the path, verifies the signature, dedups via inbox, discriminates on the body field, dispatches the right action.
defineOutbox — transactional outbox
const ordersOutbox = defineOutbox({
name: "orders",
publishes: [OrderPlacedEvent, OrderShippedEvent],
flushIntervalMs: 200,
maxBatch: 100,
});Events written to the outbox in the same DB transaction as state. A flusher drains to the cross-service bus. At-least-once delivery; readers handle dedup via inbox.
defineInbox — at-least-once dedup
const ordersInbox = defineInbox({
name: "orders",
window: "7d",
on: [confirmPayment, markPaymentFailed],
});Tracks message ids seen in the last 7 days; second arrival short-circuits.
defineCron — scheduled actions
const dailyBillingSummary = defineCron({
name: "billing.daily-summary",
schedule: "0 2 * * *", // every day at 02:00 UTC
dispatches: generateBillingSummary,
timezone: "UTC",
});A scheduler dispatches the bound action at each fire time; runtime emits cron.fired with lateByMs.
Why first-class
Generic observability sees each external call as another HTTP span. Nwire's declarative primitives let:
- Studio render each boundary as a distinct sticky on the canvas
- Idempotency be enforced consistently across providers
- SLOs be declared per provider/endpoint and scored against observed reality
- Retries be applied by the runtime, not buried in handlers
- Webhooks be verified + deduped + routed without route boilerplate