coffrify 0.9.0
coffrify: ^0.9.0 copied to clipboard
Official Dart SDK for Coffrify, encrypted file transfer infrastructure: transfers, webhooks, API keys, audit, vaults and 30+ resources. Pure Dart, no Flutter dependency.
Coffrify SDK for Dart and Flutter #
Official Dart/Flutter SDK for Coffrify — encrypted file transfer infrastructure.
- Pure-Dart core that runs on the server, in CLI tools, and in Flutter
- First-class Flutter widgets (
CoffrifyProvider,CoffrifyImage) - Standard Webhooks v1 verification + legacy
X-Coffrify-Signaturefallback - Retry policies, circuit breaker, rate limiter, idempotency stores, telemetry adapter
- 30+ typed resources covering transfers, webhooks, API keys, audit, analytics, branding, domains, folders, collections, members, GDPR, SCIM/SSO, billing, and more
Install #
dart pub add coffrify
# Or for Flutter projects:
flutter pub add coffrify
Quickstart — Dart #
import 'package:coffrify/coffrify.dart';
Future<void> main() async {
final coffrify = Coffrify(
const CoffrifyConfiguration(apiKey: 'cof_live_…'),
);
// List recent transfers (cursor-paginated stream).
await for (final t in coffrify.transfers.iterate(pageSize: 50)) {
print('${t.shortCode} → ${t.totalDownloads ?? 0} downloads');
}
// Create a transfer + PUT files to the presigned URLs.
final result = await coffrify.transfers.create(
const [
TransferFileInput(name: 'report.pdf', size: 1_234_567, mimeType: 'application/pdf'),
],
options: const CreateTransferOptions(
expiresInHours: 24,
maxDownloads: 5,
watermarkEnabled: true,
),
);
print('Share: https://coffrify.fr/t/${result.transfer.shortCode}');
coffrify.close();
}
Quickstart — Flutter #
import 'package:coffrify/coffrify.dart';
import 'package:coffrify/flutter.dart';
import 'package:flutter/material.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
final coffrify = await CoffrifyFlutter.initialize(
apiKey: 'cof_live_…',
persistSecurely: true,
);
runApp(
CoffrifyProvider(
coffrify: coffrify.instance,
child: const MyApp(),
),
);
}
class MyTransferTile extends StatelessWidget {
const MyTransferTile({super.key, required this.transferId});
final String transferId;
@override
Widget build(BuildContext context) {
final coffrify = CoffrifyProvider.of(context);
return FutureBuilder<CoffrifyTransfer>(
future: coffrify.transfers.get(transferId),
builder: (context, snap) {
if (!snap.hasData) return const CircularProgressIndicator();
return ListTile(
title: Text(snap.data!.transferTitle ?? snap.data!.shortCode),
subtitle: Text('${snap.data!.totalDownloads ?? 0} downloads'),
trailing: CoffrifyImage(transferId: transferId, width: 64, height: 64),
);
},
);
}
}
Verifying webhooks #
import 'dart:io';
import 'package:coffrify/coffrify.dart';
Future<void> handle(HttpRequest req) async {
final body = await req.cast<List<int>>().transform(const Utf8Decoder()).join();
final headers = <String, String>{
for (final name in req.headers.keys) name: req.headers.value(name) ?? '',
};
final result = await verifyWebhook(
secret: Platform.environment['COFFRIFY_WEBHOOK_SECRET']!,
body: body,
headers: headers,
);
if (!result.valid) {
req.response.statusCode = 400;
await req.response.close();
return;
}
switch (result.event!.typeEnum) {
case CoffrifyEventType.transferDownloaded:
// result.event!.data carries the typed payload — see eventCatalog.dart
break;
case CoffrifyEventType.ping:
break;
default:
break;
}
req.response.statusCode = 200;
await req.response.close();
}
Runtime extras #
final coffrify = Coffrify(CoffrifyConfiguration(
apiKey: env('COFFRIFY_API_KEY'),
retryPolicy: const DecorrelatedJitter(maxAttempts: 5),
circuitBreaker: CircuitBreaker(failureThreshold: 3, openFor: Duration(seconds: 60)),
rateLimiter: TokenBucket(capacity: 20, refillPerSecond: 5),
idempotencyStore: MemoryIdempotencyStore(),
telemetry: const NoopTelemetry(),
hooks: ClientHooks(
beforeRequest: (ctx) async => print('→ ${ctx.method} ${ctx.url}'),
afterResponse: (ctx) async => print('← ${ctx.status} in ${ctx.duration.inMilliseconds}ms'),
),
));
Testing #
import 'package:coffrify/coffrify.dart';
import 'package:coffrify/testing.dart';
import 'package:test/test.dart';
void main() {
test('signed webhook round-trips', () async {
const secret = 'whsec_0123456789abcdef';
final signed = signPayloadTest(
secret: secret,
body: {'id': 'evt_1', 'type': 'ping', 'created_at': '2026-05-26T00:00:00Z', 'workspace_id': 'ws_1', 'data': {}},
);
final result = await verifyWebhook(secret: secret, body: signed.body, headers: signed.headers);
expect(result.valid, isTrue);
expect(result.event!.typeEnum, CoffrifyEventType.ping);
});
test('transfers.create issues POST /v1/transfers', () async {
final mock = MockHttpClient()
..on('POST', '/v1/transfers', (req) => MockResponse(status: 201, body: {
'transfer': Fixtures.transfer().toJson(),
'upload_urls': [{'file_id': 'file_1', 'url': 'https://upload.test/x', 'headers': {}}],
}));
final coffrify = Coffrify(CoffrifyConfiguration(apiKey: 'cof_test_x', httpClient: mock));
final result = await coffrify.transfers.create(const [
TransferFileInput(name: 'a.bin', size: 1),
]);
expect(result.uploadUrls.first.fileId, 'file_1');
});
}
API surface #
| Resource | Description |
|---|---|
transfers |
Server-side transfers, cursor-paginated iterate(), qrcode, rescan, folder assignment |
webhooks |
CRUD, test deliveries, secret rotation with grace window, replay & retry, delivery audit |
apiKeys |
CRUD, rotation with grace window |
audit |
List, lazy iterate(), JSON/CSV export |
analytics, quotas, billing |
Usage analytics, plan consumption, Stripe portal + checkout |
branding, domains, notifications |
Branding payload, custom domains with CNAME verification, notification prefs |
folders, collections, coffres, rooms |
Workspace organisation surfaces |
members, recipients, apiTokens, templates, requests, magicLinks |
Member ops + address book + delegated tokens + drop-box inboxes |
mfa, sessions, sso, scim |
Auth + identity surfaces |
gdpr, gdprExtra, marketing, status, changelog |
Compliance, public surface, status page |
webhookExtras, workspaceExtras |
Deep webhook introspection + workspace-level extras (search, exports, health score) |
programmable |
Narrative API mirroring https://coffrify.com/programmable (maxViews, expiresIn: '12h', geo, watermark, …) |
Links #
License #
MIT