@joeybuilt/plexo-sdk 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/connect/index.d.ts +246 -0
- package/dist/connect/index.js +392 -0
- package/dist/connect/index.js.map +1 -0
- package/dist/index.d.ts +1925 -0
- package/dist/index.js +599 -0
- package/dist/index.js.map +1 -0
- package/package.json +39 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/types/channel.ts","../src/channel-client.ts","../src/types/events.ts","../src/validation/manifest.ts","../src/validation/signature.ts"],"sourcesContent":["// SPDX-License-Identifier: AGPL-3.0-only\n// Copyright (C) 2026 Joeybuilt LLC\n\n/**\n * PEX Channel Contract Types\n * Corresponds to §2.3 and §9.2 of the Plexo Extension Protocol (PEX) Specification v0.4.0\n */\n\nimport type { InboundMessage } from './messages.js'\n\nexport interface ChannelHealthResult {\n healthy: boolean\n latencyMs?: number\n error?: string\n}\n\nexport interface ChannelSendResult {\n ok: boolean\n messageId?: string\n error?: string\n}\n\nexport interface ChannelExtension {\n /**\n * Called on activate. Channel should start listening for inbound messages\n * and call sdk.channel.send() to route them into the host.\n */\n onActivate(): Promise<void>\n\n /**\n * Called when the host wants to send a message via this channel.\n * Requires channel:receive capability.\n */\n onMessage(message: InboundMessage): Promise<void>\n\n /**\n * Called periodically by the host Channel Router.\n * Return healthy: false to trigger failover.\n */\n healthCheck(): Promise<ChannelHealthResult>\n\n /**\n * Called on deactivate. Channel should stop listeners and clean up.\n */\n onDeactivate(): Promise<void>\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Phase 2 — Channel subscription contract (ADR-0002)\n//\n// The subscription contract lets sibling apps (Levio, future Fonto/Nexalog)\n// read/send/observe Channels owned by Plexo Core. Types live alongside the\n// `ChannelExtension` runtime contract because they share the same Pex layer.\n// Pex SPEC stays at 0.4.0 — this is host-side REST + SSE, not a protocol bump.\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport type PexVersion = '0.4.0'\n\nexport const PEX_VERSION: PexVersion = '0.4.0'\n\n/** Channel runtime types known to Plexo. Mirrors `channel_type` enum. */\nexport type ChannelType =\n | 'telegram'\n | 'slack'\n | 'discord'\n | 'whatsapp'\n | 'signal'\n | 'matrix'\n | 'irc'\n | 'webchat'\n | 'twilio'\n | 'gmail'\n | 'gmessages'\n\n/** Connection state machine surfaced to subscribers (ADR-0004 + ADR-0005). */\nexport type ConnectionState =\n | 'paired'\n | 'active'\n | 'refreshing'\n | 'expired'\n | 'revoked'\n | 'errored'\n\nexport interface ChannelAttachmentRef {\n /** Plexo-side attachment ID, resolvable via the attachment store. */\n id: string\n /** MIME type if known. */\n mimeType?: string\n /** Display filename. */\n filename?: string\n /** Size in bytes if known. */\n sizeBytes?: number\n /** Optional thumbnail attachment ID for image/video previews. */\n thumbnailId?: string\n}\n\n/** Canonical message envelope used by every Channel subscriber. */\nexport interface ChannelMessage {\n id: string\n channelId: string\n threadId: string\n direction: 'inbound' | 'outbound'\n /** Plain text body. Markdown is not parsed by Plexo's generic viewer. */\n text: string\n attachments?: ChannelAttachmentRef[]\n /** Sender identifier in the channel's native namespace (phone number, handle, etc.). */\n senderId: string\n /** Display name if the channel resolves one. */\n senderName?: string\n /** ISO-8601 timestamp when the message was authored upstream. */\n sentAt: string\n /** Channel-specific metadata — RCS feature flags, read receipts, etc. */\n metadata?: Record<string, unknown>\n pexVersion: PexVersion\n}\n\nexport interface ChannelThread {\n id: string\n channelId: string\n /** Display title. For 1:1 threads this is typically the contact name or phone. */\n title: string\n /** Most recent message preview (text-only, truncated). */\n lastMessagePreview?: string\n lastMessageAt?: string\n unreadCount?: number\n /** Channel-specific metadata (e.g., is_rcs flag for gmessages). */\n metadata?: Record<string, unknown>\n pexVersion: PexVersion\n}\n\nexport interface ChannelDescriptor {\n id: string\n workspaceId: string\n type: ChannelType\n name: string\n state: ConnectionState\n enabled: boolean\n lastMessageAt?: string\n pexVersion: PexVersion\n}\n\n/** Connection (credential) descriptor — paired-session metadata, no secrets. */\nexport interface PairedConnectionDescriptor {\n id: string\n workspaceId: string\n registryId: string\n state: ConnectionState\n pairedAt?: string\n lastInboundAt?: string\n decodeErrorCount?: number\n pexVersion: PexVersion\n}\n\nexport type ChannelEvent =\n | {\n type: 'message.received'\n channelId: string\n threadId: string\n message: ChannelMessage\n pexVersion: PexVersion\n }\n | {\n type: 'message.sent'\n channelId: string\n threadId: string\n message: ChannelMessage\n pexVersion: PexVersion\n }\n | {\n type: 'connection.state_changed'\n channelId: string\n state: ConnectionState\n pexVersion: PexVersion\n }\n\nexport interface ChannelSubscription {\n id: string\n appId: string\n channelId: string\n scopes: ChannelScope[]\n createdAt: string\n}\n\nexport type ChannelScope =\n | 'channels:list'\n | 'channels:subscribe'\n | 'channels:read'\n | 'channels:send'\n | 'channels:events'\n\nexport interface ChannelSendRequest {\n text: string\n attachments?: ChannelAttachmentRef[]\n /** Caller-supplied idempotency token; Plexo dedupes within a 24h window. */\n idempotencyKey: string\n}\n\nexport interface ChannelMessagePage {\n messages: ChannelMessage[]\n nextCursor?: string\n}\n\nexport interface ChannelThreadPage {\n threads: ChannelThread[]\n nextCursor?: string\n}\n","// SPDX-License-Identifier: AGPL-3.0-only\n// Copyright (C) 2026 Joeybuilt LLC\n\n/**\n * @plexo/sdk runtime channel client (ADR-0002).\n *\n * Sibling apps consume Plexo Channels — list/subscribe/read/send/events — via\n * this client. HMAC-authenticated, host-side REST + SSE. Pex SPEC stays at\n * 0.4.0; the subscription contract is host-side surface area only.\n *\n * Resolves the open question from Levio ADR-03 (\"plexo.channel.dispatch()\" —\n * unconfirmed there, confirmed and landed here).\n */\n\nimport { createHmac } from 'node:crypto'\nimport type {\n ChannelDescriptor,\n ChannelEvent,\n ChannelMessage,\n ChannelMessagePage,\n ChannelScope,\n ChannelSendRequest,\n ChannelSubscription,\n ChannelThreadPage,\n} from './types/channel.js'\n\nexport interface ChannelClientOptions {\n /** Plexo Core base URL (e.g. https://plexo.example.com). No trailing slash required. */\n baseUrl: string\n /** PLEXO_SERVICE_KEY shared secret used for HMAC body signatures. */\n serviceKey: string\n /** App identity, mirrored back to Plexo via X-App-Id for scope enforcement. */\n appId: string\n /** Optional fetch override (testing, custom retry). */\n fetchImpl?: typeof fetch\n}\n\nexport interface ChannelClient {\n list(opts?: { workspaceId?: string }): Promise<ChannelDescriptor[]>\n subscribe(channelId: string, scopes: ChannelScope[]): Promise<ChannelSubscription>\n unsubscribe(channelId: string, subscriptionId: string): Promise<void>\n threads(channelId: string, opts?: { cursor?: string; limit?: number }): Promise<ChannelThreadPage>\n messages(\n channelId: string,\n threadId: string,\n opts?: { cursor?: string; limit?: number },\n ): Promise<ChannelMessagePage>\n send(channelId: string, threadId: string, payload: ChannelSendRequest): Promise<ChannelMessage>\n /**\n * Async iterator over the SSE event stream. The generator reconnects with\n * `Last-Event-ID` on transient drops; callers may abort via the\n * `AbortSignal` parameter.\n */\n events(channelId: string, opts?: { signal?: AbortSignal; lastEventId?: string }): AsyncIterable<ChannelEvent>\n}\n\nfunction sign(secret: string, body: string): string {\n return 'sha256=' + createHmac('sha256', secret).update(body).digest('hex')\n}\n\nfunction defaultHeaders(opts: ChannelClientOptions, body: string): Record<string, string> {\n return {\n 'Content-Type': 'application/json',\n 'X-App-Id': opts.appId,\n 'X-Plexo-Timestamp': new Date().toISOString(),\n 'X-Plexo-Signature': sign(opts.serviceKey, body),\n }\n}\n\nasync function request<T>(\n opts: ChannelClientOptions,\n method: string,\n path: string,\n body?: unknown,\n): Promise<T> {\n const fetchImpl = opts.fetchImpl ?? fetch\n const serialized = body === undefined ? '' : JSON.stringify(body)\n const res = await fetchImpl(`${opts.baseUrl}${path}`, {\n method,\n headers: defaultHeaders(opts, serialized),\n body: body === undefined ? undefined : serialized,\n })\n if (!res.ok) {\n const detail = await res.text().catch(() => '')\n throw new Error(`channel-client: ${method} ${path} failed: ${res.status} ${detail}`)\n }\n if (res.status === 204) return undefined as T\n return (await res.json()) as T\n}\n\nexport function createChannelClient(opts: ChannelClientOptions): ChannelClient {\n return {\n list: (q) =>\n request<ChannelDescriptor[]>(\n opts,\n 'GET',\n `/api/plexo/channels${q?.workspaceId ? `?workspaceId=${encodeURIComponent(q.workspaceId)}` : ''}`,\n ),\n\n subscribe: (channelId, scopes) =>\n request<ChannelSubscription>(opts, 'POST', `/api/plexo/channels/${channelId}/subscribe`, { scopes }),\n\n unsubscribe: async (channelId, subscriptionId) => {\n await request<void>(\n opts,\n 'DELETE',\n `/api/plexo/channels/${channelId}/subscribe/${subscriptionId}`,\n )\n },\n\n threads: (channelId, q) => {\n const params = new URLSearchParams()\n if (q?.cursor) params.set('cursor', q.cursor)\n if (q?.limit) params.set('limit', String(q.limit))\n const qs = params.toString()\n return request<ChannelThreadPage>(\n opts,\n 'GET',\n `/api/plexo/channels/${channelId}/threads${qs ? `?${qs}` : ''}`,\n )\n },\n\n messages: (channelId, threadId, q) => {\n const params = new URLSearchParams()\n if (q?.cursor) params.set('cursor', q.cursor)\n if (q?.limit) params.set('limit', String(q.limit))\n const qs = params.toString()\n return request<ChannelMessagePage>(\n opts,\n 'GET',\n `/api/plexo/channels/${channelId}/threads/${threadId}/messages${qs ? `?${qs}` : ''}`,\n )\n },\n\n send: (channelId, threadId, payload) =>\n request<ChannelMessage>(\n opts,\n 'POST',\n `/api/plexo/channels/${channelId}/threads/${threadId}/messages`,\n payload,\n ),\n\n events: (channelId, q) => createEventStream(opts, channelId, q),\n }\n}\n\nasync function* createEventStream(\n opts: ChannelClientOptions,\n channelId: string,\n q?: { signal?: AbortSignal; lastEventId?: string },\n): AsyncGenerator<ChannelEvent, void, unknown> {\n const fetchImpl = opts.fetchImpl ?? fetch\n const url = `${opts.baseUrl}/api/plexo/channels/${channelId}/events`\n\n const headers: Record<string, string> = {\n Accept: 'text/event-stream',\n 'X-App-Id': opts.appId,\n 'X-Plexo-Timestamp': new Date().toISOString(),\n 'X-Plexo-Signature': sign(opts.serviceKey, ''),\n }\n if (q?.lastEventId) headers['Last-Event-ID'] = q.lastEventId\n\n const res = await fetchImpl(url, { method: 'GET', headers, signal: q?.signal })\n if (!res.ok || !res.body) {\n throw new Error(`channel-client: SSE ${url} failed: ${res.status}`)\n }\n\n const reader = res.body.getReader()\n const decoder = new TextDecoder()\n let buffer = ''\n\n while (true) {\n const { value, done } = await reader.read()\n if (done) break\n buffer += decoder.decode(value, { stream: true })\n\n // SSE framing: events delimited by blank lines.\n let idx\n while ((idx = buffer.indexOf('\\n\\n')) !== -1) {\n const raw = buffer.slice(0, idx)\n buffer = buffer.slice(idx + 2)\n const dataLine = raw.split('\\n').find((l) => l.startsWith('data:'))\n if (!dataLine) continue\n const json = dataLine.slice(5).trim()\n if (!json) continue\n try {\n yield JSON.parse(json) as ChannelEvent\n } catch {\n // ignore malformed frames; SSE keepalives may not be valid JSON\n }\n }\n }\n}\n","// SPDX-License-Identifier: AGPL-3.0-only\n// Copyright (C) 2026 Joeybuilt LLC\n\n/**\n * PEX Event Bus Types\n * Corresponds to §7.4 of the Plexo Extension Protocol (PEX) Specification v0.4.0\n *\n * Extensions may only publish to ext.<scope>.* namespace.\n * Standard topics are published by the host.\n *\n * v0.4.0 additions:\n * - prompt.* topics (§7.6)\n * - context.* topics (§7.7)\n *\n * v0.3.0 additions:\n * - entity.* topics (§16)\n * - escalation.* topics (§23)\n * - audit.* topics (§18)\n * - self.* topics (§20)\n * - agent.* topics (core architecture)\n * - a2a.* topics (§22)\n */\n\nimport type { EntityTypeName } from './manifest.js'\nimport type { EscalationTrigger, EscalationUserResponse } from './escalation.js'\nimport type { AuditAction, AuditOutcome } from './audit.js'\n\n/** Standard topics published by the host. Extensions subscribe but cannot publish these. */\nexport const TOPICS = {\n // Task lifecycle\n TASK_CREATED: 'task.created',\n TASK_COMPLETED: 'task.completed',\n TASK_FAILED: 'task.failed',\n TASK_BLOCKED: 'task.blocked',\n // Channel\n CHANNEL_MESSAGE_RECEIVED: 'channel.message.received',\n CHANNEL_HEALTH_CHANGED: 'channel.health.changed',\n // Extension lifecycle\n EXTENSION_ACTIVATED: 'extension.activated',\n EXTENSION_DEACTIVATED: 'extension.deactivated',\n EXTENSION_CRASHED: 'extension.crashed',\n // Connection lifecycle\n CONNECTION_ADDED: 'connection.added',\n CONNECTION_REMOVED: 'connection.removed',\n // Memory\n MEMORY_WRITTEN: 'memory.written',\n // §16 — Entity lifecycle\n ENTITY_CREATED: 'entity.created',\n ENTITY_MODIFIED: 'entity.modified',\n ENTITY_DELETED: 'entity.deleted',\n ENTITY_LINKED: 'entity.linked',\n // §23 — Escalation\n ESCALATION_TRIGGERED: 'escalation.triggered',\n ESCALATION_RESOLVED: 'escalation.resolved',\n ESCALATION_TIMED_OUT: 'escalation.timed_out',\n // §18 — Audit (host-internal, owner-tier subscribe only)\n AUDIT_ENTRY_CREATED: 'audit.entry.created',\n // §20 — UserSelf\n SELF_UPDATED: 'self.updated',\n SELF_PROPOSAL_RECEIVED: 'self.proposal.received',\n // Agent lifecycle (core architecture — Agent ≠ Extension)\n AGENT_ACTIVATED: 'agent.activated',\n AGENT_DEACTIVATED: 'agent.deactivated',\n AGENT_PLAN_CREATED: 'agent.plan.created',\n AGENT_STEP_COMPLETED: 'agent.step.completed',\n AGENT_STEP_FAILED: 'agent.step.failed',\n // §22 — A2A\n A2A_INBOUND_RECEIVED: 'a2a.inbound.received',\n A2A_DELEGATION_SENT: 'a2a.delegation.sent',\n A2A_DELEGATION_COMPLETED: 'a2a.delegation.completed',\n // §7.6 — Prompt Library\n PROMPT_REGISTERED: 'prompt.registered',\n PROMPT_ENABLED: 'prompt.enabled',\n // §7.7 — Context Layer\n CONTEXT_REGISTERED: 'context.registered',\n CONTEXT_UPDATED: 'context.updated',\n CONTEXT_EXPIRED: 'context.expired',\n} as const\n\nexport type StandardTopic = (typeof TOPICS)[keyof typeof TOPICS]\n\n/**\n * Build an extension-scoped topic name.\n * Extensions MUST use this for events they publish.\n * @example customTopic('acme', 'stripe-monitor', 'mrr.updated')\n * // => 'ext.acme.stripe-monitor.mrr.updated'\n */\nexport function customTopic(scope: string, name: string, event: string): string {\n return `ext.${scope}.${name}.${event}`\n}\n\n// ---------------------------------------------------------------------------\n// Standard topic payloads\n// ---------------------------------------------------------------------------\n\n// Task\nexport interface TaskCreatedPayload { taskId: string; title: string; type: string; workspaceId: string }\nexport interface TaskCompletedPayload {\n taskId: string\n durationMs: number\n workspaceId: string\n /** Domain mastery: inferred domain tag for this task. Null when domain mastery is off. */\n domainTag?: string | null\n /** Quality score from the quality judge (0-1). */\n qualityScore?: number | null\n /** Task type classification. */\n taskType?: string\n}\nexport interface TaskFailedPayload { taskId: string; error: string; workspaceId: string }\nexport interface TaskBlockedPayload { taskId: string; reason: string; workspaceId: string }\n\n// Channel\nexport interface ChannelMessageReceivedPayload { channelId: string; messageId: string; senderId: string }\nexport interface ChannelHealthChangedPayload { channelId: string; healthy: boolean; latencyMs?: number }\n\n// Extension\nexport interface ExtensionActivatedPayload { name: string; version: string; type: string; workspaceId: string }\nexport interface ExtensionDeactivatedPayload { name: string; workspaceId: string }\nexport interface ExtensionCrashedPayload { name: string; error: string; workspaceId: string }\n\n// Connection\nexport interface ConnectionAddedPayload { service: string; workspaceId: string }\nexport interface ConnectionRemovedPayload { service: string; workspaceId: string }\n\n// Memory\nexport interface MemoryWrittenPayload { id: string; tags?: string[]; authorExtension: string; workspaceId: string }\n\n// §16 — Entity\nexport interface EntityCreatedPayload { entityType: EntityTypeName; entityId: string; createdBy: string; workspaceId: string }\nexport interface EntityModifiedPayload { entityType: EntityTypeName; entityId: string; modifiedBy: string; workspaceId: string }\nexport interface EntityDeletedPayload { entityType: EntityTypeName; entityId: string; deletedBy: string; workspaceId: string }\nexport interface EntityLinkedPayload { sourceType: EntityTypeName; sourceId: string; targetType: EntityTypeName; targetId: string; workspaceId: string }\n\n// §23 — Escalation\nexport interface EscalationTriggeredPayload { extensionId: string; agentId?: string; trigger: EscalationTrigger; action: string; workspaceId: string }\nexport interface EscalationResolvedPayload { extensionId: string; agentId?: string; trigger: EscalationTrigger; response: EscalationUserResponse; workspaceId: string }\nexport interface EscalationTimedOutPayload { extensionId: string; agentId?: string; trigger: EscalationTrigger; workspaceId: string }\n\n// §18 — Audit\nexport interface AuditEntryCreatedPayload { extensionId: string; action: AuditAction; outcome: AuditOutcome; target: string }\n\n// §20 — UserSelf\nexport interface SelfUpdatedPayload { field: string; updatedBy: string }\nexport interface SelfProposalReceivedPayload { field: string; source: string; confidence: number }\n\n// Agent lifecycle\nexport interface AgentActivatedPayload { name: string; version: string; workspaceId: string }\nexport interface AgentDeactivatedPayload { name: string; workspaceId: string }\nexport interface AgentPlanCreatedPayload { agentName: string; taskId: string; stepCount: number; workspaceId: string }\nexport interface AgentStepCompletedPayload { agentName: string; taskId: string; stepId: string; durationMs: number; workspaceId: string }\nexport interface AgentStepFailedPayload { agentName: string; taskId: string; stepId: string; error: string; workspaceId: string }\n\n// §22 — A2A\nexport interface A2AInboundReceivedPayload { sourceEndpoint: string; taskId: string; workspaceId: string }\nexport interface A2ADelegationSentPayload { targetEndpoint: string; taskId: string; agentName: string; workspaceId: string }\nexport interface A2ADelegationCompletedPayload { targetEndpoint: string; taskId: string; status: string; workspaceId: string }\n\n// §7.6 — Prompt Library\nexport interface PromptRegisteredPayload { extensionName: string; promptId: string; workspaceId: string }\nexport interface PromptEnabledPayload { promptId: string; workspaceId: string }\n\n// §7.7 — Context Layer\nexport interface ContextRegisteredPayload { extensionName: string; contextId: string; workspaceId: string }\nexport interface ContextUpdatedPayload { extensionName: string; contextId: string; workspaceId: string }\nexport interface ContextExpiredPayload { extensionName: string; contextId: string; workspaceId: string }\n","// SPDX-License-Identifier: AGPL-3.0-only\n// Copyright (C) 2026 Joeybuilt LLC\n\n/**\n * PEX manifest validation\n * Corresponds to §3.3 of the Plexo Extension Protocol (PEX) Specification v0.4.0\n *\n * Used by:\n * - POST /api/plugins (host install validation)\n * - @plexo/cli (publish validation)\n */\n\nimport type { ExtensionManifest, ManifestType, CapabilityToken, HostComplianceLevel, EntityTypeName } from '../types/manifest.js'\nimport type { TrustTier } from '../types/trust.js'\n\n// ---------------------------------------------------------------------------\n// Valid values\n// ---------------------------------------------------------------------------\n\nconst VALID_TYPES: ManifestType[] = ['agent', 'skill', 'channel', 'tool', 'connector']\nconst LEGACY_TYPES = new Set(['function', 'mcp-server'])\n\nconst VALID_ENTITY_TYPES: EntityTypeName[] = [\n 'person', 'task', 'thread', 'note', 'transaction', 'calendar_event', 'file',\n]\n\nconst VALID_TRUST_TIERS: TrustTier[] = ['owner', 'verified', 'community']\n\nconst DISPLAY_NAME_MAX = 50\n\n/**\n * Standard capability tokens (non-parameterized).\n * Entity-scoped memory tokens are validated dynamically.\n */\nconst STANDARD_CAPABILITIES = new Set<string>([\n // Legacy (deprecated at Standard + Full)\n 'memory:read',\n 'memory:write',\n 'memory:delete',\n // Entity-scoped memory wildcards (owner tier only)\n 'memory:read:*',\n 'memory:write:*',\n // Channel\n 'channel:send',\n 'channel:send-direct',\n 'channel:receive',\n // Scheduling\n 'schedule:register',\n 'schedule:manage',\n // UI\n 'ui:register-widget',\n 'ui:notify',\n // Tasks\n 'tasks:create',\n 'tasks:read',\n 'tasks:read-all',\n // Events\n 'events:subscribe',\n 'events:publish',\n // Storage\n 'storage:read',\n 'storage:write',\n // §20 — UserSelf\n 'self:read',\n 'self:write',\n // §18 — Audit\n 'audit:read',\n // §21 — Identity\n 'identity:present',\n // §22 — A2A\n 'a2a:delegate',\n // §24 — Model\n 'model:override',\n // Prompts\n 'prompts:register',\n 'prompts:read',\n // Context\n 'context:register',\n 'context:write',\n 'context:read',\n])\n\n// ---------------------------------------------------------------------------\n// Validation types\n// ---------------------------------------------------------------------------\n\nexport interface ValidationError {\n field: string\n message: string\n severity?: 'error' | 'warning'\n}\n\nexport interface ValidationResult {\n valid: boolean\n errors: ValidationError[]\n}\n\nexport interface ValidationOptions {\n /** Host compliance level — affects which capabilities are valid */\n hostComplianceLevel?: HostComplianceLevel\n /**\n * Install source context. When set to `'sideload'` the validator applies\n * the sideload capability ceiling (rejects owner-only tokens regardless of\n * the declared `trust` value). Default: `'registry'`.\n */\n source?: 'registry' | 'sideload'\n}\n\n/**\n * Capability tokens that require `trust: 'owner'` and can never be granted to a\n * sideloaded extension. Kept in sync with `TrustTierCeilings` in `types/trust.ts`.\n */\nconst OWNER_ONLY_CAPABILITIES = new Set<string>([\n 'memory:read:*',\n 'memory:write:*',\n 'audit:read',\n 'model:override',\n])\n\n/**\n * Capabilities considered \"universally safe\" — rationale is always optional\n * for these, even at verified/owner tier. Everything else that verified/owner\n * extensions request must have a rationale.\n */\nconst RATIONALE_OPTIONAL_CAPABILITIES = new Set<string>([\n 'storage:read',\n 'storage:write',\n 'events:subscribe',\n 'events:publish',\n 'ui:register-widget',\n 'ui:notify',\n 'identity:present',\n 'prompts:register',\n 'prompts:read',\n 'context:register',\n 'context:read',\n 'schedule:register',\n])\n\n// ---------------------------------------------------------------------------\n// Validator\n// ---------------------------------------------------------------------------\n\nexport function validateManifest(raw: unknown, options?: ValidationOptions): ValidationResult {\n const errors: ValidationError[] = []\n const complianceLevel = options?.hostComplianceLevel ?? 'core'\n const installSource = options?.source ?? 'registry'\n\n if (typeof raw !== 'object' || raw === null) {\n return { valid: false, errors: [{ field: 'root', message: 'Manifest must be a JSON object' }] }\n }\n\n const m = raw as Record<string, unknown>\n\n // plexo version\n if (typeof m['plexo'] !== 'string' || !isSemver(m['plexo'])) {\n errors.push({ field: 'plexo', message: 'Must be a valid semver string (e.g. \"0.4.0\")' })\n }\n\n // name — @scope/name format\n if (typeof m['name'] !== 'string' || !isValidPackageName(m['name'])) {\n errors.push({ field: 'name', message: 'Must match @scope/name format (lowercase alphanumeric, hyphens, dots allowed)' })\n }\n\n // version\n if (typeof m['version'] !== 'string' || !isSemver(m['version'])) {\n errors.push({ field: 'version', message: 'Must be a valid semver string' })\n }\n\n // type\n const rawType = m['type'] as string\n if (LEGACY_TYPES.has(rawType)) {\n const replacement = rawType === 'function' ? 'tool (or skill)' : 'connector'\n errors.push({\n field: 'type',\n message: `Type \"${rawType}\" is deprecated in v0.4.0. Use \"${replacement}\" instead.`,\n severity: 'warning',\n })\n } else if (!VALID_TYPES.includes(rawType as ManifestType)) {\n errors.push({ field: 'type', message: `Must be one of: ${VALID_TYPES.join(', ')}` })\n }\n\n // entry\n if (typeof m['entry'] !== 'string' || m['entry'].length === 0) {\n errors.push({ field: 'entry', message: 'Must be a non-empty string path to the entry point' })\n }\n\n // capabilities\n if (!Array.isArray(m['capabilities'])) {\n errors.push({ field: 'capabilities', message: 'Must be an array of capability token strings' })\n } else {\n ; (m['capabilities'] as unknown[]).forEach((cap, i) => {\n if (typeof cap !== 'string') {\n errors.push({ field: `capabilities[${i}]`, message: 'Each capability must be a string' })\n return\n }\n\n if (!isValidCapability(cap)) {\n errors.push({\n field: `capabilities[${i}]`,\n message: `Unknown capability token \"${cap}\". Must be a standard token, entity-scoped memory, connections:<service>, or host:<hostname>:<capability>`,\n })\n return\n }\n\n if (isHostScopedCapability(cap)) {\n errors.push({\n field: `capabilities[${i}]`,\n message: `Host-scoped capability \"${cap}\" is not validated by this tool. The target host must confirm this token is supported.`,\n severity: 'warning',\n })\n }\n\n // §4 — Reject unscoped memory at Standard + Full compliance\n if (isUnscopedMemoryCapability(cap) && (complianceLevel === 'standard' || complianceLevel === 'full')) {\n errors.push({\n field: `capabilities[${i}]`,\n message: `Unscoped memory capability \"${cap}\" is invalid at ${complianceLevel} compliance. Use entity-scoped tokens (e.g. memory:read:person, memory:write:task).`,\n })\n }\n\n // §17 — Wildcard memory only for owner tier\n if (isWildcardMemoryCapability(cap)) {\n const trust = m['trust'] as string | undefined\n if (trust !== 'owner') {\n errors.push({\n field: `capabilities[${i}]`,\n message: `Wildcard memory capability \"${cap}\" is only allowed at trust tier: owner. Declared trust: ${trust ?? 'none'}`,\n })\n }\n }\n\n // §17 — audit:read only for owner tier\n if (cap === 'audit:read') {\n const trust = m['trust'] as string | undefined\n if (trust !== 'owner') {\n errors.push({\n field: `capabilities[${i}]`,\n message: `audit:read capability is only allowed at trust tier: owner. Declared trust: ${trust ?? 'none'}`,\n })\n }\n }\n\n // §8 / sideload ceiling — owner-only tokens can never appear on a\n // sideloaded manifest. The host also downgrades `trust` to `local`\n // before install, so these capabilities would otherwise slip past\n // the per-tier checks above.\n if (installSource === 'sideload' && OWNER_ONLY_CAPABILITIES.has(cap)) {\n errors.push({\n field: `capabilities[${i}]`,\n message: `Capability \"${cap}\" is restricted to owner-tier extensions and cannot be used in a sideloaded install.`,\n })\n }\n })\n }\n\n // §3.3 — capabilitiesRationale enforcement\n const trustValue = m['trust'] as TrustTier | undefined\n const capabilitiesList = Array.isArray(m['capabilities'])\n ? (m['capabilities'] as unknown[]).filter((c): c is string => typeof c === 'string')\n : []\n const rationale = m['capabilitiesRationale']\n if (rationale !== undefined) {\n if (typeof rationale !== 'object' || rationale === null || Array.isArray(rationale)) {\n errors.push({\n field: 'capabilitiesRationale',\n message: 'Must be an object mapping capability tokens to explanation strings',\n })\n } else {\n const r = rationale as Record<string, unknown>\n for (const [token, explanation] of Object.entries(r)) {\n if (!capabilitiesList.includes(token)) {\n errors.push({\n field: `capabilitiesRationale.${token}`,\n message: `Rationale declared for \"${token}\" but the capability is not in capabilities[]`,\n })\n continue\n }\n if (typeof explanation !== 'string') {\n errors.push({\n field: `capabilitiesRationale.${token}`,\n message: 'Rationale value must be a string',\n })\n continue\n }\n if (explanation.length === 0) {\n errors.push({\n field: `capabilitiesRationale.${token}`,\n message: 'Rationale value must be non-empty',\n })\n } else if (explanation.length > 200) {\n errors.push({\n field: `capabilitiesRationale.${token}`,\n message: 'Rationale must be 200 characters or fewer',\n })\n }\n }\n }\n }\n\n // Verified + owner tier extensions MUST explain each non-trivial capability.\n // Sideload (`local`) and community extensions get a warning only.\n if (trustValue === 'owner' || trustValue === 'verified') {\n const r = (rationale && typeof rationale === 'object' && !Array.isArray(rationale))\n ? (rationale as Record<string, unknown>)\n : {}\n for (const token of capabilitiesList) {\n if (RATIONALE_OPTIONAL_CAPABILITIES.has(token)) continue\n if (typeof r[token] !== 'string' || (r[token] as string).length === 0) {\n errors.push({\n field: 'capabilitiesRationale',\n message: `Capability \"${token}\" requires a rationale entry for trust tier \"${trustValue}\". Add capabilitiesRationale[\"${token}\"].`,\n })\n }\n }\n } else if (trustValue === 'community' && capabilitiesList.length > 0) {\n const r = (rationale && typeof rationale === 'object' && !Array.isArray(rationale))\n ? (rationale as Record<string, unknown>)\n : {}\n for (const token of capabilitiesList) {\n if (RATIONALE_OPTIONAL_CAPABILITIES.has(token)) continue\n if (typeof r[token] !== 'string' || (r[token] as string).length === 0) {\n errors.push({\n field: 'capabilitiesRationale',\n message: `Capability \"${token}\" has no rationale — community extensions are strongly encouraged to explain each capability.`,\n severity: 'warning',\n })\n }\n }\n }\n\n // displayName\n if (typeof m['displayName'] !== 'string' || m['displayName'].length === 0) {\n errors.push({ field: 'displayName', message: 'Must be a non-empty string' })\n } else if (m['displayName'].length > DISPLAY_NAME_MAX) {\n errors.push({ field: 'displayName', message: `Must be ${DISPLAY_NAME_MAX} characters or fewer` })\n }\n\n // description\n if (typeof m['description'] !== 'string') {\n errors.push({ field: 'description', message: 'Must be a string' })\n } else if (m['description'].length > 280) {\n errors.push({ field: 'description', message: 'Must be 280 characters or fewer' })\n }\n\n // author\n if (typeof m['author'] !== 'string' || m['author'].length === 0) {\n errors.push({ field: 'author', message: 'Must be a non-empty string' })\n }\n\n // license\n if (typeof m['license'] !== 'string' || m['license'].length === 0) {\n errors.push({ field: 'license', message: 'Must be a valid SPDX license identifier' })\n }\n\n // Optional: keywords limit\n if (m['keywords'] !== undefined) {\n if (!Array.isArray(m['keywords'])) {\n errors.push({ field: 'keywords', message: 'Must be an array of strings' })\n } else if ((m['keywords'] as unknown[]).length > 10) {\n errors.push({ field: 'keywords', message: 'Max 10 keywords allowed' })\n }\n }\n\n // Optional: screenshots limit\n if (m['screenshots'] !== undefined) {\n if (!Array.isArray(m['screenshots'])) {\n errors.push({ field: 'screenshots', message: 'Must be an array of HTTPS URLs' })\n } else if ((m['screenshots'] as unknown[]).length > 5) {\n errors.push({ field: 'screenshots', message: 'Max 5 screenshots allowed' })\n }\n }\n\n // connector requires mcpServer config\n if (m['type'] === 'connector' && m['mcpServer'] === undefined) {\n errors.push({ field: 'mcpServer', message: 'Required for connector type extensions' })\n }\n\n // channelTransport validation — only valid for channel type\n if (m['channelTransport'] !== undefined) {\n if (m['type'] !== 'channel') {\n errors.push({ field: 'channelTransport', message: 'channelTransport is only valid for channel type extensions' })\n } else if (m['channelTransport'] !== 'worker' && m['channelTransport'] !== 'api') {\n errors.push({ field: 'channelTransport', message: 'Must be \"worker\" or \"api\"' })\n }\n }\n\n // §17 — trust tier validation\n if (m['trust'] !== undefined) {\n if (!VALID_TRUST_TIERS.includes(m['trust'] as TrustTier)) {\n errors.push({ field: 'trust', message: `Must be one of: ${VALID_TRUST_TIERS.join(', ')}` })\n }\n }\n\n // §19 — Data residency validation\n if (m['dataResidency'] !== undefined) {\n validateDataResidency(m['dataResidency'], errors)\n } else if (complianceLevel === 'full') {\n errors.push({\n field: 'dataResidency',\n message: 'dataResidency is required at Full compliance. Omission treated as sendsDataExternally: true with unknown destinations.',\n severity: 'warning',\n })\n }\n\n // §23 — Escalation declaration for agents\n if (m['type'] === 'agent' && m['escalation'] !== undefined) {\n validateEscalation(m['escalation'], errors)\n }\n\n // §24 — Model requirements validation\n if (m['modelRequirements'] !== undefined) {\n validateModelRequirements(m['modelRequirements'], errors)\n }\n\n // Only hard errors count for validity\n const hardErrors = errors.filter((e) => e.severity !== 'warning')\n return { valid: hardErrors.length === 0, errors }\n}\n\n// ---------------------------------------------------------------------------\n// Sub-validators\n// ---------------------------------------------------------------------------\n\nfunction validateDataResidency(dr: unknown, errors: ValidationError[]) {\n if (typeof dr !== 'object' || dr === null) {\n errors.push({ field: 'dataResidency', message: 'Must be an object' })\n return\n }\n const obj = dr as Record<string, unknown>\n if (typeof obj['sendsDataExternally'] !== 'boolean') {\n errors.push({ field: 'dataResidency.sendsDataExternally', message: 'Must be a boolean' })\n }\n if (obj['sendsDataExternally'] === true && !Array.isArray(obj['externalDestinations'])) {\n errors.push({\n field: 'dataResidency.externalDestinations',\n message: 'Must be provided when sendsDataExternally is true',\n })\n }\n}\n\nfunction validateEscalation(esc: unknown, errors: ValidationError[]) {\n if (typeof esc !== 'object' || esc === null) {\n errors.push({ field: 'escalation', message: 'Must be an object' })\n return\n }\n const obj = esc as Record<string, unknown>\n if (obj['irreversibleActions'] !== undefined && !Array.isArray(obj['irreversibleActions'])) {\n errors.push({ field: 'escalation.irreversibleActions', message: 'Must be an array of strings' })\n }\n}\n\nfunction validateModelRequirements(mr: unknown, errors: ValidationError[]) {\n if (typeof mr !== 'object' || mr === null) {\n errors.push({ field: 'modelRequirements', message: 'Must be an object' })\n return\n }\n const obj = mr as Record<string, unknown>\n if (obj['minimumContextWindow'] !== undefined && typeof obj['minimumContextWindow'] !== 'number') {\n errors.push({ field: 'modelRequirements.minimumContextWindow', message: 'Must be a number' })\n }\n if (obj['localModelAcceptable'] !== undefined && typeof obj['localModelAcceptable'] !== 'boolean') {\n errors.push({ field: 'modelRequirements.localModelAcceptable', message: 'Must be a boolean' })\n }\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction isSemver(s: string): boolean {\n return /^\\d+\\.\\d+\\.\\d+(-[a-zA-Z0-9.]+)?(\\+[a-zA-Z0-9.]+)?$/.test(s)\n}\n\nfunction isValidPackageName(s: string): boolean {\n return /^@[a-z0-9][a-z0-9._-]*\\/[a-z0-9][a-z0-9._-]*$/.test(s)\n}\n\nfunction isValidCapability(token: string): boolean {\n if (STANDARD_CAPABILITIES.has(token)) return true\n // Entity-scoped memory: memory:read:<type> or memory:write:<type>\n if (/^memory:(read|write):([a-z_]+)$/.test(token)) {\n const entityType = token.split(':')[2]\n if (VALID_ENTITY_TYPES.includes(entityType as EntityTypeName)) return true\n }\n // Entity operations: entity:create:<type>, entity:modify:<type>, entity:delete:<type>\n if (/^entity:(create|modify|delete):([a-z_]+)$/.test(token)) {\n const entityType = token.split(':')[2]\n if (VALID_ENTITY_TYPES.includes(entityType as EntityTypeName)) return true\n }\n // Connections\n if (/^connections:[a-z0-9-]+$/.test(token)) return true\n // Host-scoped\n if (/^host:[a-z0-9-]+:[a-z0-9-:]+$/.test(token)) return true\n return false\n}\n\nfunction isHostScopedCapability(token: string): boolean {\n return /^host:[a-z0-9-]+:[a-z0-9-:]+$/.test(token)\n}\n\nfunction isUnscopedMemoryCapability(token: string): boolean {\n return token === 'memory:read' || token === 'memory:write'\n}\n\nfunction isWildcardMemoryCapability(token: string): boolean {\n return token === 'memory:read:*' || token === 'memory:write:*'\n}\n","// SPDX-License-Identifier: AGPL-3.0-only\n// Copyright (C) 2026 Joeybuilt LLC\n\n/**\n * Extension package signature verification.\n *\n * v1 strategy (documented in `docs/security/extension-security-model.md` §Q1):\n *\n * Sigstore / cosign with GitHub OIDC — keyless signing tied to the GitHub\n * Actions workflow that publishes to the registry. No long-lived keys to\n * lose. The host verifies that the signature's signer identity resolves to\n * `*@joeybuilt-official` (the owner) or to a key on the verified-publisher\n * key set.\n *\n * This module ships a **stub** verifier for v1. The intent is:\n *\n * - The registry stores signature metadata alongside every manifest row\n * (`signature`, `signature_type`, `signer_identity`, `signed_at`) — see\n * migration 0068.\n * - Install-time, the host calls `verifySignature(manifest, meta)` and, on\n * success, trusts the manifest's declared `trust` value.\n * - On failure (or `null` meta), the host downgrades `trust` to `community`\n * (for registry installs) or `local` (for sideloads), exactly as §8.4 of\n * the security spec requires.\n *\n * The real verifier will call `cosign verify` against the Rekor log, or fall\n * back to a local ECDSA P-256 public key check. For v1 we accept any Sigstore\n * metadata whose `signer_identity` ends in `@joeybuilt-official` — this lets\n * us wire the call sites now and swap the implementation later without\n * churning the install route.\n */\n\nimport type { ExtensionManifest } from '../types/manifest.js'\nimport type { TrustTier } from '../types/trust.js'\n\nexport type SignatureType = 'sigstore' | 'ecdsa-p256' | 'none'\n\nexport interface SignatureMetadata {\n /** Opaque signature payload (base64 for ECDSA, JSON bundle for Sigstore). */\n signature: string\n /** Discriminator for which verifier to use. */\n signatureType: SignatureType\n /** Human-readable signer identity (e.g. `plexo-bot@joeybuilt-official`). */\n signerIdentity: string\n /** ISO 8601 timestamp the signature was produced. */\n signedAt: string\n}\n\nexport interface SignatureVerificationResult {\n ok: boolean\n /** Matches the input `signatureType` on success, `'none'` on failure. */\n signatureType: SignatureType\n /** Signer identity extracted from the verified signature, if any. */\n signerIdentity: string | null\n /** The effective trust tier AFTER verification. May downgrade to 'community'. */\n effectiveTrust: TrustTier\n /** Human-readable message for the UI. */\n message: string\n}\n\n/**\n * The set of signer identity suffixes that qualify as \"owner\" for v1.\n * Extend this list — or replace the whole check with a real cosign call —\n * when the publishing pipeline is wired to GitHub OIDC.\n */\nconst OWNER_IDENTITY_SUFFIXES = ['@joeybuilt-official', '@plexo-official']\n\n/**\n * Verify a manifest's signature. v1 stub behavior:\n *\n * - `meta === null` → unsigned, downgrade to `community`\n * - `signatureType === 'none'` → unsigned, downgrade to `community`\n * - `signatureType === 'sigstore'`:\n * - signer_identity endsWith an OWNER_IDENTITY_SUFFIX → accept as `owner`\n * - otherwise → accept as `verified`\n * - `signatureType === 'ecdsa-p256'`:\n * - accept as `verified` (real verification TBD)\n *\n * The declared `manifest.trust` is the ceiling — we never upgrade above it.\n * An unsigned extension claiming `owner` is downgraded to `community`. A\n * signed extension claiming `community` stays at `community`.\n */\nexport function verifySignature(\n manifest: ExtensionManifest,\n meta: SignatureMetadata | null,\n): SignatureVerificationResult {\n const declared: TrustTier = (manifest.trust as TrustTier | undefined) ?? 'community'\n\n if (!meta || meta.signatureType === 'none' || !meta.signature) {\n if (declared === 'owner' || declared === 'verified') {\n return {\n ok: false,\n signatureType: 'none',\n signerIdentity: null,\n effectiveTrust: 'community',\n message: `Manifest declares trust \"${declared}\" but is unsigned — downgraded to community.`,\n }\n }\n return {\n ok: true,\n signatureType: 'none',\n signerIdentity: null,\n effectiveTrust: 'community',\n message: 'Unsigned community extension.',\n }\n }\n\n // Sigstore / cosign keyless (v1 stub: accept any identity)\n if (meta.signatureType === 'sigstore') {\n const isOwner = OWNER_IDENTITY_SUFFIXES.some((suffix) =>\n meta.signerIdentity.toLowerCase().endsWith(suffix),\n )\n const ceiling: TrustTier = isOwner ? 'owner' : 'verified'\n const effectiveTrust = lowerOf(declared, ceiling)\n return {\n ok: true,\n signatureType: 'sigstore',\n signerIdentity: meta.signerIdentity,\n effectiveTrust,\n message: `Sigstore signature accepted (stub v1) — signer ${meta.signerIdentity}.`,\n }\n }\n\n // Local ECDSA P-256 fallback (v1 stub)\n if (meta.signatureType === 'ecdsa-p256') {\n const effectiveTrust = lowerOf(declared, 'verified')\n return {\n ok: true,\n signatureType: 'ecdsa-p256',\n signerIdentity: meta.signerIdentity,\n effectiveTrust,\n message: `ECDSA signature accepted (stub v1) — signer ${meta.signerIdentity}.`,\n }\n }\n\n return {\n ok: false,\n signatureType: 'none',\n signerIdentity: null,\n effectiveTrust: 'community',\n message: `Unknown signature type: ${String((meta as SignatureMetadata).signatureType)}`,\n }\n}\n\n/** Returns the more restrictive of the two trust tiers. */\nfunction lowerOf(a: TrustTier, b: TrustTier): TrustTier {\n const order: Record<TrustTier, number> = { community: 0, verified: 1, owner: 2 }\n return order[a] <= order[b] ? a : b\n}\n"],"mappings":"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","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@joeybuilt/plexo-sdk",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"exports": {
|
|
6
|
+
".": {
|
|
7
|
+
"import": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts"
|
|
9
|
+
},
|
|
10
|
+
"./connect": {
|
|
11
|
+
"import": "./dist/connect/index.js",
|
|
12
|
+
"types": "./dist/connect/index.d.ts"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"main": "./dist/index.js",
|
|
16
|
+
"types": "./dist/index.d.ts",
|
|
17
|
+
"files": [
|
|
18
|
+
"dist"
|
|
19
|
+
],
|
|
20
|
+
"scripts": {
|
|
21
|
+
"build": "tsup",
|
|
22
|
+
"typecheck": "tsc --noEmit",
|
|
23
|
+
"test": "vitest run --passWithNoTests",
|
|
24
|
+
"prepublishOnly": "pnpm run build"
|
|
25
|
+
},
|
|
26
|
+
"dependencies": {
|
|
27
|
+
"zod": "^3.24"
|
|
28
|
+
},
|
|
29
|
+
"devDependencies": {
|
|
30
|
+
"@types/node": "^22",
|
|
31
|
+
"tsup": "^8.5.1",
|
|
32
|
+
"typescript": "^5.7",
|
|
33
|
+
"vitest": "^3"
|
|
34
|
+
},
|
|
35
|
+
"publishConfig": {
|
|
36
|
+
"access": "public"
|
|
37
|
+
},
|
|
38
|
+
"license": "AGPL-3.0-only"
|
|
39
|
+
}
|