Skip to content

feat(integrations): add support for meilisearch#6713

Open
qdequele wants to merge 18 commits into
NangoHQ:masterfrom
qdequele:feat/meilisearch-integration
Open

feat(integrations): add support for meilisearch#6713
qdequele wants to merge 18 commits into
NangoHQ:masterfrom
qdequele:feat/meilisearch-integration

Conversation

@qdequele

@qdequele qdequele commented Jul 8, 2026

Copy link
Copy Markdown

Summary

Adds Meilisearch as an integration: an API_KEY provider plus 7 pre-built zero-yaml actions covering document read/write, batch & partial updates, deletion, async-task polling, and tenant-token generation for per-tenant search ACLs.

Provider (packages/providers/providers.yaml)

  • API_KEY auth against a user-supplied instanceUrl (Meilisearch Cloud or self-hosted), authorization: Bearer ${apiKey}.
  • Credential verification via GET /version (works with the Default Admin API Key and any custom key holding the version action, without requiring key-management ACLs).
  • instanceUrl pattern rejects scheme-less values and trailing slashes (a trailing slash survives proxy interpolation and would 404 every call).

Actions (integrations/meilisearch/)

Action Purpose
search-documents / get-documents Read (search, fetch by ids/filter)
add-documents / update-documents Batch add-or-replace / partial update (async EnqueuedTask)
delete-documents By ids or filter — exactly one, enforced in exec since zod refinements are stripped from deployed schemas
get-task Poll async write status
generate-tenant-token Signs an HS256 JWT carrying searchRules (per-index filters). Hand-rolled with crypto (runner allowlist has no jsonwebtoken); key uid auto-resolved via GET /keys/{key} with a descriptive error when the key lacks keys.get; 1h default TTL

Filter inputs accept Meilisearch's full grammar (string, array, nested OR-of-ANDs arrays); searchRules values accept objects or null.

Docs

docs/integrations/all/meilisearch.mdx, docs.json nav entry, logo, regenerated LLM indexes (npm run docs:generate:llms).

Note on placement: the action scripts live in a standalone zero-yaml project under integrations/meilisearch/ in this PR. Happy to move them to integration-templates (and reduce this PR to provider + docs) if that's the preferred split.

Test Plan

  • Unit tests (13) for the tenant-token signer (independent HMAC recompute) and zod schemas — npx vitest run integrations/meilisearch
  • npm run lint / prettier clean; providers tests pass
  • Live E2E against Meilisearch v1.48 through a full local Nango stack: integration + connection created via API (verification accepts a valid key, rejects a bad one), nango deploy dev registers all 7 actions, and every action triggered via POST /action/trigger executes through the runner. The Nango-minted tenant token was verified to be accepted by Meilisearch and to enforce its filter (token sees only its tenant's documents and cannot widen scope).

Review in cubic

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

3 issues found across 23 files

Confidence score: 2/5

  • In integrations/meilisearch/meilisearch/actions/generate-tenant-token.ts, auto-resolving apiKeyUid by putting the raw API key in the URL path can leak secrets into proxy/access/APM logs, creating a concrete credential-exposure risk if merged as-is — switch to a non-secret identifier lookup path (or resolve via body/header) before merging.
  • In integrations/meilisearch/meilisearch/lib/schemas.ts, using .catchall(z.unknown()) for tenant-token search rules allows misspelled keys like filters to validate even though Meilisearch only honors filter, so policies can silently fail and produce broader-than-expected search access — restrict/whitelist allowed keys (or reject unknown keys) before merging.
  • In integrations/meilisearch/meilisearch/actions/add-documents.ts, z.array(...).min(1) may not enforce non-empty document batches in deployed actions (per the noted refinement stripping), so empty submissions can slip through and cause runtime/API errors in production — add an explicit runtime length check in action logic before merging.

Not reviewed (too large): packages/providers/providers.yaml (~29 lines), docs/llms-full.txt (~1 lines) - if these are generated or fixture files, add them to ignored paths to exclude them from future reviews.

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="integrations/meilisearch/meilisearch/lib/schemas.ts">

<violation number="1" location="integrations/meilisearch/meilisearch/lib/schemas.ts:14">
P1: The tenant-token search-rule schema allows arbitrary object keys because `.catchall(z.unknown())` is used. Meilisearch only recognizes the `filter` key in search rules, so a typo like `filters` passes validation and gets signed into the JWT. If Meilisearch ignores the unknown key, the token silently drops its intended restriction and broadens access. Replacing `.catchall(z.unknown())` with `.strict()` rejects unknown keys at validation time while still permitting `{}` (no restriction) and `null` through the union. This aligns with the team's preference for strict, explicit schemas over broad pass-through validation.</violation>
</file>

<file name="integrations/meilisearch/meilisearch/actions/add-documents.ts">

<violation number="1" location="integrations/meilisearch/meilisearch/actions/add-documents.ts:8">
P1: The `z.array(...).min(1)` guard on `documents` does not reliably enforce non-empty batches in deployed Nango actions because the same PR explicitly notes that declarative Zod refinements are stripped from deployed JSON schemas. In `delete-documents.ts`, a runtime length check is added with a comment explaining this exact limitation (`Enforced here because declarative zod refinements are stripped...`), but `add-documents.ts` omits that guard. An empty `documents` array could therefore be forwarded to Meilisearch at runtime instead of failing with a clear action error.

Consider adding a runtime length check inside `exec`, e.g.:
```typescript
if (input.documents.length === 0) {
    throw new nango.ActionError({ message: '"documents" must contain at least one document.' });
}
```</violation>
</file>

<file name="integrations/meilisearch/meilisearch/actions/generate-tenant-token.ts">

<violation number="1" location="integrations/meilisearch/meilisearch/actions/generate-tenant-token.ts:46">
P1: The auto-resolution of `apiKeyUid` sends the raw Meilisearch API key in the request URL path. URL paths are captured by HTTP access logs, reverse proxies, and APM traces, and typical header-redaction does not scrub secrets embedded in the path. Because this lookup is the default whenever `apiKeyUid` is omitted, callers may unknowingly expose their connection API key in logs. Consider adding a prominent warning to the action description or making the lookup opt-in so users are aware of the credential-exposure risk before it happens.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread integrations/meilisearch/meilisearch/lib/schemas.ts Outdated
Comment thread integrations/meilisearch/meilisearch/actions/add-documents.ts
Comment thread integrations/meilisearch/meilisearch/actions/generate-tenant-token.ts Outdated

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 6 files (changes from recent commits).

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread integrations/meilisearch/meilisearch/actions/add-documents.ts Outdated
Comment thread integrations/meilisearch/meilisearch/actions/update-documents.ts Outdated

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 7 files (changes from recent commits).

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread integrations/meilisearch/meilisearch/actions/search-documents.ts Outdated
@qdequele qdequele marked this pull request as ready for review July 8, 2026 17:31
qdequele added 18 commits July 9, 2026 15:00
- Restructure to canonical zero-yaml layout (meilisearch/actions/) so the
  CLI derives providerConfigKey 'meilisearch' instead of '.'
- Switch connection verification from GET /keys to GET /version (cheaper,
  narrower ACL requirement) and add an instanceUrl pattern rejecting
  trailing slashes and scheme-less values
- Enforce delete-documents ids/filter XOR and non-empty searchRules
  imperatively in exec (zod refinements are stripped from deployed schemas
  and never run at runtime)
- Fix searchRules grammar (allow null rules, reject booleans/arrays) and
  accept nested-array filter expressions across search/get/delete
- Default tenant tokens to a 1h TTL, document expiresAt precedence, and
  raise a descriptive error when the key uid cannot be resolved
- Add ids input to get-documents, nango devDependency, and simplify
  base64url to Buffer's native encoding; regenerate LLM doc indexes
- Make searchRule objects strict and re-validate searchRules inside exec:
  Meilisearch ignores unknown rule keys, so a typo'd key would silently
  broaden a signed tenant token's access
- Resolve the signing key uid by listing keys and matching locally instead
  of GET /keys/{key}, which put the raw key in the URL path where proxy
  and access logs record it unredacted
- Enforce non-empty document batches at runtime in add/update-documents
  (action input schemas are not validated at runtime)
Declared input schemas are not enforced by the platform at runtime, so a
missing or non-array documents field would throw a raw TypeError instead
of a clean ActionError. All actions now validate their declared schema
inside exec with nango.zodValidateInput; search/fetch keep forwarding the
raw body so extra Meilisearch params pass through.
…ough

search-documents and get-documents forward extra keys to Meilisearch, but
their plain z.object schemas published additionalProperties: false. Use
z.looseObject so the declared contract matches the passthrough behavior,
and forward the validated data instead of the raw input.
@qdequele qdequele force-pushed the feat/meilisearch-integration branch from 59b9d85 to 34e112e Compare July 9, 2026 13:03
@qdequele

Copy link
Copy Markdown
Author

Some context on why we built this, from the Meilisearch side 👋

I'm Quentin, co-founder/CEO of Meilisearch. Our customers constantly ask how to get data into their indexes from tools like Slack, Notion, Google Drive, Zendesk, HubSpot, Salesforce, Shopify, GitHub, or Gong. Nango's pre-built syncs already cover ~170 of these sources. This provider closes the loop: syncs pull the data out, and these actions push it into Meilisearch (including per-tenant search ACLs via the tenant-token action).

A few things we're planning around it:

  • Content: we'll publish a "Connect X to Meilisearch with Nango" guide series on our side, organized around our core use cases (enterprise search, knowledge search, commerce search, app search, agentic memory), starting with Slack, Zendesk, Shopify, HubSpot, and Gong. We'll produce and maintain all of that content.
  • Meilisearch Cloud: we're evaluating Nango as the main ingestion layer for Meilisearch Cloud, meaning the standard way our customers would connect and sync any source into their indexes.
  • Structure: happy to reshape this PR however you prefer. For example, we could move the action scripts to integration-templates and keep just the provider + docs here.

We'd love to make this a real partnership. If that's interesting, ping me here or at quentin@meilisearch.com and we'll set something up.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant