# @suaveplan/drive-uri - URI plugins (drive://, drive+mesh://, drive+template://) for @suaveplan/storage-uri's StorageUriResolver. Wraps a caller-supplied Drive instance in a StorageLike adapter so URI-addressed drive content resolves through the same dispatcher as storage adapters. URI plugins (`drive://`, `drive+mesh://`, `drive+template://`) for `@suaveplan/storage-uri`'s `StorageUriResolver`. Wraps a caller-supplied `Drive` instance in a `StorageLike` adapter so URI-addressed drive content resolves through the same dispatcher as `file://`, `https://`, `s3://`, and the other storage adapters — without re-implementing chunk decoding, peer discovery, or template validation. The drive itself remains the single source of truth for those concerns; `drive-uri` is a routing layer. ## Documentation tree - [adapter](./src/adapter/drive-storage-like.md) — Defines `DriveStorageLikeAdapter`, the internal shim that exposes a `Drive` instance as a `StorageLike` so it can be re… - [drive-storage-like](./src/adapter/drive-storage-like.md) — Defines `DriveStorageLikeAdapter`, the internal shim that exposes a `Drive` instance as a `StorageLike` so it can be re… - [conformance](./src/conformance/conformance.md) — Re-exports the canonical URI-plugin conformance harness from `@suaveplan/storage-uri` (`runUriPluginConformance`, `UriP… - [conformance](./src/conformance/conformance.md) — Re-exports the canonical URI-plugin conformance harness from `@suaveplan/storage-uri` (`runUriPluginConformance`, `UriP… - [error-codes](./src/error-codes/error-codes.md) — Declares the seven `DRIVE_URI.*` error codes raised by `@suaveplan/drive-uri` plugins and the `DriveUriError` discrimin… - [error-codes](./src/error-codes/error-codes.md) — Declares the seven `DRIVE_URI.*` error codes raised by `@suaveplan/drive-uri` plugins and the `DriveUriError` discrimin… - [otel](./src/otel/otel.md) — OpenTelemetry instrumentation surface for `@suaveplan/drive-uri`. Exposes a meter named `@suaveplan/drive-uri` carrying… - [otel](./src/otel/otel.md) — OpenTelemetry instrumentation surface for `@suaveplan/drive-uri`. Exposes a meter named `@suaveplan/drive-uri` carrying… - [drive](./src/plugins/drive/drive.md) — `driveUriPlugin(options)` is a factory returning a `UriPlugin` registered against the `drive://` scheme. It wraps a con… - [drive](./src/plugins/drive/drive.md) — `driveUriPlugin(options)` is a factory returning a `UriPlugin` registered against the `drive://` scheme. It wraps a con… - [drive.streams](./src/plugins/drive/drive.streams.md) — `InstrumentedDriveAdapter` is the OTel-instrumented `StorageLike` shared by all three URI plugins (`drive://`, `drive+m… - [drive-mesh](./src/plugins/drive-mesh/drive-mesh.md) — `driveMeshUriPlugin(options)` is a factory returning a `UriPlugin` registered against the `drive+mesh://` scheme. It pa… - [drive-mesh](./src/plugins/drive-mesh/drive-mesh.md) — `driveMeshUriPlugin(options)` is a factory returning a `UriPlugin` registered against the `drive+mesh://` scheme. It pa… - [drive-template](./src/plugins/drive-template/drive-template.md) — `driveTemplateUriPlugin(options)` is a factory returning a `UriPlugin` registered against the `drive+template://` schem… - [drive-template](./src/plugins/drive-template/drive-template.md) — `driveTemplateUriPlugin(options)` is a factory returning a `UriPlugin` registered against the `drive+template://` schem… ## Install ```bash bun add @suaveplan/drive-uri @suaveplan/storage-uri @suaveplan/drive ``` ## Quick start ```ts import { Drive } from "@suaveplan/drive"; import { createStorageUriResolver } from "@suaveplan/storage-uri"; import { driveMeshUriPlugin, driveTemplateUriPlugin, driveUriPlugin, } from "@suaveplan/drive-uri"; const localDrive = new Drive(localStorage); await localDrive.initialize(); const meshDrive = await buildMeshConfiguredDrive(); // your wiring const resolver = createStorageUriResolver([ driveUriPlugin({ drive: localDrive, driveId: "primary" }), driveMeshUriPlugin({ drive: meshDrive, defaultSwarmId: "swarmA" }), driveTemplateUriPlugin({ drive: meshDrive, templateProvider }), ]); // Three different schemes, one resolver, one dispatch flow. await resolver.read("drive://primary/folder/file.bin"); await resolver.open("drive+mesh://swarmA/raw/clip.mov"); await resolver.read("drive+template://templA/manifest/clip.jpg"); ``` The three plugins share zero state by default — but you can pass the same `Drive` to two factories so a hydration triggered by the template plugin populates the file-location index that the mesh plugin then uses to fetch chunks. That composition is the canonical pattern for "open a template, then stream its files". ## Composition with storage-uri plugins `drive-uri` plugins coexist with every other URI plugin. A single `StorageUriResolver` can carry a mix of schemes without any code-path divergence — each URI dispatches to the correct adapter based on its scheme prefix, and no plugin observes another plugin's state. ```ts const resolver = createStorageUriResolver([ fileUriPlugin({ rootDir: "/var/media" }), httpsUriPlugin(httpStorage), s3UriPlugin({ bucket: "uploads", region: "eu-west-1" }), driveUriPlugin({ drive: localDrive, driveId: "primary" }), driveMeshUriPlugin({ drive: meshDrive }), driveTemplateUriPlugin({ drive: meshDrive, templateProvider }), ]); const bytes = await resolver.read("drive://primary/folder/file.bin"); const headers = await resolver.read("https://cdn.example/img.png"); ``` ## Authoring a `TemplateProvider` ```ts import type { TemplateProvider } from "@suaveplan/drive-uri"; import type { DriveTemplate } from "@suaveplan/drive-template"; export const httpTemplateProvider: TemplateProvider = { async fetchTemplate(templateId: string, signal?: AbortSignal): Promise { const res = await fetch(`/api/templates/${templateId}`, { signal }); if (!res.ok) throw new Error(`HTTP ${res.status}`); return (await res.json()) as DriveTemplate; }, }; ``` The provider is invoked exactly once per `templateId` per plugin instance — the hydration cache short-circuits subsequent lookups. On a transient network failure, the cache entry is removed so a retry is possible. ## Errors Every drive-uri failure surfaces as `DriveUriError` with a `DRIVE_URI.*` code: | Code | Meaning | |---|---| | `DRIVE_URI.INVALID_URI` | URI is malformed or has an unexpected scheme | | `DRIVE_URI.DRIVE_ID_MISMATCH` | URI's driveId differs from plugin's configured driveId | | `DRIVE_URI.TEMPLATE_NOT_AVAILABLE` | `templateProvider.fetchTemplate` rejected | | `DRIVE_URI.TEMPLATE_INVALID` | `Drive.hydrateFrom` rejected (template validation failed) | | `DRIVE_URI.WRITE_UNSUPPORTED` | Initial release rejects every write | | `DRIVE_URI.CAPABILITY_MISSING` | Required option (drive, templateProvider) missing | | `DRIVE_URI.ABORTED` | `AbortSignal` was already aborted at call time | Wrapping rules are documented in the design doc — `templateProvider` rejection becomes `TEMPLATE_NOT_AVAILABLE`; `Drive.hydrateFrom` rejection (any `DTP_*` code) becomes `TEMPLATE_INVALID`. The original cause is preserved on `err.cause` so operators can drill down to the underlying drive failure. ## Observability The package emits to the `@suaveplan/drive-uri` meter and tracer: - `drive_uri.op_duration_ms{op, scheme, outcome}` — duration histogram - `drive_uri.reads_total{scheme, outcome}`, `drive_uri.writes_total{scheme, outcome}`, `drive_uri.deletes_total{scheme, outcome}` — counters - `drive_uri.errors_total{scheme, code}` — error attribution - `drive_uri.template_hydrations_total{outcome}` — increments exactly once per first-use template Span attributes: `drive.uri` (query-stripped), `drive.uri.scheme`, and one of `drive.uri.drive_id` / `drive.uri.swarm_id` / `drive.uri.template_id` depending on the scheme. ## Modules - [`src/error-codes/error-codes.md`](src/error-codes/error-codes.md) — `DRIVE_URI_CODES` + `DriveUriError` - [`src/adapter/drive-storage-like.md`](src/adapter/drive-storage-like.md) — `DriveStorageLikeAdapter` + `isDriveNotFound` - [`src/plugins/drive/drive.md`](src/plugins/drive/drive.md) — `driveUriPlugin` - [`src/plugins/drive/drive.streams.md`](src/plugins/drive/drive.streams.md) — `InstrumentedDriveAdapter` - [`src/plugins/drive-mesh/drive-mesh.md`](src/plugins/drive-mesh/drive-mesh.md) — `driveMeshUriPlugin` - [`src/plugins/drive-template/drive-template.md`](src/plugins/drive-template/drive-template.md) — `driveTemplateUriPlugin` - [`src/types/plugin-options.types.md`](src/types/plugin-options.types.md) — option-bag interfaces + `TemplateProvider` - [`src/otel/otel.md`](src/otel/otel.md) — OpenTelemetry surface - [`src/conformance/conformance.md`](src/conformance/conformance.md) — re-export of `runUriPluginConformance`