@upkeel/scenarios
v0.2.0
Published
Pre-built Upkeel instrumentation patterns — Stripe webhook roundtrips, order fulfillment pipelines, LLM tool calls, and friends. Composition over the @upkeel/sdk primitives.
Readme
@upkeel/scenarios
Pre-built Upkeel instrumentation patterns. One import per scenario
instead of ten lines of keel.expect(...) / keel.fulfill(...)
boilerplate for the same shape.
Install
npm install @upkeel/sdk @upkeel/scenariosWhat's here
All three scenarios take an @upkeel/sdk client and return a small
object with the scenario-specific affordances. No state is stored
inside the scenario — every call composes to SDK primitives, so
anything you can do with the SDK you can still do alongside.
Stripe webhook roundtrip
Monitor that a webhook you're expecting actually arrives.
import { Upkeel } from '@upkeel/sdk'
import { stripeWebhookScenario } from '@upkeel/scenarios'
const keel = new Upkeel({ apiKey: process.env.UPKEEL_API_KEY! })
const stripe = stripeWebhookScenario(keel, {
events: ['checkout.session.completed', 'payment_intent.succeeded'],
within: '60s',
})
app.post('/checkout', async (req, res) => {
const session = await stripeSdk.checkout.sessions.create({ ... })
stripe.expect('checkout.session.completed', session.id)
res.json({ url: session.url })
})
app.post('/webhooks/stripe', (req, res) => {
const evt = stripeSdk.webhooks.constructEvent(req.body, sig, secret)
stripe.fulfill(evt.type, evt.data.object.id)
res.sendStatus(200)
})Guarantees: the scenario will throw on unknown event names so you
don't silently register expectations for webhooks the scenario wasn't
configured to watch. Defaults: within: '60s', severity: 'critical'.
Order fulfillment pipeline
Declare your pipeline once; expectStep() / fulfillStep() carry the
order id as correlation and the step SLA.
import { orderFulfillmentScenario } from '@upkeel/scenarios'
const pipeline = orderFulfillmentScenario(keel, {
steps: [
{ name: 'warehouse.picked', within: '4h' },
{ name: 'shipping.label-created', within: '2h' },
{ name: 'courier.accepted', within: '24h' },
],
})
async function onOrderPaid(order) {
pipeline.expectStep(order.id, 'warehouse.picked')
}
async function onWarehouseWebhook(body) {
pipeline.fulfillStep(body.orderId, 'warehouse.picked')
pipeline.expectStep(body.orderId, 'shipping.label-created')
}
async function onRefund(orderId, reason) {
pipeline.cancelOrder(orderId, reason)
}cancelOrder() drains every in-flight expectation for the order and
emits a summary order.cancelled event with the reason for audit.
LLM tool-call roundtrip
Catches the "model claimed it called the tool; the tool was never actually invoked" class of silent failure in agent pipelines.
import { toolCallScenario } from '@upkeel/scenarios'
const tools = toolCallScenario(keel, { within: '2m' })
function onAgentToolCall(runId, toolName) {
tools.expect(runId, toolName)
}
function onToolCompleted(runId, toolName, ok) {
if (ok) tools.fulfill(runId, toolName)
else tools.cancel(runId, toolName) // explicit "abort" is not a miss
}Correlation id is ${runId}::${toolName} so two different tools
invoked in the same run don't cross-match.
Testing your own code
Scenarios work with @upkeel/testing:
import { createTestKit } from '@upkeel/testing'
import { stripeWebhookScenario } from '@upkeel/scenarios'
import { describe, it, expect } from 'vitest'
describe('checkout handler', () => {
it('misses when Stripe never sends the webhook', () => {
const { keel, clock, expectations } = createTestKit()
const stripe = stripeWebhookScenario(keel, { within: '30s' })
stripe.expect('checkout.session.completed', 'cs_test')
clock.advance('31s')
expect(expectations.missed('checkout.session.completed')).toBe(true)
})
})License
MIT. See the Upkeel SDK repo.
