/** * INJECTED-TOKEN fast path (Zibby Copilot per-turn credential injection). * * The Zibby Copilot is ONE shared Slack/Lark bot backed by ONE project's * PROJECT_API_TOKEN. resolveIntegrationToken(provider) authenticates with that * PAT, so the account is inferred SERVER-SIDE from the PAT — meaning the shared * bot would only ever see the PROJECT OWNER's LinkedIn, never the (different) * person who actually sent the Slack message. * * To let the bot post to the VERIFIED SENDER's OWN LinkedIn, the copilot-runtime * (a TRUSTED backend service that already KMS-decrypts tenants' creds directly) * resolves the EMAIL-VERIFIED Slack sender's OWN linkedin_personal token straight * from the encrypted store and injects it into THIS turn's env * (ZIBBY_INJECTED_LINKEDIN_TOKEN / ZIBBY_INJECTED_LINKEDIN_MEMBER_ID, set + * restored per-turn — never persisted, never cross-turn). When present it takes * PRECEDENCE over resolveIntegrationToken so the post is attributed to the sender. * * SCOPED to linkedin_personal ONLY (member-profile publishing). It is NEVER used * for the business/org provider (company Pages) or any other integration. Absent * (no injection) → this returns null and the normal PAT chokepoint runs * unchanged (self-host + cloud), so the Fargate linkedin-post workflow, which * never sets these vars, is byte-for-byte unaffected. */ export declare function injectedPersonalToken(): { token: string; memberId: string; }; /** * STRICT CHAT-TURN INVARIANT (fail-CLOSED) — ZIBBY_CHAT_STRICT_PERSONAL=1. * Set UNCONDITIONALLY by the Copilot runtime for EVERY chat turn (Slack + * Lark, owner or not). Under it, the PERSONAL-tier provider * (linkedin_personal) must NEVER fall through to the PAT-resolved project- * owner token: the ONLY accepted credential is the per-turn injected sender * token (the runtime injects the OWNER's own LinkedIn through the same path, * so the owner keeps working). No injected token → HARD REFUSE for ANY sender * — verified non-owner, same-account colleague, UNVERIFIED sender (the class * the old per-sender flags failed OPEN on), or the owner with no LinkedIn. * The business/org provider (company Pages) is team-tier and unaffected. * Absent the flag (Fargate workflows, self-host, direct tool use) → the * normal PAT chokepoint runs unchanged. */ export declare function chatStrictPersonal(): boolean; /** Belt-and-braces legacy flag: this turn's verified sender ≠ the tenant owner. */ export declare function senderIsNonOwner(): boolean; export declare const PERSONAL_REFUSAL = "You haven't connected your own LinkedIn account \u2014 connect it at https://studio.zibby.dev/integrations (LinkedIn). For privacy, I can't post or act as anyone else's LinkedIn (including the project owner's) on your behalf."; /** * The single PERSONAL-tier credential gate for linkedin_personal calls: * injected sender token wins; otherwise a strict chat turn (or a flagged * non-owner sender) HARD-REFUSES rather than falling through to the owner's * PAT-resolved token. Returns the injected token/memberId or null (= caller * may use the legacy PAT path). Throws PERSONAL_REFUSAL on the gated paths. */ export declare function personalTierCredentialGate(): { token: string; memberId: string; }; /** * Extract a numeric organization id from a urn (urn:li:organization:123) or a * bare numeric id. Returns the id string, or null if none can be found. */ export declare function parseOrgId(ref: any): string; /** * Single chokepoint for every LinkedIn REST call. Resolves the OAuth bearer * for the given `provider` via resolveIntegrationToken(provider) — defaulting * to 'linkedin_business' (org Community Management API); pass * 'linkedin_personal' for member-profile calls — sets the required * versioned-API headers, retries once on transient auth errors, and returns * { status, headers, body }. Throws (trimmed) on non-2xx so handleToolCall can * surface it as JSON. * * Keep this the single auth chokepoint — don't resolve tokens at call sites. */ export declare function linkedinApi(path: any, opts?: any, provider?: string): Promise<{ status: number; headers: Headers; body: any; }>; /** * Upload a LOCAL image file to LinkedIn's Images API and return its * `urn:li:image:...` URN, ready to attach to a post via * requestBody.content.media = { id: , altText }. * * Uses the SAME provider/token/gate as the post (resolveProviderToken): * 1. initializeUpload — POST /rest/images?action=initializeUpload with * { initializeUploadRequest: { owner: } } (through linkedinApi, * so it carries the versioned-API headers + the personal-tier gate). Reads * value.uploadUrl + value.image from the response. * 2. single-request upload — PUT the raw file bytes to uploadUrl with * Authorization: Bearer + the image Content-Type. * 3. return value.image (the image URN). * * Throws on any non-2xx / missing field — handleToolCall catches it and returns * { ok:false, error } so a bad image can't crash the run or cause a post. */ export declare function uploadImage(provider: any, ownerUrn: any, imagePath: any, mimeType?: any): Promise; export declare const linkedinSkill: any;