Relocate the ~6k-file docs tree from the repo root into plugins/document-navigator/docs/ so the plugin is self-contained and portable. docs/superpowers/ (specs and plans) stays at the repo root. Moved via cp+rm rather than git mv because directory rename() fails with EPERM on this WSL /mnt DrvFs mount; git rename-detection pairs the identical-content files at commit time. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@suaveplan/api-plugin-import - Tabular-data ingest plugin for @suaveplan/api. CSV / JSON / TSV-XLSX parsers, declarative transform pipeline (coerce + validate + computed), real-time progress tracker, async ImportStoreAdapter (in-memory + SurrealDB backends ship), canonical EventEmitter-based ImportService with owner-scoped jobs, 5 auth-gated OpenAPI Hono routes, RFC 7807 problem+json renderer, 9 IMPORT.* error codes, 6 OTel instruments. Server-tier.
Tabular-data ingest plugin for @suaveplan/api. Parses CSV / JSON /
TSV-XLSX payloads, applies declarative column mappings + per-field
validation + computed fields, persists owner-scoped import jobs through
a pluggable async store, emits real-time progress via an event bus, and
exposes five auth-gated OpenAPI routes with full Zod request/response
schemas. Ships nine IMPORT.* error codes (extending
SuaveplanError), four OpenTelemetry instruments (import.jobs_total,
import.rows_total, import.row_errors_total, import.duration_ms),
and a hand-rolled RFC 7807 problem+json renderer for the route layer.
Documentation tree
- error-codes — Declares the nine stable
IMPORT.*error codes used throughout@suaveplan/api-plugin-importand exports the `ImportE…- error-codes — Declares the nine stable
IMPORT.*error codes used throughout@suaveplan/api-plugin-importand exports the `ImportE…
- error-codes — Declares the nine stable
- otel — Builds the OpenTelemetry instrument bundle emitted by the canonical
ImportServiceso consumers can wire production ob…- instruments — Builds the OpenTelemetry instrument bundle emitted by the canonical
ImportServiceso consumers can wire production ob…
- instruments — Builds the OpenTelemetry instrument bundle emitted by the canonical
- csv — Provides the CSV-family parsers consumed by the canonical
ImportService.preview/startImportpipeline and by any c… - json — Parses JSON-array input documents into the same
Record<string, unknown>[]row shape produced by the CSV / XLSX parser… - xlsx — Provides a lightweight tab-separated-value parser exposed under the
xlsxformat so consumers can ingest spreadsheet-s… - plugin — Returns a typed
PluginDescriptor<ImportPluginConfig>wired onto the@suaveplan/api-pluginlifecycle. Valida…- plugin — Returns a typed
PluginDescriptor<ImportPluginConfig>wired onto the@suaveplan/api-pluginlifecycle. Valida…
- plugin — Returns a typed
- progress — Provides the
ImportProgressTrackerclass consumed by the canonicalImportService(and exported for direct use by CL…- tracker — Provides the
ImportProgressTrackerclass consumed by the canonicalImportService(and exported for direct use by CL…
- tracker — Provides the
- progress-sse — Exposes
GET /imports/:id/progressreturning a long-livedtext/event-streamso clients can subscribe to a job's real…- progress-sse — Exposes
GET /imports/:id/progressreturning a long-livedtext/event-streamso clients can subscribe to a job's real…
- progress-sse — Exposes
- build-routes — Constructs the
OpenAPIHonorouter mounted bycreateImportPluginat the configuredroutePrefix. Five routes are re… - problem-json — Bridges thrown errors from the route handlers into RFC 7807
application/problem+jsonresponses. Reads the HTTP status… - schemas — Carries the full public Zod surface used by the route handlers and any external client (CLI tool, integration test, bro…
- service — Implements the canonical
ImportServiceused bycreateImportPluginand exported for direct programmatic use. Owns th…- service — Implements the canonical
ImportServiceused bycreateImportPluginand exported for direct programmatic use. Owns th…
- service — Implements the canonical
- services — Augments the
ServiceRegistryinterface from@suaveplan/api-plugin/service-registrywith theimportServiceslot so…- registry-augmentation — Augments the
ServiceRegistryinterface from@suaveplan/api-plugin/service-registrywith theimportServiceslot so…
- registry-augmentation — Augments the
- store — Declares the async
ImportStoreAdapterinterface and ships theMemoryImportStoreimplementation used by the canonica…- surreal — Implements the canonical
ImportStoreAdapterinterface against a connectedSurrealAdapterfrom `@suaveplan/surrealdb…- surreal-import-store — Implements the canonical
ImportStoreAdapterinterface against a connectedSurrealAdapterfrom `@suaveplan/surrealdb…
- surreal-import-store — Implements the canonical
- memory — Declares the async
ImportStoreAdapterinterface and ships theMemoryImportStoreimplementation used by the canonica…
- surreal — Implements the canonical
- transform — Implements a three-stage row-transform pipeline that any consumer can drive without depending on the canonical `ImportS…
- pipeline — Implements a three-stage row-transform pipeline that any consumer can drive without depending on the canonical `ImportS…
- types — Defines the cross-module types and constants consumed by every other feature module in
@suaveplan/api-plugin-import.…- types — Defines the cross-module types and constants consumed by every other feature module in
@suaveplan/api-plugin-import.…
- types — Defines the cross-module types and constants consumed by every other feature module in
Install
bun add @suaveplan/api-plugin-import
Quick start
import { createImportPlugin } from "@suaveplan/api-plugin-import";
// Register with @suaveplan/api's plugin registry.
const importPlugin = createImportPlugin({ routePrefix: "/imports" });
// Or use the service directly:
import { ImportService } from "@suaveplan/api-plugin-import";
const service = new ImportService();
const progress = await service.startImport(
{
format: "csv",
data: "name\nAda\nBob",
mappings: [{ sourceColumn: "name", targetField: "displayName" }],
},
{ ownerId: "alice" }
);
console.log(progress.successCount); // 2
Modules
- error-codes —
IMPORT_CODES/ImportErrorregistry, 9 codes. - types — cross-module shared shapes.
- parsers/csv — CSV + streaming CSV parsers.
- parsers/json — JSON parser.
- parsers/xlsx — TSV-style XLSX parser.
- transform/pipeline — coerce / validate / computed-field pipeline.
- progress/tracker —
ImportProgressTracker. - store/memory —
ImportStoreAdapter+MemoryImportStore. - store/surreal/surreal-import-store
— durable
SurrealImportStore(SurrealDB-backed). Migration shipped atsurql/tables/import_job.surql. - service/service — canonical
ImportService. - routes/problem-json — RFC 7807 renderer.
- routes/build-routes — 5 auth-gated OpenAPI routes.
- otel/instruments — OTel bundle.
- schemas/options — plugin options schema.
- schemas/schemas — public request / response Zod surface.
- services/registry-augmentation
—
ServiceRegistry["importService"]slot. - plugin/plugin —
createImportPluginfactory.
Error codes
Every failure path raises an ImportError carrying one of nine
IMPORT.* codes — NOT_FOUND, FORBIDDEN, VALIDATION,
FILE_TOO_LARGE, UNSUPPORTED_FORMAT, PROCESSING_FAILED,
STORAGE_ERROR, TIMEOUT, INVALID_OPTIONS. Anti-enumeration:
foreign-owner lookups return NOT_FOUND, never FORBIDDEN.
SurrealDB store
SurrealImportStore is the durable alternative to MemoryImportStore,
implementing the same ImportStoreAdapter interface against a connected
@suaveplan/surrealdb SurrealAdapter. The matching schema migration
ships co-located at surql/tables/import_job.surql;
hosts apply it through @suaveplan/api-plugin-database's migration
runner or via adapter.query(readFileSync(...)). The store uses
positional $p0,$p1,… SurrealQL placeholders — the canonical pattern
used by every SurrealDB repository.
Observability
Six OpenTelemetry instruments are emitted on the production hot paths
— call getImportInstruments() to reuse the cached bundle, or
resetImportInstruments() in tests after installing a fresh
MeterProvider. Four cover the service (jobs_total, rows_total,
row_errors_total, duration_ms); two cover the store
(import.store.writes_total{outcome} and
import.store.reads_total{outcome} — emitted by SurrealImportStore
on every adapter call so host dashboards can split backend health from
upstream import success/failure).
License
MIT