experiment · shipped

Reactive Coupon Integration

A Vue 3 reactive wrapper over the coupon application engine

why a wrapper at all

The Coupon Application Engine refuses to know about frameworks on purpose: it emits events and exposes plain properties, so it can run in a content script with no UI at all. The extension interface, though, is Vue 3 — and a Vue component cannot bind to an EventEmitter

Something has to sit between the two and turn engine events into reactive state. That something is this layer, and it exists precisely because we decided not to compromise the engine

what we built

A composable that takes an engine instance and returns a reactive view of it: a human-readable status, the booleans a UI actually renders from — isRunning, canStart, isAvailable, isValidating — the index and code of the coupon currently being tried, the result, and start / stop methods. The engine instance comes back too, for the cases the composable does not cover

Internally it is ref plus computed over one piece of engine state:

const couponEngineInternalState = ref(couponEngineInstance.status)

const isRunning = computed(
  () => couponEngineInternalState.value > Status.STARTING && couponEngineInternalState.value < Status.FAIL,
)
const canStart = computed(() => couponEngineInternalState.value >= Status.AVAILABLE && !isRunning.value)

the part that bites

Subscription lifecycle. The composable subscribes to the engine’s UPDATE:status, UPDATE:processIndex and UPDATE:result events and writes each into a ref. But resetting the engine terminates its listeners — so every path that resets has to subscribe again, or the UI silently stops updating while the engine keeps working:

stop: async (): Promise<void> => {
  await couponEngineInstance.stop()

  // reset clears every listener the engine holds
  await couponEngineInstance.reset()

  subscribe()
}

That is the whole cost of the framework-free engine, paid in one file: the engine stays clean, and the wrapper remembers to re-attach

where it stands

Internal, and specific to our Vue extension UI. It is still the shape of how that UI and the engine talk to each other

Let's talk

Your contact info is sent!

We will contact you soon!