Files
2026-05-27 23:29:53 +01:00

4.6 KiB

Wire SurrealDB job-persistence store into @suaveplan/api-plugin-export

Package: @suaveplan/api-plugin-export Status: PROPOSED Type: follow-up (MODIFIED-Requirements) Spec delta: ./specs/api-plugin-export/spec.md

Why

@suaveplan/api-plugin-export shipped at 741e1b176 with the upstream §2 "Current-state assessment" surface only. The proposal (openspec/archive/2026-05-19-add-api-plugin-export/proposal.md) explicitly carved out §3 "Job persistence" via SurrealDB:

Upstream §2 ships the in-memory Map<string, ExportJob>. SurrealDB persistence is §3 work and requires surql/ migrations + integration tests against @suaveplan/api-plugin-database. Deferred.

The dependencies that were missing at ship time — @suaveplan/api-plugin-database, @suaveplan/surrealdb, @suaveplan/api-plugin-events (canonical positional-SurQL pattern) — have now landed on genesis. This change wires the previously-excluded SurrealDB job-persistence store in.

What changes

  • ADDED: ExportJobStore — formal async store contract (get, set, delete, list, has, clear) extracted from the implicit Map<string, ExportJob> surface so two backends can co-exist behind the same name.
  • ADDED: MemoryExportJobStore — Map<string, ExportJob> wrapper implementing ExportJobStore. Equivalent to the existing in-memory job store; keeps the in-memory path on the new typed contract.
  • ADDED: SurrealExportStore — SurrealDB-backed ExportJobStore implementation. CRUD over the export_job table using positional $p0…$pN placeholders (genesis canonical, matching @suaveplan/api-plugin-events repositories). Wraps every failure with ExportError(EXPORT_CODES.JOB_PERSISTENCE_FAILED).
  • ADDED: EXPORT_CODES.JOB_PERSISTENCE_FAILED — surfaces SurrealDB driver / network / parse failures from the SurrealExportStore. Cause chain preserves the underlying error.
  • ADDED: surql/tables/export_job.surql migration — DEFINE TABLE OVERWRITE export_job SCHEMAFULL + every field on ExportJobSchema + indexes on (status), (format), (resource), (created_at).
  • ADDED: ServiceRegistry slot exportJobStore: ExportJobStore via module augmentation. Independent of the pre-existing exportJobs: Map<string, ExportJob> slot, which remains for back-compat — callers wire whichever they want.
  • MODIFIED: Public surface and side-effect imports requirement — the package barrel now also re-exports ExportJobStore, MemoryExportJobStore, SurrealExportStore, and the JOB_PERSISTENCE_FAILED code; new subpath exports ./store/types, ./store/memory/memory-store, ./store/surreal/surreal-store.

Out of scope

Hard-bound to "wire SurrealDB persistence". Specifically excluded from this change (per the calling instructions):

  • Re-plumbing ExportRoutesDeps.jobs from Map<string, ExportJob> to ExportJobStore. The routes, the format writers (CSV / JSON / XLSX), and the streaming pipeline are untouched. Callers wire the new store directly until a future route-refactor change lands.
  • GET /:id/download handler — separate excluded item from the original migration; remains deferred.
  • Streaming exporters, S3 sink, OOXML extras, auth / rate-limit / idempotency / audit middleware composition, signed URLs, Parquet, scheduled exports — all unchanged from the original carve-out.

Source mapping

Requirement Source Notes
ExportJobStore async contract enterprise/api-plugin-export.md §3 + events.EventRepository shape Mirrors the IEventRepository async-CRUD convention.
SurrealExportStore positional SurQL packages/api/api-plugin-events/src/repositories/event-repository/event-repository.ts Genesis-canonical $p0/$p1 pattern.
export_job.surql migration Upstream ../suaveplan/packages/server/api-plugin-export/surql/ parity + ExportJobSchema shape All ExportJobSchema fields persisted.
JOB_PERSISTENCE_FAILED code Genesis-wide defineCodes registry + ExportError hierarchy New code; wired in SurrealExportStore only.

Impact

Affected dependents

@suaveplan/api-plugin-export ships at 0.1.0 with no genesis consumers yet:

  • bunx turbo ls --filter=...@suaveplan/api-plugin-export returns the package itself only — [x] no action needed (no downstream consumers on genesis at this date).

Migration note

No consumer-visible behavior change. The pre-existing Map-based job slot (exportJobs: Map<string, ExportJob>) is preserved unchanged. The new ExportJobStore interface and the two implementations (MemoryExportJobStore, SurrealExportStore) are additive surface; no existing call site is renamed, removed, or rerouted.