/** * Registry of shareable resources. * * Each template registers its ownable resource(s) once on module load so the * framework-level share actions (`share-resource`, `list-resource-shares`, * etc.) can dispatch to the correct tables. * * import { registerShareableResource } from "@agent-native/core/sharing"; * import * as schema from "./schema.js"; * * registerShareableResource({ * type: "document", * resourceTable: schema.documents, * sharesTable: schema.documentShares, * displayName: "Document", * titleColumn: "title", * }); */ export interface ShareableResourceRegistration { /** Stable identifier used across actions, UI, and analytics. e.g. "document". */ type: string; /** Drizzle table for the parent resource (must have ownableColumns()). */ resourceTable: any; /** Drizzle table produced by createSharesTable(). */ sharesTable: any; /** Human-readable singular label shown in the share dialog. */ displayName: string; /** * Column on the resource table that holds a human-readable title for * display in the share UI. Default: "title". */ titleColumn?: string; /** * Optional app-relative path to this resource. Used by share notifications * when the caller does not pass a more specific resourceUrl. */ getResourcePath?: (resource: any) => string | undefined; /** * Drizzle DB accessor from the template's server/db/index.ts. Required — * the framework-level share actions and access helpers call this to reach * the right DB instance (schema is template-specific). */ getDb: () => any; /** * When `false`, `visibility: "public"` is rejected by `set-resource-visibility`, * and `accessFilter` / `resolveAccess` treat any stored public row as private * (defense in depth — only owner + explicit shares grant access). * * Use this for resources that execute code or expose privileged data and must * never be reachable by a random authenticated user. Extensions set this: * extension HTML runs inside an iframe that calls actions / DB / proxied APIs * as the *viewer*, so a public extension would be arbitrary code with the * viewer's credentials. * * Default: `true` (matches the historical behavior — most resources can be public). */ allowPublic?: boolean; /** * Optional role granted by a public-by-link read. Most resources should omit * this so public visibility remains viewer-only. Use narrowly for local or * otherwise constrained resources where the resource owner intentionally wants * unauthenticated link holders to do more than view. * * When this is a function, it may read arbitrary fields on the resource row * (not just the ownership/visibility columns). Because of that, * `resolveAccess`/`assertAccess`'s opt-in `{ skipResourceBody: true }` * projected load (see `access.ts`) is automatically ignored for this * registration and always loads the full row instead — a fixed role string * has no such requirement and is compatible with the projection. */ publicAccessRole?: "viewer" | "editor" | "admin" | ((resource: any, ctx: { userEmail?: string; orgId?: string; }) => "viewer" | "editor" | "admin" | Promise<"viewer" | "editor" | "admin">); /** * When `true`, individual user shares (`principalType: "user"`) must target * an email that is already a member of the same org as the resource, OR has * a pending invitation to that org. Cross-org user shares are rejected. * * Pair with `allowPublic: false` for resources that need a hard "this org * only" trust boundary. Extensions set this so a malicious caller can't * widen reach by sharing a code-executing extension to an outsider email. * * Default: `false` (matches the historical behavior — any email can be granted). */ requireOrgMemberForUserShares?: boolean; /** * Optional per-resource access-context adapter. Most resources should use the * request user/org unchanged. Templates with an intentional alternate local * identity can normalize here so the generic framework sharing actions and * access helpers stay in sync with template-owned actions. */ resolveAccessContext?: (ctx: { userEmail?: string; orgId?: string; }) => { userEmail?: string; orgId?: string; }; /** * When true, direct ownership is recognized by owner_email regardless of the * caller's active org. Use this only for resource types where the template's * own actions already treat owner_email as the cross-org authority and list * views add their own org filters. * * Default: `false`. */ ownerAccessIgnoresOrg?: boolean; /** * Optional external-agent read handoff. When set, the framework-level * `create-agent-resource-link` action can mint a short-lived, read-only * `agent_access` URL for this resource. The context endpoint is owned by the * template so it can expose the same intentionally shareable shape as the * public page, not a generic raw database row. */ agentReadable?: false | { /** Token scope. Include the app name to avoid cross-app collisions. */ resourceKind: string; /** App-relative JSON endpoint that accepts `id` + `agent_access`. */ getContextPath: (resource: any) => string | undefined; /** Optional override for the page URL. Defaults to getResourcePath. */ getPagePath?: (resource: any) => string | undefined; /** Optional override for the default two-hour token lifetime. */ ttlSeconds?: number; }; } export declare function registerShareableResource(entry: ShareableResourceRegistration): void; export declare function getShareableResource(type: string): ShareableResourceRegistration | undefined; export declare function requireShareableResource(type: string): ShareableResourceRegistration; export declare function listShareableResources(): ShareableResourceRegistration[]; //# sourceMappingURL=registry.d.ts.map