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 requiressurql/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 implicitMap<string, ExportJob>surface so two backends can co-exist behind the same name. - ADDED:
MemoryExportJobStore—Map<string, ExportJob>wrapper implementingExportJobStore. Equivalent to the existing in-memory job store; keeps the in-memory path on the new typed contract. - ADDED:
SurrealExportStore— SurrealDB-backedExportJobStoreimplementation. CRUD over theexport_jobtable using positional$p0…$pNplaceholders (genesis canonical, matching@suaveplan/api-plugin-eventsrepositories). Wraps every failure withExportError(EXPORT_CODES.JOB_PERSISTENCE_FAILED). - ADDED:
EXPORT_CODES.JOB_PERSISTENCE_FAILED— surfaces SurrealDB driver / network / parse failures from theSurrealExportStore. Cause chain preserves the underlying error. - ADDED:
surql/tables/export_job.surqlmigration —DEFINE TABLE OVERWRITE export_job SCHEMAFULL+ every field onExportJobSchema+ indexes on(status),(format),(resource),(created_at). - ADDED:
ServiceRegistryslotexportJobStore: ExportJobStorevia module augmentation. Independent of the pre-existingexportJobs: Map<string, ExportJob>slot, which remains for back-compat — callers wire whichever they want. - MODIFIED:
Public surface and side-effect importsrequirement — the package barrel now also re-exportsExportJobStore,MemoryExportJobStore,SurrealExportStore, and theJOB_PERSISTENCE_FAILEDcode; 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.jobsfromMap<string, ExportJob>toExportJobStore. 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/downloadhandler — 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-exportreturns 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.