@whoz-oss/coday-server 0.118.0 → 0.118.1
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/package.json +1 -1
- package/server.js +1 -1
package/package.json
CHANGED
package/server.js
CHANGED
|
@@ -1299,7 +1299,7 @@ ${n}
|
|
|
1299
1299
|
b) For each query key get the allowed operators.
|
|
1300
1300
|
c) Use the query key and only the allowed operators to create the jql.
|
|
1301
1301
|
d) Explicitly calling out the JQL URL
|
|
1302
|
-
`,parameters:{type:"object",properties:{jql:{type:"string",description:"JQL query for counting issues"}}},parse:JSON.parse,function:async({jql:g})=>{let v=await this.jiraService.ensureInitialized();return v.isNewlyInitialized?{fieldMappingInfo:v.fieldMappingInfo,message:v.message}:(v.fieldMapping&&wZ(g,v.fieldMapping),Lve(g,a,s,o,this.interactor))}}},m={type:"function",function:{name:`${this.name}__postIssue`,description:"Create a new Jira issue/ticket without asking for more information from the user, directly call the function to create the ticket",parameters:{type:"object",properties:{request:{type:"object",description:"Request object containing all issue fields",properties:{projectKey:{type:"string",description:"Project key where the issue will be created"},summary:{type:"string",description:"Summary/title of the issue"},description:{type:"string",description:"Detailed description of the issue"},issuetype:{type:"string",description:"Type of issue"},assignee:{type:"string",description:"User ID of the assignee"},reporter:{type:"string",description:"User ID of the reporter"},priority:{type:"string",description:'Priority of the issue (e.g., "High", "Medium", "Low")'},labels:{type:"array",items:{type:"string"},description:"Labels to attach to the issue"},components:{type:"array",items:{type:"string"},description:"Components to associate with the issue"},fixVersions:{type:"array",items:{type:"string"},description:"Fix versions to associate with the issue"},duedate:{type:"string",description:"Due date in YYYY-MM-DD format"},parent:{type:"object",properties:{key:{type:"string",description:"The issue key of the parent"}},description:"Parent issue for this issue (directly establishes parent-child relationship)"},linkedIssues:{type:"array",items:{type:"object",properties:{key:{type:"string",description:"The key of the issue to link"},linkType:{type:"string",description:'The type of link to create (default: "is part of" for epics, "relates to" for other issue types)'},isEpicLink:{type:"boolean",description:"Whether to use Epic Link field if available (default: true for epics)"}}},description:"Issues to link to this issue after creation (especially useful for epics)"}}}}},parse:JSON.parse,function:async({request:g})=>{try{if(g.error&&g.partialRequest){let v=g.partialRequest,y=g.error||"Previous attempt failed";return this.interactor.displayText(`Retrying Jira issue creation with saved information. Previous error: ${y}`),await EZ(v,a,s,o,this.interactor)}return await EZ(g,a,s,o,this.interactor)}catch(v){throw this.interactor.error(`Error in createJiraIssue function: ${v}`),v}}}},h={type:"function",function:{name:`${this.name}__linkIssues`,description:"Link two Jira issues with a specified relationship type",parameters:{type:"object",properties:{inwardIssueKey:{type:"string",description:"The issue key that is the source of the link (inward issue)"},outwardIssueKey:{type:"string",description:"The issue key that is the target of the link (outward issue)"},linkType:{type:"string",description:'The type of link to create between issues (e.g., "relates to", "blocks", "is blocked by")'},comment:{type:"string",description:"Optional comment to add when creating the link"},isEpicLink:{type:"boolean",description:"Set to true to create an Epic-Issue relationship. This will attempt to use the Epic Link field if available, falling back to standard issue linking if not."}}},parse:JSON.parse,function:({inwardIssueKey:g,outwardIssueKey:v,linkType:y,comment:x,isEpicLink:_})=>_Z({inwardIssueKey:g,outwardIssueKey:v,linkType:y,comment:x,isEpicLink:_},a,s,o,this.interactor)}};return i.push(u),i.push(l),i.push(f),i.push(p),i.push(d),i.push(m),i.push(h),i}};KT();var g7=new Map,Wve=!1,v7=class extends Zt{constructor(t,n,i,a){super(t,i,a);this.integrationService=n}static TYPE="SLACK";async buildTools(){let t=[];if(!this.integrationService.hasIntegration(this.name))return console.log("failed to have integration slack"),t;let n=this.integrationService.getApiKey(this.name);if(!n)return console.log("no bot token"),t;let i=async(p,d={},m="GET",h)=>{let g=new URL(`https://slack.com/api/${p}`);m==="GET"&&Object.entries(d).forEach(([_,S])=>{g.searchParams.append(_,S)});let v={method:m,headers:{Authorization:`Bearer ${n}`,"Content-Type":m==="POST"?"application/json; charset=utf-8":"application/x-www-form-urlencoded"}};m==="POST"&&h&&(v.body=JSON.stringify(h));let x=await(await fetch(g.toString(),v)).json();if(!x.ok)throw new Error(`Slack API error: ${x.error||"Unknown error"}`);return x},a=async()=>{if(!Wve)try{let p;do{let d={limit:"200"};p&&(d.cursor=p);let m=await i("users.list",d);m.members?.forEach(h=>{h.deleted||g7.set(h.id,h)}),p=m.response_metadata?.next_cursor}while(p);Wve=!0}catch(p){this.interactor.debug(`Failed to populate user cache: ${p}`)}},o=async p=>(await a(),p.replace(/<@([A-Z0-9]+)>/g,(d,m)=>{let h=g7.get(m);return h?`@${h.real_name||h.name}`:d})),s={type:"function",function:{name:`${this.name}__list_channels`,description:"List Slack channels where the bot is a member. Only returns channels the bot has been invited to and can actually read/write. Returns channel ID, name, topic, and member count.",parameters:{type:"object",properties:{types:{type:"string",description:'Comma-separated list of channel types. Options: public_channel, private_channel, mpim (group DM), im (direct message). Default: "public_channel,private_channel"'},limit:{type:"number",description:"Maximum number of channels to return (default: 100, max: 1000)"}}},parse:JSON.parse,function:async p=>{try{let d={types:p.types||"public_channel,private_channel",limit:String(p.limit||100),exclude_archived:"true"},h=(await i("users.conversations",d)).channels||[];if(h.length===0)return"No channels found. The bot may need to be invited to channels first.";let g=h.map(v=>({id:v.id,name:v.name,private:v.is_private,topic:v.topic?.value||"",purpose:v.purpose?.value||"",members:v.num_members}));return JSON.stringify(g,null,2)}catch(d){return`Error listing channels: ${d instanceof Error?d.message:String(d)}`}}}},c={type:"function",function:{name:`${this.name}__read_channel`,description:"Read messages from a Slack channel. Returns messages with timestamps, user mentions resolved to names, and thread indicators. Use slack_list_channels first to get channel IDs. The channel parameter is required.",parameters:{type:"object",properties:{channel:{type:"string",description:"Channel ID (e.g., C1234567890). Get this from slack_list_channels. REQUIRED."},limit:{type:"number",description:"Number of messages to return (default: 20, max: 100)"},oldest:{type:"string",description:'Only messages after this Unix timestamp (e.g., "1234567890.123456")'},latest:{type:"string",description:"Only messages before this Unix timestamp"}}},parse:JSON.parse,function:async p=>{try{if(!p.channel)return"Error: channel parameter is required. Use slack_list_channels to get available channel IDs.";let d={channel:p.channel,limit:String(p.limit||20)};p.oldest&&(d.oldest=p.oldest),p.latest&&(d.latest=p.latest);let h=(await i("conversations.history",d)).messages||[];if(h.length===0)return"No messages found in this channel.";let g=await Promise.all(h.map(async v=>{let y=v.user?g7.get(v.user):void 0,x=await o(v.text);return{timestamp:v.ts,user:y?.real_name||y?.name||v.user||"Unknown",text:x,hasThread:!!v.thread_ts&&v.reply_count&&v.reply_count>0,replyCount:v.reply_count||0}}));return g.reverse(),JSON.stringify(g,null,2)}catch(d){return`Error reading channel: ${d instanceof Error?d.message:String(d)}`}}}},u={type:"function",function:{name:`${this.name}__read_thread`,description:"Read replies in a Slack thread. Use the timestamp from slack_read_channel to identify the thread. Returns all messages in the thread including the parent message. Both channel and thread_ts parameters are required.",parameters:{type:"object",properties:{channel:{type:"string",description:"Channel ID where the thread is located. REQUIRED."},thread_ts:{type:"string",description:"Timestamp of the parent message (thread_ts from slack_read_channel). REQUIRED."},limit:{type:"number",description:"Maximum number of replies to return (default: 50, max: 100)"}}},parse:JSON.parse,function:async p=>{try{if(!p.channel||!p.thread_ts)return"Error: both channel and thread_ts parameters are required.";let d={channel:p.channel,ts:p.thread_ts,limit:String(p.limit||50)},h=(await i("conversations.replies",d)).messages||[];if(h.length===0)return"No messages found in this thread.";let g=await Promise.all(h.map(async v=>{let y=v.user?g7.get(v.user):void 0,x=await o(v.text);return{timestamp:v.ts,user:y?.real_name||y?.name||v.user||"Unknown",text:x,isParent:v.ts===p.thread_ts}}));return JSON.stringify(g,null,2)}catch(d){return`Error reading thread: ${d instanceof Error?d.message:String(d)}`}}}},l={type:"function",function:{name:`${this.name}__post_message`,description:'Post a message to a Slack channel or DM. Can also reply to a thread by providing thread_ts. The bot must be a member of the channel to post. Both channel and text parameters are required.\n\n## Message Posting Rules\n- When interacting with a user in Slack, prefer a direct message with the user unless asked otherwise or called from a channel.\n- To mention a user, use `<@firstname.lastname>` or `<@id_of_user>`.\n- Always keep it short, under 10 lines of text.\n\n## Slack Message Formatting Constraints\n\n**What works:**\n- `*text*` for bold (single asterisk)\n- `_text_` for italic\n- `` `code` `` for inline code\n- ` ``` code block ``` ` for code blocks\n- Bullet lists with `-`\n- Numbered lists with `1. 2. 3.`\n- Direct URLs (automatically clickable): https://example.com\n- Emojis\n\n**Link formatting:**\n- To display text with a link: `<https://example.com|Link text>` (pipe separator)\n- Example: `<https://github.com/user/repo|View repository>` displays as "View repository" (clickable)\n- Avoid posting raw URLs when you can use descriptive link text\n\n**Best practices for Slack:**\n- Use single asterisks `*text*` for emphasis/titles\n- Prefer descriptive link text over raw URLs for better readability\n- For multiple links, use link text format to keep messages clean',parameters:{type:"object",properties:{channel:{type:"string",description:"Channel ID to post to. For DMs, use the user ID or DM channel ID. REQUIRED."},text:{type:"string",description:"Message text to post. Supports Slack markdown (bold, italic, links, etc.). REQUIRED."},thread_ts:{type:"string",description:"Optional: timestamp of parent message to reply in thread"}}},parse:JSON.parse,function:async p=>{try{if(!p.channel||!p.text)return"Error: both channel and text parameters are required.";let d={channel:p.channel,text:p.text};p.thread_ts&&(d.thread_ts=p.thread_ts);let m=await i("chat.postMessage",{},"POST",d);return JSON.stringify({success:!0,channel:m.channel,timestamp:m.ts,message:"Message posted successfully"})}catch(d){return`Error posting message: ${d instanceof Error?d.message:String(d)}`}}}},f={type:"function",function:{name:`${this.name}__list_users`,description:"List Slack workspace users. Useful for finding user IDs to send DMs or understanding who is mentioned in messages.",parameters:{type:"object",properties:{limit:{type:"number",description:"Maximum number of users to return (default: 100)"}}},parse:JSON.parse,function:async p=>{try{await a();let d=Array.from(g7.values()).filter(m=>!m.is_bot).slice(0,p.limit||100).map(m=>({id:m.id,name:m.name,realName:m.real_name}));return JSON.stringify(d,null,2)}catch(d){return`Error listing users: ${d instanceof Error?d.message:String(d)}`}}}};return t.push(s,c,u,l,f),t}};var IZ;(typeof navigator>"u"||!navigator.userAgent?.startsWith?.("Mozilla/5.0 "))&&(IZ="oauth4webapi/v3.8.3");function qZ(r,e){if(r==null)return!1;try{return r instanceof e||Object.getPrototypeOf(r)[Symbol.toStringTag]===e.prototype[Symbol.toStringTag]}catch{return!1}}var du="ERR_INVALID_ARG_VALUE",Pl="ERR_INVALID_ARG_TYPE";function pi(r,e,t){let n=new TypeError(r,{cause:t});return Object.assign(n,{code:e}),n}var Gve=Symbol(),yvt=Symbol(),bvt=Symbol(),Zve=Symbol(),J4r=Symbol(),DZ=Symbol(),K4r=Symbol(),xvt=new TextEncoder,wvt=new TextDecoder;function OZ(r){return typeof r=="string"?xvt.encode(r):wvt.decode(r)}var $Z;Uint8Array.prototype.toBase64?$Z=r=>(r instanceof ArrayBuffer&&(r=new Uint8Array(r)),r.toBase64({alphabet:"base64url",omitPadding:!0})):$Z=e=>{e instanceof ArrayBuffer&&(e=new Uint8Array(e));let t=[];for(let n=0;n<e.byteLength;n+=32768)t.push(String.fromCharCode.apply(null,e.subarray(n,n+32768)));return btoa(t.join("")).replace(/=/g,"").replace(/\+/g,"-").replace(/\//g,"_")};var RZ;Uint8Array.fromBase64?RZ=r=>{try{return Uint8Array.fromBase64(r,{alphabet:"base64url"})}catch(e){throw pi("The input to be decoded is not correctly encoded.",du,e)}}:RZ=r=>{try{let e=atob(r.replace(/-/g,"+").replace(/_/g,"/").replace(/\s/g,"")),t=new Uint8Array(e.length);for(let n=0;n<e.length;n++)t[n]=e.charCodeAt(n);return t}catch(e){throw pi("The input to be decoded is not correctly encoded.",du,e)}};function XT(r){return typeof r=="string"?RZ(r):$Z(r)}var S4=class extends Error{code;constructor(e,t){super(e,t),this.name=this.constructor.name,this.code=Yvt,Error.captureStackTrace?.(this,this.constructor)}},jZ=class extends Error{code;constructor(e,t){super(e,t),this.name=this.constructor.name,t?.code&&(this.code=t?.code),Error.captureStackTrace?.(this,this.constructor)}};function Nt(r,e,t){return new jZ(r,{code:e,cause:t})}function QT(r){return!(r===null||typeof r!="object"||Array.isArray(r))}function Jve(r){qZ(r,Headers)&&(r=Object.fromEntries(r.entries()));let e=new Headers(r??{});if(IZ&&!e.has("user-agent")&&e.set("user-agent",IZ),e.has("authorization"))throw pi('"options.headers" must not include the "authorization" header name',du);return e}function Kve(r,e){if(e!==void 0){if(typeof e=="function"&&(e=e(r.href)),!(e instanceof AbortSignal))throw pi('"options.signal" must return or be an instance of AbortSignal',Pl);return e}}function y7(r,e,t,n,i){try{if(typeof r!="number"||!Number.isFinite(r))throw pi(`${t} must be a number`,Pl,i);if(r>0)return;if(e){if(r!==0)throw pi(`${t} must be a non-negative number`,du,i);return}throw pi(`${t} must be a positive number`,du,i)}catch(a){throw n?Nt(a.message,n,i):a}}function Na(r,e,t,n){try{if(typeof r!="string")throw pi(`${e} must be a string`,Pl,n);if(r.length===0)throw pi(`${e} must not be empty`,du,n)}catch(i){throw t?Nt(i.message,t,n):i}}function Yve(r){Svt(r,"application/json")}function _vt(r,...e){let t='"response" content-type must be ';if(e.length>2){let n=e.pop();t+=`${e.join(", ")}, or ${n}`}else e.length===2?t+=`${e[0]} or ${e[1]}`:t+=e[0];return Nt(t,Qvt,r)}function Svt(r,e){if(Mvt(r)!==e)throw _vt(r,e)}function Xve(){return XT(crypto.getRandomValues(new Uint8Array(32)))}function rP(){return Xve()}function nP(){return Xve()}async function iP(r){return Na(r,"codeVerifier"),XT(await crypto.subtle.digest("SHA-256",OZ(r)))}function UZ(r){let e=r?.[yvt];return typeof e=="number"&&Number.isFinite(e)?e:0}function zZ(r){let e=r?.[bvt];return typeof e=="number"&&Number.isFinite(e)&&Math.sign(e)!==-1?e:30}function BZ(){return Math.floor(Date.now()/1e3)}function aP(r){if(typeof r!="object"||r===null)throw pi('"as" must be an object',Pl);Na(r.issuer,'"as.issuer"')}function oP(r){if(typeof r!="object"||r===null)throw pi('"client" must be an object',Pl);Na(r.client_id,'"client.client_id"')}function sP(r){return Na(r,'"clientSecret"'),(e,t,n,i)=>{n.set("client_id",t.client_id),n.set("client_secret",r)}}var kvt=URL.parse?(r,e)=>URL.parse(r,e):(r,e)=>{try{return new URL(r,e)}catch{return null}};function Qve(r,e){if(e&&r.protocol!=="https:")throw Nt("only requests to HTTPS are allowed",tyt,r);if(r.protocol!=="https:"&&r.protocol!=="http:")throw Nt("only HTTP and HTTPS requests are allowed",ryt,r)}function Vve(r,e,t,n){let i;if(typeof r!="string"||!(i=kvt(r)))throw Nt(`authorization server metadata does not contain a valid ${t?`"as.mtls_endpoint_aliases.${e}"`:`"as.${e}"`}`,r===void 0?nyt:iyt,{attribute:t?`mtls_endpoint_aliases.${e}`:e});return Qve(i,n),i}function Evt(r,e,t,n){return t&&r.mtls_endpoint_aliases&&e in r.mtls_endpoint_aliases?Vve(r.mtls_endpoint_aliases[e],e,t,n):Vve(r[e],e,t,n)}var NZ=class extends Error{cause;code;error;status;error_description;response;constructor(e,t){super(e,t),this.name=this.constructor.name,this.code=Kvt,this.cause=t.cause,this.error=t.cause.error,this.status=t.response.status,this.error_description=t.cause.error_description,Object.defineProperty(this,"response",{enumerable:!1,value:t.response}),Error.captureStackTrace?.(this,this.constructor)}},FZ=class extends Error{cause;code;error;error_description;constructor(e,t){super(e,t),this.name=this.constructor.name,this.code=Xvt,this.cause=t.cause,this.error=t.cause.get("error"),this.error_description=t.cause.get("error_description")??void 0,Error.captureStackTrace?.(this,this.constructor)}},MZ=class extends Error{cause;code;response;status;constructor(e,t){super(e,t),this.name=this.constructor.name,this.code=Jvt,this.cause=t.cause,this.status=t.response.status,this.response=t.response,Object.defineProperty(this,"response",{enumerable:!1}),Error.captureStackTrace?.(this,this.constructor)}},eP="[a-zA-Z0-9!#$%&\\'\\*\\+\\-\\.\\^_`\\|~]+",Cvt="[a-zA-Z0-9\\-\\._\\~\\+\\/]+={0,2}",Avt='"((?:[^"\\\\]|\\\\[\\s\\S])*)"',Tvt="("+eP+")\\s*=\\s*"+Avt,Pvt="("+eP+")\\s*=\\s*("+eP+")",Ivt=new RegExp("^[,\\s]*("+eP+")"),Dvt=new RegExp("^[,\\s]*"+Tvt+"[,\\s]*(.*)"),Ovt=new RegExp("^[,\\s]*"+Pvt+"[,\\s]*(.*)"),$vt=new RegExp("^("+Cvt+")(?:$|[,\\s])(.*)");function Rvt(r){if(!qZ(r,Response))throw pi('"response" must be an instance of Response',Pl);let e=r.headers.get("www-authenticate");if(e===null)return;let t=[],n=e;for(;n;){let i=n.match(Ivt),a=i?.[1].toLowerCase();if(!a)return;let o=n.substring(i[0].length);if(o&&!o.match(/^[\s,]/))return;let s=o.match(/^\s+(.*)$/),c=!!s;n=s?s[1]:void 0;let u={},l;if(c)for(;n;){let p,d;if(i=n.match(Dvt)){if([,p,d,n]=i,d.includes("\\"))try{d=JSON.parse(`"${d}"`)}catch{}u[p.toLowerCase()]=d;continue}if(i=n.match(Ovt)){[,p,d,n]=i,u[p.toLowerCase()]=d;continue}if(i=n.match($vt)){if(Object.keys(u).length)break;[,l,n]=i;break}return}else n=o||void 0;let f={scheme:a,parameters:u};l&&(f.token68=l),t.push(f)}if(t.length)return t}async function jvt(r){if(r.status>399&&r.status<500){oye(r),Yve(r);try{let e=await r.clone().json();if(QT(e)&&typeof e.error=="string"&&e.error.length)return e}catch{}}}async function Nvt(r,e,t){if(r.status!==e){aye(r);let n;throw(n=await jvt(r))?(await r.body?.cancel(),new NZ("server responded with an error in the response body",{cause:n,response:r})):Nt(`"response" is not a conform ${t} response (unexpected HTTP status code)`,eyt,r)}}function eye(r){if(!WZ.has(r))throw pi('"options.DPoP" is not a valid DPoPHandle',du)}async function Fvt(r,e,t,n,i,a){if(Na(r,'"accessToken"'),!(t instanceof URL))throw pi('"url" must be an instance of URL',Pl);Qve(t,a?.[Gve]!==!0),n=Jve(n),a?.DPoP&&(eye(a.DPoP),await a.DPoP.addProof(t,n,e.toUpperCase(),r)),n.set("authorization",`${n.has("dpop")?"DPoP":"Bearer"} ${r}`);let o=await(a?.[Zve]||fetch)(t.href,{body:i,headers:Object.fromEntries(n.entries()),method:e,redirect:"manual",signal:Kve(t,a?.signal)});return a?.DPoP?.cacheNonce(o,t),o}async function tye(r,e,t,n,i,a){let o=await Fvt(r,e,t,n,i,a);return aye(o),o}var Y4r=Symbol();function Mvt(r){return r.headers.get("content-type")?.split(";")[0]}async function Lvt(r,e,t,n,i,a,o){return await t(r,e,i,a),a.set("content-type","application/x-www-form-urlencoded;charset=UTF-8"),(o?.[Zve]||fetch)(n.href,{body:i,headers:Object.fromEntries(a.entries()),method:"POST",redirect:"manual",signal:Kve(n,o?.signal)})}async function rye(r,e,t,n,i,a){let o=Evt(r,"token_endpoint",e.use_mtls_endpoint_aliases,a?.[Gve]!==!0);i.set("grant_type",n);let s=Jve(a?.headers);s.set("accept","application/json"),a?.DPoP!==void 0&&(eye(a.DPoP),await a.DPoP.addProof(o,s,"POST"));let c=await Lvt(r,e,t,o,i,s,a);return a?.DPoP?.cacheNonce(c,o),c}async function cP(r,e,t,n,i){aP(r),oP(e),Na(n,'"refreshToken"');let a=new URLSearchParams(i?.additionalParameters);return a.set("refresh_token",n),rye(r,e,t,"refresh_token",a,i)}var nye=new WeakMap,qvt=new WeakMap;function iye(r){if(!r.id_token)return;let e=nye.get(r);if(!e)throw pi('"ref" was already garbage collected or did not resolve from the proper sources',du);return e}async function HZ(r,e,t,n,i,a){if(aP(r),oP(e),!qZ(t,Response))throw pi('"response" must be an instance of Response',Pl);await Nvt(t,200,"Token Endpoint"),oye(t);let o=await uyt(t);if(Na(o.access_token,'"response" body "access_token" property',Gr,{body:o}),Na(o.token_type,'"response" body "token_type" property',Gr,{body:o}),o.token_type=o.token_type.toLowerCase(),o.expires_in!==void 0){let s=typeof o.expires_in!="number"?parseFloat(o.expires_in):o.expires_in;y7(s,!0,'"response" body "expires_in" property',Gr,{body:o}),o.expires_in=s}if(o.refresh_token!==void 0&&Na(o.refresh_token,'"response" body "refresh_token" property',Gr,{body:o}),o.scope!==void 0&&typeof o.scope!="string")throw Nt('"response" body "scope" property must be a string',Gr,{body:o});if(o.id_token!==void 0){Na(o.id_token,'"response" body "id_token" property',Gr,{body:o});let s=["aud","exp","iat","iss","sub"];e.require_auth_time===!0&&s.push("auth_time"),e.default_max_age!==void 0&&(y7(e.default_max_age,!0,'"client.default_max_age"'),s.push("auth_time")),n?.length&&s.push(...n);let{claims:c,jwt:u}=await ayt(o.id_token,oyt.bind(void 0,e.id_token_signed_response_alg,r.id_token_signing_alg_values_supported,"RS256"),UZ(e),zZ(e),i).then(Vvt.bind(void 0,s)).then(zvt.bind(void 0,r)).then(Uvt.bind(void 0,e.client_id));if(Array.isArray(c.aud)&&c.aud.length!==1){if(c.azp===void 0)throw Nt('ID Token "aud" (audience) claim includes additional untrusted audiences',Rf,{claims:c,claim:"aud"});if(c.azp!==e.client_id)throw Nt('unexpected ID Token "azp" (authorized party) claim value',Rf,{expected:e.client_id,claims:c,claim:"azp"})}c.auth_time!==void 0&&y7(c.auth_time,!0,'ID Token "auth_time" (authentication time)',Gr,{claims:c}),qvt.set(t,u),nye.set(o,c)}if(a?.[o.token_type]!==void 0)a[o.token_type](t,o);else if(o.token_type!=="dpop"&&o.token_type!=="bearer")throw new S4("unsupported `token_type` value",{cause:{body:o}});return o}function aye(r){let e;if(e=Rvt(r))throw new MZ("server responded with a challenge in the WWW-Authenticate HTTP Header",{cause:e,response:r})}async function uP(r,e,t,n){return HZ(r,e,t,void 0,n?.[DZ],n?.recognizedTokenTypes)}function Uvt(r,e){if(Array.isArray(e.claims.aud)){if(!e.claims.aud.includes(r))throw Nt('unexpected JWT "aud" (audience) claim value',Rf,{expected:r,claims:e.claims,claim:"aud"})}else if(e.claims.aud!==r)throw Nt('unexpected JWT "aud" (audience) claim value',Rf,{expected:r,claims:e.claims,claim:"aud"});return e}function zvt(r,e){let t=r[lyt]?.(e)??r.issuer;if(e.claims.iss!==t)throw Nt('unexpected JWT "iss" (issuer) claim value',Rf,{expected:t,claims:e.claims,claim:"iss"});return e}var WZ=new WeakSet;function Bvt(r){return WZ.add(r),r}var Hvt=Symbol();async function lP(r,e,t,n,i,a,o){if(aP(r),oP(e),!WZ.has(n))throw pi('"callbackParameters" must be an instance of URLSearchParams obtained from "validateAuthResponse()", or "validateJwtAuthResponse()',du);Na(i,'"redirectUri"');let s=i3(n,"code");if(!s)throw Nt('no authorization code in "callbackParameters"',Gr);let c=new URLSearchParams(o?.additionalParameters);return c.set("redirect_uri",i),c.set("code",s),a!==Hvt&&(Na(a,'"codeVerifier"'),c.set("code_verifier",a)),rye(r,e,t,"authorization_code",c,o)}var Wvt={aud:"audience",c_hash:"code hash",client_id:"client id",exp:"expiration time",iat:"issued at",iss:"issuer",jti:"jwt id",nonce:"nonce",s_hash:"state hash",sub:"subject",ath:"access token hash",htm:"http method",htu:"http uri",cnf:"confirmation",auth_time:"authentication time"};function Vvt(r,e){for(let t of r)if(e.claims[t]===void 0)throw Nt(`JWT "${t}" (${Wvt[t]}) claim missing`,Gr,{claims:e.claims});return e}var TZ=Symbol(),PZ=Symbol();async function fP(r,e,t,n){return typeof n?.expectedNonce=="string"||typeof n?.maxAge=="number"||n?.requireIdToken?Gvt(r,e,t,n.expectedNonce,n.maxAge,n[DZ],n.recognizedTokenTypes):Zvt(r,e,t,n?.[DZ],n?.recognizedTokenTypes)}async function Gvt(r,e,t,n,i,a,o){let s=[];switch(n){case void 0:n=TZ;break;case TZ:break;default:Na(n,'"expectedNonce" argument'),s.push("nonce")}switch(i??=e.default_max_age,i){case void 0:i=PZ;break;case PZ:break;default:y7(i,!0,'"maxAge" argument'),s.push("auth_time")}let c=await HZ(r,e,t,s,a,o);Na(c.id_token,'"response" body "id_token" property',Gr,{body:c});let u=iye(c);if(i!==PZ){let l=BZ()+UZ(e),f=zZ(e);if(u.auth_time+i<l-f)throw Nt("too much time has elapsed since the last End-User authentication",tP,{claims:u,now:l,tolerance:f,claim:"auth_time"})}if(n===TZ){if(u.nonce!==void 0)throw Nt('unexpected ID Token "nonce" claim value',Rf,{expected:void 0,claims:u,claim:"nonce"})}else if(u.nonce!==n)throw Nt('unexpected ID Token "nonce" claim value',Rf,{expected:n,claims:u,claim:"nonce"});return c}async function Zvt(r,e,t,n,i){let a=await HZ(r,e,t,void 0,n,i),o=iye(a);if(o){if(e.default_max_age!==void 0){y7(e.default_max_age,!0,'"client.default_max_age"');let s=BZ()+UZ(e),c=zZ(e);if(o.auth_time+e.default_max_age<s-c)throw Nt("too much time has elapsed since the last End-User authentication",tP,{claims:o,now:s,tolerance:c,claim:"auth_time"})}if(o.nonce!==void 0)throw Nt('unexpected ID Token "nonce" claim value',Rf,{expected:void 0,claims:o,claim:"nonce"})}return a}var Jvt="OAUTH_WWW_AUTHENTICATE_CHALLENGE",Kvt="OAUTH_RESPONSE_BODY_ERROR",Yvt="OAUTH_UNSUPPORTED_OPERATION",Xvt="OAUTH_AUTHORIZATION_RESPONSE_ERROR";var LZ="OAUTH_PARSE_ERROR",Gr="OAUTH_INVALID_RESPONSE";var Qvt="OAUTH_RESPONSE_IS_NOT_JSON",eyt="OAUTH_RESPONSE_IS_NOT_CONFORM",tyt="OAUTH_HTTP_REQUEST_FORBIDDEN",ryt="OAUTH_REQUEST_PROTOCOL_FORBIDDEN",tP="OAUTH_JWT_TIMESTAMP_CHECK_FAILED",Rf="OAUTH_JWT_CLAIM_COMPARISON_FAILED";var nyt="OAUTH_MISSING_SERVER_METADATA",iyt="OAUTH_INVALID_SERVER_METADATA";function oye(r){if(r.bodyUsed)throw pi('"response" body has been used already',du)}async function ayt(r,e,t,n,i){let{0:a,1:o,length:s}=r.split(".");if(s===5)if(i!==void 0)r=await i(r),{0:a,1:o,length:s}=r.split(".");else throw new S4("JWE decryption is not configured",{cause:r});if(s!==3)throw Nt("Invalid JWT",Gr,r);let c;try{c=JSON.parse(OZ(XT(a)))}catch(f){throw Nt("failed to parse JWT Header body as base64url encoded JSON",LZ,f)}if(!QT(c))throw Nt("JWT Header must be a top level object",Gr,r);if(e(c),c.crit!==void 0)throw new S4('no JWT "crit" header parameter extensions are supported',{cause:{header:c}});let u;try{u=JSON.parse(OZ(XT(o)))}catch(f){throw Nt("failed to parse JWT Payload body as base64url encoded JSON",LZ,f)}if(!QT(u))throw Nt("JWT Payload must be a top level object",Gr,r);let l=BZ()+t;if(u.exp!==void 0){if(typeof u.exp!="number")throw Nt('unexpected JWT "exp" (expiration time) claim type',Gr,{claims:u});if(u.exp<=l-n)throw Nt('unexpected JWT "exp" (expiration time) claim value, expiration is past current timestamp',tP,{claims:u,now:l,tolerance:n,claim:"exp"})}if(u.iat!==void 0&&typeof u.iat!="number")throw Nt('unexpected JWT "iat" (issued at) claim type',Gr,{claims:u});if(u.iss!==void 0&&typeof u.iss!="string")throw Nt('unexpected JWT "iss" (issuer) claim type',Gr,{claims:u});if(u.nbf!==void 0){if(typeof u.nbf!="number")throw Nt('unexpected JWT "nbf" (not before) claim type',Gr,{claims:u});if(u.nbf>l+n)throw Nt('unexpected JWT "nbf" (not before) claim value',tP,{claims:u,now:l,tolerance:n,claim:"nbf"})}if(u.aud!==void 0&&typeof u.aud!="string"&&!Array.isArray(u.aud))throw Nt('unexpected JWT "aud" (audience) claim type',Gr,{claims:u});return{header:c,claims:u,jwt:r}}function oyt(r,e,t,n){if(r!==void 0){if(typeof r=="string"?n.alg!==r:!r.includes(n.alg))throw Nt('unexpected JWT "alg" header parameter',Gr,{header:n,expected:r,reason:"client configuration"});return}if(Array.isArray(e)){if(!e.includes(n.alg))throw Nt('unexpected JWT "alg" header parameter',Gr,{header:n,expected:e,reason:"authorization server metadata"});return}if(t!==void 0){if(typeof t=="string"?n.alg!==t:typeof t=="function"?!t(n.alg):!t.includes(n.alg))throw Nt('unexpected JWT "alg" header parameter',Gr,{header:n,expected:t,reason:"default value"});return}throw Nt('missing client or server configuration to verify used JWT "alg" header parameter',void 0,{client:r,issuer:e,fallback:t})}function i3(r,e){let{0:t,length:n}=r.getAll(e);if(n>1)throw Nt(`"${e}" parameter must be provided only once`,Gr);return t}var syt=Symbol(),cyt=Symbol();function pP(r,e,t,n){if(aP(r),oP(e),t instanceof URL&&(t=t.searchParams),!(t instanceof URLSearchParams))throw pi('"parameters" must be an instance of URLSearchParams, or URL',Pl);if(i3(t,"response"))throw Nt('"parameters" contains a JARM response, use validateJwtAuthResponse() instead of validateAuthResponse()',Gr,{parameters:t});let i=i3(t,"iss"),a=i3(t,"state");if(!i&&r.authorization_response_iss_parameter_supported)throw Nt('response parameter "iss" (issuer) missing',Gr,{parameters:t});if(i&&i!==r.issuer)throw Nt('unexpected "iss" (issuer) response parameter value',Gr,{expected:r.issuer,parameters:t});switch(n){case void 0:case cyt:if(a!==void 0)throw Nt('unexpected "state" response parameter encountered',Gr,{expected:void 0,parameters:t});break;case syt:break;default:if(Na(n,'"expectedState" argument'),a!==n)throw Nt(a===void 0?'response parameter "state" missing':'unexpected "state" response parameter value',Gr,{expected:n,parameters:t})}if(i3(t,"error"))throw new FZ("authorization response from the server is an error",{cause:t});let s=i3(t,"id_token"),c=i3(t,"token");if(s!==void 0||c!==void 0)throw new S4("implicit and hybrid flows are not supported");return Bvt(new URLSearchParams(t))}async function uyt(r,e=Yve){let t;try{t=await r.json()}catch(n){throw e(r),Nt('failed to parse "response" body as JSON',LZ,n)}if(!QT(t))throw Nt('"response" body must be a top level object',Gr,{body:t});return t}var X4r=Symbol(),lyt=Symbol();var dP=class{constructor(e,t,n,i,a,o,s="BASECAMP"){this.redirectUri=n;this.interactor=i;this.userService=a;this.integrationName=s;this.resolvedProjectName=a.resolveProjectName(o),this.as={issuer:"https://launchpad.37signals.com",authorization_endpoint:"https://launchpad.37signals.com/authorization/new",token_endpoint:"https://launchpad.37signals.com/authorization/token"},this.client={client_id:e},this.clientAuth=sP(t)}as;client;clientAuth;tokenData=null;accounts=[];selectedAccountHref=null;pendingState=null;pendingCodeVerifier=null;pendingResolve=null;pendingReject=null;resolvedProjectName;isAuthenticated(){return this.tokenData||this.loadTokensFromStorage(),this.tokenData?this.tokenData.expiresAt>Date.now()+300*1e3:!1}async getAccessToken(){if(!this.tokenData)throw new Error("Not authenticated. Call authenticate() first.");return!this.isAuthenticated()&&this.tokenData.refreshToken&&await this.refreshToken(),this.tokenData.accessToken}getApiBaseUrl(){if(!this.selectedAccountHref)throw new Error("No account selected");return this.selectedAccountHref}async authenticate(){if(this.isAuthenticated())return this.tokenData;let e=nP(),t=rP(),n=await iP(t);this.pendingState=e,this.pendingCodeVerifier=t;let i=new URL(this.as.authorization_endpoint);return i.searchParams.set("client_id",this.client.client_id),i.searchParams.set("redirect_uri",this.redirectUri),i.searchParams.set("response_type","code"),i.searchParams.set("state",e),i.searchParams.set("code_challenge",n),i.searchParams.set("code_challenge_method","S256"),i.searchParams.set("type","web_server"),this.interactor.sendEvent(new Ic({authUrl:i.toString(),state:e,integrationName:"BASECAMP"})),new Promise((a,o)=>{this.pendingResolve=a,this.pendingReject=o})}async handleCallback(e){if(e.integrationName==="BASECAMP"){if(e.state!==this.pendingState){this.interactor.error("Invalid OAuth state");return}if(e.error){let t=e.error==="access_denied"?"OAuth authentication denied by user":e.error==="user_cancelled"?"OAuth authentication cancelled by user":`OAuth error: ${e.error}${e.errorDescription?" - "+e.errorDescription:""}`;this.interactor.warn(t),this.pendingReject&&(this.pendingReject(new Error(t)),this.pendingReject=null),this.pendingResolve=null,this.pendingState=null,this.pendingCodeVerifier=null;return}if(!e.code||!this.pendingCodeVerifier||!this.pendingState){this.interactor.error("No pending OAuth flow or missing code");return}try{let t=new URL(this.redirectUri);t.searchParams.set("code",e.code),t.searchParams.set("state",e.state);let n=pP(this.as,this.client,t,this.pendingState),i=await lP(this.as,this.client,this.clientAuth,n,this.redirectUri,this.pendingCodeVerifier,{additionalParameters:new URLSearchParams({type:"web_server"})});this.interactor.debug(`Token exchange response status: ${i.status}`);let a=await i.text();i=new Response(a,{status:i.status,statusText:i.statusText,headers:i.headers});let o;try{o=await fP(this.as,this.client,i),this.interactor.debug("oauth4webapi validation succeeded")}catch(s){if(this.interactor.debug(`Using manual parsing for Basecamp response: ${s.message}`),!i.ok)throw new Error(`Token exchange failed: ${i.status}`);o=JSON.parse(a),this.interactor.debug("Token response parsed successfully")}this.tokenData={accessToken:o.access_token,refreshToken:o.refresh_token,expiresAt:Date.now()+(o.expires_in??1209600)*1e3},await this.fetchAccounts(),this.saveTokensToStorage(),this.pendingResolve&&(this.pendingResolve(this.tokenData),this.pendingResolve=null),this.pendingState=null,this.pendingCodeVerifier=null}catch(t){this.interactor.error(`OAuth token exchange failed: ${t.message}`),this.pendingState=null,this.pendingCodeVerifier=null}}}async fetchAccounts(){if(this.tokenData)try{let e=await tye(this.tokenData.accessToken,"GET",new URL("https://launchpad.37signals.com/authorization.json"),void 0,void 0);if(!e.ok)return;let t=await e.json();if(this.accounts=t.accounts.filter(n=>n.product==="bc3").map(n=>({id:n.id,name:n.name,href:n.href})),this.accounts.length>0){let n=this.accounts[0];n&&(this.selectedAccountHref=n.href,this.interactor.displayText(`Connected to Basecamp account: ${n.name}`))}}catch(e){this.interactor.warn(`Failed to fetch Basecamp accounts: ${e.message}`)}}async refreshToken(){if(!this.tokenData?.refreshToken)throw new Error("No refresh token available");try{let e=await cP(this.as,this.client,this.clientAuth,this.tokenData.refreshToken,{additionalParameters:new URLSearchParams({type:"refresh"})}),t=await uP(this.as,this.client,e);this.tokenData={accessToken:t.access_token,refreshToken:t.refresh_token??this.tokenData.refreshToken,expiresAt:Date.now()+(t.expires_in??1209600)*1e3},this.saveTokensToStorage()}catch(e){throw this.tokenData=null,this.clearTokensFromStorage(),new Error(`Token refresh failed: ${e.message}`)}}loadTokensFromStorage(){let t=this.userService.config.projects?.[this.resolvedProjectName]?.integration?.[this.integrationName]?.oauth2,n=t?.tokens,i=t?.account_href,a=t?.account_name;if(n){this.tokenData={accessToken:n.access_token,refreshToken:n.refresh_token,expiresAt:n.expires_at},i&&(this.selectedAccountHref=i),this.interactor.debug(`Loaded OAuth tokens from storage for ${this.integrationName}`);let o=new Date(this.tokenData.expiresAt),s=new Date,c=this.tokenData.expiresAt-s.getTime(),u=Math.floor(c/(1e3*60*60*24)),l=Math.floor(c%(1e3*60*60*24)/(1e3*60*60));this.interactor.debug(`Token expires at: ${o.toLocaleString()} (in ${u}d ${l}h)`),a&&this.interactor.displayText(`Using stored Basecamp account: ${a}`)}}saveTokensToStorage(){if(!this.tokenData)return;let e=this.userService.config;e.projects||(e.projects={}),e.projects[this.resolvedProjectName]||(e.projects[this.resolvedProjectName]={integration:{}}),e.projects[this.resolvedProjectName].integration||(e.projects[this.resolvedProjectName].integration={}),e.projects[this.resolvedProjectName].integration[this.integrationName]||(e.projects[this.resolvedProjectName].integration[this.integrationName]={}),e.projects[this.resolvedProjectName].integration[this.integrationName].oauth2||(e.projects[this.resolvedProjectName].integration[this.integrationName].oauth2={});let t=e.projects[this.resolvedProjectName].integration[this.integrationName].oauth2;t.tokens={access_token:this.tokenData.accessToken,refresh_token:this.tokenData.refreshToken,expires_at:this.tokenData.expiresAt},this.selectedAccountHref&&(t.account_href=this.selectedAccountHref);let n=this.accounts.find(u=>u.href===this.selectedAccountHref);n&&(t.account_name=n.name),this.userService.save();let i=new Date(this.tokenData.expiresAt),a=new Date,o=this.tokenData.expiresAt-a.getTime(),s=Math.floor(o/(1e3*60*60*24)),c=Math.floor(o%(1e3*60*60*24)/(1e3*60*60));this.interactor.debug(`Saved OAuth tokens to storage for ${this.integrationName}. Expires at: ${i.toLocaleString()} (in ${s}d ${c}h)`)}clearTokensFromStorage(){let t=this.userService.config.projects?.[this.resolvedProjectName]?.integration?.[this.integrationName]?.oauth2;t&&(delete t.tokens,delete t.account_href,delete t.account_name,this.userService.save(),this.interactor.debug(`Cleared OAuth tokens from storage for ${this.integrationName}`))}};async function cye(r,e){try{r.isAuthenticated()||await r.authenticate();let t=await r.getAccessToken(),n=r.getApiBaseUrl(),i=e?`${n}/projects.json?page=${e}`:`${n}/projects.json`,a=await fetch(i,{headers:{Authorization:`Bearer ${t}`,"User-Agent":"Coday (https://github.com/whoz-oss/coday)"}});if(!a.ok)return`Error fetching projects: ${a.status} ${a.statusText}`;let o=await a.json(),s=a.headers.get("X-Total-Count"),c=a.headers.get("Link"),u=null;if(c){let p=c.match(/page=(\d+)>; rel="next"/);p&&p[1]&&(u=parseInt(p[1],10))}if(o.length===0)return"No projects found in this Basecamp account.";let l=o.map(p=>{let d=(p.dock||[]).map(m=>` - ${m.title} (ID: ${m.id}, type: ${m.name})${m.enabled?"":" [disabled]"}`).join(`
|
|
1302
|
+
`,parameters:{type:"object",properties:{jql:{type:"string",description:"JQL query for counting issues"}}},parse:JSON.parse,function:async({jql:g})=>{let v=await this.jiraService.ensureInitialized();return v.isNewlyInitialized?{fieldMappingInfo:v.fieldMappingInfo,message:v.message}:(v.fieldMapping&&wZ(g,v.fieldMapping),Lve(g,a,s,o,this.interactor))}}},m={type:"function",function:{name:`${this.name}__postIssue`,description:"Create a new Jira issue/ticket without asking for more information from the user, directly call the function to create the ticket",parameters:{type:"object",properties:{request:{type:"object",description:"Request object containing all issue fields",properties:{projectKey:{type:"string",description:"Project key where the issue will be created"},summary:{type:"string",description:"Summary/title of the issue"},description:{type:"string",description:"Detailed description of the issue"},issuetype:{type:"string",description:"Type of issue"},assignee:{type:"string",description:"User ID of the assignee"},reporter:{type:"string",description:"User ID of the reporter"},priority:{type:"string",description:'Priority of the issue (e.g., "High", "Medium", "Low")'},labels:{type:"array",items:{type:"string"},description:"Labels to attach to the issue"},components:{type:"array",items:{type:"string"},description:"Components to associate with the issue"},fixVersions:{type:"array",items:{type:"string"},description:"Fix versions to associate with the issue"},duedate:{type:"string",description:"Due date in YYYY-MM-DD format"},parent:{type:"object",properties:{key:{type:"string",description:"The issue key of the parent"}},description:"Parent issue for this issue (directly establishes parent-child relationship)"},linkedIssues:{type:"array",items:{type:"object",properties:{key:{type:"string",description:"The key of the issue to link"},linkType:{type:"string",description:'The type of link to create (default: "is part of" for epics, "relates to" for other issue types)'},isEpicLink:{type:"boolean",description:"Whether to use Epic Link field if available (default: true for epics)"}}},description:"Issues to link to this issue after creation (especially useful for epics)"}}}}},parse:JSON.parse,function:async({request:g})=>{try{if(g.error&&g.partialRequest){let v=g.partialRequest,y=g.error||"Previous attempt failed";return this.interactor.displayText(`Retrying Jira issue creation with saved information. Previous error: ${y}`),await EZ(v,a,s,o,this.interactor)}return await EZ(g,a,s,o,this.interactor)}catch(v){throw this.interactor.error(`Error in createJiraIssue function: ${v}`),v}}}},h={type:"function",function:{name:`${this.name}__linkIssues`,description:"Link two Jira issues with a specified relationship type",parameters:{type:"object",properties:{inwardIssueKey:{type:"string",description:"The issue key that is the source of the link (inward issue)"},outwardIssueKey:{type:"string",description:"The issue key that is the target of the link (outward issue)"},linkType:{type:"string",description:'The type of link to create between issues (e.g., "relates to", "blocks", "is blocked by")'},comment:{type:"string",description:"Optional comment to add when creating the link"},isEpicLink:{type:"boolean",description:"Set to true to create an Epic-Issue relationship. This will attempt to use the Epic Link field if available, falling back to standard issue linking if not."}}},parse:JSON.parse,function:({inwardIssueKey:g,outwardIssueKey:v,linkType:y,comment:x,isEpicLink:_})=>_Z({inwardIssueKey:g,outwardIssueKey:v,linkType:y,comment:x,isEpicLink:_},a,s,o,this.interactor)}};return i.push(u),i.push(l),i.push(f),i.push(p),i.push(d),i.push(m),i.push(h),i}};KT();var g7=new Map,Wve=!1,v7=class extends Zt{constructor(t,n,i,a){super(t,i,a);this.integrationService=n}static TYPE="SLACK";async buildTools(){let t=[];if(!this.integrationService.hasIntegration(this.name))return console.log("failed to have integration slack"),t;let n=this.integrationService.getApiKey(this.name);if(!n)return console.log("no bot token"),t;let i=async(p,d={},m="GET",h)=>{let g=new URL(`https://slack.com/api/${p}`);m==="GET"&&Object.entries(d).forEach(([_,S])=>{g.searchParams.append(_,S)});let v={method:m,headers:{Authorization:`Bearer ${n}`,"Content-Type":m==="POST"?"application/json; charset=utf-8":"application/x-www-form-urlencoded"}};m==="POST"&&h&&(v.body=JSON.stringify(h));let x=await(await fetch(g.toString(),v)).json();if(!x.ok)throw new Error(`Slack API error: ${x.error||"Unknown error"}`);return x},a=async()=>{if(!Wve)try{let p;do{let d={limit:"200"};p&&(d.cursor=p);let m=await i("users.list",d);m.members?.forEach(h=>{h.deleted||g7.set(h.id,h)}),p=m.response_metadata?.next_cursor}while(p);Wve=!0}catch(p){this.interactor.debug(`Failed to populate user cache: ${p}`)}},o=async p=>(await a(),p.replace(/<@([A-Z0-9]+)>/g,(d,m)=>{let h=g7.get(m);return h?`@${h.real_name||h.name}`:d})),s={type:"function",function:{name:`${this.name}__list_channels`,description:"List Slack channels where the bot is a member. Only returns channels the bot has been invited to and can actually read/write. Returns channel ID, name, topic, and member count.",parameters:{type:"object",properties:{types:{type:"string",description:'Comma-separated list of channel types. Options: public_channel, private_channel, mpim (group DM), im (direct message). Default: "public_channel,private_channel"'},limit:{type:"number",description:"Maximum number of channels to return (default: 100, max: 1000)"}}},parse:JSON.parse,function:async p=>{try{let d={types:p.types||"public_channel,private_channel",limit:String(p.limit||100),exclude_archived:"true"},h=(await i("users.conversations",d)).channels||[];if(h.length===0)return"No channels found. The bot may need to be invited to channels first.";let g=h.map(v=>({id:v.id,name:v.name,private:v.is_private,topic:v.topic?.value||"",purpose:v.purpose?.value||"",members:v.num_members}));return JSON.stringify(g,null,2)}catch(d){return`Error listing channels: ${d instanceof Error?d.message:String(d)}`}}}},c={type:"function",function:{name:`${this.name}__read_channel`,description:"Read messages from a Slack channel. Returns messages with timestamps, user mentions resolved to names, and thread indicators. Use slack_list_channels first to get channel IDs. The channel parameter is required.",parameters:{type:"object",properties:{channel:{type:"string",description:"Channel ID (e.g., C1234567890). Get this from slack_list_channels. REQUIRED."},limit:{type:"number",description:"Number of messages to return (default: 20, max: 100)"},oldest:{type:"string",description:'Only messages after this Unix timestamp (e.g., "1234567890.123456")'},latest:{type:"string",description:"Only messages before this Unix timestamp"}}},parse:JSON.parse,function:async p=>{try{if(!p.channel)return"Error: channel parameter is required. Use slack_list_channels to get available channel IDs.";let d={channel:p.channel,limit:String(p.limit||20)};p.oldest&&(d.oldest=p.oldest),p.latest&&(d.latest=p.latest);let h=(await i("conversations.history",d)).messages||[];if(h.length===0)return"No messages found in this channel.";let g=await Promise.all(h.map(async v=>{let y=v.user?g7.get(v.user):void 0,x=await o(v.text);return{timestamp:v.ts,user:y?.real_name||y?.name||v.user||"Unknown",text:x,hasThread:!!v.thread_ts&&v.reply_count&&v.reply_count>0,replyCount:v.reply_count||0}}));return g.reverse(),JSON.stringify(g,null,2)}catch(d){return`Error reading channel: ${d instanceof Error?d.message:String(d)}`}}}},u={type:"function",function:{name:`${this.name}__read_thread`,description:"Read replies in a Slack thread. Use the timestamp from slack_read_channel to identify the thread. Returns all messages in the thread including the parent message. Both channel and thread_ts parameters are required.",parameters:{type:"object",properties:{channel:{type:"string",description:"Channel ID where the thread is located. REQUIRED."},thread_ts:{type:"string",description:"Timestamp of the parent message (thread_ts from slack_read_channel). REQUIRED."},limit:{type:"number",description:"Maximum number of replies to return (default: 50, max: 100)"}}},parse:JSON.parse,function:async p=>{try{if(!p.channel||!p.thread_ts)return"Error: both channel and thread_ts parameters are required.";let d={channel:p.channel,ts:p.thread_ts,limit:String(p.limit||50)},h=(await i("conversations.replies",d)).messages||[];if(h.length===0)return"No messages found in this thread.";let g=await Promise.all(h.map(async v=>{let y=v.user?g7.get(v.user):void 0,x=await o(v.text);return{timestamp:v.ts,user:y?.real_name||y?.name||v.user||"Unknown",text:x,isParent:v.ts===p.thread_ts}}));return JSON.stringify(g,null,2)}catch(d){return`Error reading thread: ${d instanceof Error?d.message:String(d)}`}}}},l={type:"function",function:{name:`${this.name}__post_message`,description:'Post a message to a Slack channel or DM. Can also reply to a thread by providing thread_ts. The bot must be a member of the channel to post. Both channel and text parameters are required.\n\n## Message Posting Rules\n- When interacting with a user in Slack, prefer a direct message with the user unless asked otherwise or called from a channel.\n- To mention a user, use `<@firstname.lastname>` or `<@id_of_user>`.\n- Always keep it short, under 10 lines of text.\n\n## Slack Message Formatting Constraints\n\n**What works:**\n- `*text*` for bold (single asterisk)\n- `_text_` for italic\n- `` `code` `` for inline code\n- ` ``` code block ``` ` for code blocks\n- Bullet lists with `-`\n- Numbered lists with `1. 2. 3.`\n- Direct URLs (automatically clickable): https://example.com\n- Emojis\n\n**Link formatting:**\n- To display text with a link: `<https://example.com|Link text>` (pipe separator)\n- Example: `<https://github.com/user/repo|View repository>` displays as "View repository" (clickable)\n- Avoid posting raw URLs when you can use descriptive link text\n\n**Best practices for Slack:**\n- Use single asterisks `*text*` for emphasis/titles\n- Prefer descriptive link text over raw URLs for better readability\n- For multiple links, use link text format to keep messages clean',parameters:{type:"object",properties:{channel:{type:"string",description:"Channel ID to post to. For DMs, use the user ID or DM channel ID. REQUIRED."},text:{type:"string",description:"Message text to post. Supports Slack markdown (bold, italic, links, etc.). REQUIRED."},thread_ts:{type:"string",description:"Optional: timestamp of parent message to reply in thread"}}},parse:JSON.parse,function:async p=>{try{if(!p.channel||!p.text)return"Error: both channel and text parameters are required.";let d={channel:p.channel,text:p.text};p.thread_ts&&(d.thread_ts=p.thread_ts);let m=await i("chat.postMessage",{},"POST",d);return JSON.stringify({success:!0,channel:m.channel,timestamp:m.ts,message:"Message posted successfully"})}catch(d){return`Error posting message: ${d instanceof Error?d.message:String(d)}`}}}},f={type:"function",function:{name:`${this.name}__list_users`,description:"List Slack workspace users. Useful for finding user IDs to send DMs or understanding who is mentioned in messages.",parameters:{type:"object",properties:{limit:{type:"number",description:"Maximum number of users to return (default: 100)"}}},parse:JSON.parse,function:async p=>{try{await a();let d=Array.from(g7.values()).filter(m=>!m.is_bot).slice(0,p.limit||100).map(m=>({id:m.id,name:m.name,realName:m.real_name}));return JSON.stringify(d,null,2)}catch(d){return`Error listing users: ${d instanceof Error?d.message:String(d)}`}}}};return t.push(s,c,u,l,f),t}};var IZ;(typeof navigator>"u"||!navigator.userAgent?.startsWith?.("Mozilla/5.0 "))&&(IZ="oauth4webapi/v3.8.3");function qZ(r,e){if(r==null)return!1;try{return r instanceof e||Object.getPrototypeOf(r)[Symbol.toStringTag]===e.prototype[Symbol.toStringTag]}catch{return!1}}var du="ERR_INVALID_ARG_VALUE",Pl="ERR_INVALID_ARG_TYPE";function pi(r,e,t){let n=new TypeError(r,{cause:t});return Object.assign(n,{code:e}),n}var Gve=Symbol(),yvt=Symbol(),bvt=Symbol(),Zve=Symbol(),J4r=Symbol(),DZ=Symbol(),K4r=Symbol(),xvt=new TextEncoder,wvt=new TextDecoder;function OZ(r){return typeof r=="string"?xvt.encode(r):wvt.decode(r)}var $Z;Uint8Array.prototype.toBase64?$Z=r=>(r instanceof ArrayBuffer&&(r=new Uint8Array(r)),r.toBase64({alphabet:"base64url",omitPadding:!0})):$Z=e=>{e instanceof ArrayBuffer&&(e=new Uint8Array(e));let t=[];for(let n=0;n<e.byteLength;n+=32768)t.push(String.fromCharCode.apply(null,e.subarray(n,n+32768)));return btoa(t.join("")).replace(/=/g,"").replace(/\+/g,"-").replace(/\//g,"_")};var RZ;Uint8Array.fromBase64?RZ=r=>{try{return Uint8Array.fromBase64(r,{alphabet:"base64url"})}catch(e){throw pi("The input to be decoded is not correctly encoded.",du,e)}}:RZ=r=>{try{let e=atob(r.replace(/-/g,"+").replace(/_/g,"/").replace(/\s/g,"")),t=new Uint8Array(e.length);for(let n=0;n<e.length;n++)t[n]=e.charCodeAt(n);return t}catch(e){throw pi("The input to be decoded is not correctly encoded.",du,e)}};function XT(r){return typeof r=="string"?RZ(r):$Z(r)}var S4=class extends Error{code;constructor(e,t){super(e,t),this.name=this.constructor.name,this.code=Yvt,Error.captureStackTrace?.(this,this.constructor)}},jZ=class extends Error{code;constructor(e,t){super(e,t),this.name=this.constructor.name,t?.code&&(this.code=t?.code),Error.captureStackTrace?.(this,this.constructor)}};function Nt(r,e,t){return new jZ(r,{code:e,cause:t})}function QT(r){return!(r===null||typeof r!="object"||Array.isArray(r))}function Jve(r){qZ(r,Headers)&&(r=Object.fromEntries(r.entries()));let e=new Headers(r??{});if(IZ&&!e.has("user-agent")&&e.set("user-agent",IZ),e.has("authorization"))throw pi('"options.headers" must not include the "authorization" header name',du);return e}function Kve(r,e){if(e!==void 0){if(typeof e=="function"&&(e=e(r.href)),!(e instanceof AbortSignal))throw pi('"options.signal" must return or be an instance of AbortSignal',Pl);return e}}function y7(r,e,t,n,i){try{if(typeof r!="number"||!Number.isFinite(r))throw pi(`${t} must be a number`,Pl,i);if(r>0)return;if(e){if(r!==0)throw pi(`${t} must be a non-negative number`,du,i);return}throw pi(`${t} must be a positive number`,du,i)}catch(a){throw n?Nt(a.message,n,i):a}}function Na(r,e,t,n){try{if(typeof r!="string")throw pi(`${e} must be a string`,Pl,n);if(r.length===0)throw pi(`${e} must not be empty`,du,n)}catch(i){throw t?Nt(i.message,t,n):i}}function Yve(r){Svt(r,"application/json")}function _vt(r,...e){let t='"response" content-type must be ';if(e.length>2){let n=e.pop();t+=`${e.join(", ")}, or ${n}`}else e.length===2?t+=`${e[0]} or ${e[1]}`:t+=e[0];return Nt(t,Qvt,r)}function Svt(r,e){if(Mvt(r)!==e)throw _vt(r,e)}function Xve(){return XT(crypto.getRandomValues(new Uint8Array(32)))}function rP(){return Xve()}function nP(){return Xve()}async function iP(r){return Na(r,"codeVerifier"),XT(await crypto.subtle.digest("SHA-256",OZ(r)))}function UZ(r){let e=r?.[yvt];return typeof e=="number"&&Number.isFinite(e)?e:0}function zZ(r){let e=r?.[bvt];return typeof e=="number"&&Number.isFinite(e)&&Math.sign(e)!==-1?e:30}function BZ(){return Math.floor(Date.now()/1e3)}function aP(r){if(typeof r!="object"||r===null)throw pi('"as" must be an object',Pl);Na(r.issuer,'"as.issuer"')}function oP(r){if(typeof r!="object"||r===null)throw pi('"client" must be an object',Pl);Na(r.client_id,'"client.client_id"')}function sP(r){return Na(r,'"clientSecret"'),(e,t,n,i)=>{n.set("client_id",t.client_id),n.set("client_secret",r)}}var kvt=URL.parse?(r,e)=>URL.parse(r,e):(r,e)=>{try{return new URL(r,e)}catch{return null}};function Qve(r,e){if(e&&r.protocol!=="https:")throw Nt("only requests to HTTPS are allowed",tyt,r);if(r.protocol!=="https:"&&r.protocol!=="http:")throw Nt("only HTTP and HTTPS requests are allowed",ryt,r)}function Vve(r,e,t,n){let i;if(typeof r!="string"||!(i=kvt(r)))throw Nt(`authorization server metadata does not contain a valid ${t?`"as.mtls_endpoint_aliases.${e}"`:`"as.${e}"`}`,r===void 0?nyt:iyt,{attribute:t?`mtls_endpoint_aliases.${e}`:e});return Qve(i,n),i}function Evt(r,e,t,n){return t&&r.mtls_endpoint_aliases&&e in r.mtls_endpoint_aliases?Vve(r.mtls_endpoint_aliases[e],e,t,n):Vve(r[e],e,t,n)}var NZ=class extends Error{cause;code;error;status;error_description;response;constructor(e,t){super(e,t),this.name=this.constructor.name,this.code=Kvt,this.cause=t.cause,this.error=t.cause.error,this.status=t.response.status,this.error_description=t.cause.error_description,Object.defineProperty(this,"response",{enumerable:!1,value:t.response}),Error.captureStackTrace?.(this,this.constructor)}},FZ=class extends Error{cause;code;error;error_description;constructor(e,t){super(e,t),this.name=this.constructor.name,this.code=Xvt,this.cause=t.cause,this.error=t.cause.get("error"),this.error_description=t.cause.get("error_description")??void 0,Error.captureStackTrace?.(this,this.constructor)}},MZ=class extends Error{cause;code;response;status;constructor(e,t){super(e,t),this.name=this.constructor.name,this.code=Jvt,this.cause=t.cause,this.status=t.response.status,this.response=t.response,Object.defineProperty(this,"response",{enumerable:!1}),Error.captureStackTrace?.(this,this.constructor)}},eP="[a-zA-Z0-9!#$%&\\'\\*\\+\\-\\.\\^_`\\|~]+",Cvt="[a-zA-Z0-9\\-\\._\\~\\+\\/]+={0,2}",Avt='"((?:[^"\\\\]|\\\\[\\s\\S])*)"',Tvt="("+eP+")\\s*=\\s*"+Avt,Pvt="("+eP+")\\s*=\\s*("+eP+")",Ivt=new RegExp("^[,\\s]*("+eP+")"),Dvt=new RegExp("^[,\\s]*"+Tvt+"[,\\s]*(.*)"),Ovt=new RegExp("^[,\\s]*"+Pvt+"[,\\s]*(.*)"),$vt=new RegExp("^("+Cvt+")(?:$|[,\\s])(.*)");function Rvt(r){if(!qZ(r,Response))throw pi('"response" must be an instance of Response',Pl);let e=r.headers.get("www-authenticate");if(e===null)return;let t=[],n=e;for(;n;){let i=n.match(Ivt),a=i?.[1].toLowerCase();if(!a)return;let o=n.substring(i[0].length);if(o&&!o.match(/^[\s,]/))return;let s=o.match(/^\s+(.*)$/),c=!!s;n=s?s[1]:void 0;let u={},l;if(c)for(;n;){let p,d;if(i=n.match(Dvt)){if([,p,d,n]=i,d.includes("\\"))try{d=JSON.parse(`"${d}"`)}catch{}u[p.toLowerCase()]=d;continue}if(i=n.match(Ovt)){[,p,d,n]=i,u[p.toLowerCase()]=d;continue}if(i=n.match($vt)){if(Object.keys(u).length)break;[,l,n]=i;break}return}else n=o||void 0;let f={scheme:a,parameters:u};l&&(f.token68=l),t.push(f)}if(t.length)return t}async function jvt(r){if(r.status>399&&r.status<500){oye(r),Yve(r);try{let e=await r.clone().json();if(QT(e)&&typeof e.error=="string"&&e.error.length)return e}catch{}}}async function Nvt(r,e,t){if(r.status!==e){aye(r);let n;throw(n=await jvt(r))?(await r.body?.cancel(),new NZ("server responded with an error in the response body",{cause:n,response:r})):Nt(`"response" is not a conform ${t} response (unexpected HTTP status code)`,eyt,r)}}function eye(r){if(!WZ.has(r))throw pi('"options.DPoP" is not a valid DPoPHandle',du)}async function Fvt(r,e,t,n,i,a){if(Na(r,'"accessToken"'),!(t instanceof URL))throw pi('"url" must be an instance of URL',Pl);Qve(t,a?.[Gve]!==!0),n=Jve(n),a?.DPoP&&(eye(a.DPoP),await a.DPoP.addProof(t,n,e.toUpperCase(),r)),n.set("authorization",`${n.has("dpop")?"DPoP":"Bearer"} ${r}`);let o=await(a?.[Zve]||fetch)(t.href,{body:i,headers:Object.fromEntries(n.entries()),method:e,redirect:"manual",signal:Kve(t,a?.signal)});return a?.DPoP?.cacheNonce(o,t),o}async function tye(r,e,t,n,i,a){let o=await Fvt(r,e,t,n,i,a);return aye(o),o}var Y4r=Symbol();function Mvt(r){return r.headers.get("content-type")?.split(";")[0]}async function Lvt(r,e,t,n,i,a,o){return await t(r,e,i,a),a.set("content-type","application/x-www-form-urlencoded;charset=UTF-8"),(o?.[Zve]||fetch)(n.href,{body:i,headers:Object.fromEntries(a.entries()),method:"POST",redirect:"manual",signal:Kve(n,o?.signal)})}async function rye(r,e,t,n,i,a){let o=Evt(r,"token_endpoint",e.use_mtls_endpoint_aliases,a?.[Gve]!==!0);i.set("grant_type",n);let s=Jve(a?.headers);s.set("accept","application/json"),a?.DPoP!==void 0&&(eye(a.DPoP),await a.DPoP.addProof(o,s,"POST"));let c=await Lvt(r,e,t,o,i,s,a);return a?.DPoP?.cacheNonce(c,o),c}async function cP(r,e,t,n,i){aP(r),oP(e),Na(n,'"refreshToken"');let a=new URLSearchParams(i?.additionalParameters);return a.set("refresh_token",n),rye(r,e,t,"refresh_token",a,i)}var nye=new WeakMap,qvt=new WeakMap;function iye(r){if(!r.id_token)return;let e=nye.get(r);if(!e)throw pi('"ref" was already garbage collected or did not resolve from the proper sources',du);return e}async function HZ(r,e,t,n,i,a){if(aP(r),oP(e),!qZ(t,Response))throw pi('"response" must be an instance of Response',Pl);await Nvt(t,200,"Token Endpoint"),oye(t);let o=await uyt(t);if(Na(o.access_token,'"response" body "access_token" property',Gr,{body:o}),Na(o.token_type,'"response" body "token_type" property',Gr,{body:o}),o.token_type=o.token_type.toLowerCase(),o.expires_in!==void 0){let s=typeof o.expires_in!="number"?parseFloat(o.expires_in):o.expires_in;y7(s,!0,'"response" body "expires_in" property',Gr,{body:o}),o.expires_in=s}if(o.refresh_token!==void 0&&Na(o.refresh_token,'"response" body "refresh_token" property',Gr,{body:o}),o.scope!==void 0&&typeof o.scope!="string")throw Nt('"response" body "scope" property must be a string',Gr,{body:o});if(o.id_token!==void 0){Na(o.id_token,'"response" body "id_token" property',Gr,{body:o});let s=["aud","exp","iat","iss","sub"];e.require_auth_time===!0&&s.push("auth_time"),e.default_max_age!==void 0&&(y7(e.default_max_age,!0,'"client.default_max_age"'),s.push("auth_time")),n?.length&&s.push(...n);let{claims:c,jwt:u}=await ayt(o.id_token,oyt.bind(void 0,e.id_token_signed_response_alg,r.id_token_signing_alg_values_supported,"RS256"),UZ(e),zZ(e),i).then(Vvt.bind(void 0,s)).then(zvt.bind(void 0,r)).then(Uvt.bind(void 0,e.client_id));if(Array.isArray(c.aud)&&c.aud.length!==1){if(c.azp===void 0)throw Nt('ID Token "aud" (audience) claim includes additional untrusted audiences',Rf,{claims:c,claim:"aud"});if(c.azp!==e.client_id)throw Nt('unexpected ID Token "azp" (authorized party) claim value',Rf,{expected:e.client_id,claims:c,claim:"azp"})}c.auth_time!==void 0&&y7(c.auth_time,!0,'ID Token "auth_time" (authentication time)',Gr,{claims:c}),qvt.set(t,u),nye.set(o,c)}if(a?.[o.token_type]!==void 0)a[o.token_type](t,o);else if(o.token_type!=="dpop"&&o.token_type!=="bearer")throw new S4("unsupported `token_type` value",{cause:{body:o}});return o}function aye(r){let e;if(e=Rvt(r))throw new MZ("server responded with a challenge in the WWW-Authenticate HTTP Header",{cause:e,response:r})}async function uP(r,e,t,n){return HZ(r,e,t,void 0,n?.[DZ],n?.recognizedTokenTypes)}function Uvt(r,e){if(Array.isArray(e.claims.aud)){if(!e.claims.aud.includes(r))throw Nt('unexpected JWT "aud" (audience) claim value',Rf,{expected:r,claims:e.claims,claim:"aud"})}else if(e.claims.aud!==r)throw Nt('unexpected JWT "aud" (audience) claim value',Rf,{expected:r,claims:e.claims,claim:"aud"});return e}function zvt(r,e){let t=r[lyt]?.(e)??r.issuer;if(e.claims.iss!==t)throw Nt('unexpected JWT "iss" (issuer) claim value',Rf,{expected:t,claims:e.claims,claim:"iss"});return e}var WZ=new WeakSet;function Bvt(r){return WZ.add(r),r}var Hvt=Symbol();async function lP(r,e,t,n,i,a,o){if(aP(r),oP(e),!WZ.has(n))throw pi('"callbackParameters" must be an instance of URLSearchParams obtained from "validateAuthResponse()", or "validateJwtAuthResponse()',du);Na(i,'"redirectUri"');let s=i3(n,"code");if(!s)throw Nt('no authorization code in "callbackParameters"',Gr);let c=new URLSearchParams(o?.additionalParameters);return c.set("redirect_uri",i),c.set("code",s),a!==Hvt&&(Na(a,'"codeVerifier"'),c.set("code_verifier",a)),rye(r,e,t,"authorization_code",c,o)}var Wvt={aud:"audience",c_hash:"code hash",client_id:"client id",exp:"expiration time",iat:"issued at",iss:"issuer",jti:"jwt id",nonce:"nonce",s_hash:"state hash",sub:"subject",ath:"access token hash",htm:"http method",htu:"http uri",cnf:"confirmation",auth_time:"authentication time"};function Vvt(r,e){for(let t of r)if(e.claims[t]===void 0)throw Nt(`JWT "${t}" (${Wvt[t]}) claim missing`,Gr,{claims:e.claims});return e}var TZ=Symbol(),PZ=Symbol();async function fP(r,e,t,n){return typeof n?.expectedNonce=="string"||typeof n?.maxAge=="number"||n?.requireIdToken?Gvt(r,e,t,n.expectedNonce,n.maxAge,n[DZ],n.recognizedTokenTypes):Zvt(r,e,t,n?.[DZ],n?.recognizedTokenTypes)}async function Gvt(r,e,t,n,i,a,o){let s=[];switch(n){case void 0:n=TZ;break;case TZ:break;default:Na(n,'"expectedNonce" argument'),s.push("nonce")}switch(i??=e.default_max_age,i){case void 0:i=PZ;break;case PZ:break;default:y7(i,!0,'"maxAge" argument'),s.push("auth_time")}let c=await HZ(r,e,t,s,a,o);Na(c.id_token,'"response" body "id_token" property',Gr,{body:c});let u=iye(c);if(i!==PZ){let l=BZ()+UZ(e),f=zZ(e);if(u.auth_time+i<l-f)throw Nt("too much time has elapsed since the last End-User authentication",tP,{claims:u,now:l,tolerance:f,claim:"auth_time"})}if(n===TZ){if(u.nonce!==void 0)throw Nt('unexpected ID Token "nonce" claim value',Rf,{expected:void 0,claims:u,claim:"nonce"})}else if(u.nonce!==n)throw Nt('unexpected ID Token "nonce" claim value',Rf,{expected:n,claims:u,claim:"nonce"});return c}async function Zvt(r,e,t,n,i){let a=await HZ(r,e,t,void 0,n,i),o=iye(a);if(o){if(e.default_max_age!==void 0){y7(e.default_max_age,!0,'"client.default_max_age"');let s=BZ()+UZ(e),c=zZ(e);if(o.auth_time+e.default_max_age<s-c)throw Nt("too much time has elapsed since the last End-User authentication",tP,{claims:o,now:s,tolerance:c,claim:"auth_time"})}if(o.nonce!==void 0)throw Nt('unexpected ID Token "nonce" claim value',Rf,{expected:void 0,claims:o,claim:"nonce"})}return a}var Jvt="OAUTH_WWW_AUTHENTICATE_CHALLENGE",Kvt="OAUTH_RESPONSE_BODY_ERROR",Yvt="OAUTH_UNSUPPORTED_OPERATION",Xvt="OAUTH_AUTHORIZATION_RESPONSE_ERROR";var LZ="OAUTH_PARSE_ERROR",Gr="OAUTH_INVALID_RESPONSE";var Qvt="OAUTH_RESPONSE_IS_NOT_JSON",eyt="OAUTH_RESPONSE_IS_NOT_CONFORM",tyt="OAUTH_HTTP_REQUEST_FORBIDDEN",ryt="OAUTH_REQUEST_PROTOCOL_FORBIDDEN",tP="OAUTH_JWT_TIMESTAMP_CHECK_FAILED",Rf="OAUTH_JWT_CLAIM_COMPARISON_FAILED";var nyt="OAUTH_MISSING_SERVER_METADATA",iyt="OAUTH_INVALID_SERVER_METADATA";function oye(r){if(r.bodyUsed)throw pi('"response" body has been used already',du)}async function ayt(r,e,t,n,i){let{0:a,1:o,length:s}=r.split(".");if(s===5)if(i!==void 0)r=await i(r),{0:a,1:o,length:s}=r.split(".");else throw new S4("JWE decryption is not configured",{cause:r});if(s!==3)throw Nt("Invalid JWT",Gr,r);let c;try{c=JSON.parse(OZ(XT(a)))}catch(f){throw Nt("failed to parse JWT Header body as base64url encoded JSON",LZ,f)}if(!QT(c))throw Nt("JWT Header must be a top level object",Gr,r);if(e(c),c.crit!==void 0)throw new S4('no JWT "crit" header parameter extensions are supported',{cause:{header:c}});let u;try{u=JSON.parse(OZ(XT(o)))}catch(f){throw Nt("failed to parse JWT Payload body as base64url encoded JSON",LZ,f)}if(!QT(u))throw Nt("JWT Payload must be a top level object",Gr,r);let l=BZ()+t;if(u.exp!==void 0){if(typeof u.exp!="number")throw Nt('unexpected JWT "exp" (expiration time) claim type',Gr,{claims:u});if(u.exp<=l-n)throw Nt('unexpected JWT "exp" (expiration time) claim value, expiration is past current timestamp',tP,{claims:u,now:l,tolerance:n,claim:"exp"})}if(u.iat!==void 0&&typeof u.iat!="number")throw Nt('unexpected JWT "iat" (issued at) claim type',Gr,{claims:u});if(u.iss!==void 0&&typeof u.iss!="string")throw Nt('unexpected JWT "iss" (issuer) claim type',Gr,{claims:u});if(u.nbf!==void 0){if(typeof u.nbf!="number")throw Nt('unexpected JWT "nbf" (not before) claim type',Gr,{claims:u});if(u.nbf>l+n)throw Nt('unexpected JWT "nbf" (not before) claim value',tP,{claims:u,now:l,tolerance:n,claim:"nbf"})}if(u.aud!==void 0&&typeof u.aud!="string"&&!Array.isArray(u.aud))throw Nt('unexpected JWT "aud" (audience) claim type',Gr,{claims:u});return{header:c,claims:u,jwt:r}}function oyt(r,e,t,n){if(r!==void 0){if(typeof r=="string"?n.alg!==r:!r.includes(n.alg))throw Nt('unexpected JWT "alg" header parameter',Gr,{header:n,expected:r,reason:"client configuration"});return}if(Array.isArray(e)){if(!e.includes(n.alg))throw Nt('unexpected JWT "alg" header parameter',Gr,{header:n,expected:e,reason:"authorization server metadata"});return}if(t!==void 0){if(typeof t=="string"?n.alg!==t:typeof t=="function"?!t(n.alg):!t.includes(n.alg))throw Nt('unexpected JWT "alg" header parameter',Gr,{header:n,expected:t,reason:"default value"});return}throw Nt('missing client or server configuration to verify used JWT "alg" header parameter',void 0,{client:r,issuer:e,fallback:t})}function i3(r,e){let{0:t,length:n}=r.getAll(e);if(n>1)throw Nt(`"${e}" parameter must be provided only once`,Gr);return t}var syt=Symbol(),cyt=Symbol();function pP(r,e,t,n){if(aP(r),oP(e),t instanceof URL&&(t=t.searchParams),!(t instanceof URLSearchParams))throw pi('"parameters" must be an instance of URLSearchParams, or URL',Pl);if(i3(t,"response"))throw Nt('"parameters" contains a JARM response, use validateJwtAuthResponse() instead of validateAuthResponse()',Gr,{parameters:t});let i=i3(t,"iss"),a=i3(t,"state");if(!i&&r.authorization_response_iss_parameter_supported)throw Nt('response parameter "iss" (issuer) missing',Gr,{parameters:t});if(i&&i!==r.issuer)throw Nt('unexpected "iss" (issuer) response parameter value',Gr,{expected:r.issuer,parameters:t});switch(n){case void 0:case cyt:if(a!==void 0)throw Nt('unexpected "state" response parameter encountered',Gr,{expected:void 0,parameters:t});break;case syt:break;default:if(Na(n,'"expectedState" argument'),a!==n)throw Nt(a===void 0?'response parameter "state" missing':'unexpected "state" response parameter value',Gr,{expected:n,parameters:t})}if(i3(t,"error"))throw new FZ("authorization response from the server is an error",{cause:t});let s=i3(t,"id_token"),c=i3(t,"token");if(s!==void 0||c!==void 0)throw new S4("implicit and hybrid flows are not supported");return Bvt(new URLSearchParams(t))}async function uyt(r,e=Yve){let t;try{t=await r.json()}catch(n){throw e(r),Nt('failed to parse "response" body as JSON',LZ,n)}if(!QT(t))throw Nt('"response" body must be a top level object',Gr,{body:t});return t}var X4r=Symbol(),lyt=Symbol();var dP=class{constructor(e,t,n,i,a,o,s="BASECAMP"){this.redirectUri=n;this.interactor=i;this.userService=a;this.integrationName=s;this.resolvedProjectName=a.resolveProjectName(o),this.as={issuer:"https://launchpad.37signals.com",authorization_endpoint:"https://launchpad.37signals.com/authorization/new",token_endpoint:"https://launchpad.37signals.com/authorization/token"},this.client={client_id:e},this.clientAuth=sP(t)}as;client;clientAuth;tokenData=null;accounts=[];selectedAccountHref=null;pendingState=null;pendingCodeVerifier=null;pendingResolve=null;pendingReject=null;resolvedProjectName;isAuthenticated(){return this.tokenData||this.loadTokensFromStorage(),this.tokenData?this.tokenData.expiresAt>Date.now()+300*1e3:!1}async getAccessToken(){if(!this.tokenData)throw new Error("Not authenticated. Call authenticate() first.");return!this.isAuthenticated()&&this.tokenData.refreshToken&&await this.refreshToken(),this.tokenData.accessToken}getApiBaseUrl(){if(!this.selectedAccountHref)throw new Error("No account selected");return this.selectedAccountHref}async authenticate(){if(this.isAuthenticated())return this.tokenData;if(this.tokenData?.refreshToken)try{return this.interactor.debug("Access token expired, attempting silent refresh..."),await this.refreshToken(),this.interactor.debug("Token refreshed successfully"),this.tokenData}catch(a){this.interactor.debug(`Silent refresh failed (${a.message}), starting full re-authentication`)}let e=nP(),t=rP(),n=await iP(t);this.pendingState=e,this.pendingCodeVerifier=t;let i=new URL(this.as.authorization_endpoint);return i.searchParams.set("client_id",this.client.client_id),i.searchParams.set("redirect_uri",this.redirectUri),i.searchParams.set("response_type","code"),i.searchParams.set("state",e),i.searchParams.set("code_challenge",n),i.searchParams.set("code_challenge_method","S256"),i.searchParams.set("type","web_server"),this.interactor.sendEvent(new Ic({authUrl:i.toString(),state:e,integrationName:"BASECAMP"})),new Promise((a,o)=>{this.pendingResolve=a,this.pendingReject=o})}async handleCallback(e){if(e.integrationName==="BASECAMP"){if(e.state!==this.pendingState){this.interactor.error("Invalid OAuth state");return}if(e.error){let t=e.error==="access_denied"?"OAuth authentication denied by user":e.error==="user_cancelled"?"OAuth authentication cancelled by user":`OAuth error: ${e.error}${e.errorDescription?" - "+e.errorDescription:""}`;this.interactor.warn(t),this.pendingReject&&(this.pendingReject(new Error(t)),this.pendingReject=null),this.pendingResolve=null,this.pendingState=null,this.pendingCodeVerifier=null;return}if(!e.code||!this.pendingCodeVerifier||!this.pendingState){this.interactor.error("No pending OAuth flow or missing code");return}try{let t=new URL(this.redirectUri);t.searchParams.set("code",e.code),t.searchParams.set("state",e.state);let n=pP(this.as,this.client,t,this.pendingState),i=await lP(this.as,this.client,this.clientAuth,n,this.redirectUri,this.pendingCodeVerifier,{additionalParameters:new URLSearchParams({type:"web_server"})});this.interactor.debug(`Token exchange response status: ${i.status}`);let a=await i.text();i=new Response(a,{status:i.status,statusText:i.statusText,headers:i.headers});let o;try{o=await fP(this.as,this.client,i),this.interactor.debug("oauth4webapi validation succeeded")}catch(s){if(this.interactor.debug(`Using manual parsing for Basecamp response: ${s.message}`),!i.ok)throw new Error(`Token exchange failed: ${i.status}`);o=JSON.parse(a),this.interactor.debug("Token response parsed successfully")}this.tokenData={accessToken:o.access_token,refreshToken:o.refresh_token,expiresAt:Date.now()+(o.expires_in??1209600)*1e3},await this.fetchAccounts(),this.saveTokensToStorage(),this.pendingResolve&&(this.pendingResolve(this.tokenData),this.pendingResolve=null),this.pendingState=null,this.pendingCodeVerifier=null}catch(t){this.interactor.error(`OAuth token exchange failed: ${t.message}`),this.pendingState=null,this.pendingCodeVerifier=null}}}async fetchAccounts(){if(this.tokenData)try{let e=await tye(this.tokenData.accessToken,"GET",new URL("https://launchpad.37signals.com/authorization.json"),void 0,void 0);if(!e.ok)return;let t=await e.json();if(this.accounts=t.accounts.filter(n=>n.product==="bc3").map(n=>({id:n.id,name:n.name,href:n.href})),this.accounts.length>0){let n=this.accounts[0];n&&(this.selectedAccountHref=n.href,this.interactor.displayText(`Connected to Basecamp account: ${n.name}`))}}catch(e){this.interactor.warn(`Failed to fetch Basecamp accounts: ${e.message}`)}}async refreshToken(){if(!this.tokenData?.refreshToken)throw new Error("No refresh token available");try{let e=await cP(this.as,this.client,this.clientAuth,this.tokenData.refreshToken,{additionalParameters:new URLSearchParams({type:"refresh"})}),t=await uP(this.as,this.client,e);this.tokenData={accessToken:t.access_token,refreshToken:t.refresh_token??this.tokenData.refreshToken,expiresAt:Date.now()+(t.expires_in??1209600)*1e3},this.saveTokensToStorage()}catch(e){throw this.tokenData=null,this.clearTokensFromStorage(),new Error(`Token refresh failed: ${e.message}`)}}loadTokensFromStorage(){let t=this.userService.config.projects?.[this.resolvedProjectName]?.integration?.[this.integrationName]?.oauth2,n=t?.tokens,i=t?.account_href,a=t?.account_name;if(n){this.tokenData={accessToken:n.access_token,refreshToken:n.refresh_token,expiresAt:n.expires_at},i&&(this.selectedAccountHref=i),this.interactor.debug(`Loaded OAuth tokens from storage for ${this.integrationName}`);let o=new Date(this.tokenData.expiresAt),s=new Date,c=this.tokenData.expiresAt-s.getTime(),u=Math.floor(c/(1e3*60*60*24)),l=Math.floor(c%(1e3*60*60*24)/(1e3*60*60));this.interactor.debug(`Token expires at: ${o.toLocaleString()} (in ${u}d ${l}h)`),a&&this.interactor.displayText(`Using stored Basecamp account: ${a}`)}}saveTokensToStorage(){if(!this.tokenData)return;let e=this.userService.config;e.projects||(e.projects={}),e.projects[this.resolvedProjectName]||(e.projects[this.resolvedProjectName]={integration:{}}),e.projects[this.resolvedProjectName].integration||(e.projects[this.resolvedProjectName].integration={}),e.projects[this.resolvedProjectName].integration[this.integrationName]||(e.projects[this.resolvedProjectName].integration[this.integrationName]={}),e.projects[this.resolvedProjectName].integration[this.integrationName].oauth2||(e.projects[this.resolvedProjectName].integration[this.integrationName].oauth2={});let t=e.projects[this.resolvedProjectName].integration[this.integrationName].oauth2;t.tokens={access_token:this.tokenData.accessToken,refresh_token:this.tokenData.refreshToken,expires_at:this.tokenData.expiresAt},this.selectedAccountHref&&(t.account_href=this.selectedAccountHref);let n=this.accounts.find(u=>u.href===this.selectedAccountHref);n&&(t.account_name=n.name),this.userService.save();let i=new Date(this.tokenData.expiresAt),a=new Date,o=this.tokenData.expiresAt-a.getTime(),s=Math.floor(o/(1e3*60*60*24)),c=Math.floor(o%(1e3*60*60*24)/(1e3*60*60));this.interactor.debug(`Saved OAuth tokens to storage for ${this.integrationName}. Expires at: ${i.toLocaleString()} (in ${s}d ${c}h)`)}clearTokensFromStorage(){let t=this.userService.config.projects?.[this.resolvedProjectName]?.integration?.[this.integrationName]?.oauth2;t&&(delete t.tokens,delete t.account_href,delete t.account_name,this.userService.save(),this.interactor.debug(`Cleared OAuth tokens from storage for ${this.integrationName}`))}};async function cye(r,e){try{r.isAuthenticated()||await r.authenticate();let t=await r.getAccessToken(),n=r.getApiBaseUrl(),i=e?`${n}/projects.json?page=${e}`:`${n}/projects.json`,a=await fetch(i,{headers:{Authorization:`Bearer ${t}`,"User-Agent":"Coday (https://github.com/whoz-oss/coday)"}});if(!a.ok)return`Error fetching projects: ${a.status} ${a.statusText}`;let o=await a.json(),s=a.headers.get("X-Total-Count"),c=a.headers.get("Link"),u=null;if(c){let p=c.match(/page=(\d+)>; rel="next"/);p&&p[1]&&(u=parseInt(p[1],10))}if(o.length===0)return"No projects found in this Basecamp account.";let l=o.map(p=>{let d=(p.dock||[]).map(m=>` - ${m.title} (ID: ${m.id}, type: ${m.name})${m.enabled?"":" [disabled]"}`).join(`
|
|
1303
1303
|
`);return`- ${p.name} (ID: ${p.id})${p.description?`: ${p.description}`:""}${d?`
|
|
1304
1304
|
Tools:
|
|
1305
1305
|
${d}`:""}`}).join(`
|