import { packageStorage } from 'kody:runtime' import { parseJsonArraySafe } from './util.ts' export type SqlResult = { columns?: string[] rows?: Array> rowCount?: number } export type StashNote = { id: string rawText: string summary: string kind: string tags: string[] entities: string[] dueAt: string | null archivedAt: string | null createdAt: string updatedAt: string } function storageError(cause?: unknown): Error { const detail = cause instanceof Error ? ` (${cause.message})` : '' return new Error( `@kody/stash needs this package's own packageStorage()${detail}. Fork https://kody.codes/@kody/stash into your account so notes land in your bucket, or call packages.invoke({ kodyId: 'stash', exportName: 'recent' }) so the export runs in the package runtime. A static import of the live @kody/stash listing shares the platform package bucket, not yours.`, ) } function getStore() { let store: ReturnType try { store = packageStorage() } catch (error) { throw storageError(error) } if (!store || typeof store.sql !== 'function') { throw storageError() } return store } export async function sql( query: string, sqlParams: Array = [], ): Promise { return (await getStore().sql(query, sqlParams)) as SqlResult } export async function ensureSchema(): Promise { await sql( 'CREATE TABLE IF NOT EXISTS notes (id TEXT PRIMARY KEY, raw_text TEXT NOT NULL, summary TEXT NOT NULL, kind TEXT NOT NULL, tags_json TEXT NOT NULL, entities_json TEXT NOT NULL, due_at TEXT, archived_at TEXT, created_at TEXT NOT NULL, updated_at TEXT NOT NULL)', ) await sql('CREATE INDEX IF NOT EXISTS notes_created_at_idx ON notes(created_at)') await sql('CREATE INDEX IF NOT EXISTS notes_kind_idx ON notes(kind)') } export function toNote(row: Record): StashNote { return { id: String(row.id ?? ''), rawText: String(row.raw_text ?? ''), summary: String(row.summary ?? ''), kind: String(row.kind ?? 'note'), tags: parseJsonArraySafe(row.tags_json), entities: parseJsonArraySafe(row.entities_json), dueAt: typeof row.due_at === 'string' ? row.due_at : null, archivedAt: typeof row.archived_at === 'string' ? row.archived_at : null, createdAt: String(row.created_at ?? ''), updatedAt: String(row.updated_at ?? ''), } }