mirror of
https://github.com/profullstack/logicsrc.git
synced 2026-10-02 20:57:03 +00:00
@logicsrc/plugin-agentmail provides read/search/compose/send/flag/delete over an injected MailTransport, gated to Founding Lifetime (paid) members. Returns plain JSON-serializable domain objects so the same API serves a human TUI, the CLI, MCP, and bots. - domain.ts: transport-agnostic types + pure helpers (parse/format address, normalizeDraft, isValidEmail, snippet) - ports.ts: MailTransport seam - service.ts: AgentMailService (inbox/list/read/search/send/reply/flag/delete) - access.ts: paid-member gate (assertPaid) + capability constants - transports/memory.ts: complete in-memory backend (tests/dev/reference) - transports/mailu.ts: self-hosted Mailu seam (mail.profullstack.com IMAP + smtp.profullstack.com submission) with injected IMAP/SMTP drivers - index.ts: PluginDefinition (manifest, routes, capabilities, tuiPanels) - registered in the root build; 20 vitest tests pass Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
40 lines
1.4 KiB
TypeScript
40 lines
1.4 KiB
TypeScript
// Access control for AgentMail. Mail is a Founding Lifetime Member (paid) perk,
|
|
// so every service call is gated on a paid identity. Capability constants keep
|
|
// route/manifest wiring and runtime checks in sync.
|
|
|
|
export const AGENTMAIL_CAPABILITIES = {
|
|
mailboxList: "mailbox.list",
|
|
messageList: "message.list",
|
|
messageRead: "message.read",
|
|
messageSearch: "message.search",
|
|
messageCompose: "message.compose",
|
|
messageSend: "message.send",
|
|
messageFlag: "message.flag",
|
|
messageDelete: "message.delete",
|
|
accessGate: "access.gate"
|
|
} as const;
|
|
|
|
export type AgentMailCapability = (typeof AGENTMAIL_CAPABILITIES)[keyof typeof AGENTMAIL_CAPABILITIES];
|
|
|
|
/** Who is acting: a BBS member name and whether they hold the paid membership. */
|
|
export interface MailIdentity {
|
|
/** The member's local-part / handle, e.g. "alice". */
|
|
name: string;
|
|
/** True for a Founding Lifetime Member; mail is gated on this. */
|
|
paid: boolean;
|
|
}
|
|
|
|
/** Raised when a non-paid (or missing) identity attempts a mail action. */
|
|
export class MailAccessError extends Error {
|
|
constructor(message = "AgentMail is a Founding Lifetime Member feature ($99 one-time) — upgrade: ssh join@bbs.profullstack.com") {
|
|
super(message);
|
|
this.name = "MailAccessError";
|
|
}
|
|
}
|
|
|
|
/** Throws MailAccessError unless the identity is a paid member. */
|
|
export function assertPaid(identity: MailIdentity): void {
|
|
if (!identity || !identity.name || !identity.paid) {
|
|
throw new MailAccessError();
|
|
}
|
|
}
|