Skip to content

Drupal connector

A Drupal 10/11 module that maps nodes, taxonomy terms, and Drupal Commerce products to bAInquet IngestItems, signs every request with the connector HMAC scheme, and POSTs idempotent batches.

The module lives under connectors/drupal/bainquet and sends X-Connector-Type: drupal.

What it maps

Drupal entityIngestItem typeNotes
Node (page-like bundle)pageThe body field's text-format-processed HTML becomes html; a deterministic plain-text rendition becomes text.
Node (article, blog, news)postBundles named event or faq map to those types; everything else falls back to post.
Drupal Commerce productproductVariations carry SKU and typed price { value, unit, currency } in json.product, never a concatenated string.
Taxonomy termcategory
Userprofile
Mediamedia
  • Custom fields. field_* values are read structurally via the Field API into json.fields as typed values, never scraped. Entity-reference fields become { id, label }; link fields become { uri, title }.
  • Stable ids. Built from the entity UUID (for example post:<uuid>), so ids survive a site export or migration.
  • Language and canonical. Language is the entity's langcode normalized to BCP-47; canonical_url is the entity's absolute toUrl().

Install

bash
composer require drupal/bainquet
drush en bainquet

Or copy the bainquet folder into web/modules/custom/ and enable it from Extend.

Configure

Go to Configuration, Web services, bAInquet Connector (/admin/config/services/bainquet).

  1. Paste the connector token (connectorId.secret) from your dashboard. It is shown once; copy it immediately.
  2. Enter the Website ID the token is scoped to.
  3. Confirm the Site domain (defaults to this site host) and the API base URL (defaults to https://api.bainquet.online/v1/ingest).
  4. Under Content to sync, tick the entity_type:bundle pairs to ingest, for example node:article, node:page, commerce_product:default.
  5. Save the configuration, then click Test connection to send a heartbeat.
  6. Run drush bainquet:sync to backfill.

How incremental sync works

The module uses Drupal entity hooks.

  • Upsert. hook_entity_insert and hook_entity_update on an in-scope, published entity map it and POST to POST /v1/ingest/item.
  • Tombstone. hook_entity_delete, and any unpublish transition, POST a tombstone to POST /v1/ingest/delete with the entity's stable id, so the public node drops it.

How backfill works

bash
drush bainquet:sync

It walks every in-scope, published, access-granted entity in chunks of 50 per batch and batch-POSTs to POST /v1/ingest/batch, staying under the payload cap.

bash
drush bainquet:sync --dry-run

The dry run builds and prints the batch it would send, locally, without posting.

Privacy and access

Only published entities are ingested, and drush bainquet:sync runs the entity query with accessCheck(TRUE) so access-restricted content is never loaded. An entity that becomes unpublished after ingest is tombstoned, so the public AI node drops it.

Out of scope

Single-item upserts are sent synchronously on the hook. A persistent Queue API plus cron outbox with debounce and coalesce is a later-phase enhancement. Planned

Uninstall

Uninstalling the module removes the bainquet.settings config (including the stored token) via Drupal's standard config-on-uninstall cleanup.

HMAC signing

Every request is signed exactly as the server verifies it, using the shared bq.connector.hmac.v1 scheme:

signingKey  = HKDF-SHA256(secret, salt = websiteId, info = "bq.connector.hmac.v1", 32 bytes)
canonical   = METHOD \n path \n sha256(body) \n timestamp \n nonce \n websiteId
X-Signature = hex HMAC-SHA256(signingKey, canonical)

Headers sent: Authorization: Bearer <token>, X-Site-Domain, X-Connector-Type: drupal, X-Connector-Version, X-Signature, X-Timestamp, X-Nonce, X-Body-Sha256, and Idempotency-Key. Retries on 5xx and 429 reuse the same Idempotency-Key with a fresh nonce and timestamp.

The signing is parity-tested with a standalone test that needs no Drupal boot (php tests/SignerParityTest.php); it asserts X-Body-Sha256 and X-Signature match the frozen vector byte-for-byte. Full entity-hook, Commerce, and Drush behavior still requires a live Drupal install to validate. The full scheme is documented in Ingestion and signing.

Owner-controlled structured data for AI.