mirror of
https://github.com/profullstack/logicsrc.git
synced 2026-08-14 06:47:28 +00:00
Add communication account plugin scaffolds
This commit is contained in:
parent
5cfeea6b57
commit
c23ce42948
48 changed files with 1949 additions and 13 deletions
43
packages/account-core/src/audit.ts
Normal file
43
packages/account-core/src/audit.ts
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
import type { LogicSrcAccountAuditEvent, LogicSrcAccountKind, LogicSrcPolicyDecision, LogicSrcPrincipal } from "./types.js";
|
||||
|
||||
const REDACTED_KEYS = new Set(["accessToken", "refreshToken", "token", "password", "secret", "clientSecret", "authorization"]);
|
||||
|
||||
export function redactedPreview(input: Record<string, unknown>) {
|
||||
const output: Record<string, unknown> = {};
|
||||
|
||||
for (const [key, value] of Object.entries(input)) {
|
||||
output[key] = REDACTED_KEYS.has(key) ? "[redacted]" : value;
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
export function createAccountAuditEvent(input: {
|
||||
id?: string;
|
||||
accountId?: string;
|
||||
provider: string;
|
||||
kind: LogicSrcAccountKind;
|
||||
principal: LogicSrcPrincipal;
|
||||
action: string;
|
||||
decision: LogicSrcPolicyDecision;
|
||||
riskScore?: number;
|
||||
requestPreview?: Record<string, unknown>;
|
||||
resultPreview?: Record<string, unknown>;
|
||||
correlationId?: string;
|
||||
createdAt?: string;
|
||||
}): LogicSrcAccountAuditEvent {
|
||||
return {
|
||||
id: input.id ?? `acct_audit_${Date.now()}`,
|
||||
accountId: input.accountId,
|
||||
provider: input.provider,
|
||||
kind: input.kind,
|
||||
principal: input.principal,
|
||||
action: input.action,
|
||||
decision: input.decision,
|
||||
riskScore: input.riskScore ?? 0,
|
||||
requestPreview: redactedPreview(input.requestPreview ?? {}),
|
||||
resultPreview: redactedPreview(input.resultPreview ?? {}),
|
||||
correlationId: input.correlationId,
|
||||
createdAt: input.createdAt ?? new Date().toISOString()
|
||||
};
|
||||
}
|
||||
57
packages/account-core/src/index.test.ts
Normal file
57
packages/account-core/src/index.test.ts
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
import { describe, expect, it } from "vitest";
|
||||
import { createAccountAuditEvent, createProviderRegistry, evaluateAccountPolicy, isPolicyGatedPermission, riskBandForScore, scoreAccountActionRisk } from "./index.js";
|
||||
|
||||
describe("account-core", () => {
|
||||
it("indexes account providers by kind and id", () => {
|
||||
const registry = createProviderRegistry([
|
||||
{ id: "gmail", name: "Gmail", kind: "email", authMethods: ["oauth2"], capabilities: ["email.search"] },
|
||||
{ id: "mastodon", name: "Mastodon", kind: "social", authMethods: ["oauth2"], capabilities: ["social.post.publish"] }
|
||||
]);
|
||||
|
||||
expect(registry.list("email")).toHaveLength(1);
|
||||
expect(registry.require("mastodon").name).toBe("Mastodon");
|
||||
});
|
||||
|
||||
it("keeps write and private actions policy-gated", () => {
|
||||
expect(isPolicyGatedPermission("email:send")).toBe(true);
|
||||
expect(isPolicyGatedPermission("social:profile:read")).toBe(false);
|
||||
});
|
||||
|
||||
it("scores and bands risky account actions", () => {
|
||||
const score = scoreAccountActionRisk({ action: "email:send", externalRecipientCount: 1, hasAttachment: true, sensitiveKeywordDetected: true });
|
||||
|
||||
expect(score).toBe(0.55);
|
||||
expect(riskBandForScore(score)).toBe("high");
|
||||
});
|
||||
|
||||
it("requires approval for gated actions with matching grants", () => {
|
||||
const result = evaluateAccountPolicy({
|
||||
action: "email:send",
|
||||
principal: { type: "agent", id: "marketing-agent" },
|
||||
grant: {
|
||||
id: "grant_1",
|
||||
accountId: "account_1",
|
||||
principal: { type: "agent", id: "marketing-agent" },
|
||||
permissions: ["email:send"],
|
||||
policy: [],
|
||||
createdAt: new Date(0).toISOString()
|
||||
}
|
||||
});
|
||||
|
||||
expect(result.decision).toBe("approval_required");
|
||||
});
|
||||
|
||||
it("redacts secret-like audit previews", () => {
|
||||
const event = createAccountAuditEvent({
|
||||
provider: "gmail",
|
||||
kind: "email",
|
||||
principal: { type: "user", id: "user_1" },
|
||||
action: "accounts:connect",
|
||||
decision: "allow",
|
||||
requestPreview: { accessToken: "raw-token", provider: "gmail" }
|
||||
});
|
||||
|
||||
expect(event.requestPreview.accessToken).toBe("[redacted]");
|
||||
expect(event.requestPreview.provider).toBe("gmail");
|
||||
});
|
||||
});
|
||||
13
packages/account-core/src/index.ts
Normal file
13
packages/account-core/src/index.ts
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
export * from "./types.js";
|
||||
export {
|
||||
ACCOUNT_PERMISSIONS,
|
||||
EMAIL_PERMISSIONS,
|
||||
POLICY_GATED_PERMISSIONS,
|
||||
SOCIAL_PERMISSIONS,
|
||||
SHARED_ACCOUNT_PERMISSIONS,
|
||||
accountPermissionList,
|
||||
isPolicyGatedPermission
|
||||
} from "./permissions.js";
|
||||
export { createProviderRegistry } from "./provider-registry.js";
|
||||
export { createAccountAuditEvent, redactedPreview } from "./audit.js";
|
||||
export { evaluateAccountPolicy, riskBandForScore, scoreAccountActionRisk } from "./policy.js";
|
||||
59
packages/account-core/src/permissions.ts
Normal file
59
packages/account-core/src/permissions.ts
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
export const SHARED_ACCOUNT_PERMISSIONS = [
|
||||
"accounts:connect",
|
||||
"accounts:list",
|
||||
"accounts:read_metadata",
|
||||
"accounts:test",
|
||||
"accounts:revoke",
|
||||
"accounts:sync",
|
||||
"accounts:audit:read"
|
||||
] as const;
|
||||
|
||||
export const SOCIAL_PERMISSIONS = [
|
||||
"social:profile:read",
|
||||
"social:post:draft",
|
||||
"social:post:publish",
|
||||
"social:post:delete",
|
||||
"social:media:upload",
|
||||
"social:mentions:read",
|
||||
"social:comments:read",
|
||||
"social:dm:read",
|
||||
"social:dm:send",
|
||||
"social:analytics:read"
|
||||
] as const;
|
||||
|
||||
export const EMAIL_PERMISSIONS = [
|
||||
"email:headers:read",
|
||||
"email:body:read",
|
||||
"email:attachments:read",
|
||||
"email:search",
|
||||
"email:draft",
|
||||
"email:send",
|
||||
"email:reply",
|
||||
"email:forward",
|
||||
"email:archive",
|
||||
"email:labels:modify",
|
||||
"email:delete",
|
||||
"email:sync"
|
||||
] as const;
|
||||
|
||||
export const ACCOUNT_PERMISSIONS = [...SHARED_ACCOUNT_PERMISSIONS, ...SOCIAL_PERMISSIONS, ...EMAIL_PERMISSIONS] as const;
|
||||
|
||||
export const POLICY_GATED_PERMISSIONS = [
|
||||
"social:post:publish",
|
||||
"social:post:delete",
|
||||
"social:dm:read",
|
||||
"social:dm:send",
|
||||
"email:attachments:read",
|
||||
"email:send",
|
||||
"email:delete"
|
||||
] as const;
|
||||
|
||||
export type LogicSrcAccountPermission = (typeof ACCOUNT_PERMISSIONS)[number];
|
||||
|
||||
export function accountPermissionList() {
|
||||
return [...ACCOUNT_PERMISSIONS];
|
||||
}
|
||||
|
||||
export function isPolicyGatedPermission(permission: string) {
|
||||
return (POLICY_GATED_PERMISSIONS as readonly string[]).includes(permission);
|
||||
}
|
||||
92
packages/account-core/src/policy.ts
Normal file
92
packages/account-core/src/policy.ts
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
import { isPolicyGatedPermission } from "./permissions.js";
|
||||
import type { LogicSrcPolicyEvaluationInput, LogicSrcPolicyEvaluationResult, LogicSrcRiskBand } from "./types.js";
|
||||
|
||||
const WRITE_ACTIONS = new Set([
|
||||
"social:post:publish",
|
||||
"social:post:delete",
|
||||
"social:dm:send",
|
||||
"email:send",
|
||||
"email:reply",
|
||||
"email:forward",
|
||||
"email:delete",
|
||||
"email:labels:modify",
|
||||
"email:archive"
|
||||
]);
|
||||
|
||||
export function riskBandForScore(score: number): LogicSrcRiskBand {
|
||||
if (score >= 0.75) {
|
||||
return "critical";
|
||||
}
|
||||
if (score >= 0.5) {
|
||||
return "high";
|
||||
}
|
||||
if (score >= 0.25) {
|
||||
return "medium";
|
||||
}
|
||||
return "low";
|
||||
}
|
||||
|
||||
export function scoreAccountActionRisk(input: {
|
||||
action: string;
|
||||
externalRecipientCount?: number;
|
||||
newRecipientOrDomain?: boolean;
|
||||
hasAttachment?: boolean;
|
||||
highReachAccount?: boolean;
|
||||
sensitiveKeywordDetected?: boolean;
|
||||
rawCredentialAccessAttempted?: boolean;
|
||||
}) {
|
||||
let score = 0;
|
||||
|
||||
if (input.externalRecipientCount && input.externalRecipientCount > 0) score += 0.1;
|
||||
if (input.newRecipientOrDomain) score += 0.15;
|
||||
if (input.hasAttachment) score += 0.15;
|
||||
if (input.action === "social:post:publish") score += 0.2;
|
||||
if (input.action.includes("delete")) score += 0.2;
|
||||
if (input.action.includes("dm:read") || input.action.includes("attachments:read")) score += 0.25;
|
||||
if (input.highReachAccount) score += 0.25;
|
||||
if (input.sensitiveKeywordDetected) score += 0.3;
|
||||
if (input.rawCredentialAccessAttempted) score += 0.4;
|
||||
|
||||
return Math.min(1, Number(score.toFixed(2)));
|
||||
}
|
||||
|
||||
export function evaluateAccountPolicy(input: LogicSrcPolicyEvaluationInput): LogicSrcPolicyEvaluationResult {
|
||||
const riskScore = Math.min(1, Math.max(0, input.riskScore ?? scoreAccountActionRisk({ action: input.action })));
|
||||
const grantActive = input.grant && !input.grant.revokedAt && (!input.grant.expiresAt || Date.parse(input.grant.expiresAt) > Date.now());
|
||||
const hasPermission = Boolean(grantActive && input.grant?.permissions.includes(input.action));
|
||||
|
||||
if (!hasPermission) {
|
||||
return { decision: "deny", riskScore, reason: `missing grant for ${input.action}` };
|
||||
}
|
||||
|
||||
if (input.dryRun) {
|
||||
return { decision: "allow", riskScore, reason: "dry run with matching grant" };
|
||||
}
|
||||
|
||||
const policy = input.grant?.policy.find((entry) => entry.action === input.action);
|
||||
if (policy?.default === "deny") {
|
||||
return { decision: "deny", riskScore, reason: `policy ${policy.id} denies ${input.action}` };
|
||||
}
|
||||
if (policy?.default === "approval_required") {
|
||||
return { decision: "approval_required", riskScore, reason: `policy ${policy.id} requires approval` };
|
||||
}
|
||||
if (policy?.default === "allow_if_trusted_agent" && input.principal?.trusted) {
|
||||
return { decision: "allow", riskScore, reason: `policy ${policy.id} allows trusted principal` };
|
||||
}
|
||||
if (policy?.default === "allow_if_below_risk_score") {
|
||||
const maxRiskScore = typeof policy.conditions?.maxRiskScore === "number" ? policy.conditions.maxRiskScore : 0.25;
|
||||
return riskScore <= maxRiskScore
|
||||
? { decision: "allow", riskScore, reason: `risk score is within policy ${policy.id}` }
|
||||
: { decision: "approval_required", riskScore, reason: `risk score exceeds policy ${policy.id}` };
|
||||
}
|
||||
|
||||
const band = riskBandForScore(riskScore);
|
||||
if (band === "critical") {
|
||||
return { decision: "deny", riskScore, reason: "critical risk requires admin override" };
|
||||
}
|
||||
if (isPolicyGatedPermission(input.action) || (WRITE_ACTIONS.has(input.action) && band !== "low")) {
|
||||
return { decision: "approval_required", riskScore, reason: "default gate for risky account action" };
|
||||
}
|
||||
|
||||
return { decision: "allow", riskScore, reason: "grant allows account action" };
|
||||
}
|
||||
28
packages/account-core/src/provider-registry.ts
Normal file
28
packages/account-core/src/provider-registry.ts
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
import type { LogicSrcAccountKind, LogicSrcAccountProviderManifest } from "./types.js";
|
||||
|
||||
export function createProviderRegistry(providers: LogicSrcAccountProviderManifest[]) {
|
||||
const byId = new Map<string, LogicSrcAccountProviderManifest>();
|
||||
|
||||
for (const provider of providers) {
|
||||
if (byId.has(provider.id)) {
|
||||
throw new Error(`Duplicate account provider: ${provider.id}`);
|
||||
}
|
||||
byId.set(provider.id, provider);
|
||||
}
|
||||
|
||||
return {
|
||||
list(kind?: LogicSrcAccountKind) {
|
||||
return providers.filter((provider) => !kind || provider.kind === kind);
|
||||
},
|
||||
get(id: string) {
|
||||
return byId.get(id);
|
||||
},
|
||||
require(id: string) {
|
||||
const provider = byId.get(id);
|
||||
if (!provider) {
|
||||
throw new Error(`Unknown account provider: ${id}`);
|
||||
}
|
||||
return provider;
|
||||
}
|
||||
};
|
||||
}
|
||||
447
packages/account-core/src/types.ts
Normal file
447
packages/account-core/src/types.ts
Normal file
|
|
@ -0,0 +1,447 @@
|
|||
export type LogicSrcAccountKind = "social" | "email";
|
||||
|
||||
export type LogicSrcAccountStatus = "connected" | "expired" | "revoked" | "error" | "disabled" | "pending";
|
||||
|
||||
export type LogicSrcAccountAuthMethod = "oauth2" | "api_key" | "imap_smtp" | "local_bridge";
|
||||
|
||||
export type LogicSrcPrincipalType = "user" | "agent" | "workflow" | "plugin";
|
||||
|
||||
export type LogicSrcPolicyMode =
|
||||
| "allow"
|
||||
| "approval_required"
|
||||
| "deny"
|
||||
| "allow_if_dry_run"
|
||||
| "allow_if_trusted_agent"
|
||||
| "allow_if_below_risk_score";
|
||||
|
||||
export type LogicSrcPolicyDecision = "allow" | "approval_required" | "deny";
|
||||
|
||||
export type LogicSrcRiskBand = "low" | "medium" | "high" | "critical";
|
||||
|
||||
export interface LogicSrcConnectedAccount {
|
||||
id: string;
|
||||
orgId?: string;
|
||||
projectId?: string;
|
||||
boardId?: string;
|
||||
ownerUserId: string;
|
||||
kind: LogicSrcAccountKind;
|
||||
provider: string;
|
||||
providerAccountId?: string;
|
||||
displayName: string;
|
||||
handle?: string;
|
||||
email?: string;
|
||||
avatarUrl?: string;
|
||||
homepageUrl?: string;
|
||||
status: LogicSrcAccountStatus;
|
||||
scopes: string[];
|
||||
capabilities: string[];
|
||||
credentialRef: string;
|
||||
metadata: Record<string, unknown>;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
lastSyncedAt?: string;
|
||||
}
|
||||
|
||||
export interface LogicSrcAccountProviderManifest {
|
||||
id: string;
|
||||
name: string;
|
||||
kind: LogicSrcAccountKind;
|
||||
authMethods: LogicSrcAccountAuthMethod[];
|
||||
capabilities: string[];
|
||||
defaultScopes?: string[];
|
||||
status?: "available" | "planned" | "disabled";
|
||||
docsUrl?: string;
|
||||
}
|
||||
|
||||
export interface LogicSrcAccountProvider extends LogicSrcAccountProviderManifest {
|
||||
getAuthUrl?(input: AuthUrlInput): Promise<AuthUrlResult>;
|
||||
completeAuth?(input: CompleteAuthInput): Promise<ConnectedAccountResult>;
|
||||
refreshCredential?(input: RefreshCredentialInput): Promise<CredentialRefreshResult>;
|
||||
testConnection(input: TestConnectionInput): Promise<TestConnectionResult>;
|
||||
revoke?(input: RevokeAccountInput): Promise<RevokeAccountResult>;
|
||||
}
|
||||
|
||||
export interface SocialAccountProvider extends LogicSrcAccountProvider {
|
||||
kind: "social";
|
||||
getProfile(input: SocialAccountInput): Promise<SocialProfile>;
|
||||
draftPost(input: DraftSocialPostInput): Promise<SocialDraft>;
|
||||
publishPost(input: PublishSocialPostInput): Promise<PublishedSocialPost>;
|
||||
uploadMedia?(input: UploadSocialMediaInput): Promise<UploadedMedia>;
|
||||
searchMentions?(input: SearchMentionsInput): Promise<SocialMention[]>;
|
||||
listComments?(input: ListCommentsInput): Promise<SocialComment[]>;
|
||||
getAnalytics?(input: SocialAnalyticsInput): Promise<SocialAnalyticsResult>;
|
||||
}
|
||||
|
||||
export interface EmailAccountProvider extends LogicSrcAccountProvider {
|
||||
kind: "email";
|
||||
searchMessages(input: EmailSearchInput): Promise<EmailSearchResult>;
|
||||
readMessage(input: ReadEmailMessageInput): Promise<EmailMessage>;
|
||||
draftMessage(input: DraftEmailInput): Promise<EmailDraft>;
|
||||
sendMessage(input: SendEmailInput): Promise<SentEmailResult>;
|
||||
replyToMessage?(input: ReplyEmailInput): Promise<SentEmailResult>;
|
||||
forwardMessage?(input: ForwardEmailInput): Promise<SentEmailResult>;
|
||||
archiveMessage?(input: EmailMessageMutationInput): Promise<EmailMutationResult>;
|
||||
applyLabels?(input: EmailLabelInput): Promise<EmailMutationResult>;
|
||||
deleteMessage?(input: EmailMessageMutationInput): Promise<EmailMutationResult>;
|
||||
}
|
||||
|
||||
export interface AuthUrlInput {
|
||||
redirectUri: string;
|
||||
state: string;
|
||||
scopes: string[];
|
||||
metadata?: Record<string, unknown>;
|
||||
}
|
||||
|
||||
export interface AuthUrlResult {
|
||||
url: string;
|
||||
state: string;
|
||||
expiresAt?: string;
|
||||
}
|
||||
|
||||
export interface CompleteAuthInput {
|
||||
code: string;
|
||||
redirectUri: string;
|
||||
state: string;
|
||||
principal: LogicSrcPrincipal;
|
||||
}
|
||||
|
||||
export interface ConnectedAccountResult {
|
||||
account: LogicSrcConnectedAccount;
|
||||
auditEvent: LogicSrcAccountAuditEvent;
|
||||
}
|
||||
|
||||
export interface RefreshCredentialInput {
|
||||
account: LogicSrcConnectedAccount;
|
||||
broker: LogicSrcCredentialBroker;
|
||||
}
|
||||
|
||||
export interface CredentialRefreshResult {
|
||||
credentialRef: string;
|
||||
scopes: string[];
|
||||
expiresAt?: string;
|
||||
}
|
||||
|
||||
export interface TestConnectionInput {
|
||||
account: LogicSrcConnectedAccount;
|
||||
broker: LogicSrcCredentialBroker;
|
||||
}
|
||||
|
||||
export interface TestConnectionResult {
|
||||
ok: boolean;
|
||||
provider: string;
|
||||
checkedAt: string;
|
||||
message?: string;
|
||||
}
|
||||
|
||||
export interface RevokeAccountInput {
|
||||
account: LogicSrcConnectedAccount;
|
||||
broker: LogicSrcCredentialBroker;
|
||||
principal: LogicSrcPrincipal;
|
||||
}
|
||||
|
||||
export interface RevokeAccountResult {
|
||||
ok: boolean;
|
||||
revokedAt: string;
|
||||
}
|
||||
|
||||
export interface LogicSrcPrincipal {
|
||||
type: LogicSrcPrincipalType;
|
||||
id: string;
|
||||
trusted?: boolean;
|
||||
}
|
||||
|
||||
export interface LogicSrcAccountPermissionGrant {
|
||||
id: string;
|
||||
accountId: string;
|
||||
principal: LogicSrcPrincipal;
|
||||
permissions: string[];
|
||||
policy: LogicSrcAccountPolicy[];
|
||||
expiresAt?: string;
|
||||
createdBy?: string;
|
||||
createdAt: string;
|
||||
revokedAt?: string;
|
||||
}
|
||||
|
||||
export interface LogicSrcAccountPolicy {
|
||||
id: string;
|
||||
resource: string;
|
||||
action: string;
|
||||
default: LogicSrcPolicyMode;
|
||||
conditions?: Record<string, unknown>;
|
||||
}
|
||||
|
||||
export interface LogicSrcPolicyEvaluationInput {
|
||||
action: string;
|
||||
grant?: LogicSrcAccountPermissionGrant;
|
||||
riskScore?: number;
|
||||
dryRun?: boolean;
|
||||
principal?: LogicSrcPrincipal;
|
||||
}
|
||||
|
||||
export interface LogicSrcPolicyEvaluationResult {
|
||||
decision: LogicSrcPolicyDecision;
|
||||
riskScore: number;
|
||||
reason: string;
|
||||
}
|
||||
|
||||
export interface LogicSrcCredentialBroker {
|
||||
getCredential(input: CredentialBrokerGetInput): Promise<CredentialBrokerGetResult>;
|
||||
storeCredential(input: CredentialBrokerStoreInput): Promise<CredentialBrokerStoreResult>;
|
||||
revokeCredential(input: CredentialBrokerRevokeInput): Promise<CredentialBrokerRevokeResult>;
|
||||
}
|
||||
|
||||
export interface CredentialBrokerGetInput {
|
||||
credentialRef: string;
|
||||
accountId: string;
|
||||
provider: string;
|
||||
purpose: string;
|
||||
principal: LogicSrcPrincipal;
|
||||
}
|
||||
|
||||
export interface CredentialBrokerGetResult {
|
||||
credentialRef: string;
|
||||
token: string;
|
||||
expiresAt?: string;
|
||||
}
|
||||
|
||||
export interface CredentialBrokerStoreInput {
|
||||
provider: string;
|
||||
kind: LogicSrcAccountKind;
|
||||
scopes: string[];
|
||||
secret: string;
|
||||
metadata?: Record<string, unknown>;
|
||||
}
|
||||
|
||||
export interface CredentialBrokerStoreResult {
|
||||
credentialRef: string;
|
||||
}
|
||||
|
||||
export interface CredentialBrokerRevokeInput {
|
||||
credentialRef: string;
|
||||
accountId: string;
|
||||
provider: string;
|
||||
principal: LogicSrcPrincipal;
|
||||
}
|
||||
|
||||
export interface CredentialBrokerRevokeResult {
|
||||
ok: boolean;
|
||||
revokedAt: string;
|
||||
}
|
||||
|
||||
export interface LogicSrcAccountAuditEvent {
|
||||
id: string;
|
||||
accountId?: string;
|
||||
provider: string;
|
||||
kind: LogicSrcAccountKind;
|
||||
principal: LogicSrcPrincipal;
|
||||
action: string;
|
||||
decision: LogicSrcPolicyDecision;
|
||||
riskScore: number;
|
||||
requestPreview: Record<string, unknown>;
|
||||
resultPreview: Record<string, unknown>;
|
||||
correlationId?: string;
|
||||
createdAt: string;
|
||||
}
|
||||
|
||||
export interface SocialAccountInput {
|
||||
account: LogicSrcConnectedAccount;
|
||||
broker: LogicSrcCredentialBroker;
|
||||
}
|
||||
|
||||
export interface SocialProfile {
|
||||
providerAccountId: string;
|
||||
displayName: string;
|
||||
handle?: string;
|
||||
avatarUrl?: string;
|
||||
homepageUrl?: string;
|
||||
metadata?: Record<string, unknown>;
|
||||
}
|
||||
|
||||
export interface DraftSocialPostInput extends SocialAccountInput {
|
||||
text: string;
|
||||
media?: SocialMediaInput[];
|
||||
principal: LogicSrcPrincipal;
|
||||
}
|
||||
|
||||
export interface PublishSocialPostInput extends DraftSocialPostInput {
|
||||
dryRun?: boolean;
|
||||
approvalId?: string;
|
||||
}
|
||||
|
||||
export interface SocialDraft {
|
||||
id: string;
|
||||
accountId: string;
|
||||
text: string;
|
||||
media: SocialMediaInput[];
|
||||
createdAt: string;
|
||||
}
|
||||
|
||||
export interface PublishedSocialPost {
|
||||
providerPostId?: string;
|
||||
url?: string;
|
||||
publishedAt: string;
|
||||
dryRun?: boolean;
|
||||
}
|
||||
|
||||
export interface SocialMediaInput {
|
||||
url?: string;
|
||||
fileRef?: string;
|
||||
altText?: string;
|
||||
mimeType?: string;
|
||||
}
|
||||
|
||||
export interface UploadSocialMediaInput extends SocialAccountInput {
|
||||
media: SocialMediaInput;
|
||||
}
|
||||
|
||||
export interface UploadedMedia {
|
||||
providerMediaId: string;
|
||||
url?: string;
|
||||
}
|
||||
|
||||
export interface SearchMentionsInput extends SocialAccountInput {
|
||||
query?: string;
|
||||
limit?: number;
|
||||
}
|
||||
|
||||
export interface SocialMention {
|
||||
id: string;
|
||||
text: string;
|
||||
authorHandle?: string;
|
||||
url?: string;
|
||||
createdAt?: string;
|
||||
}
|
||||
|
||||
export interface ListCommentsInput extends SocialAccountInput {
|
||||
postId: string;
|
||||
limit?: number;
|
||||
}
|
||||
|
||||
export interface SocialComment extends SocialMention {
|
||||
postId: string;
|
||||
}
|
||||
|
||||
export interface SocialAnalyticsInput extends SocialAccountInput {
|
||||
postId?: string;
|
||||
since?: string;
|
||||
until?: string;
|
||||
}
|
||||
|
||||
export interface SocialAnalyticsResult {
|
||||
metrics: Record<string, number>;
|
||||
metadata?: Record<string, unknown>;
|
||||
}
|
||||
|
||||
export interface EmailSearchInput {
|
||||
account: LogicSrcConnectedAccount;
|
||||
broker: LogicSrcCredentialBroker;
|
||||
query: string;
|
||||
limit?: number;
|
||||
headersOnly?: boolean;
|
||||
principal: LogicSrcPrincipal;
|
||||
}
|
||||
|
||||
export interface EmailSearchResult {
|
||||
messages: EmailMessageMetadata[];
|
||||
nextPageToken?: string;
|
||||
}
|
||||
|
||||
export interface EmailMessageMetadata {
|
||||
id: string;
|
||||
providerMessageId: string;
|
||||
threadId?: string;
|
||||
subject?: string;
|
||||
fromAddress?: string;
|
||||
toAddresses: string[];
|
||||
ccAddresses: string[];
|
||||
snippet?: string;
|
||||
labels: string[];
|
||||
hasAttachments: boolean;
|
||||
receivedAt?: string;
|
||||
sentAt?: string;
|
||||
}
|
||||
|
||||
export interface ReadEmailMessageInput {
|
||||
account: LogicSrcConnectedAccount;
|
||||
broker: LogicSrcCredentialBroker;
|
||||
messageId: string;
|
||||
includeBody?: boolean;
|
||||
includeAttachments?: boolean;
|
||||
principal: LogicSrcPrincipal;
|
||||
}
|
||||
|
||||
export interface EmailMessage extends EmailMessageMetadata {
|
||||
bodyText?: string;
|
||||
bodyHtml?: string;
|
||||
attachments?: EmailAttachment[];
|
||||
}
|
||||
|
||||
export interface EmailAttachment {
|
||||
id: string;
|
||||
filename: string;
|
||||
mimeType: string;
|
||||
sizeBytes?: number;
|
||||
contentRef?: string;
|
||||
}
|
||||
|
||||
export interface DraftEmailInput {
|
||||
account: LogicSrcConnectedAccount;
|
||||
to: string[];
|
||||
cc?: string[];
|
||||
bcc?: string[];
|
||||
subject: string;
|
||||
bodyText?: string;
|
||||
bodyHtml?: string;
|
||||
attachmentRefs?: string[];
|
||||
principal: LogicSrcPrincipal;
|
||||
}
|
||||
|
||||
export interface EmailDraft {
|
||||
id: string;
|
||||
accountId: string;
|
||||
to: string[];
|
||||
cc: string[];
|
||||
bcc: string[];
|
||||
subject: string;
|
||||
bodyPreview: string;
|
||||
attachmentRefs: string[];
|
||||
createdAt: string;
|
||||
}
|
||||
|
||||
export interface SendEmailInput extends DraftEmailInput {
|
||||
draftId?: string;
|
||||
dryRun?: boolean;
|
||||
approvalId?: string;
|
||||
}
|
||||
|
||||
export interface SentEmailResult {
|
||||
providerMessageId?: string;
|
||||
sentAt: string;
|
||||
dryRun?: boolean;
|
||||
}
|
||||
|
||||
export interface ReplyEmailInput extends SendEmailInput {
|
||||
messageId: string;
|
||||
}
|
||||
|
||||
export interface ForwardEmailInput extends SendEmailInput {
|
||||
messageId: string;
|
||||
}
|
||||
|
||||
export interface EmailMessageMutationInput {
|
||||
account: LogicSrcConnectedAccount;
|
||||
broker: LogicSrcCredentialBroker;
|
||||
messageId: string;
|
||||
principal: LogicSrcPrincipal;
|
||||
}
|
||||
|
||||
export interface EmailLabelInput extends EmailMessageMutationInput {
|
||||
add?: string[];
|
||||
remove?: string[];
|
||||
}
|
||||
|
||||
export interface EmailMutationResult {
|
||||
ok: boolean;
|
||||
messageId: string;
|
||||
changedAt: string;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue