Annotation
This content is for the 0.6.3 version. Switch to the latest version for up-to-date documentation.
The Raindrop annotation interface provides structured metadata storage using Machine-Readable Name (MRN) objects for addressing. This system acts as a key-value store designed for application metadata with hierarchical organization and automatic versioning. You can use annotations as a breadcrumb system to leave small hints and context about implementation decisions, bug fixes, and other metadata. Future AI coding assistants examining the deployed application can discover and use these breadcrumbs to understand previous changes.
Annotations store arbitrary data up to 64MB per entry. They support multiple data types including strings, binary data, and structured objects. The MRN addressing system enables precise targeting of metadata to specific application components, modules, or individual items.
Creating
Annotations are automatically available in all Raindrop applications without additional configuration. Access through the env.annotation
interface:
export default { async fetch(request: Request, env: Env): Promise<Response> { // Annotation interface available on env.annotation const metadata = await env.annotation.get(mrn); return new Response('OK'); }};
Accessing
Use the annotation interface through environment bindings to store and retrieve metadata:
// Store debugging context for AI assistantconst debugMRN = { module: 'auth', item: 'login-handler', key: 'fix-context'};
await env.annotation.put(debugMRN, JSON.stringify({ issue: 'JWT token validation failing', solution: 'Updated key rotation logic', timestamp: new Date().toISOString()}));
// Retrieve context laterconst context = await env.annotation.get(debugMRN);if (context) { const data = JSON.parse(await context.text()); console.log(`Previous fix: ${data.solution}`);}
Core Concepts
Main Interfaces
get()
- Retrieve annotation data by MRNput()
- Store annotation with automatic revision managementlist()
- Query annotations with prefix filtering
MRN Object Structure
Machine-Readable Name objects provide hierarchical addressing for annotations:
// Complete MRN with all optional fieldsconst fullMRN: MRNObject = { type: 'annotation', // Resource type (annotation or label) applicationName: 'my-app', // Application identifier versionId: 'v1.0.0', // Version identifier module: 'user-service', // Optional module name item: 'auth-handler', // Optional item identifier key: 'config', // Optional key name revision: 'rev123' // Optional revision (read-only for get)};
Bucket Object Body
Response object for retrieved annotations with data access methods:
// Annotation data wrapper with multiple access patternsinterface BucketObjectBody { readonly key: string; // Storage key readonly version: string; // Object version readonly size: number; // Data size in bytes readonly etag: string; // Entity tag readonly uploaded: Date; // Upload timestamp get body(): ReadableStream; // Raw data stream text(): Promise<string>; // Text content json<T>(): Promise<T>; // JSON parsed content arrayBuffer(): Promise<ArrayBuffer>; // Binary content blob(): Promise<Blob>; // Blob representation}
System Limits
- Maximum annotation size: 64MB per entry
- Hierarchical addressing through MRN structure
- Automatic revision management prevents conflicts
get
get(mrn: MRNObject): Promise<BucketObjectBody | null>
// Returns annotation data or null if not found{ key: string; version: string; size: number; body: ReadableStream; text(): Promise<string>; json<T>(): Promise<T>; // ... other properties} | null
Example
Retrieve stored annotation metadata by MRN address:
const mrn = { module: 'payment', item: 'stripe-webhook', key: 'error-patterns'};
// Get annotation dataconst annotation = await env.annotation.get(mrn);if (annotation) { const errorData = await annotation.json(); console.log(`Found ${errorData.patterns.length} error patterns`);}
put
put( mrn: MRNObject, data: ReadableStream | ArrayBuffer | string | Blob | null, options?: BucketPutOptions): Promise<BucketObject>
// Returns stored object metadata{ key: string; version: string; size: number; etag: string; uploaded: Date; storageClass: string; // ... other properties}
Example
Store annotation data with automatic revision management:
const mrn = { module: 'api', item: 'rate-limiter', key: 'optimization-notes'};
// Store optimization contextconst metadata = { changes: 'Increased burst limit for premium users', performance: '50ms avg response improvement', date: new Date().toISOString()};
const result = await env.annotation.put(mrn, JSON.stringify(metadata));console.log(`Stored annotation: ${result.key} (${result.size} bytes)`);
list
list(options?: BucketListOptions): Promise<BucketObjects>
// Returns list of matching annotations{ objects: BucketObject[]; delimitedPrefixes: string[]; truncated: boolean; cursor?: string; // If truncated}
Example
Query annotations with prefix filtering for discovery:
// List all authentication-related annotationsconst authAnnotations = await env.annotation.list({ prefix: 'annotation:my-app:v1.0.0:auth', limit: 50});
// Process resultsfor (const obj of authAnnotations.objects) { console.log(`Found annotation: ${obj.key} (${obj.size} bytes)`);}
// Handle pagination if neededif (authAnnotations.truncated) { const nextPage = await env.annotation.list({ prefix: 'annotation:my-app:v1.0.0:auth', cursor: authAnnotations.cursor, limit: 50 });}