Files & renderer
Two features for file storage and notification HTML rendering.
files-provider-s3
Section titled “files-provider-s3”Status: ✅ Stable
What: S3-compatible file-storage backend. Targets AWS S3,
Cloudflare R2, MinIO, Backblaze B2, anything that speaks the S3 API.
Implements FileStorageProvider (write / writeStream / read /
readStream / getSignedUrl / delete).
How it works: createS3Provider({ region, bucket, accessKeyId, secretAccessKey, endpoint?, forcePathStyle? }) builds the provider.
forcePathStyle (or a custom endpoint) matters for MinIO + R2.
Wire it into the files / file-foundation stack as your storage provider.
Env helper: createS3ProviderFromEnv() reads the S3_ prefix by
default (S3_BUCKET, S3_REGION, S3_ACCESS_KEY, S3_SECRET_KEY,
optional S3_ENDPOINT, S3_FORCE_PATH_STYLE). Pass another prefix
(e.g. "MINIO_") when needed.
Example:
import { createS3Provider, createS3ProviderFromEnv,} from "@cosmicdrift/kumiko-bundled-features/files-provider-s3";
const fileProvider = createS3Provider({ region: "eu-central-1", bucket: "kumiko-app-files", accessKeyId: process.env["S3_ACCESS_KEY"]!, secretAccessKey: process.env["S3_SECRET_KEY"]!,});
// or: const fileProvider = createS3ProviderFromEnv(); // reads S3_* env
// Presigned GET URL (download). Upload path uses write/writeStream or the// files feature upload routes, there is no uploadUrl helper.const url = await fileProvider.getSignedUrl!( `tenant-${tenantId}/${filename}`, 600, { contentDisposition: `attachment; filename="${filename}"` },);renderer-simple
Section titled “renderer-simple”Status: ✅ Stable
What: Default notification HTML renderer for delivery. No React,
no SSR pipeline, structured notification templates
(header / sections / button / footer) → HTML.
How it works: Register createRendererSimpleFeature() next to
delivery. You do not declare templates with r.template, use
r.notification(...) (or ctx.notify) and put per-channel shapes in
templates.email / templates.inApp / templates.push. The simple
renderer turns the email template object into HTML.
When not: Marketing mails with complex layouts → produce HTML
elsewhere (MJML, etc.) and send via a custom channel/transport.
renderer-simple is for transactional notifications the app sends
itself.
Example:
import { createDeliveryFeature } from "@cosmicdrift/kumiko-bundled-features/delivery";import { createRendererSimpleFeature } from "@cosmicdrift/kumiko-bundled-features/renderer-simple";import { defineFeature } from "@cosmicdrift/kumiko-framework/engine";
features: [createRendererSimpleFeature(), createDeliveryFeature(), /* ... */];
defineFeature("incidents", (r) => { r.requires("delivery"); const created = r.writeHandler(/* ... */);
r.notification("incident-created", { trigger: { on: created }, recipient: (result) => result.data["assigneeId"] as string, data: (result) => ({ title: result.data["title"] as string, body: (result.data["body"] as string) ?? "", }), templates: { email: (data) => ({ subject: `Incident: ${data["title"]}`, header: String(data["title"]), sections: [{ text: String(data["body"]) }], }), inApp: (data) => ({ title: String(data["title"]), body: String(data["body"]), }), }, });});See also
Section titled “See also”- Bundled-features overview
- Notifications,
delivery+ channels - Recipe
delivery-notifications