JavaScript Sources

Push graph changes into the engine from your own Node.js code.

A JavaScript source lets you feed the engine directly from your application — an event stream, a webhook handler, database CDC, or anything else your code already sees. You register the source with addJsSource and push changes into it with pushChange. No Rust and no plugins required.

Register a source

import { Drasi } from '@drasi/lib';

const drasi = await Drasi.create('orders-app');
await drasi.start();

await drasi.addJsSource('orders');

A JS source maintains a current-state snapshot of the elements you’ve pushed, so a query that subscribes after you’ve already pushed changes still receives a bootstrap replay of the live elements.

Push a node change

Nodes are graph elements with labels and properties. The op is one of insert, update, or delete (add/remove are accepted aliases, case-insensitive):

await drasi.pushChange('orders', {
  op: 'insert',
  id: 'o1',
  labels: ['Order'],
  properties: { id: 'o1', status: 'open', total: 42 },
});

// Later, update it — the change flows through every subscribed query.
await drasi.pushChange('orders', {
  op: 'update',
  id: 'o1',
  labels: ['Order'],
  properties: { id: 'o1', status: 'closed', total: 42 },
});

// Or delete it.
await drasi.pushChange('orders', { op: 'delete', id: 'o1', labels: ['Order'] });

Push a relation (edge)

To emit a relation instead of a node, include both startId and endId (aliases inId / outId). Supplying only one is an error:

await drasi.pushChange('orders', {
  op: 'insert',
  id: 'o1-c1',
  labels: ['PLACED_BY'],
  startId: 'o1',    // the Order node
  endId: 'c1',      // the Customer node
});

Backpressure

pushChange writes into a bounded channel (capacity 1024). The returned promise resolves once the change is buffered, and applies backpressure when the buffer is full — so await-ing each pushChange naturally paces a fast producer:

for (const event of hugeStream) {
  await drasi.pushChange('orders', toChange(event)); // waits if the buffer is full
}

Fields reference

FieldTypeRequiredNotes
op'insert' | 'update' | 'delete'yesadd/remove accepted as aliases.
idstringyesElement id.
labelsstring[] | stringnoNode labels or relation type.
propertiesRecord<string, unknown>noArbitrary element properties.
startId / endIdstringboth-or-neitherPresent ⇒ the change is a relation.
effectiveFromnumbernoEpoch ms; defaults to now.

Error cases

pushChange validates its input synchronously and throws a typed DrasiErrorCode:

  • NO_JS_SOURCE — no JS source with that id.
  • CHANGE_NOT_OBJECT, CHANGE_OP_REQUIRED, CHANGE_ID_REQUIRED, UNKNOWN_CHANGE_OP.
  • RELATION_REQUIRES_BOTH_ENDS — only one of startId/endId was supplied.
  • JS_SOURCE_CLOSED — the source was removed mid-push (this one can surface as an async rejection; see Error handling).

Next

  • JavaScript reactions — consume the query results your source drives.
  • Trading demo — a JS source (a live price feed) joined against a real PostgreSQL database.