@sr-connect/cli 0.1.2 → 0.1.3
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/README.md +5 -0
- package/dist/index.js +7 -6
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
A CLI to work with [ScriptRunner Connect](https://scriptrunnerconnect.com). Run it with nothing but a verb and it asks for what it needs. Run it with flags and `--agent` and it never asks, which is what scripts and AI agents want.
|
|
4
4
|
|
|
5
|
+
Driving it from an agent? Install the companion [skill](https://www.skills.sh/adaptavist/scriptrunner-skills/sr-connect), which teaches the product behind the commands. See [For agents](#for-agents).
|
|
6
|
+
|
|
5
7
|
```sh
|
|
6
8
|
npx @sr-connect/cli # no install; lists the command groups
|
|
7
9
|
npm i -g @sr-connect/cli # then: sr-connect
|
|
@@ -57,6 +59,8 @@ Commands that change something the clone contains also keep the clone current. S
|
|
|
57
59
|
|
|
58
60
|
**Pass `--agent` on every call, or set `SR_CONNECT_CLI_AGENT=1` once.** That is the whole of it: `--agent` switches off every question on its own, so anything missing becomes exit 2 instead of a hang, and it tells the API that an agent is driving. You do not also need `--no-prompts`, which is the same prompt switch without the declaration and is there for scripts that are not agents. `--agent` does not change what stdout looks like — pair it with `--raw`, or set `SR_CONNECT_CLI_RAW=1` beside the other one.
|
|
59
61
|
|
|
62
|
+
**There is a companion skill.** [`sr-connect`](https://www.skills.sh/adaptavist/scriptrunner-skills/sr-connect) teaches an agent the product behind the commands: what a workspace, connector, event listener and scheduled trigger are, what the runtime can and cannot do, and how to drive this CLI to build any of it. Install it wherever your agent reads skills from. This document is orientation for the CLI, and `--explain` answers for a single verb; the skill is the part neither of them covers.
|
|
63
|
+
|
|
60
64
|
- **Ask a verb what it takes before calling it — this is the fastest thing in the CLI, and it is where the per-verb documentation lives.** Every verb takes `--explain`: on stdout the example `--input` body where the verb has one and `{}` where it does not, and on stderr a sentence per parameter plus notes on everything the parameters do not cover — outcomes, exit codes, the shape of the document it answers with. Exit 0, no credentials, no scope, no request. This document does not repeat any of it, so `--explain` is the answer rather than a second opinion. Run it before a flags-only call too: a body key is a flag under another spelling, and the rule says which (`version` is `--package-version`, `eventListenerTypeId` is `--listener-type-id`, `waitForResponse` is `--wait`).
|
|
61
65
|
|
|
62
66
|
```sh
|
|
@@ -545,6 +549,7 @@ npx @sr-connect/cli event-listener update --explain
|
|
|
545
549
|
- `workspace get` — Get a single workspace
|
|
546
550
|
- `workspace update` — Update a workspace
|
|
547
551
|
- `workspace delete` — Delete a workspace
|
|
552
|
+
- `workspace check-package-versions` — Check the packages a workspace depends on against the versions NPM publishes
|
|
548
553
|
|
|
549
554
|
### workspace-lock (wl)
|
|
550
555
|
|
package/dist/index.js
CHANGED
|
@@ -39,7 +39,7 @@ ${renderHuman(detail)}`)}var KNOWN_INSTANCES={eu:{label:"EU",url:"https://api.sc
|
|
|
39
39
|
`,{mode:384}),renameSync2(tmp,path2)}catch(err){throw rmSync2(tmp,{force:!0}),err}return cache=stored,forced}function setSetting(key,value){let stored=readSettings(),values=Object.fromEntries(SETTING_KEYS.map(candidate=>[candidate,candidate===key?value:stored[candidate]!==!1]));return writeSettings(values)}function settingStates(flagOff={}){let stored=readSettings();return SETTING_KEYS.map(key=>{let descriptor=SETTINGS[key],flagDisabled=flagOff[key]===!0,env=envDisabled(key),value=stored[key],source=flagDisabled?"flag":env?"env":value===void 0?"default":"stored";return{key,label:descriptor.label,hint:descriptor.hint,enabled:!flagDisabled&&!env&&value!==!1,stored:value??null,envVar:descriptor.envVar,envDisabled:env,flag:descriptor.flag,flagDisabled,source}})}var ENTRY_VERSION=2,MAX_BODY=4*1024,PRUNE_MS2=10080*60*1e3,MAX_SESSION_BYTES=25*1024*1024,ROLLED=".1.jsonl",SECRET_KEY=/password|secret|token|credential|apikey|authorization|lockid/i,SECRET_PARAM=/^(x-amz-signature|x-amz-credential|x-amz-security-token|signature|awsaccesskeyid|googleaccessid|sig|se|sp|sig_key|token|password|apikey)$/i,REDACTED="<redacted>",KEEP_HEADERS=["content-type","content-length","retry-after","x-sr-connect-workspace-lock-expires-at","x-request-id","x-amzn-requestid","x-amzn-trace-id"],enabled2=!1,argv=[],instance,runId="",runSequence=0,runStarted="",runWritten=!1,maintained=!1,SECRET_ARGV_FLAG=/^(--header|--lock-id)(=|$)/;function redactArg(flag,value){if(flag.startsWith("--lock-id"))return REDACTED;let at2=value.indexOf(":");return at2===-1?REDACTED:`${value.slice(0,at2)}: ${REDACTED}`}function sanitizeArgv(tokens){let out=[];for(let i=0;i<tokens.length;i++){let token=tokens[i]??"";if(!SECRET_ARGV_FLAG.test(token)){out.push(token);continue}let eq=token.indexOf("=");if(eq!==-1){out.push(`${token.slice(0,eq)}=${redactArg(token,token.slice(eq+1))}`);continue}out.push(token);let next=tokens[i+1];next!==void 0&&(out.push(redactArg(token,next)),i++)}return out}function configureRecorder(opts){let off=process.env.SR_CONNECT_CLI_NO_RECORD_API_CALLS;enabled2=opts.enabled!==!1&&(off===void 0||/^(0|false|no|off|)$/i.test(off.trim()))&&settingEnabled("recordApiCalls"),instance=opts.instance,argv=sanitizeArgv(process.argv.slice(2)),runStarted=new Date().toISOString(),runSequence+=1,runId=`${RUN_ID}-${runSequence}`,runWritten=!1,maintained=!1}function recordingEnabled(){return enabled2}function apiCallsDir(){return join5(stateHome(),APP_DIR,"api-calls")}function sessionFile2(key){return join5(apiCallsDir(),`${key}.jsonl`)}function sessionOf(name){return name.replace(/(\.1)?\.jsonl$/,"")}function sanitizeBody(text){if(text==="")return"";let bytes=Buffer.byteLength(text),out;try{out=JSON.stringify(redact(JSON.parse(text)))}catch{return`<non-json, ${bytes} bytes>`}return out.length>MAX_BODY?`${out.slice(0,MAX_BODY)}\u2026(truncated, ${bytes} bytes)`:out}function redactHeaders(value){return Array.isArray(value)?value.map(entry2=>entry2&&typeof entry2=="object"&&!Array.isArray(entry2)&&"name"in entry2&&"value"in entry2?{...entry2,value:REDACTED}:redact(entry2)):redact(value)}function redactAttachments(value){return Array.isArray(value)?value.map(entry2=>entry2&&typeof entry2=="object"&&!Array.isArray(entry2)&&"content"in entry2?{...entry2,content:REDACTED}:redact(entry2)):redact(value)}function redact(value){return Array.isArray(value)?value.map(redact):value&&typeof value=="object"?Object.fromEntries(Object.entries(value).map(([key,child])=>[key,SECRET_KEY.test(key)?REDACTED:key==="headers"?redactHeaders(child):key==="attachments"?redactAttachments(child):redact(child)])):typeof value=="string"&&/^https?:\/\//i.test(value)?sanitizeUrl(value):value}function pickHeaders(headers){let picked={};for(let name of KEEP_HEADERS){let value=headers.get(name);value!==null&&(picked[name]=value)}return picked}function instanceBaseUrl(value=instance){let resolved=resolveInstance(value);return resolved?baseUrl(resolved):void 0}function redactLockPath(url2){return url2.replace(/\/lock\/[^/?#]+/i,`/lock/${REDACTED}`)}function sanitizeUrl(url2,base=instanceBaseUrl()){if(url2=redactLockPath(url2),base!==void 0&&url2.startsWith(base))return url2;let cut=url2.indexOf("?");if(cut===-1)return url2;let query=url2.slice(cut+1).split("&").map(pair=>{let eq=pair.indexOf("="),name=eq===-1?pair:pair.slice(0,eq);return SECRET_PARAM.test(name)?`${name}=${REDACTED}`:pair}).join("&");return`${url2.slice(0,cut)}?${query}`}function recordApiCall(call){if(!enabled2)return;let key=sessionKey();if(!key)return;let path2=sessionFile2(key);try{mkdirSync4(apiCallsDir(),{recursive:!0,mode:448}),maintainOnce(path2,key);let lines=[];runWritten||lines.push({v:ENTRY_VERSION,t:"run",runId,ts:runStarted,argv,pid:process.pid,...instance===void 0?{}:{instance}}),lines.push({v:ENTRY_VERSION,t:"call",runId,...call,url:sanitizeUrl(call.url)}),appendFileSync2(path2,lines.map(line=>`${JSON.stringify(line)}
|
|
40
40
|
`).join(""),{mode:384}),runWritten=!0}catch(err){enabled2=!1;let message=err instanceof Error?err.message:String(err);warnLine(`\u26A0 Could not record API calls to ${path2}: ${message}`)}}function maintainOnce(path2,key){maintained||(maintained=!0,prune2(),roll(path2,key))}function prune2(){for(let name of listFiles()){let path2=join5(apiCallsDir(),name);try{Date.now()-statSync2(path2).mtimeMs>PRUNE_MS2&&rmSync3(path2)}catch{}}}function roll(path2,key){try{if(statSync2(path2).size<MAX_SESSION_BYTES)return;renameSync3(path2,join5(apiCallsDir(),`${key}${ROLLED}`))}catch{}}function listFiles(){try{return readdirSync2(apiCallsDir()).filter(name=>name.endsWith(".jsonl")).sort()}catch{return[]}}function filesToRead(opts){if(opts.allSessions)return listFiles();let key=opts.session??sessionKey();if(!key)return[];let present=new Set(listFiles());return[`${key}${ROLLED}`,`${key}.jsonl`].filter(name=>present.has(name))}function parseFile(name){let text;try{text=readFileSync5(join5(apiCallsDir(),name),"utf8")}catch{return[]}let lines=[];for(let line of text.split(`
|
|
41
41
|
`))if(line.trim()!=="")try{let parsed=JSON.parse(line);parsed.v===ENTRY_VERSION&&lines.push(parsed)}catch{}return lines}function readApiCalls(opts){let runs=[],byId=new Map;for(let name of filesToRead(opts)){let session=sessionOf(name),runOf=(id,ts)=>{let runKey=`${session}\0${id}`,known=byId.get(runKey);if(known)return known;let created={runId:id,ts,argv:[],pid:0,session,calls:[],totalCalls:0};return byId.set(runKey,created),runs.push(created),created};for(let line of parseFile(name)){if(line.t==="run"){let run2=runOf(line.runId,line.ts);run2.ts=line.ts,run2.argv=line.argv,run2.pid=line.pid,run2.instance=line.instance;continue}let run=runOf(line.runId,line.ts),{v:_version,t:_type,runId:_runId,...call}=line;run.calls.push(call),run.totalCalls+=1}}return runs.sort((a,b2)=>a.ts.localeCompare(b2.ts))}function listRecordedSessions(){return summarize(listFiles())}function recordedTargets(opts){return summarize(filesToRead(opts))}function summarize(names){let rows2=new Map;for(let name of names){let session=sessionOf(name),row=rows2.get(session)??{session,files:0,runs:0,calls:0,bytes:0},lines=parseFile(name),calls=lines.filter(line=>line.t==="call");row.files+=1,row.runs+=lines.filter(line=>line.t==="run").length,row.calls+=calls.length,row.first??=calls[0]?.ts,row.last=calls.at(-1)?.ts??row.last;try{row.bytes+=statSync2(join5(apiCallsDir(),name)).size}catch{}rows2.set(session,row)}return[...rows2.values()]}function clearApiCalls(opts){let removed=new Set;for(let name of filesToRead(opts))try{rmSync3(join5(apiCallsDir(),name)),removed.add(sessionOf(name))}catch{}return[...removed]}import{closeSync,mkdirSync as mkdirSync6,openSync,readFileSync as readFileSync8,readSync,readdirSync as readdirSync4,rmSync as rmSync5,statSync as statSync4,writeFileSync as writeFileSync5}from"fs";import{arch,platform,release}from"os";import{join as join8}from"path";var PATH_PARAM_RE=/\{[^{}]+\}/g,supportsRequestInitExt=()=>typeof process=="object"&&Number.parseInt(process?.versions?.node?.substring(0,2))>=18&&process.versions.undici;function randomID(){return Math.random().toString(36).slice(2,11)}function createClient(clientOptions){let{baseUrl:baseUrl2="",Request:CustomRequest=globalThis.Request,fetch:baseFetch=globalThis.fetch,querySerializer:globalQuerySerializer,bodySerializer:globalBodySerializer,pathSerializer:globalPathSerializer,headers:baseHeaders,requestInitExt=void 0,...baseOptions}={...clientOptions};requestInitExt=supportsRequestInitExt()?requestInitExt:void 0,baseUrl2=removeTrailingSlash(baseUrl2);let globalMiddlewares=[];async function coreFetch(schemaPath,fetchOptions){let{baseUrl:localBaseUrl,fetch:fetch2=baseFetch,Request:Request2=CustomRequest,headers,params={},parseAs="json",querySerializer:requestQuerySerializer,bodySerializer=globalBodySerializer??defaultBodySerializer,pathSerializer:requestPathSerializer,body,middleware:requestMiddlewares=[],...init}=fetchOptions||{},finalBaseUrl=baseUrl2;localBaseUrl&&(finalBaseUrl=removeTrailingSlash(localBaseUrl)??baseUrl2);let querySerializer=typeof globalQuerySerializer=="function"?globalQuerySerializer:createQuerySerializer(globalQuerySerializer);requestQuerySerializer&&(querySerializer=typeof requestQuerySerializer=="function"?requestQuerySerializer:createQuerySerializer({...typeof globalQuerySerializer=="object"?globalQuerySerializer:{},...requestQuerySerializer}));let pathSerializer=requestPathSerializer||globalPathSerializer||defaultPathSerializer,serializedBody=body===void 0?void 0:bodySerializer(body,mergeHeaders(baseHeaders,headers,params.header)),finalHeaders=mergeHeaders(serializedBody===void 0||serializedBody instanceof FormData?{}:{"Content-Type":"application/json"},baseHeaders,headers,params.header),finalMiddlewares=[...globalMiddlewares,...requestMiddlewares],requestInit={redirect:"follow",...baseOptions,...init,body:serializedBody,headers:finalHeaders},id,options,request=new Request2(createFinalURL(schemaPath,{baseUrl:finalBaseUrl,params,querySerializer,pathSerializer}),requestInit),response;for(let key in init)key in request||(request[key]=init[key]);if(finalMiddlewares.length){id=randomID(),options=Object.freeze({baseUrl:finalBaseUrl,fetch:fetch2,parseAs,querySerializer,bodySerializer,pathSerializer});for(let m2 of finalMiddlewares)if(m2&&typeof m2=="object"&&typeof m2.onRequest=="function"){let result=await m2.onRequest({request,schemaPath,params,options,id});if(result)if(result instanceof Request2)request=result;else if(result instanceof Response){response=result;break}else throw new Error("onRequest: must return new Request() or Response() when modifying the request")}}if(!response){try{response=await fetch2(request,requestInitExt)}catch(error210){let errorAfterMiddleware=error210;if(finalMiddlewares.length)for(let i=finalMiddlewares.length-1;i>=0;i--){let m2=finalMiddlewares[i];if(m2&&typeof m2=="object"&&typeof m2.onError=="function"){let result=await m2.onError({request,error:errorAfterMiddleware,schemaPath,params,options,id});if(result){if(result instanceof Response){errorAfterMiddleware=void 0,response=result;break}if(result instanceof Error){errorAfterMiddleware=result;continue}throw new Error("onError: must return new Response() or instance of Error")}}}if(errorAfterMiddleware)throw errorAfterMiddleware}if(finalMiddlewares.length)for(let i=finalMiddlewares.length-1;i>=0;i--){let m2=finalMiddlewares[i];if(m2&&typeof m2=="object"&&typeof m2.onResponse=="function"){let result=await m2.onResponse({request,response,schemaPath,params,options,id});if(result){if(!(result instanceof Response))throw new Error("onResponse: must return new Response() when modifying the response");response=result}}}}let contentLength=response.headers.get("Content-Length");if(response.status===204||request.method==="HEAD"||contentLength==="0"&&!response.headers.get("Transfer-Encoding")?.includes("chunked"))return response.ok?{data:void 0,response}:{error:void 0,response};if(response.ok)return{data:await(async()=>{if(parseAs==="stream")return response.body;if(parseAs==="json"&&!contentLength){let raw=await response.text();return raw?JSON.parse(raw):void 0}return await response[parseAs]()})(),response};let error51=await response.text();try{error51=JSON.parse(error51)}catch{}return{error:error51,response}}return{request(method,url2,init){return coreFetch(url2,{...init,method:method.toUpperCase()})},GET(url2,init){return coreFetch(url2,{...init,method:"GET"})},PUT(url2,init){return coreFetch(url2,{...init,method:"PUT"})},POST(url2,init){return coreFetch(url2,{...init,method:"POST"})},DELETE(url2,init){return coreFetch(url2,{...init,method:"DELETE"})},OPTIONS(url2,init){return coreFetch(url2,{...init,method:"OPTIONS"})},HEAD(url2,init){return coreFetch(url2,{...init,method:"HEAD"})},PATCH(url2,init){return coreFetch(url2,{...init,method:"PATCH"})},TRACE(url2,init){return coreFetch(url2,{...init,method:"TRACE"})},use(...middleware){for(let m2 of middleware)if(m2){if(typeof m2!="object"||!("onRequest"in m2||"onResponse"in m2||"onError"in m2))throw new Error("Middleware must be an object with one of `onRequest()`, `onResponse() or `onError()`");globalMiddlewares.push(m2)}},eject(...middleware){for(let m2 of middleware){let i=globalMiddlewares.indexOf(m2);i!==-1&&globalMiddlewares.splice(i,1)}}}}function serializePrimitiveParam(name,value,options){if(value==null)return"";if(typeof value=="object")throw new Error("Deeply-nested arrays/objects aren\u2019t supported. Provide your own `querySerializer()` to handle these.");return`${name}=${options?.allowReserved===!0?value:encodeURIComponent(value)}`}function serializeObjectParam(name,value,options){if(!value||typeof value!="object")return"";let values=[],joiner={simple:",",label:".",matrix:";"}[options.style]||"&";if(options.style!=="deepObject"&&options.explode===!1){for(let k2 in value)values.push(k2,options.allowReserved===!0?value[k2]:encodeURIComponent(value[k2]));let final2=values.join(",");switch(options.style){case"form":return`${name}=${final2}`;case"label":return`.${final2}`;case"matrix":return`;${name}=${final2}`;default:return final2}}for(let k2 in value){let finalName=options.style==="deepObject"?`${name}[${k2}]`:k2;values.push(serializePrimitiveParam(finalName,value[k2],options))}let final=values.join(joiner);return options.style==="label"||options.style==="matrix"?`${joiner}${final}`:final}function serializeArrayParam(name,value,options){if(!Array.isArray(value))return"";if(options.explode===!1){let joiner2={form:",",spaceDelimited:"%20",pipeDelimited:"|"}[options.style]||",",final=(options.allowReserved===!0?value:value.map(v2=>encodeURIComponent(v2))).join(joiner2);switch(options.style){case"simple":return final;case"label":return`.${final}`;case"matrix":return`;${name}=${final}`;default:return`${name}=${final}`}}let joiner={simple:",",label:".",matrix:";"}[options.style]||"&",values=[];for(let v2 of value)options.style==="simple"||options.style==="label"?values.push(options.allowReserved===!0?v2:encodeURIComponent(v2)):values.push(serializePrimitiveParam(name,v2,options));return options.style==="label"||options.style==="matrix"?`${joiner}${values.join(joiner)}`:values.join(joiner)}function createQuerySerializer(options){return function(queryParams){let search=[];if(queryParams&&typeof queryParams=="object")for(let name in queryParams){let value=queryParams[name];if(value!=null){if(Array.isArray(value)){if(value.length===0)continue;search.push(serializeArrayParam(name,value,{style:"form",explode:!0,...options?.array,allowReserved:options?.allowReserved||!1}));continue}if(typeof value=="object"){search.push(serializeObjectParam(name,value,{style:"deepObject",explode:!0,...options?.object,allowReserved:options?.allowReserved||!1}));continue}search.push(serializePrimitiveParam(name,value,options))}}return search.join("&")}}function defaultPathSerializer(pathname,pathParams){let nextURL=pathname;for(let match of pathname.match(PATH_PARAM_RE)??[]){let name=match.substring(1,match.length-1),explode=!1,style="simple";if(name.endsWith("*")&&(explode=!0,name=name.substring(0,name.length-1)),name.startsWith(".")?(style="label",name=name.substring(1)):name.startsWith(";")&&(style="matrix",name=name.substring(1)),!pathParams||pathParams[name]===void 0||pathParams[name]===null)continue;let value=pathParams[name];if(Array.isArray(value)){nextURL=nextURL.replace(match,serializeArrayParam(name,value,{style,explode}));continue}if(typeof value=="object"){nextURL=nextURL.replace(match,serializeObjectParam(name,value,{style,explode}));continue}if(style==="matrix"){nextURL=nextURL.replace(match,`;${serializePrimitiveParam(name,value)}`);continue}nextURL=nextURL.replace(match,style==="label"?`.${encodeURIComponent(value)}`:encodeURIComponent(value))}return nextURL}function defaultBodySerializer(body,headers){return body instanceof FormData?body:headers&&(headers.get instanceof Function?headers.get("Content-Type")??headers.get("content-type"):headers["Content-Type"]??headers["content-type"])==="application/x-www-form-urlencoded"?new URLSearchParams(body).toString():JSON.stringify(body)}function createFinalURL(pathname,options){let finalURL=`${options.baseUrl}${pathname}`;options.params?.path&&(finalURL=options.pathSerializer(finalURL,options.params.path));let search=options.querySerializer(options.params.query??{});return search.startsWith("?")&&(search=search.substring(1)),search&&(finalURL+=`?${search}`),finalURL}function mergeHeaders(...allHeaders){let finalHeaders=new Headers;for(let h of allHeaders){if(!h||typeof h!="object")continue;let iterator=h instanceof Headers?h.entries():Object.entries(h);for(let[k2,v2]of iterator)if(v2===null)finalHeaders.delete(k2);else if(Array.isArray(v2))for(let v22 of v2)finalHeaders.append(k2,v22);else v2!==void 0&&finalHeaders.set(k2,v2)}return finalHeaders}function removeTrailingSlash(url2){return url2.endsWith("/")?url2.substring(0,url2.length-1):url2}var import_picocolors4=__toESM(require_picocolors(),1);import{chmodSync,mkdirSync as mkdirSync5,readFileSync as readFileSync6,rmSync as rmSync4,writeFileSync as writeFileSync4}from"fs";import{join as join6}from"path";var SERVICE=APP_DIR,ACCOUNT="default";async function entry(){if(process.env.SR_CONNECT_CLI_DISABLE_KEYCHAIN)throw new Error("Keychain disabled via SR_CONNECT_CLI_DISABLE_KEYCHAIN.");let{Entry}=await import("@napi-rs/keyring");return new Entry(SERVICE,ACCOUNT)}async function keychainGet(){try{let raw=(await entry()).getPassword();return raw?JSON.parse(raw):null}catch{return null}}async function keychainSet(creds){(await entry()).setPassword(JSON.stringify(creds))}async function keychainDelete(){try{return(await entry()).deletePassword()}catch{return!1}}var CREDENTIALS_FILE=()=>join6(configDir(),"credentials.json");function fileGet(){try{return JSON.parse(readFileSync6(CREDENTIALS_FILE(),"utf8"))}catch{return null}}function fileSet(creds){mkdirSync5(configDir(),{recursive:!0}),writeFileSync4(CREDENTIALS_FILE(),JSON.stringify(creds,null,2)+`
|
|
42
|
-
`,{mode:384}),chmodSync(CREDENTIALS_FILE(),384)}function fileDelete(){rmSync4(CREDENTIALS_FILE(),{force:!0})}async function resolveCredentials(){let creds=await lookupCredentials();return creds&&(resolvedUsername=creds.username),creds}async function lookupCredentials(){let envUser=process.env.SR_CONNECT_CLI_USERNAME,envPass=process.env.SR_CONNECT_CLI_PASSWORD;if(envUser&&envPass)return{username:envUser,password:envPass,source:"env"};let fromKeychain=await keychainGet();if(fromKeychain)return{...fromKeychain,source:"keychain"};let fromFile=fileGet();return fromFile?{...fromFile,source:"file"}:null}var resolvedUsername;function currentUsername(){return resolvedUsername}async function requireCredentials(){let creds=await resolveCredentials();return creds||fail(EXIT.UNAUTHENTICATED,"UNAUTHENTICATED","Not authenticated.",{hint:`Run \`${CLI} auth login\`, or set SR_CONNECT_CLI_USERNAME, SR_CONNECT_CLI_PASSWORD and SR_CONNECT_CLI_INSTANCE.`}),creds}function basicAuthHeader(creds){return"Basic "+Buffer.from(`${creds.username}:${creds.password}`).toString("base64")}var MIN_NODE_MAJOR=22;function runtimeNodeVersion(){return process.versions.node}function nodeMajor(version2=runtimeNodeVersion()){let major=Number.parseInt(version2??"",10);return Number.isFinite(major)?major:void 0}function nodeVersionWarning(version2=runtimeNodeVersion()){let major=Number.parseInt(version2??"",10);if(!(!Number.isFinite(major)||major>=MIN_NODE_MAJOR))return`\u26A0 Node ${version2} is older than the Node ${MIN_NODE_MAJOR} this CLI needs \u2014 live log streaming (--stream-logs) is unavailable and other commands may fail.`}var warned2=!1;function warnIfNodeUnsupported(){if(warned2)return;let warning=nodeVersionWarning();warning&&(warned2=!0,warnLine(warning))}var SEMVER_FORMAT="major.minor.patch",SEMVER=/^\d+\.\d+\.\d+$/;function semverError(version2){let trimmed=version2.trim();if(!SEMVER.test(trimmed))return`Expected a version in ${SEMVER_FORMAT} format, e.g. 1.4.0 \u2014 got "${trimmed}".`}function assertSemver(version2){let error51=semverError(version2);return error51&&fail(EXIT.USAGE,"INVALID_VERSION",error51),version2.trim()}var LOOSE_SEMVER=/^v?(\d+)\.(\d+)\.(\d+)(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/;function parseVersion(version2){let trimmed=version2.trim(),match=LOOSE_SEMVER.exec(trimmed);if(match)return{major:Number(match[1]??0),minor:Number(match[2]??0),patch:Number(match[3]??0),release:trimmed.includes("-")?0:1}}function compareSemver(a,b2){let left=parseVersion(a),right=parseVersion(b2);return left?right?left.major-right.major||left.minor-right.minor||left.patch-right.patch||left.release-right.release:1:right?-1:0}var DEFAULT_REGISTRY="https://registry.npmjs.org",LOOKUP_TIMEOUT_MS=5e3,MAX_OFFERED_VERSIONS=30,fetchImpl=(...args)=>fetch(...args);function registryBase(){let configured=process.env.SR_CONNECT_CLI_NPM_REGISTRY;return(configured&&configured.trim()!==""?configured.trim():DEFAULT_REGISTRY).replace(/\/+$/,"")}function isPrerelease(version2){return version2.includes("-")}async function fetchVersions(name){try{let response=await fetchImpl(`${registryBase()}/${encodeURIComponent(name)}`,{headers:{accept:"application/vnd.npm.install-v1+json","user-agent":USER_AGENT},signal:AbortSignal.timeout(LOOKUP_TIMEOUT_MS)});if(response.status===404)return"not-found";if(!response.ok)return;let body=await response.json();if(!body.versions||typeof body.versions!="object"||Array.isArray(body.versions))return;let versions=Object.keys(body.versions).reverse();if(versions.length===0)return;let distTags=body["dist-tags"]&&typeof body["dist-tags"]=="object"&&!Array.isArray(body["dist-tags"])?body["dist-tags"]:{},latest=typeof distTags.latest=="string"?distTags.latest:void 0;return{versions,distTags,...latest?{latest}:{}}}catch{return}}var enabled3=!0;function configureUpdateCheck(opts){let off=process.env.SR_CONNECT_CLI_NO_UPDATE_CHECK;enabled3=opts.enabled&&(off===void 0||/^(0|false|no|off|)$/i.test(off.trim()))}function latestStable(lookup){return lookup.latest&&!isPrerelease(lookup.latest)?lookup.latest:lookup.versions.filter(v2=>!isPrerelease(v2)).sort(compareSemver).at(-1)}function isFresh(checkedAt){let age=Date.now()-Date.parse(checkedAt);return Number.isFinite(age)&&age>=0&&age<SESSION_TTL_MS}function startUpdateCheck(){if(!enabled3)return;let stored=readUpdateCheck();stored&&isFresh(stored.checkedAt)||fetchVersions(PACKAGE).then(lookup=>{if(!lookup||lookup==="not-found")return;let latest=latestStable(lookup);latest&&storeUpdateCheck({checkedAt:new Date().toISOString(),latest})})}function updateCommand(kind,manager){let spec=`${PACKAGE}@latest`;return kind==="npx"?`npx ${spec}`:kind!=="global"?`npm install ${spec}`:manager==="pnpm"?`pnpm add -g ${spec}`:manager==="bun"?`bun add -g ${spec}`:`npm install -g ${spec}`}function updateNotice(latest,current=VERSION,site=currentSite()){if(compareSemver(latest,current)<=0)return;let{kind,manager}=classifyInstall(site);return{command:updateCommand(kind,manager),current,latest}}function renderBanner(body){let width=Math.max(...body.map(line=>Array.from(line).length)),rule="*".repeat(width+6),pad=line=>`* ${line}${" ".repeat(width-Array.from(line).length)} *`;return[rule,pad(""),...body.map(pad),pad(""),rule]}function updateBody(notice){return[`New version of ${PACKAGE} available!`,`${notice.current} \u2192 ${notice.latest}`,"","Update with:",notice.command]}function unsupportedNotice(current=VERSION,site=currentSite()){let{kind,manager}=classifyInstall(site),command=updateCommand(kind,manager);return{message:`${PACKAGE} ${current} is no longer supported by this deployment.`,hint:`Update with: ${command}`,banner:renderBanner([`${PACKAGE} ${current} is no longer supported.`,"","Update with:",command])}}function renderCompact(notice){return[`\u2714 ${PACKAGE} ${notice.latest} is available (you have ${notice.current}).`,` Update with: ${notice.command}`]}var announced=!1;function printUpdateNotice(){if(announced||!enabled3)return;let stored=readUpdateCheck();if(!stored)return;let notice=updateNotice(stored.latest);if(notice){announced=!0;for(let line of isRaw()?renderCompact(notice):renderBanner(updateBody(notice)))successLine(line)}}function asksForUpdates(argv2){let words=argv2.slice(2).filter(token=>!token.startsWith("-"));return words[0]==="cli"&&words[1]==="check-updates"}async function checkForUpdate(){let lookup=await fetchVersions(PACKAGE);if(lookup==="not-found")return{state:"unpublished"};if(!lookup)return{state:"unreachable"};let latest=latestStable(lookup);if(!latest)return{state:"unpublished"};storeUpdateCheck({checkedAt:new Date().toISOString(),latest});let notice=updateNotice(latest);return notice?{notice,state:"available"}:{current:VERSION,latest,state:"current"}}function renderUpdateLine(answer){if(answer.state==="available"){let{command,current,latest}=answer.notice;return`\u2714 ${PACKAGE} ${latest} is available (you have ${current}). Update with: ${command}`}return`\u2714 ${PACKAGE} ${answer.current} is the latest version.`}var flagEnabled=!0;function configureVersionGate(opts){flagEnabled=opts.enabled}function gateEnabled(){return flagEnabled&&!process.env.SR_CONNECT_CLI_NO_VERSION_GATE}var refreshed=!1;async function readServiceInfo(client,opts={}){let cached2=cachedServiceInfo(),refresh=opts.refreshWithoutStreamUrl===!0&&!cached2?.logsStreamUrl&&!refreshed;if(cached2&&!refresh)return cached2;refresh&&cached2&&(refreshed=!0);let answer=await client.GET("/v1/serviceInfo",{}).catch(()=>{});if(!answer)return cached2;let{data,response}=answer;if(response.status===401&&fail(EXIT.UNAUTHENTICATED,"INVALID_CREDENTIALS","The API rejected these credentials.",{hint:`Run \`${CLI} auth login\` and try again.`}),!response.ok||!data)return cached2;let info={readAt:new Date().toISOString(),...data.logsStreamUrl?{logsStreamUrl:data.logsStreamUrl}:{},...data.minimumCliVersion?{minimumCliVersion:data.minimumCliVersion}:{}};return cacheServiceInfo(info),info}async function assertSupportedVersion(client){if(!gateEnabled())return;let minimum=(await readServiceInfo(client))?.minimumCliVersion;if(!minimum||compareSemver(VERSION,minimum)>=0)return;let notice=unsupportedNotice();fail(EXIT.USAGE,"CLI_TOO_OLD",notice.message,{banner:notice.banner,hint:notice.hint})}var import_picocolors3=__toESM(require_picocolors(),1);import crypto from"crypto";var ENCODING="0123456789ABCDEFGHJKMNPQRSTVWXYZ",ENCODING_LEN=32;var RANDOM_LEN=16,TIME_LEN=10,TIME_MAX=0xffffffffffff;var ULIDErrorCode;(function(ULIDErrorCode2){ULIDErrorCode2.Base32IncorrectEncoding="B32_ENC_INVALID",ULIDErrorCode2.DecodeTimeInvalidCharacter="DEC_TIME_CHAR",ULIDErrorCode2.DecodeTimeValueMalformed="DEC_TIME_MALFORMED",ULIDErrorCode2.EncodeTimeNegative="ENC_TIME_NEG",ULIDErrorCode2.EncodeTimeSizeExceeded="ENC_TIME_SIZE_EXCEED",ULIDErrorCode2.EncodeTimeValueMalformed="ENC_TIME_MALFORMED",ULIDErrorCode2.PRNGDetectFailure="PRNG_DETECT",ULIDErrorCode2.ULIDInvalid="ULID_INVALID",ULIDErrorCode2.Unexpected="UNEXPECTED",ULIDErrorCode2.UUIDInvalid="UUID_INVALID"})(ULIDErrorCode||(ULIDErrorCode={}));var ULIDError=class extends Error{constructor(errorCode,message){super(`${message} (${errorCode})`),this.name="ULIDError",this.code=errorCode}};function randomChar(prng){let randomPosition=Math.floor(prng()*ENCODING_LEN)%ENCODING_LEN;return ENCODING.charAt(randomPosition)}function detectPRNG(root){let rootLookup=detectRoot(),globalCrypto=rootLookup&&(rootLookup.crypto||rootLookup.msCrypto)||(typeof crypto<"u"?crypto:null);if(typeof globalCrypto?.getRandomValues=="function")return()=>{let buffer=new Uint8Array(1);return globalCrypto.getRandomValues(buffer),buffer[0]/256};if(typeof globalCrypto?.randomBytes=="function")return()=>globalCrypto.randomBytes(1).readUInt8()/256;if(crypto?.randomBytes)return()=>crypto.randomBytes(1).readUInt8()/256;throw new ULIDError(ULIDErrorCode.PRNGDetectFailure,"Failed to find a reliable PRNG")}function detectRoot(){return inWebWorker()?self:typeof window<"u"?window:typeof global<"u"?global:typeof globalThis<"u"?globalThis:null}function encodeRandom(len,prng){let str="";for(;len>0;len--)str=randomChar(prng)+str;return str}function encodeTime(now,len=TIME_LEN){if(isNaN(now))throw new ULIDError(ULIDErrorCode.EncodeTimeValueMalformed,`Time must be a number: ${now}`);if(now>TIME_MAX)throw new ULIDError(ULIDErrorCode.EncodeTimeSizeExceeded,`Cannot encode a time larger than ${TIME_MAX}: ${now}`);if(now<0)throw new ULIDError(ULIDErrorCode.EncodeTimeNegative,`Time must be positive: ${now}`);if(Number.isInteger(now)===!1)throw new ULIDError(ULIDErrorCode.EncodeTimeValueMalformed,`Time must be an integer: ${now}`);let mod,str="";for(let currentLen=len;currentLen>0;currentLen--)mod=now%ENCODING_LEN,str=ENCODING.charAt(mod)+str,now=(now-mod)/ENCODING_LEN;return str}function inWebWorker(){return typeof WorkerGlobalScope<"u"&&self instanceof WorkerGlobalScope}function ulid(seedTime,prng){let currentPRNG=prng||detectPRNG(),seed=!seedTime||isNaN(seedTime)?Date.now():seedTime;return encodeTime(seed,TIME_LEN)+encodeRandom(RANDOM_LEN,currentPRNG)}function personName(person){return[person.firstName,person.lastName].filter(Boolean).join(" ")||person.email||""}function personCell(person){return`${personName(person)||person.id}${person.id?` (${person.id})`:""}`}var import_cronstrue=__toESM(require_cronstrue(),1);var CRON_FIELDS="second minute hour day-of-month month day-of-week",HOURLY_CRON="0 0 * * * *";function everyMinutesCron(minutes){return`0 */${minutes} * * * *`}function dailyCron(hour,minute){return`0 ${minute} ${hour} * * *`}function weeklyCron(day,hour,minute){return`0 ${minute} ${hour} * * ${day}`}function normalizeCron(expression){return expression.trim().split(/\s+/).join(" ")}function errorForNormalized(normalized){let parts=normalized.split(" ").filter(Boolean);if(parts.length!==6)return`CRON expression must have 6 fields (${CRON_FIELDS}) \u2014 got ${parts.length}.`;try{(0,import_cronstrue.toString)(parts.join(" "))}catch(err){return`Invalid CRON expression: ${(err instanceof Error?err.message:String(err)).replace(/^Error:\s*/,"")}`}}function cronError(expression){return errorForNormalized(normalizeCron(expression))}function describeCron(expression){try{return(0,import_cronstrue.toString)(normalizeCron(expression))}catch{return}}var MIN_TRIGGER_INTERVAL_MINUTES=15;function scheduleOf(trigger){return trigger.cronExpressionDescription??trigger.cronExpression??"not scheduled"}function assertCron(expression){let normalized=normalizeCron(expression),message=errorForNormalized(normalized);return message&&fail(EXIT.USAGE,"INVALID_CRON",message,{hint:`Once per hour is ${HOURLY_CRON}`}),normalized}var ResolverFetchError=class extends Error{status;constructor(status,message){super(message),this.status=status}};function listenerAppRegistry(){let app=RESOLVERS.app;return app?{...RESOLVERS,app:{...app,async fetch(client,deps){let payload=await fetchApps(client),withListeners=new Set(payload.apps.filter(a=>connectionTypes(a).some(ct2=>(ct2.eventListenerTypes??[]).length>0)).map(a=>a.id));return(await app.fetch(client,deps)).filter(choice=>withListeners.has(choice.value))}}}:RESOLVERS}function mapResolverError(err,spec){err.status===401&&fail(EXIT.UNAUTHENTICATED,"INVALID_CREDENTIALS",err.message,{status:401}),fail(err.status===404?EXIT.NOT_FOUND:EXIT.API_ERROR,err.status===404?"NOT_FOUND":"API_ERROR",`Fetching ${spec.plural} failed: ${err.message}`,{status:err.status})}function must(deps,key){let v2=deps[key];if(!v2)throw new Error(`resolver dependency '${key}' missing`);return v2}async function unwrap(res){if(!res.response.ok||res.data===void 0){let message=res.error?.errorMessage??`Request failed with HTTP status ${res.response.status}.`;throw new ResolverFetchError(res.response.status,message)}return res.data}var appsCache=new WeakMap,featuresCache=new WeakMap;async function teamFeatures(client,teamId){return await teamFeaturesIfKnown(client,teamId)??{eventQueues:!1,remoteWorkspace:!1}}async function teamFeaturesIfKnown(client,teamId){let perTeam=featuresCache.get(client);perTeam||featuresCache.set(client,perTeam=new Map);let cached2=perTeam.get(teamId);return cached2||(cached2=client.GET("/v1/team/{teamId}",{params:{path:{teamId}}}).then(res=>res.response.ok&&res.data?res.data.features:void 0).catch(()=>{}),perTeam.set(teamId,cached2)),cached2}function connectionTypes(app){return app.connectionTypes??(app.connectionType?[app.connectionType]:[])}async function fetchApps(client){let cached2=appsCache.get(client);return cached2||(cached2=client.GET("/v1/apps").then(unwrap),appsCache.set(client,cached2)),cached2}function findApp(payload,appId){return payload.apps.find(a=>a.id===appId)}function findApiConnectionType(app,apiConnectionTypeId){return connectionTypes(app).flatMap(ct2=>ct2.apiConnectionTypes??[]).find(t=>t.id===apiConnectionTypeId)}async function apiConnectionPackages(client,appId,apiConnectionTypeId){let app=findApp(await fetchApps(client),appId);if(!app)throw new ResolverFetchError(404,`App '${appId}' not found.`);let type=findApiConnectionType(app,apiConnectionTypeId);if(!type)throw new ResolverFetchError(404,`API connection type '${apiConnectionTypeId}' not found.`);return type.packages??[]}var GENERIC_APP="Generic";async function appConnectionTypeName(client,appId){let app=findApp(await fetchApps(client),appId);if(app)return connectionTypes(app)[0]?.name}async function isGenericApp(client,appId){try{return await appConnectionTypeName(client,appId)===GENERIC_APP}catch{return!1}}var environmentsCache=new WeakMap;function fetchEnvironments(client,workspaceId){let perWorkspace=environmentsCache.get(client);perWorkspace||environmentsCache.set(client,perWorkspace=new Map);let cached2=perWorkspace.get(workspaceId);return cached2||(cached2=client.GET("/v1/workspace/{workspaceId}/environments",{params:{path:{workspaceId}}}).then(unwrap),cached2.catch(()=>perWorkspace.delete(workspaceId)),perWorkspace.set(workspaceId,cached2)),cached2}async function environmentRelease(client,workspaceId,environmentId){return(await environmentInfo(client,workspaceId,environmentId))?.release}async function environmentInfo(client,workspaceId,environmentId){return(await fetchEnvironments(client,workspaceId).catch(()=>{}))?.environments.find(e=>e.id===environmentId)}async function environmentBelongsTo(client,workspaceId,environmentId){let data=await fetchEnvironments(client,workspaceId).catch(()=>{});if(data)return data.environments.some(e=>e.id===environmentId)}var packagesCache=new WeakMap;function fetchWorkspacePackages(client,workspaceId){let perWorkspace=packagesCache.get(client);perWorkspace||packagesCache.set(client,perWorkspace=new Map);let cached2=perWorkspace.get(workspaceId);return cached2||(cached2=client.GET("/v1/workspace/{workspaceId}/packages",{params:{path:{workspaceId}}}).then(unwrap),cached2.catch(()=>perWorkspace.delete(workspaceId)),perWorkspace.set(workspaceId,cached2)),cached2}async function packageInfo(client,workspaceId,packageId){return(await fetchWorkspacePackages(client,workspaceId).catch(()=>{}))?.packages.find(p=>p.id===packageId)}var connectorsCache=new WeakMap;function fetchConnectors(client,teamId){let perTeam=connectorsCache.get(client);perTeam||connectorsCache.set(client,perTeam=new Map);let cached2=perTeam.get(teamId);return cached2||(cached2=client.GET("/v1/team/{teamId}/connectors",{params:{path:{teamId}}}).then(unwrap),cached2.catch(()=>perTeam.delete(teamId)),perTeam.set(teamId,cached2)),cached2}async function connectorInfo(client,teamId,connectorId){return(await fetchConnectors(client,teamId).catch(()=>{}))?.connections.find(c=>c.id===connectorId)}var userCache=new WeakMap;async function currentUser(client){let cached2=userCache.get(client);return cached2||(cached2=client.GET("/v1/user/me").then(res=>res.response.ok&&res.data?res.data:void 0).catch(()=>{}),userCache.set(client,cached2)),cached2}async function currentUserId(client){return(await currentUser(client))?.id}var RESOLVERS={team:{key:"team",flag:"--team",label:"Team",plural:"teams",listCommand:`${CLI} team list`,dependsOn:[],async fetch(client){return(await unwrap(await client.GET("/v1/teams"))).teams.map(t=>({value:t.id,label:t.name,hint:t.id}))}},workspace:{key:"workspace",flag:"-w, --workspace",label:"Workspace",plural:"workspaces",listCommand:`${CLI} workspace list`,dependsOn:["team"],async fetch(client,deps){return(await unwrap(await client.GET("/v1/team/{teamId}/workspaces",{params:{path:{teamId:must(deps,"team")}}}))).workspaces.map(w=>({value:w.id,label:w.name,hint:w.id}))}},environment:{key:"environment",flag:"-e, --env",label:"Environment",plural:"environments",listCommand:`${CLI} environment list`,dependsOn:["workspace"],async fetch(client,deps){return(await fetchEnvironments(client,must(deps,"workspace"))).environments.map(e=>({value:e.id??"",label:e.name??e.id??"?",display:`${e.name??e.id??"?"} (${e.release?.version??"HEAD"})`,hint:e.id}))}},release:{key:"release",flag:"<releaseId>",label:"Release",plural:"releases",listCommand:`${CLI} release list`,dependsOn:["workspace"],async fetch(client,deps){return[...(await unwrap(await client.GET("/v1/workspace/{workspaceId}/releases",{params:{path:{workspaceId:must(deps,"workspace")}}}))).releases].reverse().map(r=>({value:r.id,label:r.version,...r.label?{display:`${r.version} \u2014 ${r.label}`}:{},hint:r.created}))}},parameter:{key:"parameter",flag:"<parameterId>",label:"Parameter",plural:"parameters",listCommand:`${CLI} environment-parameter list`,dependsOn:["workspace","environment"],async fetch(client,deps){let data=await unwrap(await client.GET("/v1/workspace/{workspaceId}/environment/{environmentId}/parameters",{params:{path:{workspaceId:must(deps,"workspace"),environmentId:must(deps,"environment")}}})),flatten2=(params,prefix="")=>params.flatMap(p=>{let path2=prefix?`${prefix} / ${p.key}`:p.key,self2={value:p.id,label:`${path2} \xB7 ${p.type}`,hint:p.id};return p.children?.length?[self2,...flatten2(p.children,path2)]:[self2]});return flatten2(data.parameters)}},app:{key:"app",flag:"--app-id",label:"App",plural:"apps",listCommand:`${CLI} app list`,dependsOn:[],async fetch(client){return(await fetchApps(client)).apps.map(a=>({value:a.id??"",label:a.name??a.id??"?",hint:a.id}))}},apiConnectionType:{key:"apiConnectionType",flag:"--api-connection-type-id",label:"API connection type",plural:"API connection types",listCommand:`${CLI} app list`,dependsOn:["app"],autoSelectSingle:!0,async fetch(client,deps){let app=findApp(await fetchApps(client),must(deps,"app"));if(!app)throw new ResolverFetchError(404,`App '${deps.app}' not found.`);return connectionTypes(app).flatMap(ct2=>(ct2.apiConnectionTypes??[]).map(t=>({value:t.id??"",label:t.name??t.id??"?",hint:ct2.name})))}},apiConnectionPackage:{key:"apiConnectionPackage",flag:"--package-id",label:"API connection package",plural:"API connection packages",listCommand:`${CLI} app list`,dependsOn:["app","apiConnectionType"],async fetch(client,deps){return(await apiConnectionPackages(client,must(deps,"app"),must(deps,"apiConnectionType"))).map(p=>({value:p.id??"",label:p.name??p.id??"?",hint:p.recommended?"recommended":p.deprecated?"deprecated":void 0}))}},listenerType:{key:"listenerType",flag:"--listener-type-id",label:"Event listener type",plural:"event listener types",listCommand:`${CLI} app list`,dependsOn:["app"],autoSelectSingle:!0,async fetch(client,deps){let app=findApp(await fetchApps(client),must(deps,"app"));if(!app)throw new ResolverFetchError(404,`App '${deps.app}' not found.`);return connectionTypes(app).flatMap(ct2=>(ct2.eventListenerTypes??[]).map(lt2=>({value:lt2.id??"",label:lt2.name??lt2.id??"?",hint:ct2.name})))}},eventType:{key:"eventType",flag:"--event-type-id",label:"Event type",plural:"event types",listCommand:`${CLI} app list`,dependsOn:["app","listenerType"],async fetch(client,deps){let app=findApp(await fetchApps(client),must(deps,"app"));if(!app)throw new ResolverFetchError(404,`App '${deps.app}' not found.`);let listenerType=connectionTypes(app).flatMap(ct2=>ct2.eventListenerTypes??[]).find(lt2=>lt2.id===must(deps,"listenerType"));if(!listenerType)throw new ResolverFetchError(404,`Event listener type '${deps.listenerType}' not found.`);return(listenerType.eventTypes??[]).map(et2=>({value:et2.id??"",label:et2.name??et2.id??"?",hint:et2.category}))}},connector:{key:"connector",flag:"--connector-id",label:"Connector",plural:"connectors",listCommand:`${CLI} connector list`,dependsOn:["team"],async fetch(client,deps){let data=await fetchConnectors(client,must(deps,"team")),me2=await currentUserId(client),allowed,appId=deps.app;if(appId){let app=findApp(await fetchApps(client),appId);if(app){let cts=connectionTypes(app),listenerTypeId=deps.listenerType;if(listenerTypeId){let owning=cts.filter(ct2=>(ct2.eventListenerTypes??[]).some(lt2=>lt2.id===listenerTypeId));owning.length>0&&(cts=owning)}let apiConnectionTypeId=deps.apiConnectionType;if(apiConnectionTypeId){let owning=cts.filter(ct2=>(ct2.apiConnectionTypes??[]).some(t=>t.id===apiConnectionTypeId));owning.length>0&&(cts=owning)}allowed=new Set(cts.map(ct2=>ct2.id??""))}}return data.connections.filter(c=>!allowed||allowed.has(c.connectionType?.id??"")).filter(c=>!appId||c.canUse!==!1).map(c=>{let sharer=me2&&c.owner?.id&&c.owner.id!==me2?personName(c.owner):"",notes=[c.authorized===!1?"unauthorized":void 0,sharer?`explicitly shared with you by ${sharer}`:void 0,c.canUse===!1?"not for use":void 0].filter(note=>note!==void 0),label=c.name??c.id??"?";return{value:c.id??"",label,...notes.length>0?{display:`${label} (${notes.join(", ")})`}:{},hint:c.connectionType?.name}})}},ownedConnector:{key:"ownedConnector",flag:"--connector-id",label:"Connector",plural:"connectors you own",listCommand:`${CLI} connector list`,dependsOn:["team"],async fetch(client,deps){let data=await fetchConnectors(client,must(deps,"team")),me2=await currentUserId(client);return data.connections.filter(c=>!me2||c.owner?.id===me2).map(c=>{let label=c.name??c.id??"?";return{value:c.id??"",label,...c.authorized===!1?{display:`${label} (unauthorized)`}:{},hint:c.connectionType?.name}})}},script:{key:"script",flag:"<scriptId>",label:"Script",plural:"scripts",dependsOn:["workspace","environment"],async fetch(client,deps){return(await unwrap(await client.GET("/v1/workspace/{workspaceId}/environment/{environmentId}/scripts",{params:{path:{workspaceId:must(deps,"workspace"),environmentId:must(deps,"environment")}}}))).scripts.map(s=>({value:s.id,label:s.name,hint:s.id}))}},eventListener:{key:"eventListener",flag:"<eventListenerId>",label:"Event listener",plural:"event listeners",listCommand:`${CLI} event-listener list`,dependsOn:["workspace","environment"],async fetch(client,deps){return(await unwrap(await client.GET("/v1/workspace/{workspaceId}/environment/{environmentId}/eventListeners",{params:{path:{workspaceId:must(deps,"workspace"),environmentId:must(deps,"environment")}}}))).eventListeners.map(el=>({value:el.id,label:el.eventType?`${el.app.name} \xB7 ${el.eventType.name}${el.script?` \u2192 ${el.script.name}`:""}`:`${el.app.name} (setup incomplete)`,hint:el.id}))}},apiConnection:{key:"apiConnection",flag:"<apiConnectionId>",label:"API connection",plural:"API connections",listCommand:`${CLI} api-connection list`,dependsOn:["workspace","environment"],async fetch(client,deps){return(await unwrap(await client.GET("/v1/workspace/{workspaceId}/environment/{environmentId}/apiConnections",{params:{path:{workspaceId:must(deps,"workspace"),environmentId:must(deps,"environment")}}}))).apiConnections.map(c=>{let label=c.path??c.id;return{value:c.id,label,display:`${label} \xB7 ${c.app.name}${c.connector?` \u2014 ${c.connector.name||c.connector.id}`:" \u2014 no connector here"}`,hint:c.id}})}},eventQueue:{key:"eventQueue",flag:"--event-queue-id",label:"Event queue",plural:"event queues",listCommand:`${CLI} event-queue list`,dependsOn:["workspace","environment"],async fetch(client,deps){return(await unwrap(await client.GET("/v1/workspace/{workspaceId}/environment/{environmentId}/eventQueues",{params:{path:{workspaceId:must(deps,"workspace"),environmentId:must(deps,"environment")}}}))).eventQueues.map(q2=>({value:q2.id,label:q2.name,...q2.disabled?{display:`${q2.name} (disabled)`}:{},hint:q2.id}))}},testPayload:{key:"testPayload",flag:"<testPayloadId>",label:"Test payload",plural:"test payloads",listCommand:`${CLI} event-listener-test-payload list`,dependsOn:["workspace","environment","eventListener"],async fetch(client,deps){let data=await unwrap(await client.GET("/v1/workspace/{workspaceId}/environment/{environmentId}/eventListener/{eventListenerId}/testPayloads",{params:{path:{workspaceId:must(deps,"workspace"),environmentId:must(deps,"environment"),eventListenerId:must(deps,"eventListener")}}}));return data.testPayloads.map(p=>({value:p.id,label:p.name,...p.id===data.defaultTestPayloadId?{display:`${p.name} (default)`}:{},hint:p.id}))}},scheduledTrigger:{key:"scheduledTrigger",flag:"<scheduledTriggerId>",label:"Scheduled trigger",plural:"scheduled triggers",listCommand:`${CLI} scheduled-trigger list`,dependsOn:["workspace","environment"],async fetch(client,deps){return(await unwrap(await client.GET("/v1/workspace/{workspaceId}/environment/{environmentId}/scheduledTriggers",{params:{path:{workspaceId:must(deps,"workspace"),environmentId:must(deps,"environment")}}}))).scheduledTriggers.map(t=>{let label=t.script?.name??t.id;return{value:t.id,label,display:`${label} \xB7 ${scheduleOf(t)}${t.disabled?" (disabled)":""}`,hint:t.id}})}},workspacePackage:{key:"workspacePackage",flag:"<packageId>",label:"Package",plural:"packages",listCommand:`${CLI} package list`,dependsOn:["workspace"],async fetch(client,deps){return(await fetchWorkspacePackages(client,must(deps,"workspace"))).packages.map(p=>({value:p.id,label:p.name,display:`${p.name}@${p.version} \xB7 ${p.type}${p.required?" \xB7 required":""}`,hint:p.id}))}}};var import_picocolors2=__toESM(require_picocolors(),1);import{existsSync,lstatSync,readdirSync as readdirSync3}from"fs";import{dirname as dirname2,join as join7}from"path";import{PassThrough}from"stream";import{styleText}from"util";function pathOptions(userInput,extensions){if(userInput==="")return[];let allowed=p=>!extensions?.length||extensions.some(ext=>p.toLowerCase().endsWith(ext.toLowerCase())),isDirectory=p=>{try{return lstatSync(p).isDirectory()}catch{return!1}},entriesOf=(dir,prefix)=>readdirSync3(dir).map(name=>join7(dir,name)).filter(full=>full.startsWith(prefix)).filter(full=>isDirectory(full)||allowed(full)).map(full=>isDirectory(full)?`${full}/`:full);try{let insideDir=userInput.length>1&&userInput.endsWith("/"),prefix=insideDir?userInput.slice(0,-1):userInput,values=[];insideDir||values.push(...entriesOf(dirname2(userInput),prefix)),isDirectory(userInput)&&values.push(...entriesOf(userInput,prefix));let options=[...new Set(values)].map(value=>({value}));return existsSync(userInput)&&lstatSync(userInput).isFile()&&!options.some(o=>o.value===userInput)&&options.unshift({value:userInput}),options}catch{return[]}}var AUTOCOMPLETE_THRESHOLD=8;function cancelled(){fail(EXIT.CANCELLED,"CANCELLED","Cancelled.")}var SUBMIT_KEY="Ctrl-S",CTRL_S=19,TAB=9,TAB_SENTINEL_BYTE=28,TAB_SENTINEL="";function detabSentinel(text){return text.replaceAll(TAB_SENTINEL," ")}function rewriteSubmitKeys(chunk){let out=[];for(let byte of chunk)byte===CTRL_S?out.push(TAB):byte===TAB?out.push(TAB_SENTINEL_BYTE):out.push(byte);return Buffer.from(out)}function submitOnCtrlS(source=process.stdin){if(!source.isTTY)return;let proxy=new PassThrough,onData=chunk=>{proxy.write(rewriteSubmitKeys(chunk))};source.on("data",onData),source.resume();let restoreTty=()=>{source.isRaw&&source.setRawMode(!1)};process.once("exit",restoreTty);let input=Object.assign(proxy,{isTTY:!0,setRawMode(mode){return source.setRawMode(mode),input}});return{input,done:()=>{process.off("exit",restoreTty),source.off("data",onData),source.pause(),proxy.end()}}}var clackAdapter={async select(message,choices,opts){let clack=await import("./dist-A3XXQMMP.js"),options=choices.map(c=>({value:c.value,label:c.display??c.label,hint:c.hint,disabled:c.disabled})),initialValue=opts?.initial,result=choices.length>AUTOCOMPLETE_THRESHOLD?await clack.autocomplete({message,options,initialValue,maxItems:10,output:process.stderr}):await clack.select({message,options,initialValue,output:process.stderr});return clack.isCancel(result)&&cancelled(),result},async multiselect(message,choices,opts){let clack=await import("./dist-A3XXQMMP.js"),options=choices.map(c=>({value:c.value,label:c.display??c.label,hint:c.hint,disabled:c.disabled})),initialValues=opts?.initial,result=choices.length>AUTOCOMPLETE_THRESHOLD?await clack.autocompleteMultiselect({message,options,initialValues,required:!1,maxItems:10,output:process.stderr}):await clack.multiselect({message,options,initialValues,required:!1,output:process.stderr});return clack.isCancel(result)&&cancelled(),result},async confirm(message,initial=!1){let clack=await import("./dist-A3XXQMMP.js"),result=await clack.confirm({message,initialValue:initial,output:process.stderr});return clack.isCancel(result)&&cancelled(),result},async text(message,opts){let clack=await import("./dist-A3XXQMMP.js"),result=await clack.text({message,initialValue:opts?.initial,validate:v2=>v2||opts?.allowEmpty?void 0:"Required.",output:process.stderr});return clack.isCancel(result)&&cancelled(),result},async multiline(message,opts){let clack=await import("./dist-A3XXQMMP.js"),core=await import("./dist-UQEAKLYF.js"),{highlightWithCursor,insertCursor}=await import("./highlight-7NU3CBVT.js"),keys=submitOnCtrlS();try{let language=opts?.language,output=process.stderr,style=(format,text)=>styleText(format,text,{stream:output}),result=await new core.MultiLinePrompt({placeholder:opts?.placeholder,initialValue:opts?.initial,showSubmit:!0,validate:()=>{},output,...keys?{input:keys.input}:{},render(){let withGuide=clack.settings.withGuide,title=`${withGuide?`${style("gray",clack.S_BAR)}
|
|
42
|
+
`,{mode:384}),chmodSync(CREDENTIALS_FILE(),384)}function fileDelete(){rmSync4(CREDENTIALS_FILE(),{force:!0})}async function resolveCredentials(){let creds=await lookupCredentials();return creds&&(resolvedUsername=creds.username),creds}async function lookupCredentials(){let envUser=process.env.SR_CONNECT_CLI_USERNAME,envPass=process.env.SR_CONNECT_CLI_PASSWORD;if(envUser&&envPass)return{username:envUser,password:envPass,source:"env"};let fromKeychain=await keychainGet();if(fromKeychain)return{...fromKeychain,source:"keychain"};let fromFile=fileGet();return fromFile?{...fromFile,source:"file"}:null}var resolvedUsername;function currentUsername(){return resolvedUsername}async function requireCredentials(){let creds=await resolveCredentials();return creds||fail(EXIT.UNAUTHENTICATED,"UNAUTHENTICATED","Not authenticated.",{hint:`Run \`${CLI} auth login\`, or set SR_CONNECT_CLI_USERNAME, SR_CONNECT_CLI_PASSWORD and SR_CONNECT_CLI_INSTANCE.`}),creds}function basicAuthHeader(creds){return"Basic "+Buffer.from(`${creds.username}:${creds.password}`).toString("base64")}var MIN_NODE_MAJOR=22;function runtimeNodeVersion(){return process.versions.node}function nodeMajor(version2=runtimeNodeVersion()){let major=Number.parseInt(version2??"",10);return Number.isFinite(major)?major:void 0}function nodeVersionWarning(version2=runtimeNodeVersion()){let major=Number.parseInt(version2??"",10);if(!(!Number.isFinite(major)||major>=MIN_NODE_MAJOR))return`\u26A0 Node ${version2} is older than the Node ${MIN_NODE_MAJOR} this CLI needs \u2014 live log streaming (--stream-logs) is unavailable and other commands may fail.`}var warned2=!1;function warnIfNodeUnsupported(){if(warned2)return;let warning=nodeVersionWarning();warning&&(warned2=!0,warnLine(warning))}var SEMVER_FORMAT="major.minor.patch",SEMVER=/^\d+\.\d+\.\d+$/;function semverError(version2){let trimmed=version2.trim();if(!SEMVER.test(trimmed))return`Expected a version in ${SEMVER_FORMAT} format, e.g. 1.4.0 \u2014 got "${trimmed}".`}function assertSemver(version2){let error51=semverError(version2);return error51&&fail(EXIT.USAGE,"INVALID_VERSION",error51),version2.trim()}var LOOSE_SEMVER=/^v?(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?(?:\+[0-9A-Za-z.-]+)?$/;function parseVersion(version2){let match=LOOSE_SEMVER.exec(version2.trim());if(!match)return;let prerelease=match[4];return{major:Number(match[1]??0),minor:Number(match[2]??0),patch:Number(match[3]??0),...prerelease===void 0?{}:{prerelease:prerelease.split(".")}}}var NUMERIC_IDENTIFIER=/^\d+$/;function comparePrerelease(a,b2){for(let index=0;index<Math.max(a.length,b2.length);index++){let left=a[index],right=b2[index];if(left===void 0)return-1;if(right===void 0)return 1;if(left===right)continue;let leftIsNumeric=NUMERIC_IDENTIFIER.test(left),rightIsNumeric=NUMERIC_IDENTIFIER.test(right);return leftIsNumeric&&rightIsNumeric?Number(left)-Number(right):leftIsNumeric!==rightIsNumeric?leftIsNumeric?-1:1:left<right?-1:1}return 0}function isComparableVersion(version2){return parseVersion(version2)!==void 0}function compareSemver(a,b2){let left=parseVersion(a),right=parseVersion(b2);if(!left)return right?-1:0;if(!right)return 1;let core=left.major-right.major||left.minor-right.minor||left.patch-right.patch;return core!==0?core:left.prerelease?right.prerelease?comparePrerelease(left.prerelease,right.prerelease):-1:right.prerelease?1:0}var DEFAULT_REGISTRY="https://registry.npmjs.org",LOOKUP_TIMEOUT_MS=5e3,MAX_OFFERED_VERSIONS=30,fetchImpl=(...args)=>fetch(...args);function registryBase(){let configured=process.env.SR_CONNECT_CLI_NPM_REGISTRY;return(configured&&configured.trim()!==""?configured.trim():DEFAULT_REGISTRY).replace(/\/+$/,"")}function isPrerelease(version2){return version2.includes("-")}async function fetchVersions(name){try{let response=await fetchImpl(`${registryBase()}/${encodeURIComponent(name)}`,{headers:{accept:"application/vnd.npm.install-v1+json","user-agent":USER_AGENT},signal:AbortSignal.timeout(LOOKUP_TIMEOUT_MS)});if(response.status===404)return"not-found";if(!response.ok)return;let body=await response.json();if(!body.versions||typeof body.versions!="object"||Array.isArray(body.versions))return;let versions=Object.keys(body.versions).reverse();if(versions.length===0)return;let distTags=body["dist-tags"]&&typeof body["dist-tags"]=="object"&&!Array.isArray(body["dist-tags"])?body["dist-tags"]:{},latest=typeof distTags.latest=="string"?distTags.latest:void 0;return{versions,distTags,...latest?{latest}:{}}}catch{return}}function latestStable(lookup){return lookup.latest&&!isPrerelease(lookup.latest)?lookup.latest:lookup.versions.filter(v2=>!isPrerelease(v2)).sort(compareSemver).at(-1)}function versionCheck(current,lookup,opts={}){if(lookup==="not-found")return{updateAvailable:!1,status:"unpublished"};if(!lookup)return{updateAvailable:!1,status:"unknown"};let latest=opts.includePrereleases?[...lookup.versions].sort(compareSemver).at(-1):latestStable(lookup);if(latest===void 0)return{updateAvailable:!1,status:"unknown"};if(!isComparableVersion(current)||!isComparableVersion(latest))return{latest,updateAvailable:!1,status:"unknown"};let outdated=compareSemver(latest,current)>0;return{latest,updateAvailable:outdated,status:outdated?"outdated":"current"}}var enabled3=!0;function configureUpdateCheck(opts){let off=process.env.SR_CONNECT_CLI_NO_UPDATE_CHECK;enabled3=opts.enabled&&(off===void 0||/^(0|false|no|off|)$/i.test(off.trim()))}function isFresh(checkedAt){let age=Date.now()-Date.parse(checkedAt);return Number.isFinite(age)&&age>=0&&age<SESSION_TTL_MS}function startUpdateCheck(){if(!enabled3)return;let stored=readUpdateCheck();stored&&isFresh(stored.checkedAt)||fetchVersions(PACKAGE).then(lookup=>{if(!lookup||lookup==="not-found")return;let latest=latestStable(lookup);latest&&storeUpdateCheck({checkedAt:new Date().toISOString(),latest})})}function updateCommand(kind,manager){let spec=`${PACKAGE}@latest`;return kind==="npx"?`npx ${spec}`:kind!=="global"?`npm install ${spec}`:manager==="pnpm"?`pnpm add -g ${spec}`:manager==="bun"?`bun add -g ${spec}`:`npm install -g ${spec}`}function updateNotice(latest,current=VERSION,site=currentSite()){if(compareSemver(latest,current)<=0)return;let{kind,manager}=classifyInstall(site);return{command:updateCommand(kind,manager),current,latest}}function renderBanner(body){let width=Math.max(...body.map(line=>Array.from(line).length)),rule="*".repeat(width+6),pad=line=>`* ${line}${" ".repeat(width-Array.from(line).length)} *`;return[rule,pad(""),...body.map(pad),pad(""),rule]}function updateBody(notice){return[`New version of ${PACKAGE} available!`,`${notice.current} \u2192 ${notice.latest}`,"","Update with:",notice.command]}function unsupportedNotice(current=VERSION,site=currentSite()){let{kind,manager}=classifyInstall(site),command=updateCommand(kind,manager);return{message:`${PACKAGE} ${current} is no longer supported by this deployment.`,hint:`Update with: ${command}`,banner:renderBanner([`${PACKAGE} ${current} is no longer supported.`,"","Update with:",command])}}function renderCompact(notice){return[`\u2714 ${PACKAGE} ${notice.latest} is available (you have ${notice.current}).`,` Update with: ${notice.command}`]}var announced=!1;function printUpdateNotice(){if(announced||!enabled3)return;let stored=readUpdateCheck();if(!stored)return;let notice=updateNotice(stored.latest);if(notice){announced=!0;for(let line of isRaw()?renderCompact(notice):renderBanner(updateBody(notice)))successLine(line)}}function asksForUpdates(argv2){let words=argv2.slice(2).filter(token=>!token.startsWith("-"));return words[0]==="cli"&&words[1]==="check-updates"}async function checkForUpdate(){let lookup=await fetchVersions(PACKAGE);if(lookup==="not-found")return{state:"unpublished"};if(!lookup)return{state:"unreachable"};let latest=latestStable(lookup);if(!latest)return{state:"unpublished"};storeUpdateCheck({checkedAt:new Date().toISOString(),latest});let notice=updateNotice(latest);return notice?{notice,state:"available"}:{current:VERSION,latest,state:"current"}}function renderUpdateLine(answer){if(answer.state==="available"){let{command,current,latest}=answer.notice;return`\u2714 ${PACKAGE} ${latest} is available (you have ${current}). Update with: ${command}`}return`\u2714 ${PACKAGE} ${answer.current} is the latest version.`}var flagEnabled=!0;function configureVersionGate(opts){flagEnabled=opts.enabled}function gateEnabled(){return flagEnabled&&!process.env.SR_CONNECT_CLI_NO_VERSION_GATE}var refreshed=!1;async function readServiceInfo(client,opts={}){let cached2=cachedServiceInfo(),refresh=opts.refreshWithoutStreamUrl===!0&&!cached2?.logsStreamUrl&&!refreshed;if(cached2&&!refresh)return cached2;refresh&&cached2&&(refreshed=!0);let answer=await client.GET("/v1/serviceInfo",{}).catch(()=>{});if(!answer)return cached2;let{data,response}=answer;if(response.status===401&&fail(EXIT.UNAUTHENTICATED,"INVALID_CREDENTIALS","The API rejected these credentials.",{hint:`Run \`${CLI} auth login\` and try again.`}),!response.ok||!data)return cached2;let info={readAt:new Date().toISOString(),...data.logsStreamUrl?{logsStreamUrl:data.logsStreamUrl}:{},...data.minimumCliVersion?{minimumCliVersion:data.minimumCliVersion}:{}};return cacheServiceInfo(info),info}async function assertSupportedVersion(client){if(!gateEnabled())return;let minimum=(await readServiceInfo(client))?.minimumCliVersion;if(!minimum||compareSemver(VERSION,minimum)>=0)return;let notice=unsupportedNotice();fail(EXIT.USAGE,"CLI_TOO_OLD",notice.message,{banner:notice.banner,hint:notice.hint})}var import_picocolors3=__toESM(require_picocolors(),1);import crypto from"crypto";var ENCODING="0123456789ABCDEFGHJKMNPQRSTVWXYZ",ENCODING_LEN=32;var RANDOM_LEN=16,TIME_LEN=10,TIME_MAX=0xffffffffffff;var ULIDErrorCode;(function(ULIDErrorCode2){ULIDErrorCode2.Base32IncorrectEncoding="B32_ENC_INVALID",ULIDErrorCode2.DecodeTimeInvalidCharacter="DEC_TIME_CHAR",ULIDErrorCode2.DecodeTimeValueMalformed="DEC_TIME_MALFORMED",ULIDErrorCode2.EncodeTimeNegative="ENC_TIME_NEG",ULIDErrorCode2.EncodeTimeSizeExceeded="ENC_TIME_SIZE_EXCEED",ULIDErrorCode2.EncodeTimeValueMalformed="ENC_TIME_MALFORMED",ULIDErrorCode2.PRNGDetectFailure="PRNG_DETECT",ULIDErrorCode2.ULIDInvalid="ULID_INVALID",ULIDErrorCode2.Unexpected="UNEXPECTED",ULIDErrorCode2.UUIDInvalid="UUID_INVALID"})(ULIDErrorCode||(ULIDErrorCode={}));var ULIDError=class extends Error{constructor(errorCode,message){super(`${message} (${errorCode})`),this.name="ULIDError",this.code=errorCode}};function randomChar(prng){let randomPosition=Math.floor(prng()*ENCODING_LEN)%ENCODING_LEN;return ENCODING.charAt(randomPosition)}function detectPRNG(root){let rootLookup=detectRoot(),globalCrypto=rootLookup&&(rootLookup.crypto||rootLookup.msCrypto)||(typeof crypto<"u"?crypto:null);if(typeof globalCrypto?.getRandomValues=="function")return()=>{let buffer=new Uint8Array(1);return globalCrypto.getRandomValues(buffer),buffer[0]/256};if(typeof globalCrypto?.randomBytes=="function")return()=>globalCrypto.randomBytes(1).readUInt8()/256;if(crypto?.randomBytes)return()=>crypto.randomBytes(1).readUInt8()/256;throw new ULIDError(ULIDErrorCode.PRNGDetectFailure,"Failed to find a reliable PRNG")}function detectRoot(){return inWebWorker()?self:typeof window<"u"?window:typeof global<"u"?global:typeof globalThis<"u"?globalThis:null}function encodeRandom(len,prng){let str="";for(;len>0;len--)str=randomChar(prng)+str;return str}function encodeTime(now,len=TIME_LEN){if(isNaN(now))throw new ULIDError(ULIDErrorCode.EncodeTimeValueMalformed,`Time must be a number: ${now}`);if(now>TIME_MAX)throw new ULIDError(ULIDErrorCode.EncodeTimeSizeExceeded,`Cannot encode a time larger than ${TIME_MAX}: ${now}`);if(now<0)throw new ULIDError(ULIDErrorCode.EncodeTimeNegative,`Time must be positive: ${now}`);if(Number.isInteger(now)===!1)throw new ULIDError(ULIDErrorCode.EncodeTimeValueMalformed,`Time must be an integer: ${now}`);let mod,str="";for(let currentLen=len;currentLen>0;currentLen--)mod=now%ENCODING_LEN,str=ENCODING.charAt(mod)+str,now=(now-mod)/ENCODING_LEN;return str}function inWebWorker(){return typeof WorkerGlobalScope<"u"&&self instanceof WorkerGlobalScope}function ulid(seedTime,prng){let currentPRNG=prng||detectPRNG(),seed=!seedTime||isNaN(seedTime)?Date.now():seedTime;return encodeTime(seed,TIME_LEN)+encodeRandom(RANDOM_LEN,currentPRNG)}function personName(person){return[person.firstName,person.lastName].filter(Boolean).join(" ")||person.email||""}function personCell(person){return`${personName(person)||person.id}${person.id?` (${person.id})`:""}`}var import_cronstrue=__toESM(require_cronstrue(),1);var CRON_FIELDS="second minute hour day-of-month month day-of-week",HOURLY_CRON="0 0 * * * *";function everyMinutesCron(minutes){return`0 */${minutes} * * * *`}function dailyCron(hour,minute){return`0 ${minute} ${hour} * * *`}function weeklyCron(day,hour,minute){return`0 ${minute} ${hour} * * ${day}`}function normalizeCron(expression){return expression.trim().split(/\s+/).join(" ")}function errorForNormalized(normalized){let parts=normalized.split(" ").filter(Boolean);if(parts.length!==6)return`CRON expression must have 6 fields (${CRON_FIELDS}) \u2014 got ${parts.length}.`;try{(0,import_cronstrue.toString)(parts.join(" "))}catch(err){return`Invalid CRON expression: ${(err instanceof Error?err.message:String(err)).replace(/^Error:\s*/,"")}`}}function cronError(expression){return errorForNormalized(normalizeCron(expression))}function describeCron(expression){try{return(0,import_cronstrue.toString)(normalizeCron(expression))}catch{return}}var MIN_TRIGGER_INTERVAL_MINUTES=15;function scheduleOf(trigger){return trigger.cronExpressionDescription??trigger.cronExpression??"not scheduled"}function assertCron(expression){let normalized=normalizeCron(expression),message=errorForNormalized(normalized);return message&&fail(EXIT.USAGE,"INVALID_CRON",message,{hint:`Once per hour is ${HOURLY_CRON}`}),normalized}var ResolverFetchError=class extends Error{status;constructor(status,message){super(message),this.status=status}};function listenerAppRegistry(){let app=RESOLVERS.app;return app?{...RESOLVERS,app:{...app,async fetch(client,deps){let payload=await fetchApps(client),withListeners=new Set(payload.apps.filter(a=>connectionTypes(a).some(ct2=>(ct2.eventListenerTypes??[]).length>0)).map(a=>a.id));return(await app.fetch(client,deps)).filter(choice=>withListeners.has(choice.value))}}}:RESOLVERS}function mapResolverError(err,spec){err.status===401&&fail(EXIT.UNAUTHENTICATED,"INVALID_CREDENTIALS",err.message,{status:401}),fail(err.status===404?EXIT.NOT_FOUND:EXIT.API_ERROR,err.status===404?"NOT_FOUND":"API_ERROR",`Fetching ${spec.plural} failed: ${err.message}`,{status:err.status})}function must(deps,key){let v2=deps[key];if(!v2)throw new Error(`resolver dependency '${key}' missing`);return v2}async function unwrap(res){if(!res.response.ok||res.data===void 0){let message=res.error?.errorMessage??`Request failed with HTTP status ${res.response.status}.`;throw new ResolverFetchError(res.response.status,message)}return res.data}var appsCache=new WeakMap,featuresCache=new WeakMap;async function teamFeatures(client,teamId){return await teamFeaturesIfKnown(client,teamId)??{eventQueues:!1,remoteWorkspace:!1}}async function teamFeaturesIfKnown(client,teamId){let perTeam=featuresCache.get(client);perTeam||featuresCache.set(client,perTeam=new Map);let cached2=perTeam.get(teamId);return cached2||(cached2=client.GET("/v1/team/{teamId}",{params:{path:{teamId}}}).then(res=>res.response.ok&&res.data?res.data.features:void 0).catch(()=>{}),perTeam.set(teamId,cached2)),cached2}function connectionTypes(app){return app.connectionTypes??(app.connectionType?[app.connectionType]:[])}async function fetchApps(client){let cached2=appsCache.get(client);return cached2||(cached2=client.GET("/v1/apps").then(unwrap),appsCache.set(client,cached2)),cached2}function findApp(payload,appId){return payload.apps.find(a=>a.id===appId)}function findApiConnectionType(app,apiConnectionTypeId){return connectionTypes(app).flatMap(ct2=>ct2.apiConnectionTypes??[]).find(t=>t.id===apiConnectionTypeId)}async function apiConnectionPackages(client,appId,apiConnectionTypeId){let app=findApp(await fetchApps(client),appId);if(!app)throw new ResolverFetchError(404,`App '${appId}' not found.`);let type=findApiConnectionType(app,apiConnectionTypeId);if(!type)throw new ResolverFetchError(404,`API connection type '${apiConnectionTypeId}' not found.`);return type.packages??[]}var GENERIC_APP="Generic";async function appConnectionTypeName(client,appId){let app=findApp(await fetchApps(client),appId);if(app)return connectionTypes(app)[0]?.name}async function isGenericApp(client,appId){try{return await appConnectionTypeName(client,appId)===GENERIC_APP}catch{return!1}}var environmentsCache=new WeakMap;function fetchEnvironments(client,workspaceId){let perWorkspace=environmentsCache.get(client);perWorkspace||environmentsCache.set(client,perWorkspace=new Map);let cached2=perWorkspace.get(workspaceId);return cached2||(cached2=client.GET("/v1/workspace/{workspaceId}/environments",{params:{path:{workspaceId}}}).then(unwrap),cached2.catch(()=>perWorkspace.delete(workspaceId)),perWorkspace.set(workspaceId,cached2)),cached2}async function environmentRelease(client,workspaceId,environmentId){return(await environmentInfo(client,workspaceId,environmentId))?.release}async function environmentInfo(client,workspaceId,environmentId){return(await fetchEnvironments(client,workspaceId).catch(()=>{}))?.environments.find(e=>e.id===environmentId)}async function environmentBelongsTo(client,workspaceId,environmentId){let data=await fetchEnvironments(client,workspaceId).catch(()=>{});if(data)return data.environments.some(e=>e.id===environmentId)}var packagesCache=new WeakMap;function fetchWorkspacePackages(client,workspaceId){let perWorkspace=packagesCache.get(client);perWorkspace||packagesCache.set(client,perWorkspace=new Map);let cached2=perWorkspace.get(workspaceId);return cached2||(cached2=client.GET("/v1/workspace/{workspaceId}/packages",{params:{path:{workspaceId}}}).then(unwrap),cached2.catch(()=>perWorkspace.delete(workspaceId)),perWorkspace.set(workspaceId,cached2)),cached2}async function packageInfo(client,workspaceId,packageId){return(await fetchWorkspacePackages(client,workspaceId).catch(()=>{}))?.packages.find(p=>p.id===packageId)}var connectorsCache=new WeakMap;function fetchConnectors(client,teamId){let perTeam=connectorsCache.get(client);perTeam||connectorsCache.set(client,perTeam=new Map);let cached2=perTeam.get(teamId);return cached2||(cached2=client.GET("/v1/team/{teamId}/connectors",{params:{path:{teamId}}}).then(unwrap),cached2.catch(()=>perTeam.delete(teamId)),perTeam.set(teamId,cached2)),cached2}async function connectorInfo(client,teamId,connectorId){return(await fetchConnectors(client,teamId).catch(()=>{}))?.connections.find(c=>c.id===connectorId)}var userCache=new WeakMap;async function currentUser(client){let cached2=userCache.get(client);return cached2||(cached2=client.GET("/v1/user/me").then(res=>res.response.ok&&res.data?res.data:void 0).catch(()=>{}),userCache.set(client,cached2)),cached2}async function currentUserId(client){return(await currentUser(client))?.id}var RESOLVERS={team:{key:"team",flag:"--team",label:"Team",plural:"teams",listCommand:`${CLI} team list`,dependsOn:[],async fetch(client){return(await unwrap(await client.GET("/v1/teams"))).teams.map(t=>({value:t.id,label:t.name,hint:t.id}))}},workspace:{key:"workspace",flag:"-w, --workspace",label:"Workspace",plural:"workspaces",listCommand:`${CLI} workspace list`,dependsOn:["team"],async fetch(client,deps){return(await unwrap(await client.GET("/v1/team/{teamId}/workspaces",{params:{path:{teamId:must(deps,"team")}}}))).workspaces.map(w=>({value:w.id,label:w.name,hint:w.id}))}},environment:{key:"environment",flag:"-e, --env",label:"Environment",plural:"environments",listCommand:`${CLI} environment list`,dependsOn:["workspace"],async fetch(client,deps){return(await fetchEnvironments(client,must(deps,"workspace"))).environments.map(e=>({value:e.id??"",label:e.name??e.id??"?",display:`${e.name??e.id??"?"} (${e.release?.version??"HEAD"})`,hint:e.id}))}},release:{key:"release",flag:"<releaseId>",label:"Release",plural:"releases",listCommand:`${CLI} release list`,dependsOn:["workspace"],async fetch(client,deps){return[...(await unwrap(await client.GET("/v1/workspace/{workspaceId}/releases",{params:{path:{workspaceId:must(deps,"workspace")}}}))).releases].reverse().map(r=>({value:r.id,label:r.version,...r.label?{display:`${r.version} \u2014 ${r.label}`}:{},hint:r.created}))}},parameter:{key:"parameter",flag:"<parameterId>",label:"Parameter",plural:"parameters",listCommand:`${CLI} environment-parameter list`,dependsOn:["workspace","environment"],async fetch(client,deps){let data=await unwrap(await client.GET("/v1/workspace/{workspaceId}/environment/{environmentId}/parameters",{params:{path:{workspaceId:must(deps,"workspace"),environmentId:must(deps,"environment")}}})),flatten2=(params,prefix="")=>params.flatMap(p=>{let path2=prefix?`${prefix} / ${p.key}`:p.key,self2={value:p.id,label:`${path2} \xB7 ${p.type}`,hint:p.id};return p.children?.length?[self2,...flatten2(p.children,path2)]:[self2]});return flatten2(data.parameters)}},app:{key:"app",flag:"--app-id",label:"App",plural:"apps",listCommand:`${CLI} app list`,dependsOn:[],async fetch(client){return(await fetchApps(client)).apps.map(a=>({value:a.id??"",label:a.name??a.id??"?",hint:a.id}))}},apiConnectionType:{key:"apiConnectionType",flag:"--api-connection-type-id",label:"API connection type",plural:"API connection types",listCommand:`${CLI} app list`,dependsOn:["app"],autoSelectSingle:!0,async fetch(client,deps){let app=findApp(await fetchApps(client),must(deps,"app"));if(!app)throw new ResolverFetchError(404,`App '${deps.app}' not found.`);return connectionTypes(app).flatMap(ct2=>(ct2.apiConnectionTypes??[]).map(t=>({value:t.id??"",label:t.name??t.id??"?",hint:ct2.name})))}},apiConnectionPackage:{key:"apiConnectionPackage",flag:"--package-id",label:"API connection package",plural:"API connection packages",listCommand:`${CLI} app list`,dependsOn:["app","apiConnectionType"],async fetch(client,deps){return(await apiConnectionPackages(client,must(deps,"app"),must(deps,"apiConnectionType"))).map(p=>({value:p.id??"",label:p.name??p.id??"?",hint:p.recommended?"recommended":p.deprecated?"deprecated":void 0}))}},listenerType:{key:"listenerType",flag:"--listener-type-id",label:"Event listener type",plural:"event listener types",listCommand:`${CLI} app list`,dependsOn:["app"],autoSelectSingle:!0,async fetch(client,deps){let app=findApp(await fetchApps(client),must(deps,"app"));if(!app)throw new ResolverFetchError(404,`App '${deps.app}' not found.`);return connectionTypes(app).flatMap(ct2=>(ct2.eventListenerTypes??[]).map(lt2=>({value:lt2.id??"",label:lt2.name??lt2.id??"?",hint:ct2.name})))}},eventType:{key:"eventType",flag:"--event-type-id",label:"Event type",plural:"event types",listCommand:`${CLI} app list`,dependsOn:["app","listenerType"],async fetch(client,deps){let app=findApp(await fetchApps(client),must(deps,"app"));if(!app)throw new ResolverFetchError(404,`App '${deps.app}' not found.`);let listenerType=connectionTypes(app).flatMap(ct2=>ct2.eventListenerTypes??[]).find(lt2=>lt2.id===must(deps,"listenerType"));if(!listenerType)throw new ResolverFetchError(404,`Event listener type '${deps.listenerType}' not found.`);return(listenerType.eventTypes??[]).map(et2=>({value:et2.id??"",label:et2.name??et2.id??"?",hint:et2.category}))}},connector:{key:"connector",flag:"--connector-id",label:"Connector",plural:"connectors",listCommand:`${CLI} connector list`,dependsOn:["team"],async fetch(client,deps){let data=await fetchConnectors(client,must(deps,"team")),me2=await currentUserId(client),allowed,appId=deps.app;if(appId){let app=findApp(await fetchApps(client),appId);if(app){let cts=connectionTypes(app),listenerTypeId=deps.listenerType;if(listenerTypeId){let owning=cts.filter(ct2=>(ct2.eventListenerTypes??[]).some(lt2=>lt2.id===listenerTypeId));owning.length>0&&(cts=owning)}let apiConnectionTypeId=deps.apiConnectionType;if(apiConnectionTypeId){let owning=cts.filter(ct2=>(ct2.apiConnectionTypes??[]).some(t=>t.id===apiConnectionTypeId));owning.length>0&&(cts=owning)}allowed=new Set(cts.map(ct2=>ct2.id??""))}}return data.connections.filter(c=>!allowed||allowed.has(c.connectionType?.id??"")).filter(c=>!appId||c.canUse!==!1).map(c=>{let sharer=me2&&c.owner?.id&&c.owner.id!==me2?personName(c.owner):"",notes=[c.authorized===!1?"unauthorized":void 0,sharer?`explicitly shared with you by ${sharer}`:void 0,c.canUse===!1?"not for use":void 0].filter(note=>note!==void 0),label=c.name??c.id??"?";return{value:c.id??"",label,...notes.length>0?{display:`${label} (${notes.join(", ")})`}:{},hint:c.connectionType?.name}})}},ownedConnector:{key:"ownedConnector",flag:"--connector-id",label:"Connector",plural:"connectors you own",listCommand:`${CLI} connector list`,dependsOn:["team"],async fetch(client,deps){let data=await fetchConnectors(client,must(deps,"team")),me2=await currentUserId(client);return data.connections.filter(c=>!me2||c.owner?.id===me2).map(c=>{let label=c.name??c.id??"?";return{value:c.id??"",label,...c.authorized===!1?{display:`${label} (unauthorized)`}:{},hint:c.connectionType?.name}})}},script:{key:"script",flag:"<scriptId>",label:"Script",plural:"scripts",dependsOn:["workspace","environment"],async fetch(client,deps){return(await unwrap(await client.GET("/v1/workspace/{workspaceId}/environment/{environmentId}/scripts",{params:{path:{workspaceId:must(deps,"workspace"),environmentId:must(deps,"environment")}}}))).scripts.map(s=>({value:s.id,label:s.name,hint:s.id}))}},eventListener:{key:"eventListener",flag:"<eventListenerId>",label:"Event listener",plural:"event listeners",listCommand:`${CLI} event-listener list`,dependsOn:["workspace","environment"],async fetch(client,deps){return(await unwrap(await client.GET("/v1/workspace/{workspaceId}/environment/{environmentId}/eventListeners",{params:{path:{workspaceId:must(deps,"workspace"),environmentId:must(deps,"environment")}}}))).eventListeners.map(el=>({value:el.id,label:el.eventType?`${el.app.name} \xB7 ${el.eventType.name}${el.script?` \u2192 ${el.script.name}`:""}`:`${el.app.name} (setup incomplete)`,hint:el.id}))}},apiConnection:{key:"apiConnection",flag:"<apiConnectionId>",label:"API connection",plural:"API connections",listCommand:`${CLI} api-connection list`,dependsOn:["workspace","environment"],async fetch(client,deps){return(await unwrap(await client.GET("/v1/workspace/{workspaceId}/environment/{environmentId}/apiConnections",{params:{path:{workspaceId:must(deps,"workspace"),environmentId:must(deps,"environment")}}}))).apiConnections.map(c=>{let label=c.path??c.id;return{value:c.id,label,display:`${label} \xB7 ${c.app.name}${c.connector?` \u2014 ${c.connector.name||c.connector.id}`:" \u2014 no connector here"}`,hint:c.id}})}},eventQueue:{key:"eventQueue",flag:"--event-queue-id",label:"Event queue",plural:"event queues",listCommand:`${CLI} event-queue list`,dependsOn:["workspace","environment"],async fetch(client,deps){return(await unwrap(await client.GET("/v1/workspace/{workspaceId}/environment/{environmentId}/eventQueues",{params:{path:{workspaceId:must(deps,"workspace"),environmentId:must(deps,"environment")}}}))).eventQueues.map(q2=>({value:q2.id,label:q2.name,...q2.disabled?{display:`${q2.name} (disabled)`}:{},hint:q2.id}))}},testPayload:{key:"testPayload",flag:"<testPayloadId>",label:"Test payload",plural:"test payloads",listCommand:`${CLI} event-listener-test-payload list`,dependsOn:["workspace","environment","eventListener"],async fetch(client,deps){let data=await unwrap(await client.GET("/v1/workspace/{workspaceId}/environment/{environmentId}/eventListener/{eventListenerId}/testPayloads",{params:{path:{workspaceId:must(deps,"workspace"),environmentId:must(deps,"environment"),eventListenerId:must(deps,"eventListener")}}}));return data.testPayloads.map(p=>({value:p.id,label:p.name,...p.id===data.defaultTestPayloadId?{display:`${p.name} (default)`}:{},hint:p.id}))}},scheduledTrigger:{key:"scheduledTrigger",flag:"<scheduledTriggerId>",label:"Scheduled trigger",plural:"scheduled triggers",listCommand:`${CLI} scheduled-trigger list`,dependsOn:["workspace","environment"],async fetch(client,deps){return(await unwrap(await client.GET("/v1/workspace/{workspaceId}/environment/{environmentId}/scheduledTriggers",{params:{path:{workspaceId:must(deps,"workspace"),environmentId:must(deps,"environment")}}}))).scheduledTriggers.map(t=>{let label=t.script?.name??t.id;return{value:t.id,label,display:`${label} \xB7 ${scheduleOf(t)}${t.disabled?" (disabled)":""}`,hint:t.id}})}},workspacePackage:{key:"workspacePackage",flag:"<packageId>",label:"Package",plural:"packages",listCommand:`${CLI} package list`,dependsOn:["workspace"],async fetch(client,deps){return(await fetchWorkspacePackages(client,must(deps,"workspace"))).packages.map(p=>({value:p.id,label:p.name,display:`${p.name}@${p.version} \xB7 ${p.type}${p.required?" \xB7 required":""}`,hint:p.id}))}}};var import_picocolors2=__toESM(require_picocolors(),1);import{existsSync,lstatSync,readdirSync as readdirSync3}from"fs";import{dirname as dirname2,join as join7}from"path";import{PassThrough}from"stream";import{styleText}from"util";function pathOptions(userInput,extensions){if(userInput==="")return[];let allowed=p=>!extensions?.length||extensions.some(ext=>p.toLowerCase().endsWith(ext.toLowerCase())),isDirectory=p=>{try{return lstatSync(p).isDirectory()}catch{return!1}},entriesOf=(dir,prefix)=>readdirSync3(dir).map(name=>join7(dir,name)).filter(full=>full.startsWith(prefix)).filter(full=>isDirectory(full)||allowed(full)).map(full=>isDirectory(full)?`${full}/`:full);try{let insideDir=userInput.length>1&&userInput.endsWith("/"),prefix=insideDir?userInput.slice(0,-1):userInput,values=[];insideDir||values.push(...entriesOf(dirname2(userInput),prefix)),isDirectory(userInput)&&values.push(...entriesOf(userInput,prefix));let options=[...new Set(values)].map(value=>({value}));return existsSync(userInput)&&lstatSync(userInput).isFile()&&!options.some(o=>o.value===userInput)&&options.unshift({value:userInput}),options}catch{return[]}}var AUTOCOMPLETE_THRESHOLD=8;function cancelled(){fail(EXIT.CANCELLED,"CANCELLED","Cancelled.")}var SUBMIT_KEY="Ctrl-S",CTRL_S=19,TAB=9,TAB_SENTINEL_BYTE=28,TAB_SENTINEL="";function detabSentinel(text){return text.replaceAll(TAB_SENTINEL," ")}function rewriteSubmitKeys(chunk){let out=[];for(let byte of chunk)byte===CTRL_S?out.push(TAB):byte===TAB?out.push(TAB_SENTINEL_BYTE):out.push(byte);return Buffer.from(out)}function submitOnCtrlS(source=process.stdin){if(!source.isTTY)return;let proxy=new PassThrough,onData=chunk=>{proxy.write(rewriteSubmitKeys(chunk))};source.on("data",onData),source.resume();let restoreTty=()=>{source.isRaw&&source.setRawMode(!1)};process.once("exit",restoreTty);let input=Object.assign(proxy,{isTTY:!0,setRawMode(mode){return source.setRawMode(mode),input}});return{input,done:()=>{process.off("exit",restoreTty),source.off("data",onData),source.pause(),proxy.end()}}}var clackAdapter={async select(message,choices,opts){let clack=await import("./dist-A3XXQMMP.js"),options=choices.map(c=>({value:c.value,label:c.display??c.label,hint:c.hint,disabled:c.disabled})),initialValue=opts?.initial,result=choices.length>AUTOCOMPLETE_THRESHOLD?await clack.autocomplete({message,options,initialValue,maxItems:10,output:process.stderr}):await clack.select({message,options,initialValue,output:process.stderr});return clack.isCancel(result)&&cancelled(),result},async multiselect(message,choices,opts){let clack=await import("./dist-A3XXQMMP.js"),options=choices.map(c=>({value:c.value,label:c.display??c.label,hint:c.hint,disabled:c.disabled})),initialValues=opts?.initial,result=choices.length>AUTOCOMPLETE_THRESHOLD?await clack.autocompleteMultiselect({message,options,initialValues,required:!1,maxItems:10,output:process.stderr}):await clack.multiselect({message,options,initialValues,required:!1,output:process.stderr});return clack.isCancel(result)&&cancelled(),result},async confirm(message,initial=!1){let clack=await import("./dist-A3XXQMMP.js"),result=await clack.confirm({message,initialValue:initial,output:process.stderr});return clack.isCancel(result)&&cancelled(),result},async text(message,opts){let clack=await import("./dist-A3XXQMMP.js"),result=await clack.text({message,initialValue:opts?.initial,validate:v2=>v2||opts?.allowEmpty?void 0:"Required.",output:process.stderr});return clack.isCancel(result)&&cancelled(),result},async multiline(message,opts){let clack=await import("./dist-A3XXQMMP.js"),core=await import("./dist-UQEAKLYF.js"),{highlightWithCursor,insertCursor}=await import("./highlight-7NU3CBVT.js"),keys=submitOnCtrlS();try{let language=opts?.language,output=process.stderr,style=(format,text)=>styleText(format,text,{stream:output}),result=await new core.MultiLinePrompt({placeholder:opts?.placeholder,initialValue:opts?.initial,showSubmit:!0,validate:()=>{},output,...keys?{input:keys.input}:{},render(){let withGuide=clack.settings.withGuide,title=`${withGuide?`${style("gray",clack.S_BAR)}
|
|
43
43
|
`:""}${clack.symbol(this.state)} ${message}
|
|
44
44
|
`,placeholder=opts?.placeholder&&opts.placeholder.length>0?style("inverse",opts.placeholder[0])+style("dim",opts.placeholder.slice(1)):style(["inverse","hidden"],"_"),userInput=detabSentinel(this.userInput),input=userInput?language?highlightWithCursor(userInput,this.cursor,language):insertCursor(userInput,userInput,this.cursor):placeholder,value=detabSentinel(this.value??""),submit=`
|
|
45
45
|
${style("dim",`${SUBMIT_KEY} to reach [ submit ], then enter`)}
|
|
@@ -1288,7 +1288,8 @@ export default (API_REGISTRY['${input.path}'] as ${input.namespace}) ??
|
|
|
1288
1288
|
})();
|
|
1289
1289
|
`}function guessNamespace(packageName){let bare=packageName.replace(/^@[^/]+\//,"").replace(/-sr-connect$/,"").replace(/-v\d+([.-]\d+)*$/,"");return`${pascalCase(bare)}Api`}function pascalCase(text){return text.split(/[^a-zA-Z0-9]+/).filter(Boolean).map(part=>part.charAt(0).toUpperCase()+part.slice(1)).join("")}function buildDependencies(packages){let dependencies={};for(let pkg of[...packages].sort((a,b2)=>a.name.localeCompare(b2.name)))dependencies[pkg.name]=pkg.version;for(let name of TYPE_PACKAGES)dependencies[name]="latest";return dependencies}function toJson(value){return JSON.stringify(value,null,4)}function generatePackageJson(workspaceName,packages){let template=JSON.parse(PACKAGE_JSON_TEMPLATE);return template.description=workspaceName,template.dependencies=buildDependencies(packages),toJson(template)}function mergePackageJson(existing,packages){let parsed;try{parsed=JSON.parse(existing)}catch{return}if(parsed===null||typeof parsed!="object"||Array.isArray(parsed))return;let merged=parsed;return merged.dependencies=buildDependencies(packages),toJson(merged)+(existing.endsWith(`
|
|
1290
1290
|
`)?`
|
|
1291
|
-
`:"")}function generateTsconfigBase(language){let template=JSON.parse(TSCONFIG_BASE_TEMPLATE);return template.compilerOptions.strict=language==="ts-strict",toJson(template)}var FORBIDDEN_IN_FILE_NAME='<>:"/\\|?*',WINDOWS_RESERVED=/^(con|prn|aux|nul|com[0-9]|lpt[0-9])$/i;function unportableNameReason(name){if(!name.trim())return"it is blank";let forbidden=Array.from(new Set(Array.from(name).filter(ch=>FORBIDDEN_IN_FILE_NAME.includes(ch)||ch<" ")));if(forbidden.length>0){let printable=forbidden.map(ch=>ch<" "?"a control character":`'${ch}'`);return`${printable.length>1?`${printable.slice(0,-1).join(", ")} and ${printable.at(-1)}`:printable[0]} cannot appear in a file name on every platform`}if(/[. ]$/.test(name))return"it ends in a dot or a space, which Windows strips";let base=name.split(".")[0]??name;if(WINDOWS_RESERVED.test(base))return`${base} is a reserved device name on Windows`}function listenerFolderName(listener){let app=pascalCase(listener.app.name)||listener.app.name,event=listener.eventType?pascalCase(listener.eventType.name)||listener.eventType.name:void 0;return`${event?`${app}\u2192${event}`:app} (${listener.id})`}function payloadFileName(payloadName){return`${payloadName}.json`}var CONCURRENCY=5;async function apiConnectionFileInputs(client,connections){let withPath=connections.filter(c=>c.path);return(await throttleAll(CONCURRENCY,withPath.map(connection=>async()=>{let catalogue=await apiConnectionPackages(client,connection.app.id,connection.apiConnectionTypeId).catch(()=>[]),fromCatalogue=connection.package?catalogue.find(p=>p.id===connection.package?.id):catalogue.find(p=>p.recommended&&!p.deprecated)??catalogue.find(p=>!p.deprecated)??catalogue[0],packageName=connection.package?.name??fromCatalogue?.name;if(!packageName){warnLine(`\u26A0 API connection "${connection.path}" has no package and the catalogue offers none \u2014 scripts/api/${connection.path}/index.ts was not generated.`);return}let namespace=fromCatalogue?.namespace;return namespace||warnLine(`\u26A0 The app catalogue records no exported class for ${packageName} \u2014 scripts/api/${connection.path}/index.ts uses the guessed name ${guessNamespace(packageName)}.`),{path:connection.path??"",namespace:namespace??guessNamespace(packageName),packageName,connectionId:connection.id,namespaceGuessed:!namespace}}))).filter(input=>input!==void 0)}function apiConnectionFilePath(connectionPath){return`scripts/api/${connectionPath.replaceAll(/\/+/g,"/").replace(/^\//,"").replace(/\/$/,"")}/index.ts`}async function apiConnectionFiles(client,connections){return(await apiConnectionFileInputs(client,connections)).map(input=>({path:apiConnectionFilePath(input.path),content:generateApiConnectionFile(input)}))}import{lstatSync as lstatSync2,mkdirSync as mkdirSync7,readFileSync as readFileSync10,readdirSync as readdirSync5,rmSync as rmSync6,unlinkSync,writeFileSync as writeFileSync6}from"fs";import{join as join10,resolve as resolve3,sep as sep3}from"path";var MARKER_PACKAGES=[...TYPE_PACKAGES,"@sr-connect/convert","@sr-connect/record-storage"],EMPTINESS_IGNORED=new Set([".git",".DS_Store"]);function mergedDependencies(parsed){if(parsed===null||typeof parsed!="object"||Array.isArray(parsed))return{};let manifest=parsed,merged={};for(let section of[manifest.dependencies,manifest.devDependencies])section!==null&&typeof section=="object"&&!Array.isArray(section)&&Object.assign(merged,section);return merged}function looksLikeClonedWorkspace(directory){try{return lstatSync2(join10(directory,METADATA_FILE)),!0}catch{}let raw;try{raw=readFileSync10(join10(directory,"package.json"),"utf8")}catch{return!1}let parsed;try{parsed=JSON.parse(raw)}catch{return!1}let dependencies=mergedDependencies(parsed);return MARKER_PACKAGES.every(name=>name in dependencies)}function inspectDirectory(directory){let entries;try{entries=readdirSync5(directory)}catch{return"empty"}return entries.every(entry2=>EMPTINESS_IGNORED.has(entry2))?"empty":looksLikeClonedWorkspace(directory)?"cloned-workspace":"non-empty"}var KEPT_IN_UPDATE_MODE=new Set(["tsconfig.json","tsconfig.base.json","eslint.config.js",".gitignore",".prettierrc","pnpm-workspace.yaml",".vscode/extensions.json","node/apiRegistry.ts","node/runtimeMocks.ts","node/global.d.ts","node/tsconfig.json","node/jest.config.ts"]),BARE_DIRECTORIES=["scripts/api","node/tests"];function assertInside(directory,relativePath){let absolute2=resolve3(directory,relativePath),base=resolve3(directory);if(absolute2!==base&&!absolute2.startsWith(base+sep3))throw new Error(`Refusing to write outside the target directory: ${relativePath}`);return absolute2}function entryExists(absolute2){try{return lstatSync2(absolute2),!0}catch{return!1}}function ensureParents(directory,relativePath){let segments=relativePath.split("/").slice(0,-1),current=resolve3(directory);for(let segment of segments){current=join10(current,segment);let stat=entryExists(current)?lstatSync2(current):void 0;stat?.isSymbolicLink()?unlinkSync(current):stat&&!stat.isDirectory()&&rmSync6(current,{force:!0}),mkdirSync7(current,{recursive:!0})}}function writeClone(directory,files,updateMode){let written=[],kept=[];mkdirSync7(resolve3(directory),{recursive:!0});for(let file2 of files){let absolute2=assertInside(directory,file2.path);if(updateMode&&KEPT_IN_UPDATE_MODE.has(file2.path)&&entryExists(absolute2)){kept.push(file2.path);continue}ensureParents(directory,file2.path);let existing=entryExists(absolute2)?lstatSync2(absolute2):void 0;existing?.isSymbolicLink()?unlinkSync(absolute2):existing&&!existing.isFile()&&rmSync6(absolute2,{recursive:!0,force:!0}),writeFileSync6(absolute2,file2.content),written.push(file2.path)}for(let bare of BARE_DIRECTORIES)ensureParents(directory,`${bare}/.`),mkdirSync7(assertInside(directory,bare),{recursive:!0});return{written,kept}}function walkFiles(root,prefix,out){let entries;try{entries=readdirSync5(root)}catch{return}for(let entry2 of entries){let absolute2=join10(root,entry2),relativePath=prefix?`${prefix}/${entry2}`:entry2;lstatSync2(absolute2).isDirectory()?walkFiles(absolute2,relativePath,out):out.push(relativePath)}}var SWEPT_ROOTS=["scripts/api","test-payloads"];function sweepStaleFiles(directory,manifestPaths){return SWEPT_ROOTS.flatMap(root=>sweepRoot(directory,root,manifestPaths))}function sweepRoot(directory,root,keep){let deleted=[],rootPath=resolve3(directory,root),present=[];walkFiles(rootPath,root,present);for(let relativePath of present)keep.has(relativePath)||(rmSync6(assertInside(directory,relativePath),{force:!0}),deleted.push(relativePath));return prune3(rootPath,rootPath),deleted}function prune3(dir,root){let entries;try{entries=readdirSync5(dir)}catch{return}for(let entry2 of entries){let absolute2=join10(dir,entry2);lstatSync2(absolute2).isDirectory()&&prune3(absolute2,root)}resolve3(dir)!==root&&readdirSync5(dir).length===0&&rmSync6(dir,{recursive:!0})}var CONCURRENCY2=5,enabled5=!0,instance2;function configureLocalSync(opts){enabled5=opts.enabled!==!1&&!truthy2(process.env.SR_CONNECT_CLI_NO_LOCAL_SYNC)&&settingEnabled("localSync"),instance2=opts.instance}function truthy2(value){return value===void 0?!1:!["","0","false","no","off"].includes(value.trim().toLowerCase())}var MAX_LEVELS=40,lookedUp=!1,found;function findLocalClone(){if(lookedUp)return found;lookedUp=!0;let directory=resolve4(process.cwd());for(let level=0;level<MAX_LEVELS;level+=1){let read=readMetadata(directory);if(read.metadata)return found={directory,metadata:read.metadata},found;if(read.problem){warnLine(`\u26A0 ${displayPath(join11(directory,METADATA_FILE))}: ${read.problem} Ignoring the local copy.`);return}let parent=dirname3(directory);if(parent===directory)break;directory=parent}}var noted=new Set;function noteOnce(line){noted.has(line)||(noted.add(line),warnLine(line))}function cloneFor(scope2){if(!enabled5)return;let clone2=findLocalClone();if(!clone2)return;let record4=clone2.metadata;if(instance2!==void 0&&record4.instance!==""&&baseUrl(record4.instance)!==baseUrl(instance2)){noteOnce(`\u26A0 The local copy in ${displayPath(clone2.directory)} was cloned from ${record4.instance} \u2014 not updated.`);return}if(record4.workspace.id!==scope2.workspaceId){noteOnce(`\u26A0 The local copy in ${displayPath(clone2.directory)} is workspace ${record4.workspace.name??record4.workspace.id} (${record4.workspace.id}) \u2014 not updated.`);return}if(scope2.environmentId!==void 0&&record4.environment.id!==scope2.environmentId){noteOnce(`\u26A0 The local copy in ${displayPath(clone2.directory)} is environment ${record4.environment.name??record4.environment.id} (${record4.environment.id}) \u2014 not updated.`);return}if(record4.environment.release){noteOnce(`\u26A0 The local copy in ${displayPath(clone2.directory)} is release ${record4.environment.release}'s snapshot \u2014 not updated. Re-clone it to pick up what the environment runs now.`);return}return clone2}function absolute(clone2,relativePath){return assertInside(clone2.directory,relativePath)}function readLocal(clone2,relativePath){try{return readFileSync11(absolute(clone2,relativePath),"utf8")}catch{return}}function noteWritten(relativePath){isRaw()||noteLine(`\u2714 Local copy updated: ${relativePath}`)}function noteRemoved(relativePath){isRaw()||noteLine(`\u2714 Local copy updated: ${relativePath} removed`)}function warnDirty(relativePath){warnLine(`\u26A0 ${relativePath} has local changes \u2014 left alone. It no longer matches the workspace.`)}function warnLeftBehind(scope2,relativePath){cloneFor(scope2)&&warnLine(`\u26A0 ${relativePath??"The local copy"} was not updated \u2014 you chose to edit the version in the workspace. Fetch it with \`${CLI} local-workspace clone\`, which rewrites the whole local copy, so check for other unsynced changes first.`)}function ensureParent(clone2,relativePath){mkdirSync8(dirname3(absolute(clone2,relativePath)),{recursive:!0})}async function attempt(run){try{return await run()}catch{return}}async function readOrSkip(run){let got=await attempt(run);return got?.response.ok?got.data:void 0}function writeOrWarn(relativePath,run){try{return run()}catch(error51){warnLine(`\u26A0 ${relativePath} could not be updated in the local copy (${describeError(error51)}). The workspace has the change; this directory does not.`);return}}function putFile(clone2,relativePath,content){return readLocal(clone2,relativePath)===content||!writeOrWarn(relativePath,()=>(ensureParent(clone2,relativePath),writeFileSync7(absolute(clone2,relativePath),content),!0))?!1:(noteWritten(relativePath),!0)}function dropFile(clone2,relativePath){let target=absolute(clone2,relativePath);try{lstatSync3(target)}catch{return!1}return writeOrWarn(relativePath,()=>(rmSync7(target,{force:!0}),pruneUpwards(clone2,dirname3(relativePath)),!0))?(noteRemoved(relativePath),!0):!1}function pruneUpwards(clone2,relativeDir){let roots=new Set([".","","scripts","scripts/api","test-payloads"]),current=relativeDir;for(;!roots.has(current);){let target=absolute(clone2,current);try{if(readdirSync6(target).length>0)return;rmSync7(target,{recursive:!0,force:!0})}catch{return}current=dirname3(current)}}function saveRecord(clone2,mutate){mutate(clone2.metadata),clone2.metadata.cli=writerTag();try{writeFileSync7(absolute(clone2,METADATA_FILE),renderMetadata(clone2.metadata))}catch{warnLine(`\u26A0 ${METADATA_FILE} could not be updated \u2014 the next \`${CLI} local-workspace push\` may re-send files that are already in the workspace.`)}}function syncScript(scope2,change){if(change.mode==="skip-write"){warnLeftBehind(scope2,scriptPath(change.name));return}let clone2=cloneFor(scope2);if(!clone2)return;let relativePath=scriptPath(change.name),recordedName=change.id===void 0?void 0:Object.entries(clone2.metadata.scripts).find(([,entry2])=>entry2.id===change.id)?.[0],candidate=change.previousName??recordedName,previous=candidate!==void 0&&candidate!==change.name?candidate:void 0;if(previous!==void 0){let from=scriptPath(previous),recorded2=clone2.metadata.scripts[previous];if(readLocal(clone2,from)!==void 0)try{ensureParent(clone2,relativePath),renameSync4(absolute(clone2,from),absolute(clone2,relativePath)),pruneUpwards(clone2,dirname3(from)),noteWritten(`${from} \u2192 ${relativePath}`)}catch{warnLine(`\u26A0 ${from} could not be moved to ${relativePath}.`)}saveRecord(clone2,record4=>{delete record4.scripts[previous],recorded2&&(record4.scripts[change.name]=recorded2)})}let recorded=clone2.metadata.scripts[change.name],onDisk=readLocal(clone2,relativePath);onDisk!==void 0&&recorded?.checksum!==void 0&&recorded.checksum!==""&&checksumOf(onDisk)!==recorded.checksum&&onDisk!==change.content&&change.mode!=="always"?warnDirty(relativePath):putFile(clone2,relativePath,change.content),saveRecord(clone2,record4=>{record4.scripts[change.name]={...change.id===void 0?{}:{id:change.id},checksum:checksumOf(change.content)}})}async function syncScriptFromServer(client,scope2,scriptId){if(!cloneFor(scope2)||scope2.environmentId===void 0)return;let path2={workspaceId:scope2.workspaceId,environmentId:scope2.environmentId},data=await readOrSkip(()=>client.GET("/v1/workspace/{workspaceId}/environment/{environmentId}/script/{scriptId}",{params:{path:{...path2,scriptId}}}));data&&syncScript(scope2,{name:data.name,content:data.content,id:data.id})}function syncScriptDeleted(scope2,ref){let clone2=cloneFor(scope2);if(!clone2)return;let name=ref.name??Object.entries(clone2.metadata.scripts).find(([,entry2])=>entry2.id===ref.id)?.[0];if(name===void 0)return;let relativePath=scriptPath(name),recorded=clone2.metadata.scripts[name],onDisk=readLocal(clone2,relativePath);onDisk!==void 0&&recorded?.checksum&&checksumOf(onDisk)!==recorded.checksum?warnLine(`\u26A0 ${relativePath} has local changes \u2014 left in place, though the script is gone from the workspace.`):dropFile(clone2,relativePath),saveRecord(clone2,record4=>{delete record4.scripts[name]})}var folderCache=new Map;async function folderForListener(clone2,client,scope2,eventListenerId){let cached2=folderCache.get(eventListenerId);if(cached2!==void 0)return cached2;for(let[path2,entry2]of Object.entries(clone2.metadata.testPayloads)){if(entry2.eventListenerId!==eventListenerId)continue;let folder2=path2.split("/")[1];if(folder2)return folderCache.set(eventListenerId,folder2),folder2}let listener=await fetchListener(client,scope2,eventListenerId),folder=listener?listenerFolderName(listener):void 0;if(folder&&unportableNameReason(folder)){folderCache.set(eventListenerId,void 0);return}return folderCache.set(eventListenerId,folder),folder}async function fetchListener(client,scope2,eventListenerId){let environmentId=scope2.environmentId;if(environmentId===void 0)return;let data=await readOrSkip(()=>client.GET("/v1/workspace/{workspaceId}/environment/{environmentId}/eventListeners",{params:{path:{workspaceId:scope2.workspaceId,environmentId}}}));if(data)return data.eventListeners.find(listener=>listener.id===eventListenerId)}function payloadPathById(clone2,id){if(id!==void 0)return Object.entries(clone2.metadata.testPayloads).find(([,entry2])=>entry2.id===id)?.[0]}function payloadNameFromPath(path2){let file2=path2.split("/")[2];return file2?.endsWith(".json")?file2.slice(0,-5):void 0}async function syncTestPayload(client,scope2,eventListenerId,change){if(change.mode==="skip-write"){let skipped=cloneFor(scope2),folder2=skipped?await folderForListener(skipped,client,scope2,eventListenerId):void 0;warnLeftBehind(scope2,folder2&&change.name?`test-payloads/${folder2}/${payloadFileName(change.name)}`:void 0);return}let clone2=cloneFor(scope2);if(!clone2)return;let folder=await folderForListener(clone2,client,scope2,eventListenerId);if(!folder)return;let knownPath=payloadPathById(clone2,change.id),recordedName=knownPath===void 0?void 0:payloadNameFromPath(knownPath),name=change.name??recordedName;if(name===void 0)return;let previousName=change.previousName??recordedName,reason=unportableNameReason(payloadFileName(name));if(reason){warnLine(`\u26A0 Test payload "${name}" was not written to the local copy: ${reason}.`);return}let relativePath=`test-payloads/${folder}/${payloadFileName(name)}`;if(previousName!==void 0&&previousName!==name){let from=`test-payloads/${folder}/${payloadFileName(previousName)}`,recorded2=clone2.metadata.testPayloads[from];if(readLocal(clone2,from)!==void 0)try{ensureParent(clone2,relativePath),renameSync4(absolute(clone2,from),absolute(clone2,relativePath)),noteWritten(`${from} \u2192 ${relativePath}`)}catch{warnLine(`\u26A0 ${from} could not be moved to ${relativePath}.`)}saveRecord(clone2,record4=>{delete record4.testPayloads[from],recorded2&&(record4.testPayloads[relativePath]=recorded2)})}let recorded=clone2.metadata.testPayloads[relativePath],onDisk=readLocal(clone2,relativePath);onDisk!==void 0&&recorded?.checksum!==void 0&&recorded.checksum!==""&&checksumOf(onDisk)!==recorded.checksum&&onDisk!==change.content&&change.mode!=="always"?warnDirty(relativePath):putFile(clone2,relativePath,change.content),saveRecord(clone2,record4=>{record4.testPayloads[relativePath]={eventListenerId,...change.id===void 0?{}:{id:change.id},checksum:checksumOf(change.content)}})}async function syncTestPayloadDeleted(client,scope2,eventListenerId,ref){let clone2=cloneFor(scope2);if(!clone2)return;let byId=payloadPathById(clone2,ref.id),folder=byId?void 0:await folderForListener(clone2,client,scope2,eventListenerId),relativePath=byId??(folder&&ref.name!==void 0?`test-payloads/${folder}/${payloadFileName(ref.name)}`:void 0);relativePath!==void 0&&(dropFile(clone2,relativePath),saveRecord(clone2,record4=>{delete record4.testPayloads[relativePath]}))}async function syncTestPayloadRenamed(client,scope2,eventListenerId,change){let clone2=cloneFor(scope2);if(!clone2)return;let from=payloadPathById(clone2,change.id);if(from===void 0)return;let folder=from.split("/")[1];if(!folder||unportableNameReason(payloadFileName(change.name)))return;let to=`test-payloads/${folder}/${payloadFileName(change.name)}`;if(to===from)return;let entry2=clone2.metadata.testPayloads[from];if(readLocal(clone2,from)!==void 0)try{renameSync4(absolute(clone2,from),absolute(clone2,to)),noteWritten(`${from} \u2192 ${to}`)}catch{warnLine(`\u26A0 ${from} could not be moved to ${to}.`);return}saveRecord(clone2,record4=>{delete record4.testPayloads[from],entry2&&(record4.testPayloads[to]=entry2)})}async function syncTestPayloadById(client,scope2,eventListenerId,testPayloadId){let environmentId=scope2.environmentId;if(!cloneFor(scope2)||environmentId===void 0)return;let data=await readOrSkip(()=>client.GET("/v1/workspace/{workspaceId}/environment/{environmentId}/eventListener/{eventListenerId}/testPayload/{testPayloadId}",{params:{path:{workspaceId:scope2.workspaceId,environmentId,eventListenerId,testPayloadId}}}));data&&await syncTestPayload(client,scope2,eventListenerId,{name:data.name,content:data.content,id:data.id})}async function syncNewEventListener(client,scope2,eventListenerId){let clone2=cloneFor(scope2);if(!clone2||scope2.environmentId===void 0||!await folderForListener(clone2,client,scope2,eventListenerId))return;let path2={workspaceId:scope2.workspaceId,environmentId:scope2.environmentId},list=await readOrSkip(()=>client.GET("/v1/workspace/{workspaceId}/environment/{environmentId}/eventListener/{eventListenerId}/testPayloads",{params:{path:{...path2,eventListenerId}}}));if(!list)return;let contents=await throttleAll(CONCURRENCY2,list.testPayloads.map(payload=>async()=>readOrSkip(()=>client.GET("/v1/workspace/{workspaceId}/environment/{environmentId}/eventListener/{eventListenerId}/testPayload/{testPayloadId}",{params:{path:{...path2,eventListenerId,testPayloadId:payload.id}}}))));for(let payload of contents)payload&&await syncTestPayload(client,scope2,eventListenerId,{name:payload.name,content:payload.content,id:payload.id})}async function syncEventListenerFolder(client,scope2,eventListenerId,op){let clone2=cloneFor(scope2);if(!clone2)return;let current=folderFromRecord(clone2,eventListenerId);if(!current)return;if(op==="delete"){let removed=Object.keys(clone2.metadata.testPayloads).filter(path2=>path2.startsWith(`test-payloads/${current}/`));try{rmSync7(absolute(clone2,`test-payloads/${current}`),{recursive:!0,force:!0}),noteRemoved(`test-payloads/${current}`)}catch{}saveRecord(clone2,record4=>{for(let path2 of removed)delete record4.testPayloads[path2]});return}folderCache.delete(eventListenerId);let listener=await fetchListener(client,scope2,eventListenerId);if(!listener)return;let next=listenerFolderName(listener);if(!(next===current||unportableNameReason(next))){try{renameSync4(absolute(clone2,`test-payloads/${current}`),absolute(clone2,`test-payloads/${next}`)),noteWritten(`test-payloads/${current} \u2192 test-payloads/${next}`)}catch{return}saveRecord(clone2,record4=>{for(let[path2,entry2]of Object.entries(record4.testPayloads))path2.startsWith(`test-payloads/${current}/`)&&(delete record4.testPayloads[path2],record4.testPayloads[path2.replace(`test-payloads/${current}/`,`test-payloads/${next}/`)]=entry2)}),folderCache.set(eventListenerId,next)}}function folderFromRecord(clone2,eventListenerId){for(let[path2,entry2]of Object.entries(clone2.metadata.testPayloads))if(entry2.eventListenerId===eventListenerId)return path2.split("/")[1]}async function syncParameters(client,scope2){let clone2=cloneFor(scope2),environmentId=scope2.environmentId;if(!clone2||environmentId===void 0)return;let data=await readOrSkip(()=>client.GET("/v1/workspace/{workspaceId}/environment/{environmentId}/parameters",{params:{path:{workspaceId:scope2.workspaceId,environmentId}}}));data&&putFile(clone2,"ev-params.ts",generateEvParams(data.parameters))}async function syncPackages(client,workspaceId){let clone2=cloneFor({workspaceId});if(!clone2)return;let existing=readLocal(clone2,"package.json");if(existing===void 0)return;let data=await readOrSkip(()=>client.GET("/v1/workspace/{workspaceId}/packages",{params:{path:{workspaceId}}}));if(!data)return;let merged=mergePackageJson(existing,data.packages);if(merged===void 0)return;let delta=dependencyDelta(existing,merged);putFile(clone2,"package.json",merged)&&delta.length>0&&warnDependenciesChanged(clone2,delta)}function dependencyDelta(before,after){let read=raw=>{try{return JSON.parse(raw).dependencies??{}}catch{return{}}},from=read(before),to=read(after),words=[];for(let[name,version2]of Object.entries(to))from[name]===void 0?words.push(`+${name}@${version2}`):from[name]!==version2&&words.push(`${name} ${from[name]} \u2192 ${version2}`);for(let name of Object.keys(from))to[name]===void 0&&words.push(`-${name}`);return words}function installCommand(clone2){let lockFiles=[["pnpm-lock.yaml","pnpm install"],["yarn.lock","yarn install"],["package-lock.json","npm install"]];for(let[file2,command]of lockFiles)try{return lstatSync3(absolute(clone2,file2)),command}catch{}}function warnDependenciesChanged(clone2,delta){let command=installCommand(clone2);warnLine(`\u26A0 The workspace's dependencies changed (${delta.join(", ")}) and package.json was updated. `+(command?`Install them again: ${command}`:"Install them again with whichever package manager this project uses."))}function syncReadme(scope2,content,mode){if(mode==="skip-write"){warnLeftBehind(scope2,"README.md");return}let clone2=cloneFor(scope2);if(!clone2)return;let recorded=clone2.metadata.readme,onDisk=readLocal(clone2,"README.md");onDisk!==void 0&&recorded?.checksum!==void 0&&recorded.checksum!==""&&checksumOf(onDisk)!==recorded.checksum&&onDisk!==content&&mode!=="always"?warnDirty("README.md"):putFile(clone2,"README.md",content),saveRecord(clone2,record4=>{record4.readme={checksum:checksumOf(content)}})}async function syncWorkspaceSettings(workspaceId,change){let clone2=cloneFor({workspaceId});if(!clone2)return;if(change.language!==void 0){let existing=readLocal(clone2,"tsconfig.base.json"),strictNow=existing!==void 0&&/"strict"\s*:\s*true/.test(existing);change.language==="ts-strict"?existing===void 0?putFile(clone2,"tsconfig.base.json",generateTsconfigBase("ts-strict")):strictNow||putFile(clone2,"tsconfig.base.json",existing.replace(/"strict"(\s*):(\s*)false/,'"strict"$1:$2true')):strictNow&&!isRaw()&¬eLine("\u2714 tsconfig.base.json keeps strict mode \u2014 the local copy is stricter than the workspace, which is allowed.")}let previousName=change.previousName??clone2.metadata.workspace.name;if(change.name!==void 0&&previousName!==void 0){let existing=readLocal(clone2,"package.json");if(existing===void 0)return;let parsed;try{parsed=JSON.parse(existing)}catch{return}if(parsed.description!==previousName)return;parsed.description=change.name;let trailing=existing.endsWith(`
|
|
1291
|
+
`:"")}function generateTsconfigBase(language){let template=JSON.parse(TSCONFIG_BASE_TEMPLATE);return template.compilerOptions.strict=language==="ts-strict",toJson(template)}var FORBIDDEN_IN_FILE_NAME='<>:"/\\|?*',WINDOWS_RESERVED=/^(con|prn|aux|nul|com[0-9]|lpt[0-9])$/i;function unportableNameReason(name){if(!name.trim())return"it is blank";let forbidden=Array.from(new Set(Array.from(name).filter(ch=>FORBIDDEN_IN_FILE_NAME.includes(ch)||ch<" ")));if(forbidden.length>0){let printable=forbidden.map(ch=>ch<" "?"a control character":`'${ch}'`);return`${printable.length>1?`${printable.slice(0,-1).join(", ")} and ${printable.at(-1)}`:printable[0]} cannot appear in a file name on every platform`}if(/[. ]$/.test(name))return"it ends in a dot or a space, which Windows strips";let base=name.split(".")[0]??name;if(WINDOWS_RESERVED.test(base))return`${base} is a reserved device name on Windows`}function listenerFolderName(listener){let app=pascalCase(listener.app.name)||listener.app.name,event=listener.eventType?pascalCase(listener.eventType.name)||listener.eventType.name:void 0;return`${event?`${app}\u2192${event}`:app} (${listener.id})`}function payloadFileName(payloadName){return`${payloadName}.json`}var CONCURRENCY=5;async function apiConnectionFileInputs(client,connections){let withPath=connections.filter(c=>c.path);return(await throttleAll(CONCURRENCY,withPath.map(connection=>async()=>{let catalogue=await apiConnectionPackages(client,connection.app.id,connection.apiConnectionTypeId).catch(()=>[]),fromCatalogue=connection.package?catalogue.find(p=>p.id===connection.package?.id):catalogue.find(p=>p.recommended&&!p.deprecated)??catalogue.find(p=>!p.deprecated)??catalogue[0],packageName=connection.package?.name??fromCatalogue?.name;if(!packageName){warnLine(`\u26A0 API connection "${connection.path}" has no package and the catalogue offers none \u2014 scripts/api/${connection.path}/index.ts was not generated.`);return}let namespace=fromCatalogue?.namespace;return namespace||warnLine(`\u26A0 The app catalogue records no exported class for ${packageName} \u2014 scripts/api/${connection.path}/index.ts uses the guessed name ${guessNamespace(packageName)}.`),{path:connection.path??"",namespace:namespace??guessNamespace(packageName),packageName,connectionId:connection.id,namespaceGuessed:!namespace}}))).filter(input=>input!==void 0)}function apiConnectionFilePath(connectionPath){return`scripts/api/${connectionPath.replaceAll(/\/+/g,"/").replace(/^\//,"").replace(/\/$/,"")}/index.ts`}async function apiConnectionFiles(client,connections){return(await apiConnectionFileInputs(client,connections)).map(input=>({path:apiConnectionFilePath(input.path),content:generateApiConnectionFile(input)}))}import{lstatSync as lstatSync2,mkdirSync as mkdirSync7,readFileSync as readFileSync10,readdirSync as readdirSync5,rmSync as rmSync6,unlinkSync,writeFileSync as writeFileSync6}from"fs";import{join as join10,resolve as resolve3,sep as sep3}from"path";var MARKER_PACKAGES=[...TYPE_PACKAGES,"@sr-connect/convert","@sr-connect/record-storage"],EMPTINESS_IGNORED=new Set([".git",".DS_Store"]);function mergedDependencies(parsed){if(parsed===null||typeof parsed!="object"||Array.isArray(parsed))return{};let manifest=parsed,merged={};for(let section of[manifest.dependencies,manifest.devDependencies])section!==null&&typeof section=="object"&&!Array.isArray(section)&&Object.assign(merged,section);return merged}function looksLikeClonedWorkspace(directory){try{return lstatSync2(join10(directory,METADATA_FILE)),!0}catch{}let raw;try{raw=readFileSync10(join10(directory,"package.json"),"utf8")}catch{return!1}let parsed;try{parsed=JSON.parse(raw)}catch{return!1}let dependencies=mergedDependencies(parsed);return MARKER_PACKAGES.every(name=>name in dependencies)}function inspectDirectory(directory){let entries;try{entries=readdirSync5(directory)}catch{return"empty"}return entries.every(entry2=>EMPTINESS_IGNORED.has(entry2))?"empty":looksLikeClonedWorkspace(directory)?"cloned-workspace":"non-empty"}var KEPT_IN_UPDATE_MODE=new Set(["tsconfig.json","tsconfig.base.json","eslint.config.js",".gitignore",".prettierrc","pnpm-workspace.yaml",".vscode/extensions.json","node/apiRegistry.ts","node/runtimeMocks.ts","node/global.d.ts","node/tsconfig.json","node/jest.config.ts"]),BARE_DIRECTORIES=["scripts/api","node/tests"];function assertInside(directory,relativePath){let absolute2=resolve3(directory,relativePath),base=resolve3(directory);if(absolute2!==base&&!absolute2.startsWith(base+sep3))throw new Error(`Refusing to write outside the target directory: ${relativePath}`);return absolute2}function entryExists(absolute2){try{return lstatSync2(absolute2),!0}catch{return!1}}function ensureParents(directory,relativePath){let segments=relativePath.split("/").slice(0,-1),current=resolve3(directory);for(let segment of segments){current=join10(current,segment);let stat=entryExists(current)?lstatSync2(current):void 0;stat?.isSymbolicLink()?unlinkSync(current):stat&&!stat.isDirectory()&&rmSync6(current,{force:!0}),mkdirSync7(current,{recursive:!0})}}function writeClone(directory,files,updateMode){let written=[],kept=[];mkdirSync7(resolve3(directory),{recursive:!0});for(let file2 of files){let absolute2=assertInside(directory,file2.path);if(updateMode&&KEPT_IN_UPDATE_MODE.has(file2.path)&&entryExists(absolute2)){kept.push(file2.path);continue}ensureParents(directory,file2.path);let existing=entryExists(absolute2)?lstatSync2(absolute2):void 0;existing?.isSymbolicLink()?unlinkSync(absolute2):existing&&!existing.isFile()&&rmSync6(absolute2,{recursive:!0,force:!0}),writeFileSync6(absolute2,file2.content),written.push(file2.path)}for(let bare of BARE_DIRECTORIES)ensureParents(directory,`${bare}/.`),mkdirSync7(assertInside(directory,bare),{recursive:!0});return{written,kept}}function walkFiles(root,prefix,out){let entries;try{entries=readdirSync5(root)}catch{return}for(let entry2 of entries){let absolute2=join10(root,entry2),relativePath=prefix?`${prefix}/${entry2}`:entry2;lstatSync2(absolute2).isDirectory()?walkFiles(absolute2,relativePath,out):out.push(relativePath)}}var SWEPT_ROOTS=["scripts/api","test-payloads"];function sweepStaleFiles(directory,manifestPaths){return SWEPT_ROOTS.flatMap(root=>sweepRoot(directory,root,manifestPaths))}function sweepRoot(directory,root,keep){let deleted=[],rootPath=resolve3(directory,root),present=[];walkFiles(rootPath,root,present);for(let relativePath of present)keep.has(relativePath)||(rmSync6(assertInside(directory,relativePath),{force:!0}),deleted.push(relativePath));return prune3(rootPath,rootPath),deleted}function prune3(dir,root){let entries;try{entries=readdirSync5(dir)}catch{return}for(let entry2 of entries){let absolute2=join10(dir,entry2);lstatSync2(absolute2).isDirectory()&&prune3(absolute2,root)}resolve3(dir)!==root&&readdirSync5(dir).length===0&&rmSync6(dir,{recursive:!0})}var CONCURRENCY2=5,enabled5=!0,instance2;function configureLocalSync(opts){enabled5=opts.enabled!==!1&&!truthy2(process.env.SR_CONNECT_CLI_NO_LOCAL_SYNC)&&settingEnabled("localSync"),instance2=opts.instance}function truthy2(value){return value===void 0?!1:!["","0","false","no","off"].includes(value.trim().toLowerCase())}var MAX_LEVELS=40,lookedUp=!1,found;function findLocalClone(){if(lookedUp)return found;lookedUp=!0;let directory=resolve4(process.cwd());for(let level=0;level<MAX_LEVELS;level+=1){let read=readMetadata(directory);if(read.metadata)return found={directory,metadata:read.metadata},found;if(read.problem){warnLine(`\u26A0 ${displayPath(join11(directory,METADATA_FILE))}: ${read.problem} Ignoring the local copy.`);return}let parent=dirname3(directory);if(parent===directory)break;directory=parent}}var noted=new Set;function noteOnce(line){noted.has(line)||(noted.add(line),warnLine(line))}function cloneFor(scope2){if(!enabled5)return;let clone2=findLocalClone();if(!clone2)return;let record4=clone2.metadata;if(instance2!==void 0&&record4.instance!==""&&baseUrl(record4.instance)!==baseUrl(instance2)){noteOnce(`\u26A0 The local copy in ${displayPath(clone2.directory)} was cloned from ${record4.instance} \u2014 not updated.`);return}if(record4.workspace.id!==scope2.workspaceId){noteOnce(`\u26A0 The local copy in ${displayPath(clone2.directory)} is workspace ${record4.workspace.name??record4.workspace.id} (${record4.workspace.id}) \u2014 not updated.`);return}if(scope2.environmentId!==void 0&&record4.environment.id!==scope2.environmentId){noteOnce(`\u26A0 The local copy in ${displayPath(clone2.directory)} is environment ${record4.environment.name??record4.environment.id} (${record4.environment.id}) \u2014 not updated.`);return}if(record4.environment.release){noteOnce(`\u26A0 The local copy in ${displayPath(clone2.directory)} is release ${record4.environment.release}'s snapshot \u2014 not updated. Re-clone it to pick up what the environment runs now.`);return}return clone2}function absolute(clone2,relativePath){return assertInside(clone2.directory,relativePath)}function readLocal(clone2,relativePath){try{return readFileSync11(absolute(clone2,relativePath),"utf8")}catch{return}}function noteWritten(relativePath){isRaw()||noteLine(`\u2714 Local copy updated: ${relativePath}`)}function noteRemoved(relativePath){isRaw()||noteLine(`\u2714 Local copy updated: ${relativePath} removed`)}function warnDirty(relativePath){warnLine(`\u26A0 ${relativePath} has local changes \u2014 left alone. It no longer matches the workspace.`)}function warnLeftBehind(scope2,relativePath){cloneFor(scope2)&&warnLine(`\u26A0 ${relativePath??"The local copy"} was not updated \u2014 you chose to edit the version in the workspace. Fetch it with \`${CLI} local-workspace clone\`, which rewrites the whole local copy, so check for other unsynced changes first.`)}function ensureParent(clone2,relativePath){mkdirSync8(dirname3(absolute(clone2,relativePath)),{recursive:!0})}async function attempt(run){try{return await run()}catch{return}}async function readOrSkip(run){let got=await attempt(run);return got?.response.ok?got.data:void 0}function writeOrWarn(relativePath,run){try{return run()}catch(error51){warnLine(`\u26A0 ${relativePath} could not be updated in the local copy (${describeError(error51)}). The workspace has the change; this directory does not.`);return}}function putFile(clone2,relativePath,content){return readLocal(clone2,relativePath)===content||!writeOrWarn(relativePath,()=>(ensureParent(clone2,relativePath),writeFileSync7(absolute(clone2,relativePath),content),!0))?!1:(noteWritten(relativePath),!0)}function dropFile(clone2,relativePath){let target=absolute(clone2,relativePath);try{lstatSync3(target)}catch{return!1}return writeOrWarn(relativePath,()=>(rmSync7(target,{force:!0}),pruneUpwards(clone2,dirname3(relativePath)),!0))?(noteRemoved(relativePath),!0):!1}function pruneUpwards(clone2,relativeDir){let roots=new Set([".","","scripts","scripts/api","test-payloads"]),current=relativeDir;for(;!roots.has(current);){let target=absolute(clone2,current);try{if(readdirSync6(target).length>0)return;rmSync7(target,{recursive:!0,force:!0})}catch{return}current=dirname3(current)}}function saveRecord(clone2,mutate){mutate(clone2.metadata),clone2.metadata.cli=writerTag();try{writeFileSync7(absolute(clone2,METADATA_FILE),renderMetadata(clone2.metadata))}catch{warnLine(`\u26A0 ${METADATA_FILE} could not be updated \u2014 the next \`${CLI} local-workspace push\` may re-send files that are already in the workspace.`)}}function syncScript(scope2,change){if(change.mode==="skip-write"){warnLeftBehind(scope2,scriptPath(change.name));return}let clone2=cloneFor(scope2);if(!clone2)return;let relativePath=scriptPath(change.name),recordedName=change.id===void 0?void 0:Object.entries(clone2.metadata.scripts).find(([,entry2])=>entry2.id===change.id)?.[0],candidate=change.previousName??recordedName,previous=candidate!==void 0&&candidate!==change.name?candidate:void 0;if(previous!==void 0){let from=scriptPath(previous),recorded2=clone2.metadata.scripts[previous];if(readLocal(clone2,from)!==void 0)try{ensureParent(clone2,relativePath),renameSync4(absolute(clone2,from),absolute(clone2,relativePath)),pruneUpwards(clone2,dirname3(from)),noteWritten(`${from} \u2192 ${relativePath}`)}catch{warnLine(`\u26A0 ${from} could not be moved to ${relativePath}.`)}saveRecord(clone2,record4=>{delete record4.scripts[previous],recorded2&&(record4.scripts[change.name]=recorded2)})}let recorded=clone2.metadata.scripts[change.name],onDisk=readLocal(clone2,relativePath);onDisk!==void 0&&recorded?.checksum!==void 0&&recorded.checksum!==""&&checksumOf(onDisk)!==recorded.checksum&&onDisk!==change.content&&change.mode!=="always"?warnDirty(relativePath):putFile(clone2,relativePath,change.content),saveRecord(clone2,record4=>{record4.scripts[change.name]={...change.id===void 0?{}:{id:change.id},checksum:checksumOf(change.content)}})}async function syncScriptFromServer(client,scope2,scriptId){if(!cloneFor(scope2)||scope2.environmentId===void 0)return;let path2={workspaceId:scope2.workspaceId,environmentId:scope2.environmentId},data=await readOrSkip(()=>client.GET("/v1/workspace/{workspaceId}/environment/{environmentId}/script/{scriptId}",{params:{path:{...path2,scriptId}}}));data&&syncScript(scope2,{name:data.name,content:data.content,id:data.id})}function syncScriptDeleted(scope2,ref){let clone2=cloneFor(scope2);if(!clone2)return;let name=ref.name??Object.entries(clone2.metadata.scripts).find(([,entry2])=>entry2.id===ref.id)?.[0];if(name===void 0)return;let relativePath=scriptPath(name),recorded=clone2.metadata.scripts[name],onDisk=readLocal(clone2,relativePath);onDisk!==void 0&&recorded?.checksum&&checksumOf(onDisk)!==recorded.checksum?warnLine(`\u26A0 ${relativePath} has local changes \u2014 left in place, though the script is gone from the workspace.
|
|
1292
|
+
\`${CLI} local-workspace push\` would create the script again from this file. Delete it to drop the work, or move it out of the local copy to keep it.`):dropFile(clone2,relativePath),saveRecord(clone2,record4=>{delete record4.scripts[name]})}var folderCache=new Map;async function folderForListener(clone2,client,scope2,eventListenerId){let cached2=folderCache.get(eventListenerId);if(cached2!==void 0)return cached2;for(let[path2,entry2]of Object.entries(clone2.metadata.testPayloads)){if(entry2.eventListenerId!==eventListenerId)continue;let folder2=path2.split("/")[1];if(folder2)return folderCache.set(eventListenerId,folder2),folder2}let listener=await fetchListener(client,scope2,eventListenerId),folder=listener?listenerFolderName(listener):void 0;if(folder&&unportableNameReason(folder)){folderCache.set(eventListenerId,void 0);return}return folderCache.set(eventListenerId,folder),folder}async function fetchListener(client,scope2,eventListenerId){let environmentId=scope2.environmentId;if(environmentId===void 0)return;let data=await readOrSkip(()=>client.GET("/v1/workspace/{workspaceId}/environment/{environmentId}/eventListeners",{params:{path:{workspaceId:scope2.workspaceId,environmentId}}}));if(data)return data.eventListeners.find(listener=>listener.id===eventListenerId)}function payloadPathById(clone2,id){if(id!==void 0)return Object.entries(clone2.metadata.testPayloads).find(([,entry2])=>entry2.id===id)?.[0]}function payloadNameFromPath(path2){let file2=path2.split("/")[2];return file2?.endsWith(".json")?file2.slice(0,-5):void 0}async function syncTestPayload(client,scope2,eventListenerId,change){if(change.mode==="skip-write"){let skipped=cloneFor(scope2),folder2=skipped?await folderForListener(skipped,client,scope2,eventListenerId):void 0;warnLeftBehind(scope2,folder2&&change.name?`test-payloads/${folder2}/${payloadFileName(change.name)}`:void 0);return}let clone2=cloneFor(scope2);if(!clone2)return;let folder=await folderForListener(clone2,client,scope2,eventListenerId);if(!folder)return;let knownPath=payloadPathById(clone2,change.id),recordedName=knownPath===void 0?void 0:payloadNameFromPath(knownPath),name=change.name??recordedName;if(name===void 0)return;let previousName=change.previousName??recordedName,reason=unportableNameReason(payloadFileName(name));if(reason){warnLine(`\u26A0 Test payload "${name}" was not written to the local copy: ${reason}.`);return}let relativePath=`test-payloads/${folder}/${payloadFileName(name)}`;if(previousName!==void 0&&previousName!==name){let from=`test-payloads/${folder}/${payloadFileName(previousName)}`,recorded2=clone2.metadata.testPayloads[from];if(readLocal(clone2,from)!==void 0)try{ensureParent(clone2,relativePath),renameSync4(absolute(clone2,from),absolute(clone2,relativePath)),noteWritten(`${from} \u2192 ${relativePath}`)}catch{warnLine(`\u26A0 ${from} could not be moved to ${relativePath}.`)}saveRecord(clone2,record4=>{delete record4.testPayloads[from],recorded2&&(record4.testPayloads[relativePath]=recorded2)})}let recorded=clone2.metadata.testPayloads[relativePath],onDisk=readLocal(clone2,relativePath);onDisk!==void 0&&recorded?.checksum!==void 0&&recorded.checksum!==""&&checksumOf(onDisk)!==recorded.checksum&&onDisk!==change.content&&change.mode!=="always"?warnDirty(relativePath):putFile(clone2,relativePath,change.content),saveRecord(clone2,record4=>{record4.testPayloads[relativePath]={eventListenerId,...change.id===void 0?{}:{id:change.id},checksum:checksumOf(change.content)}})}async function syncTestPayloadDeleted(client,scope2,eventListenerId,ref){let clone2=cloneFor(scope2);if(!clone2)return;let byId=payloadPathById(clone2,ref.id),folder=byId?void 0:await folderForListener(clone2,client,scope2,eventListenerId),relativePath=byId??(folder&&ref.name!==void 0?`test-payloads/${folder}/${payloadFileName(ref.name)}`:void 0);relativePath!==void 0&&(dropFile(clone2,relativePath),saveRecord(clone2,record4=>{delete record4.testPayloads[relativePath]}))}async function syncTestPayloadRenamed(client,scope2,eventListenerId,change){let clone2=cloneFor(scope2);if(!clone2)return;let from=payloadPathById(clone2,change.id);if(from===void 0)return;let folder=from.split("/")[1];if(!folder||unportableNameReason(payloadFileName(change.name)))return;let to=`test-payloads/${folder}/${payloadFileName(change.name)}`;if(to===from)return;let entry2=clone2.metadata.testPayloads[from];if(readLocal(clone2,from)!==void 0)try{renameSync4(absolute(clone2,from),absolute(clone2,to)),noteWritten(`${from} \u2192 ${to}`)}catch{warnLine(`\u26A0 ${from} could not be moved to ${to}.`);return}saveRecord(clone2,record4=>{delete record4.testPayloads[from],entry2&&(record4.testPayloads[to]=entry2)})}async function syncTestPayloadById(client,scope2,eventListenerId,testPayloadId){let environmentId=scope2.environmentId;if(!cloneFor(scope2)||environmentId===void 0)return;let data=await readOrSkip(()=>client.GET("/v1/workspace/{workspaceId}/environment/{environmentId}/eventListener/{eventListenerId}/testPayload/{testPayloadId}",{params:{path:{workspaceId:scope2.workspaceId,environmentId,eventListenerId,testPayloadId}}}));data&&await syncTestPayload(client,scope2,eventListenerId,{name:data.name,content:data.content,id:data.id})}async function syncNewEventListener(client,scope2,eventListenerId){let clone2=cloneFor(scope2);if(!clone2||scope2.environmentId===void 0||!await folderForListener(clone2,client,scope2,eventListenerId))return;let path2={workspaceId:scope2.workspaceId,environmentId:scope2.environmentId},list=await readOrSkip(()=>client.GET("/v1/workspace/{workspaceId}/environment/{environmentId}/eventListener/{eventListenerId}/testPayloads",{params:{path:{...path2,eventListenerId}}}));if(!list)return;let contents=await throttleAll(CONCURRENCY2,list.testPayloads.map(payload=>async()=>readOrSkip(()=>client.GET("/v1/workspace/{workspaceId}/environment/{environmentId}/eventListener/{eventListenerId}/testPayload/{testPayloadId}",{params:{path:{...path2,eventListenerId,testPayloadId:payload.id}}}))));for(let payload of contents)payload&&await syncTestPayload(client,scope2,eventListenerId,{name:payload.name,content:payload.content,id:payload.id})}async function syncEventListenerFolder(client,scope2,eventListenerId,op){let clone2=cloneFor(scope2);if(!clone2)return;let current=folderFromRecord(clone2,eventListenerId);if(!current)return;if(op==="delete"){let removed=Object.keys(clone2.metadata.testPayloads).filter(path2=>path2.startsWith(`test-payloads/${current}/`));try{rmSync7(absolute(clone2,`test-payloads/${current}`),{recursive:!0,force:!0}),noteRemoved(`test-payloads/${current}`)}catch{}saveRecord(clone2,record4=>{for(let path2 of removed)delete record4.testPayloads[path2]});return}folderCache.delete(eventListenerId);let listener=await fetchListener(client,scope2,eventListenerId);if(!listener)return;let next=listenerFolderName(listener);if(!(next===current||unportableNameReason(next))){try{renameSync4(absolute(clone2,`test-payloads/${current}`),absolute(clone2,`test-payloads/${next}`)),noteWritten(`test-payloads/${current} \u2192 test-payloads/${next}`)}catch{return}saveRecord(clone2,record4=>{for(let[path2,entry2]of Object.entries(record4.testPayloads))path2.startsWith(`test-payloads/${current}/`)&&(delete record4.testPayloads[path2],record4.testPayloads[path2.replace(`test-payloads/${current}/`,`test-payloads/${next}/`)]=entry2)}),folderCache.set(eventListenerId,next)}}function folderFromRecord(clone2,eventListenerId){for(let[path2,entry2]of Object.entries(clone2.metadata.testPayloads))if(entry2.eventListenerId===eventListenerId)return path2.split("/")[1]}async function syncParameters(client,scope2){let clone2=cloneFor(scope2),environmentId=scope2.environmentId;if(!clone2||environmentId===void 0)return;let data=await readOrSkip(()=>client.GET("/v1/workspace/{workspaceId}/environment/{environmentId}/parameters",{params:{path:{workspaceId:scope2.workspaceId,environmentId}}}));data&&putFile(clone2,"ev-params.ts",generateEvParams(data.parameters))}async function syncPackages(client,workspaceId){let clone2=cloneFor({workspaceId});if(!clone2)return;let existing=readLocal(clone2,"package.json");if(existing===void 0)return;let data=await readOrSkip(()=>client.GET("/v1/workspace/{workspaceId}/packages",{params:{path:{workspaceId}}}));if(!data)return;let merged=mergePackageJson(existing,data.packages);if(merged===void 0)return;let delta=dependencyDelta(existing,merged);putFile(clone2,"package.json",merged)&&delta.length>0&&warnDependenciesChanged(clone2,delta)}function dependencyDelta(before,after){let read=raw=>{try{return JSON.parse(raw).dependencies??{}}catch{return{}}},from=read(before),to=read(after),words=[];for(let[name,version2]of Object.entries(to))from[name]===void 0?words.push(`+${name}@${version2}`):from[name]!==version2&&words.push(`${name} ${from[name]} \u2192 ${version2}`);for(let name of Object.keys(from))to[name]===void 0&&words.push(`-${name}`);return words}function installCommand(clone2){let lockFiles=[["pnpm-lock.yaml","pnpm install"],["yarn.lock","yarn install"],["package-lock.json","npm install"]];for(let[file2,command]of lockFiles)try{return lstatSync3(absolute(clone2,file2)),command}catch{}}function warnDependenciesChanged(clone2,delta){let command=installCommand(clone2);warnLine(`\u26A0 The workspace's dependencies changed (${delta.join(", ")}) and package.json was updated. `+(command?`Install them again: ${command}`:"Install them again with whichever package manager this project uses."))}function syncReadme(scope2,content,mode){if(mode==="skip-write"){warnLeftBehind(scope2,"README.md");return}let clone2=cloneFor(scope2);if(!clone2)return;let recorded=clone2.metadata.readme,onDisk=readLocal(clone2,"README.md");onDisk!==void 0&&recorded?.checksum!==void 0&&recorded.checksum!==""&&checksumOf(onDisk)!==recorded.checksum&&onDisk!==content&&mode!=="always"?warnDirty("README.md"):putFile(clone2,"README.md",content),saveRecord(clone2,record4=>{record4.readme={checksum:checksumOf(content)}})}async function syncWorkspaceSettings(workspaceId,change){let clone2=cloneFor({workspaceId});if(!clone2)return;if(change.language!==void 0){let existing=readLocal(clone2,"tsconfig.base.json"),strictNow=existing!==void 0&&/"strict"\s*:\s*true/.test(existing);change.language==="ts-strict"?existing===void 0?putFile(clone2,"tsconfig.base.json",generateTsconfigBase("ts-strict")):strictNow||putFile(clone2,"tsconfig.base.json",existing.replace(/"strict"(\s*):(\s*)false/,'"strict"$1:$2true')):strictNow&&!isRaw()&¬eLine("\u2714 tsconfig.base.json keeps strict mode \u2014 the local copy is stricter than the workspace, which is allowed.")}let previousName=change.previousName??clone2.metadata.workspace.name;if(change.name!==void 0&&previousName!==void 0){let existing=readLocal(clone2,"package.json");if(existing===void 0)return;let parsed;try{parsed=JSON.parse(existing)}catch{return}if(parsed.description!==previousName)return;parsed.description=change.name;let trailing=existing.endsWith(`
|
|
1292
1293
|
`)?`
|
|
1293
1294
|
`:"";putFile(clone2,"package.json",`${JSON.stringify(parsed,null,4)}${trailing}`),saveRecord(clone2,record4=>{record4.workspace.name=change.name})}}async function syncApiConnections(client,scope2){let clone2=cloneFor(scope2);if(!clone2)return;let environmentId=scope2.environmentId??clone2.metadata.environment.id,data=await readOrSkip(()=>client.GET("/v1/workspace/{workspaceId}/environment/{environmentId}/apiConnections",{params:{path:{workspaceId:scope2.workspaceId,environmentId}}}));if(!data)return;let files=await attempt(()=>apiConnectionFiles(client,data.apiConnections));if(!files)return;for(let file2 of files)putFile(clone2,file2.path,file2.content);let swept=sweepRoot(clone2.directory,"scripts/api",new Set(files.map(file2=>file2.path)));for(let path2 of swept)noteRemoved(path2)}function noteRedeployed(scope2,what){let clone2=cloneFor(scope2);clone2&&warnLine(`\u26A0 The local copy in ${displayPath(clone2.directory)} no longer matches this environment (${what}). Re-clone it with \`${CLI} local-workspace clone\`.`)}async function localEditSource(client,scope2,target,serverContent){let clone2=cloneFor(scope2);if(!clone2)return{content:serverContent,mode:"if-clean"};let relativePath=await editPath(clone2,client,scope2,target);if(!relativePath)return{content:serverContent,mode:"if-clean"};let onDisk=readLocal(clone2,relativePath);return onDisk===void 0||onDisk===serverContent?{content:serverContent,mode:"if-clean"}:canPrompt()?(prompts().note(`This ${nounOf(target)} differs from your local copy at ${relativePath}.`),await prompts().select("Which one do you want to edit?",[{value:"local",label:`The local file \u2014 ${relativePath}`,hint:"edited here, then uploaded"},{value:"server",label:"The version in the workspace",hint:"the local file is left alone"}],{initial:"local"})==="local"?{content:onDisk,mode:"always"}:{content:serverContent,mode:"skip-write"}):{content:serverContent,mode:"if-clean"}}function nounOf(target){return target.kind==="script"?"script":target.kind==="payload"?"test payload":"README"}async function editPath(clone2,client,scope2,target){if(target.kind==="script")return scriptPath(target.name);if(target.kind==="readme")return"README.md";let folder=await folderForListener(clone2,client,scope2,target.eventListenerId);return folder?`test-payloads/${folder}/${payloadFileName(target.name)}`:void 0}var flagEnabled2=!0,instance3;function configureLocalWorkspaceScope(opts){flagEnabled2=opts.enabled!==!1,instance3=opts.instance}function truthy3(value){return value===void 0?!1:!["","0","false","no","off"].includes(value.trim().toLowerCase())}function localWorkspaceScopeEnabled(){return flagEnabled2&&!truthy3(process.env.SR_CONNECT_CLI_NO_LOCAL_WORKSPACE)}function localWorkspaceScope(){if(!localWorkspaceScopeEnabled())return;let clone2=findLocalClone();if(!clone2)return;let record4=clone2.metadata;if(instance3!==void 0&&record4.instance!==""&&baseUrl(record4.instance)!==baseUrl(instance3))return;let labels={team:record4.team.name};return record4.workspace.name&&(labels.workspace=record4.workspace.name),record4.environment.name&&(labels.environment=record4.environment.name),{directory:clone2.directory,recordPath:join12(clone2.directory,METADATA_FILE),values:{team:record4.team.id,workspace:record4.workspace.id,environment:record4.environment.id},labels}}var SCOPE_ENV={team:"SR_CONNECT_CLI_TEAM",workspace:"SR_CONNECT_CLI_WORKSPACE",environment:"SR_CONNECT_CLI_ENVIRONMENT"};function scopeEnvVar(key){return Object.hasOwn(SCOPE_ENV,key)?SCOPE_ENV[key]:void 0}var SKIPPED_DEFAULT_HINT={destructive:"A session default and a local workspace record are only borrowed by a destructive verb when someone is there to see the question naming it \u2014 pass the scope with flags or environment variables, or run it on a terminal.","save-flow":"This verb writes the session defaults rather than reading them, so a stored value is never the answer here \u2014 pass all three with flags or environment variables, or run it on a terminal to pick them."},workspaceOrigin,inheritedWorkspaceNoted=!1;function inheritedWorkspaceNote(from,workspaceId){return from===void 0||from==="flag"||from==="picker"?void 0:`\u26A0 Workspace ${workspaceId} came from ${from==="env"?"SR_CONNECT_CLI_WORKSPACE":from==="local"?"a local workspace's workspace.json":"this shell's session defaults"}, not from -w \u2014 ${from==="local"?"the clone may name a workspace that no longer exists.":"check that it is the one the ID belongs to."}`}function warnInheritedWorkspace(from,workspaceId){if(inheritedWorkspaceNoted)return;let origin=from!==void 0&&workspaceId!==void 0?{from,value:workspaceId}:workspaceOrigin;if(origin===void 0)return;let note=inheritedWorkspaceNote(origin.from,origin.value);note!==void 0&&(inheritedWorkspaceNoted=!0,warnLine(note))}function recordWorkspaceOrigin(source,values){let from=source.get("workspace"),value=values.workspace;from===void 0||value===void 0||(workspaceOrigin={from,value})}var sessionAnswers=new Map,announcedKeys=new Set,localAnswers=new Map,announcedLocalKeys=new Set,notedLocalClash=!1;function relevantScope(keys,registry2){let seen=new Set,walk2=key=>{if(!seen.has(key)){seen.add(key);for(let dep of registry2[key]?.dependsOn??[])walk2(dep)}};for(let key of keys)walk2(key);return seen}function describeScope(list,record4,registry2){return list.map(k2=>{let noun=(registry2[k2]?.label??k2).toLowerCase(),label=record4.labels?.[k2];return label?`${noun} "${label}" (${record4[k2]??""})`:`${noun} ${record4[k2]??""}`}).join(", ")}async function resolveParams(keys,provided,ctx){let registry2=ctx.registry??RESOLVERS,values={},userProvided=new Set,source=new Map;for(let[key,value]of Object.entries(provided))value&&(values[key]=value,userProvided.add(key),source.set(key,"flag"));for(let key of SESSION_KEYS){let fromEnv=process.env[SCOPE_ENV[key]];!values[key]&&fromEnv&&fromEnv!==""&&(values[key]=fromEnv,userProvided.add(key),source.set(key,"env"))}let blame=(key,form)=>{let spec=registry2[key],value=values[key]??"",origin=source.get(key)==="env"?scopeEnvVar(key)??key:source.get(key)==="session"?`session default \u2014 ${CLI} cli clear-session to clear`:source.get(key)==="local"?`local workspace record \u2014 ${local?.recordPath??""}`:ctx.blame?.[key]??spec?.flag??key;return form==="long"?`${spec?.label??key} '${value}' (${origin})`:`${origin} '${value}'`},skippedDefault=key=>ctx.useSession!==!1||!SESSION_KEYS.includes(key)?!1:readSession()?.[key]?!0:!!localWorkspaceScope()?.values[key],local=ctx.useSession===!1?void 0:localWorkspaceScope();local&&await applyLocalScope(local);let session=ctx.useSession===!1?void 0:readSession(),instanceCleared2=takeInstanceClear();if(instanceCleared2&&prompts().note(`Session defaults cleared \u2014 they belonged to instance '${instanceCleared2}', which is no longer the active instance.`),session){let applied=[];for(let key of SESSION_KEYS){let value=session[key];value&&!values[key]&&(values[key]=value,userProvided.add(key),source.set(key,"session"),applied.push(key))}let relevant=relevantScope(ctx.needs??keys,registry2),shown=applied.filter(k2=>relevant.has(k2)),describeKeys=list=>describeScope(list,session,registry2),drop=list=>{for(let key of list)delete values[key],userProvided.delete(key),source.delete(key)};if(canPrompt()){let unanswered=shown.filter(k2=>!sessionAnswers.has(k2));if(unanswered.length>0){let use=await prompts().confirm(`Use session defaults: ${describeKeys(unanswered)}?`,!0);for(let key of unanswered)sessionAnswers.set(key,use);use||prompts().note("Not using session defaults \u2014 resolving for this run only.")}let refused=applied.filter(k2=>sessionAnswers.get(k2)===!1);drop(refused),shown=shown.filter(k2=>!refused.includes(k2))}else if(shown.length>0){let fresh=shown.filter(k2=>!announcedKeys.has(k2));if(fresh.length>0){for(let key of fresh)announcedKeys.add(key);prompts().note(`Using session defaults: ${describeKeys(fresh)} (${CLI} cli clear-session to clear)`)}}}async function applyLocalScope(record4){let asRecord={...record4.values,labels:record4.labels},clash=SESSION_KEYS.filter(k2=>values[k2]&&values[k2]!==record4.values[k2]);if(clash.length>0&&!(clash.length===1&&clash[0]==="environment"&&await environmentBelongsTo(ctx.client,record4.values.workspace,values.environment??"")===!0)){if(!notedLocalClash){notedLocalClash=!0;let blamed=clash.map(k2=>blame(k2,"short")).join(", ");prompts().note(`The local workspace in ${displayPath(record4.directory)} is ${describeScope(clash,asRecord,registry2)} \u2014 set aside for this run, because ${blamed} was passed instead; its team and workspace are not used either.`)}return}let missing=SESSION_KEYS.filter(k2=>!values[k2]);if(missing.length===0)return;let relevant=relevantScope(ctx.needs??keys,registry2),shown=missing.filter(k2=>relevant.has(k2));if(canPrompt()){let unanswered=shown.filter(k2=>!localAnswers.has(k2));if(unanswered.length>0){let use=await prompts().confirm(`Use the local workspace in ${displayPath(record4.directory)} \u2014 ${describeScope(unanswered,asRecord,registry2)}?`,!0);for(let key of unanswered)localAnswers.set(key,use);if(!use){for(let key of SESSION_KEYS)localAnswers.set(key,!1);prompts().note("Not using the local workspace \u2014 resolving for this run only.")}}}else{let fresh=shown.filter(k2=>!announcedLocalKeys.has(k2));if(fresh.length>0){for(let key of fresh)announcedLocalKeys.add(key);prompts().note(`Using the local workspace in ${displayPath(record4.directory)}: ${describeScope(fresh,asRecord,registry2)} (--no-local-workspace to ignore)`)}}for(let key of missing)localAnswers.get(key)!==!1&&(values[key]=record4.values[key],userProvided.add(key),source.set(key,"local"))}let resolving=new Set,picked=new Set,labels={};async function need(key){let existing=values[key];if(existing)return existing;if(resolving.has(key))throw new Error(`circular resolver dependency at '${key}'`);resolving.add(key);let spec=registry2[key];if(!spec)throw new Error(`no resolver registered for param '${key}'`);if(!ctx.interactive){let envVar=scopeEnvVar(key);fail(EXIT.USAGE,"USAGE_ERROR",ctx.missing?.[key]??`${ctx.blame?.[key]??spec.flag} is required. ${supplyHint({env:envVar})}`,skippedDefault(key)?{hint:SKIPPED_DEFAULT_HINT[ctx.sessionSkipped??"destructive"]}:void 0)}let deps={};for(let dep of spec.dependsOn)deps[dep]=await need(dep);let providedDeps=spec.dependsOn.filter(d=>userProvided.has(d)),choices;try{choices=await withSpinner(`Fetching ${spec.plural}`,()=>spec.fetch(ctx.client,{...values}))}catch(err){if(err instanceof ResolverFetchError){if(err.status===404&&providedDeps.length>0){let blamed=providedDeps.map(d=>blame(d,"long")).join(", ");fail(EXIT.NOT_FOUND,"INVALID_PARAM",`${blamed} is invalid \u2014 the API returned 404 for it.`,{status:404})}mapResolverError(err,spec)}throw err}if(choices.length===0){if(providedDeps.length>0){let blamed=providedDeps.map(d=>blame(d,"short")).join(", ");fail(EXIT.NOT_FOUND,"NO_RESULTS",`No ${spec.plural} found for ${blamed} \u2014 double-check the value.`,{hint:spec.listCommand?`See what exists with \`${spec.listCommand}\`.`:void 0})}fail(EXIT.NOT_FOUND,"NO_RESULTS",`No ${spec.plural} available.`)}let sole=spec.autoSelectSingle&&choices.length===1?choices[0]:void 0,value,label;return sole?(value=sole.value,label=sole.label,prompts().note(`\u2714 ${spec.label}: ${label} (${value}) \u2014 only one, auto-selected`)):(value=await prompts().select(`${spec.label}:`,choices),label=choices.find(c=>c.value===value)?.label??value,prompts().note(`\u2714 ${spec.label}: ${label} (${value})`)),values[key]=value,labels[key]=label,ctx.labels&&(ctx.labels[key]=label),source.set(key,"picker"),picked.add(key),resolving.delete(key),value}for(let key of Object.keys(values))picked.has(key)||(values[key]=assertResourceId(values[key]??"",blame(key,"short")));recordWorkspaceOrigin(source,values);for(let key of keys)await need(key);if(ctx.sources)for(let[key,from]of source)ctx.sources[key]=from;recordWorkspaceOrigin(source,values);let pickedScope=SESSION_KEYS.some(k2=>picked.has(k2));return ctx.offerSession!==!1&&pickedScope&&keys.includes("environment")&&await maybeOfferSession(values,session,registry2,labels),values}async function maybeOfferSession(values,existing,registry2,labels){if(!sessionEnabled()||!canPrompt()||existing?.declined||hasScope(existing)||!values.environment||!values.workspace)return;let record4={team:values.team,workspace:values.workspace,environment:values.environment,labels:pickLabels(values,labels)},summary=describeScope(SESSION_KEYS.filter(k2=>values[k2]),record4,registry2);if(await prompts().confirm(`Remember these as defaults for this shell session \u2014 ${summary}?`,!0)){writeSession(record4);for(let key of SESSION_KEYS)record4[key]&&sessionAnswers.set(key,!0);prompts().note(`\u2714 Saved. Clear with: ${CLI} cli clear-session (or just open a new shell)`)}else writeSession({declined:!0}),prompts().note(`Not saved. Run ${CLI} cli set-session if you change your mind.`)}function pickLabels(values,labels){if(!labels)return;let out={};for(let key of SESSION_KEYS){let label=labels[key];label&&values[key]&&(out[key]=label)}return Object.keys(out).length>0?out:void 0}async function askVersion(message,allowEmpty=!1){for(;;){let answer=(await prompts().text(message,{allowEmpty})).trim();if(answer===""&&allowEmpty)return;let error51=semverError(answer);if(!error51)return answer;prompts().note(`\u2716 ${error51}`)}}var OTHER_INSTANCE="",INSTANCE_URL_PROMPT="Instance API base URL (usually https://api.<your-domain>)";async function askInstance(current){let known=current!==void 0&&INSTANCE_KEYS.includes(current),choice=await prompts().select("Instance:",[...INSTANCE_KEYS.map(key=>({value:key,label:KNOWN_INSTANCES[key].label,hint:KNOWN_INSTANCES[key].url})),{value:OTHER_INSTANCE,label:"Other\u2026",hint:"enter an API base URL"}],{initial:current===void 0?void 0:known?current:OTHER_INSTANCE});if(choice!==OTHER_INSTANCE)return choice;for(;;){let answer=await prompts().text(INSTANCE_URL_PROMPT,{initial:current!==void 0&&!known?current:"https://"}),error51=instanceError(answer);if(!error51)return normalizeInstance(answer);prompts().note(`\u2716 ${error51}`)}}async function askOutputCopy(){if(outputCopyPath())return outputCopyPath();if(!await prompts().confirm("Also copy the output to a file?",!1))return;let answer=await prompts().text(`File name (empty for ${generatedOutputName()} in the current directory)`,{allowEmpty:!0});return setOutputCopy(answer.trim()||!0)}async function resolverChoices(client,key,deps){let spec=RESOLVERS[key];if(!spec)throw new Error(`no resolver registered for param '${key}'`);try{return await withSpinner(`Fetching ${spec.plural}`,()=>spec.fetch(client,deps))}catch(err){if(!(err instanceof ResolverFetchError))throw err;mapResolverError(err,spec)}}async function pickEnvironments(client,workspaceId,message="Deploy into which environments? (space to pick, enter for none)"){let environments=await resolverChoices(client,"environment",{workspace:workspaceId});if(environments.length===0)return prompts().note("\u26A0 No environments in this workspace \u2014 nothing to deploy into."),{ids:[],labels:{}};let ids=await prompts().multiselect(message,environments),labels=Object.fromEntries(ids.map(id=>[id,environments.find(e=>e.value===id)?.label??id]));return{ids,labels}}async function askScript(opts){let existing={value:"existing",label:"Pick an existing script"},create={value:"new",label:"Create a new script",...opts.recommendCreate?{hint:opts.recommendCreate}:{}};if(await prompts().select(opts.message??"Script to run:",opts.recommendCreate?[create,existing]:[existing,create])==="existing")try{return{scriptId:(await resolveParams(["script"],{workspace:opts.workspace,environment:opts.environment},{client:opts.client,interactive:!0,offerSession:!1})).script}}catch(err){if(!(err instanceof CliError)||err.code!=="NO_RESULTS")throw err;prompts().note("\u26A0 No scripts in this environment yet \u2014 creating a new one instead.")}return{scriptName:await askScriptName(opts.suggestedName)}}async function askScriptName(suggested){for(;;){let answer=await prompts().text("New script name (use / for folders, e.g. handlers/OnIssueCreated)",{...suggested?{initial:suggested}:{},allowEmpty:!0}),error51=scriptNameError(answer);if(!error51)return normalizeScriptName(answer);prompts().note(`\u2716 ${error51}`)}}async function askKeepOrChange(opts){let choices=await resolverChoices(opts.client,opts.key,opts.deps),currentValue=opts.current?.value,marked=choices.map(choice=>choice.value===currentValue?{...choice,display:`${choice.display??choice.label} (current)`}:choice),missing=!!currentValue&&!choices.some(c=>c.value===currentValue);if(currentValue&&missing){let label=opts.current?.label??currentValue;marked.unshift({value:currentValue,label,display:`${label} (${opts.missingCurrentMark??"current"})`,hint:currentValue})}let offered=[...marked,...opts.extra??[]];if(offered.length===0)return;let picked=await prompts().select(opts.message,offered,currentValue?{initial:currentValue}:{});return picked===currentValue?void 0:picked}async function askStatus(current,noun="it"){let disabled=await prompts().select("Status:",[{value:"enabled",label:"Enabled",...current?{}:{hint:`enables ${noun}`}},{value:"disabled",label:"Disabled",...current?{hint:`disables ${noun}`}:{}}].map(choice=>choice.value==="disabled"===current?{...choice,display:`${choice.label} (current)`}:choice),{initial:current?"disabled":"enabled"})==="disabled";return disabled===current?void 0:disabled}var REGISTRY=new Map;function defineCommandDoc(command,doc){return REGISTRY.set(command,doc),doc}function docKeys(schema,hidden=[]){let json2=external_exports.toJSONSchema(schema,{unrepresentable:"any"}),all=Object.keys(json2.properties??{}).filter(key=>!hidden.includes(key)),required2=new Set(json2.required??[]);return{required:all.filter(key=>required2.has(key)).sort(),optional:all.filter(key=>!required2.has(key)).sort()}}function nestedKeysOf(property,key){let properties=[property,...property?.anyOf??[]].find(shape=>shape?.type==="object"&&shape.properties)?.properties;return properties?Object.keys(properties).map(child=>`${key}.${child}`):[]}function flagBlockKeys(schema,order){let json2=external_exports.toJSONSchema(schema,{unrepresentable:"any"});return order.flatMap(key=>[key,...nestedKeysOf(json2.properties?.[key],key)])}function aligned(rows2){let width=Math.max(...rows2.map(row=>row.term.length));return rows2.map(row=>` ${row.term.padEnd(width)} ${row.description}`)}function explainLines(doc,ctx={}){let lines=[],flagFor=ctx.flagFor;if(ctx.arguments&&ctx.arguments.length>0&&(lines.push("Arguments:"),lines.push(...aligned(ctx.arguments))),ctx.scope&&ctx.scope.length>0&&(lines.push("Scope flags:"),lines.push(...aligned(ctx.scope)),ctx.ttyOnlyScope&&lines.push(` ${TTY_ONLY_SCOPE_NOTE}`)),doc.schema){let{required:required2,optional:optional2}=docKeys(doc.schema,doc.hidden),conditional=doc.conditional??[];lines.push(`Required: ${required2.length>0?required2.join(", "):"none"}`),optional2.length>0&&lines.push(`Optional: ${optional2.map(key=>conditional.includes(key)?`${key}*`:key).join(", ")}`),conditional.length>0&&lines.push(` * ${conditional.join(" and ")} are optional to the schema; a rule below makes one required.`);let mapped=flagFor?flagBlockKeys(doc.schema,[...required2,...optional2]).map(key=>[key,flagFor(key)]).filter(([,flag])=>flag):[];if(mapped.length>0){lines.push("Keys as flags:");for(let[key,flag]of mapped){let env=credentialEnvFor(key,doc);lines.push(` ${key} = ${flag??""}${env===void 0?"":` + ${env}`}`)}}}if(doc.rules.length>0){lines.push("Rules:");for(let rule of doc.rules)lines.push(` \xB7 ${rule}`)}if(doc.notes&&doc.notes.length>0){lines.push("Notes:");for(let note of doc.notes)lines.push(` \xB7 ${note}`)}return lines}function explained(cmd,doc){return cmd.opts().explain!==!0?!1:(printExplain(doc,explainContext(cmd,doc)),!0)}var SCOPE_FLAGS=["--workspace","--env","--team"],TTY_ONLY_TOKEN="session default on a TTY only",TTY_ONLY_SCOPE_NOTE=`${TTY_ONLY_TOKEN}: the session record and a clone's workspace.json answer such a flag only on a terminal, where the confirmation names what is about to change; elsewhere pass it or its environment variable, or the run is exit 2.`;function explainContext(cmd,doc){return{flagFor:flagResolver(cmd,doc),arguments:cmd.registeredArguments.map(argument=>({term:argument.required?`<${argument.name()}>`:`[${argument.name()}]`,description:argument.description})),scope:SCOPE_FLAGS.flatMap(long=>{let option=cmd.options.find(declared=>declared.long===long);return option?[{term:option.flags,description:option.description}]:[]}),ttyOnlyScope:SCOPE_FLAGS.some(long=>cmd.options.some(declared=>declared.long===long&&declared.description.includes(TTY_ONLY_TOKEN)))}}var SCOPE_KEY_FLAGS={teamId:"--team",workspaceId:"--workspace",environmentId:"--env",environmentIds:"--env"};function nestedFlag(key,doc,declared){let rule=doc.rules.find(text=>text.startsWith(`${key}:`)||text.startsWith(`${key} `));if(rule===void 0)return;let mentioned=new Set([...rule.matchAll(/--[a-z][a-z-]*/g)].map(match=>match[0]).filter(long=>declared.has(long)));if(mentioned.size!==1)return;let flag=/(--[a-z][a-z-]*)(?: <[^>]+>)? as a (?:repeatable )?flag/i.exec(rule)?.[1];return flag!==void 0&&mentioned.has(flag)?flag:void 0}function credentialEnvFor(key,doc){let rule=doc.rules.find(text=>text.startsWith(`${key}:`)||text.startsWith(`${key} `));if(rule===void 0||!/never from argv/i.test(rule))return;let named=new Set([...rule.matchAll(/SR_CONNECT_CLI_[A-Z0-9_]+/g)].map(match=>match[0]));return named.size===1?[...named][0]:void 0}function flagResolver(cmd,doc){let declared=new Set(cmd.options.map(option=>option.long).filter(long=>long!==void 0));return key=>{let kebab=`--${key.slice(key.lastIndexOf(".")+1).replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase()}`;if(declared.has(kebab))return kebab;if(key.includes("."))return nestedFlag(key,doc,declared);let scope2=SCOPE_KEY_FLAGS[key];if(scope2!==void 0&&declared.has(scope2))return scope2;let beside=doc.rules.map(text=>new RegExp(`${key} \\((?:spelled )?(?:-[a-z]/)?(--[a-z][a-z-]*) as a flag[^)]*\\)`).exec(text)).find(match=>match!==null);if(beside?.[1]!==void 0&&declared.has(beside[1]))return beside[1];let spelled=doc.rules.find(text=>text.startsWith(`${key}:`)||text.startsWith(`${key} `))?.match(/(?:spelled|it is the) (?:-[a-z]\/)?(--[a-z][a-z-]*)|\((?:-[a-z]\/)?(--[a-z][a-z-]*) as a flag\)/i),flag=spelled?.[1]??spelled?.[2];return flag!==void 0&&declared.has(flag)?flag:void 0}}function printExplain(doc,ctx={}){let body=doc.body??{};if(isRaw())okText(JSON.stringify(body));else{let pretty=JSON.stringify(body,null,2);okText(process.stdout.isTTY?highlightContent(pretty,"json"):pretty)}for(let line of explainLines(doc,ctx))noteLine(line)}import{readFileSync as readFileSync12}from"fs";import{readSync as readSync2}from"fs";var CHUNK_BYTES=65536,IDLE_WAIT_MS=5;function readStdinSync(){let chunks=[],buffer=Buffer.alloc(CHUNK_BYTES),parked=new Int32Array(new SharedArrayBuffer(4));for(;;){let read;try{read=readSync2(0,buffer,0,CHUNK_BYTES,null)}catch(err){let code=err.code;if(code==="EAGAIN"){Atomics.wait(parked,0,0,IDLE_WAIT_MS);continue}if(code==="EOF")break;throw err}if(read===0)break;chunks.push(Buffer.from(buffer.subarray(0,read)))}return Buffer.concat(chunks).toString("utf8")}var SCOPE_ENV_VAR={team:"SR_CONNECT_CLI_TEAM",workspace:"SR_CONNECT_CLI_WORKSPACE",environment:"SR_CONNECT_CLI_ENVIRONMENT"};function scopeDescription(noun,opts={}){let tokens=[opts.required===!1||opts.behindPositional?"optional":"required","interactive",opts.sessionOnTty?"session default on a TTY only":"session default",`env ${SCOPE_ENV_VAR[noun]}`];return opts.behindPositional&&tokens.push("ignored when the positional argument is given"),`${capitalize(opts.prose??`${noun} ID`)} (${tokens.join(", ")})`}function capitalize(prose){return prose.charAt(0).toUpperCase()+prose.slice(1)}var SCOPE_TEAM=scopeDescription("team"),SCOPE_WORKSPACE=scopeDescription("workspace"),SCOPE_ENVIRONMENT=scopeDescription("environment"),SCOPE_ENVIRONMENT_BESIDE_POSITIONAL=scopeDescription("environment",{behindPositional:!0}),SCOPE_ENVIRONMENT_BESIDE_POSITIONAL_DESTRUCTIVE=scopeDescription("environment",{behindPositional:!0,sessionOnTty:!0}),SCOPE_TEAM_FILTER=scopeDescription("team",{prose:"team ID \u2014 filters the interactive workspace picker",required:!1}),SCOPE_TEAM_SEARCHED=scopeDescription("team",{prose:"team ID \u2014 searched for when omitted, every workspace read being keyed by team",required:!1}),SCOPE_TEAM_DESTRUCTIVE=scopeDescription("team",{sessionOnTty:!0}),SCOPE_WORKSPACE_DESTRUCTIVE=scopeDescription("workspace",{sessionOnTty:!0}),SCOPE_ENVIRONMENT_DESTRUCTIVE=scopeDescription("environment",{sessionOnTty:!0}),SCOPE_TEAM_FILTER_DESTRUCTIVE=scopeDescription("team",{prose:"team ID \u2014 filters the interactive workspace picker",required:!1,sessionOnTty:!0}),GATE_PROSE="environment ID \u2014 the change applies to the whole workspace, whatever environment is named",SCOPE_ENVIRONMENT_GATE=scopeDescription("environment",{prose:GATE_PROSE}),SCOPE_ENVIRONMENT_GATE_DESTRUCTIVE=scopeDescription("environment",{prose:GATE_PROSE,sessionOnTty:!0}),SCOPE_ENVIRONMENT_GATE_HEAD=scopeDescription("environment",{prose:"environment ID \u2014 the change applies to the whole workspace, and the environment named must run HEAD"}),INPUT_BODY="Read the full request body as JSON from a file, or - for stdin (optional, supersedes every body flag)",EXPLAIN="Print what the verb takes on stdout and the rules for every parameter on stderr, then exit without sending anything (optional, supersedes every other flag)",CONFIRM_YES="Skip the confirmation prompt (optional on a TTY, required otherwise)";function readInput(input){try{let raw=input==="-"?readStdinSync():readFileSync12(input,"utf8");return JSON.parse(raw)}catch(error51){fail(EXIT.USAGE,"INVALID_INPUT",`--input ${input==="-"?"stdin":input} could not be read or is not valid JSON.`,{hint:describeError(error51)})}}function validate(schema,body){let result=schema.safeParse(body);return result.success||fail(EXIT.USAGE,"INVALID_BODY",formatBodyError(result.error,body),{hint:EXPLAIN_HINT}),normalizeBodyIds(result.data,schema),result.data}function normalizeBodyIds(body,schema){if(body===null||typeof body!="object")return;let shape=objectShape(schema),record4=body;for(let[key,value]of Object.entries(record4)){if(/Ids?$/.test(key)){if(typeof value=="string"&&(record4[key]=assertBodyId(value,key)),Array.isArray(value))for(let[index,item]of value.entries())typeof item=="string"&&(value[index]=assertBodyId(item,key));continue}if(value===null||typeof value!="object"||Array.isArray(value))continue;let declared=shape?.[key];objectShape(declared)&&normalizeBodyIds(value,declared)}}function objectShape(schema){let current=schema;for(;current instanceof external_exports.ZodOptional||current instanceof external_exports.ZodNullable||current instanceof external_exports.ZodDefault||current instanceof external_exports.ZodReadonly;)current=current.unwrap();return current instanceof external_exports.ZodObject?current.shape:void 0}function assertBodyId(value,key){return value.trim()||fail(EXIT.USAGE,"INVALID_ID",`${key} is empty. Pass ${RESOURCE_ID_FORMAT}, null to detach where the key accepts it, or omit the key to leave it as it is.`),assertResourceId(value,key)}function formatBodyError(error51,body){let seen=new Set;for(let issue2 of error51.issues)seen.add(houseSentence(issue2,body));return[...seen].join(" ")}var EXPLAIN_HINT="Run the verb with --explain to see every key it takes and the flag each key is spelled as.";function houseSentence(issue2,body){let path2=issue2.path.map(String).join("."),subject=path2===""?"body":path2;if(issue2.code==="unrecognized_keys"){let keys=issue2.keys.join(", "),verb=issue2.keys.length>1?"are not keys":"is not a key";return`${keys} ${verb} of this body.`}if(issue2.code==="invalid_type"){if(valueAt(body,issue2.path)===void 0)return`${subject} is required.`;let wanted=TYPE_NOUNS[issue2.expected];if(wanted)return`${subject} must be ${wanted}.`}return issue2.code==="too_big"?issue2.origin==="array"?`${subject} takes at most ${issue2.maximum} items.`:isNumeric(issue2.origin)?`${subject} can be at most ${issue2.maximum}.`:`${subject} can be at most ${issue2.maximum} characters.`:issue2.code==="too_small"?issue2.origin==="array"?`${subject} needs at least ${issue2.minimum} items.`:isNumeric(issue2.origin)?`${subject} must be ${issue2.minimum} or more.`:`${subject} needs at least ${plural(Number(issue2.minimum),"character")}.`:path2===""?issue2.message:`${path2}: ${issue2.message}`}var TYPE_NOUNS={int:"a whole number",number:"a number",string:"text",boolean:"true or false",array:"a list",object:"an object"};function isNumeric(origin){return origin==="number"||origin==="int"||origin==="bigint"||origin==="date"}function plural(count,noun){return`${count} ${noun}${count===1?"":"s"}`}function valueAt(body,path2){let cursor=body;for(let key of path2){if(cursor===null||typeof cursor!="object")return;cursor=cursor[key]}return cursor}function failNothingToUpdate(flags){let list=flags.length>1?`${flags.slice(0,-1).join(", ")} or ${flags.at(-1)}`:flags[0]??"--input";fail(EXIT.USAGE,"USAGE_ERROR",`Nothing to update: pass ${list}.`)}function failNeedsYes(target,verb="Deleting"){fail(EXIT.USAGE,"CONFIRMATION_REQUIRED",`${verb} ${target} is irreversible. Re-run with --yes to confirm.`)}function assertChoice(flag,value,allowed){if(value!==void 0)return allowed.includes(value)||fail(EXIT.USAGE,"INVALID_OPTION",`${flag} must be one of: ${allowed.join(", ")}.`),value}function collect(value,previous){return[...previous??[],...value.split(",").map(v2=>v2.trim()).filter(v2=>v2!=="")]}function disabledFromFlags(opts){return switchFromFlags(opts,"disabled","enabled")}function switchFromFlags(opts,on2,off){if(opts[on2]&&opts[off]&&fail(EXIT.USAGE,"USAGE_ERROR",`--${on2} and --${off} cannot be combined.`),opts[on2])return!0;if(opts[off])return!1}function assertExplicitEnvironmentAgrees(envFlag,inBody){let explicit2=envFlag??process.env.SR_CONNECT_CLI_ENVIRONMENT;if(!explicit2||!inBody||explicit2===inBody)return;let source=envFlag===void 0?"SR_CONNECT_CLI_ENVIRONMENT names":"-e/--env names";fail(EXIT.USAGE,"USAGE_ERROR",`${source} ${explicit2} but the --input body's environmentId is ${inBody}; the body is what is sent, so drop one of them or make them agree.`)}async function teamForQuestions(scope2,globals){let known=scope2.team??globals.team;if(known)return known;if(canPrompt()){if(scope2.askedTeam!==void 0)return scope2.askedTeam||void 0;try{let resolved=await resolveParams(["team"],{},{client:scope2.client,interactive:!0,offerSession:!1});scope2.askedTeam=resolved.team??""}catch(err){if(!(err instanceof CliError))throw err;scope2.askedTeam=""}return scope2.askedTeam||void 0}}function stripUndefined(obj){return Object.fromEntries(Object.entries(obj).filter(([,v2])=>v2!==void 0))}function implicitShareMark(owner){let who=owner?personName(owner):"";return who?`current \u2014 implicitly shared via the workspace, owned by ${who}`:"current \u2014 implicitly shared via the workspace"}async function confirmImplicitReplacement(current,replacement,owner){let who=owner?personName(owner):"",contact=owner?.email&&who!==owner.email?` (${owner.email})`:"";return prompts().note([`"${current}" is attached here and reaches this workspace only because the workspace`,"is shared with you. Removing it cannot be undone by you: only",who?`${who}${contact}, who owns it, or someone it is explicitly shared with, can`:"the connector's owner, or someone it is explicitly shared with, can","attach it back."].join(`
|
|
1294
1295
|
`)),prompts().confirm(`Replace it with "${replacement}"?`,!1)}var createBodySchema=external_exports.object({appId:external_exports.string().min(1),apiConnectionTypeId:external_exports.string().min(1),path:external_exports.string(),packageId:external_exports.string().optional(),connectorId:external_exports.string().optional(),environmentId:external_exports.string().optional()}).strict(),updateBodySchema=external_exports.object({path:external_exports.string().optional(),connectorId:external_exports.string().min(1).optional(),packageId:external_exports.string().min(1).optional()}).strict().refine(body=>Object.keys(body).length>0,{message:"At least one of path, connectorId or packageId is required."}),LIST_DOC=defineCommandDoc("api-connection list",{rules:["The workspace is -w and the environment -e; there is no positional argument, the verb listing every API connection of the workspace."],notes:["A path and its package belong to the workspace, so every environment lists the same connections. The connector column is the exception: it shows what is attached in the environment -e names, which is per-environment configuration."]}),GET_DOC=defineCommandDoc("api-connection get",{rules:["The API connection is the positional argument; the workspace is -w and the environment -e."],notes:["The one read that names the attached connector's owner, which matters because a connector you cannot use is still reported as attached.","Read through a non-HEAD environment it answers what that release captured."]}),DELETE_DOC=defineCommandDoc("api-connection delete",{rules:["The API connection is the positional argument; the workspace is -w and the environment -e, which gates the write rather than choosing what is deleted.","--yes skips the confirmation, and is required without a terminal."],notes:["Removes the API connection from the whole workspace rather than from one environment, and every script importing ./api/<path> stops working.","Its package leaves the workspace unless another API connection on HEAD still uses it. A release that captured a connection on that package does not keep the package in the workspace's dependency list, and pointing a connection back at it puts the package back.","A non-HEAD environment keeps running the copy its release captured."]}),CREATE_DOC=defineCommandDoc("api-connection create",{schema:createBodySchema,body:{appId:"<appId>",apiConnectionTypeId:"<apiConnectionTypeId>",path:"jira",packageId:"<packageId>",connectorId:"<connectorId>",environmentId:"<environmentId>"},rules:[`appId and apiConnectionTypeId come from ${CLI} app list, and the type must be one of the app's.`,`path: ${API_CONNECTION_PATH_FORMAT}; scripts import the connection as ./api/<path>, a pasted ./api/ prefix is dropped, and uniqueness within the workspace is the API's to refuse.`,"packageId: the vendor API package the connection is built on, one of the app's packages in app list; omitted, the API picks the recommended package, or the first one not deprecated, and refuses to choose at all when every package for the API connection type is deprecated.","connectorId attaches a connector in one environment and needs environmentId in the same body: -e/--env fills it on the flags path only, an --input body superseding every body flag; the connector must be of the same API connection type and usable by you in the team; connector list reports each connector's connectionType, which is the app's, and never its API connection type.","environmentId is required with connectorId, and validated whenever it is sent: it must exist and belong to the workspace, and the attachment is refused when that environment is non-HEAD. Sent without connectorId it attaches nothing, so the flags path drops it. The body is what is sent: an -e or SR_CONNECT_CLI_ENVIRONMENT that names a different environment from the body is exit 2 rather than a tie-break, and the session record and a clone's workspace.json are not consulted for the environment when a body is given.","The workspace is -w and never a body key; path and packageId are shared by every environment."]}),UPDATE_DOC=defineCommandDoc("api-connection update",{schema:updateBodySchema,body:{path:"jira",packageId:"<packageId>",connectorId:"<connectorId>"},rules:["An omitted key keeps the current value, and a body with no keys is refused: at least one of path, connectorId or packageId is required.",`connectorId attaches a connector in the environment named by -e, and there is no way to detach one; the connector must be of the connection's API connection type and usable by you in the team, and connector list reports each connector's connectionType, which is the app's, never its API connection type. Omitted, it is kept from that environment's own record, so an API connection with nothing attached there refuses every update \u2014 a path-only one included \u2014 with 400 "Connector is required." until a connector is sent.`,`path: ${API_CONNECTION_PATH_FORMAT}; a pasted ./api/ prefix is dropped; shared by every environment, and every script importing the old ./api/<path> breaks.`,"packageId: the vendor API package, as reported in package.id by get; shared by every environment.","In a non-HEAD environment only connectorId can change. path and packageId are read-only rather than refused there: echo back what that environment's own get reports, or omit them, and only a differing value is a 400 naming it."]});function withScope(cmd,opts={}){let env=opts.gate?opts.destructive?SCOPE_ENVIRONMENT_GATE_DESTRUCTIVE:SCOPE_ENVIRONMENT_GATE:opts.destructive?SCOPE_ENVIRONMENT_DESTRUCTIVE:SCOPE_ENVIRONMENT;return cmd.option("-w, --workspace <workspaceId>",opts.destructive?SCOPE_WORKSPACE_DESTRUCTIVE:SCOPE_WORKSPACE).option("-e, --env <environmentId>",env).option("--team <teamId>",opts.destructive?SCOPE_TEAM_FILTER_DESTRUCTIVE:SCOPE_TEAM_FILTER)}async function resolveScope(globals,opts={}){let client=await apiClient(globals.instance),resolved=await resolveParams(["workspace","environment"],{team:globals.team,workspace:globals.workspace,environment:globals.env},{client,interactive:canPrompt(),useSession:opts.useSession});return{client,workspace:resolved.workspace??"",environment:resolved.environment??"",team:resolved.team}}async function resolveApiConnection(scope2,provided){if(provided)return{id:assertResourceId(provided,"apiConnectionId")};canPrompt()||fail(EXIT.USAGE,"USAGE_ERROR",`<apiConnectionId> is required. ${supplyHint()}`);let labels={};return{id:(await resolveParams(["apiConnection"],{workspace:scope2.workspace,environment:scope2.environment},{client:scope2.client,interactive:!0,labels})).apiConnection??"",label:labels.apiConnection}}function connectorCell(connection,empty="\u2014"){let connector=connection.connector;return connector?`${connector.name||connector.id} (${connector.id})`:empty}function packageCell(pkg,empty="\u2014"){return pkg?pkg.label??pkg.name:empty}function packageDetail(pkg,empty="(none)"){return pkg?pkg.label?`${pkg.label} (${pkg.name})`:pkg.name:empty}async function askPackage(client,appId,apiConnectionTypeId){let packages;try{packages=await withSpinner("Fetching packages",()=>apiConnectionPackages(client,appId,apiConnectionTypeId))}catch{return}if(packages.length===0)return;let auto=packages.find(p=>p.recommended)??packages.find(p=>!p.deprecated);if(auto&&packages.length===1)return;auto||prompts().note("Every package for this API connection type is deprecated \u2014 pick one.");let choices=packages.map(p=>{let label=p.name??p.id??"?",hint=p.deprecated?"deprecated":p.recommended?"recommended":void 0;return{value:p.id??"",label,...p.id===auto?.id?{display:`${label} (default)`,hint:hint??"the API picks this"}:hint?{hint}:{}}}),picked=await prompts().select("Package:",choices,auto?.id?{initial:auto.id}:{});return picked===auto?.id?void 0:picked}async function askPath(initial){for(;;){let answer=await prompts().text(PATH_PROMPT,{...initial?{initial}:{},allowEmpty:!0}),error51=apiConnectionPathError(answer);if(!error51)return normalizeApiConnectionPath(answer);prompts().note(`\u2716 ${error51}`)}}function updateFail(status,body,scope2){let error51=body,message=error51?.errorMessage??error51?.message??"";status===400&&/^connector is required\.?$/i.test(message.trim())&&fail(EXIT.API_ERROR,"BAD_REQUEST",message,{status,hint:`No connector is attached in that environment, and an omitted --connector-id keeps whatever is: send one. \`${CLI} api-connection list -w ${scope2.workspace} -e ${scope2.environment}\` shows what each environment has.`}),apiFail(status,body)}function releasedNote(version2){return`\u26A0 This environment has ${version2?`release ${version2}`:"a release"} deployed. Only the connector can be changed there; the import path and the package belong to the API connection and are shared by every environment.`}async function askConnector(scope2,globals,current){let team=await teamForQuestions(scope2,globals);if(!team)return;let deps={team,app:current.appId,apiConnectionType:current.apiConnectionTypeId,workspace:scope2.workspace,environment:scope2.environment},implicit=!1;if(current.connectorId)try{let absent=!(await resolverChoices(scope2.client,"connector",deps)).some(choice=>choice.value===current.connectorId),me2=await currentUserId(scope2.client),someoneElse=!current.owner||!me2||current.owner.id!==me2;implicit=absent&&someoneElse}catch(err){if(!(err instanceof CliError))throw err}for(;;){let picked;try{picked=await askKeepOrChange({client:scope2.client,key:"connector",deps,message:"Connector:",current:{value:current.connectorId,label:current.label},...implicit?{missingCurrentMark:implicitShareMark(current.owner)}:{}})}catch(err){if(!(err instanceof CliError))throw err;return}if(picked===void 0||!implicit)return picked;let replacement=await connectorName(scope2.client,deps,picked);if(await confirmImplicitReplacement(current.label??current.connectorId??"",replacement,current.owner))return picked}}async function connectorName(client,deps,connectorId){try{return(await resolverChoices(client,"connector",deps)).find(choice=>choice.value===connectorId)?.label??connectorId}catch{return connectorId}}var NO_CONNECTOR="\0no-connector";async function askConnectorOnCreate(client,globals,current,scopeTeam){let scope2={client,workspace:current.workspace,environment:current.environment??"",team:scopeTeam},team=await teamForQuestions(scope2,globals);if(!team)return;let choices;try{choices=await resolverChoices(client,"connector",{team,app:current.appId,apiConnectionType:current.apiConnectionTypeId,workspace:current.workspace,...current.environment?{environment:current.environment}:{}})}catch(err){if(!(err instanceof CliError))throw err;return}if(choices.length===0){prompts().note("\u26A0 No connector of this type exists in the team \u2014 creating the API connection unattached.");return}let picked=await prompts().select("Connector:",[{value:NO_CONNECTOR,label:"No connector",hint:"attach one later; scripts using it fail until then"},...choices],{initial:choices[0]?.value??NO_CONNECTOR});return picked===NO_CONNECTOR?void 0:picked}async function buildCreateBody(client,workspaceId,scope2,opts,interactive){let labels={},resolved=await resolveParams(["app","apiConnectionType"],{team:scope2.team,workspace:workspaceId,environment:opts.env??scope2.environment,app:opts.appId,apiConnectionType:opts.apiConnectionTypeId},{client,interactive,labels,offerSession:!1}),appId=resolved.app??"",apiConnectionTypeId=resolved.apiConnectionType??"",path2=opts.path;path2===void 0&&(interactive||fail(EXIT.USAGE,"USAGE_ERROR","--path is required."),path2=await askPath(suggestPathFromLabel(labels.app??"")));let packageId=opts.packageId??(interactive?await askPackage(client,appId,apiConnectionTypeId):void 0),environmentId=opts.env??scope2.environment,connectorId=opts.connectorId;return!connectorId&&interactive&&(connectorId=await askConnectorOnCreate(client,{team:opts.team},{workspace:workspaceId,...environmentId?{environment:environmentId}:{},appId,apiConnectionTypeId},resolved.team)),connectorId&&!environmentId&&interactive&&(environmentId=(await resolveParams(["environment"],{team:resolved.team,workspace:workspaceId},{client,interactive:!0,offerSession:!1})).environment),stripUndefined({appId,apiConnectionTypeId,path:path2,packageId,connectorId,environmentId:connectorId?environmentId:void 0})}async function buildUpdateBody(scope2,globals,apiConnectionId,opts){if(opts.input)return readInput(opts.input);if(!canPrompt()){let rawBody=stripUndefined({path:opts.path===void 0?void 0:assertApiConnectionPath(opts.path),connectorId:opts.connectorId,packageId:opts.packageId});return Object.keys(rawBody).length===0&&failNothingToUpdate(["--path","--connector-id","--package-id","--input"]),rawBody}let current=await withSpinner("Fetching API connection",()=>scope2.client.GET("/v1/workspace/{workspaceId}/environment/{environmentId}/apiConnection/{apiConnectionId}",{params:{path:{workspaceId:scope2.workspace,environmentId:scope2.environment,apiConnectionId}}}));(!current.response.ok||!current.data)&&apiFail(current.response.status,current.error);let release2=await withSpinner("Checking the environment",()=>environmentRelease(scope2.client,scope2.workspace,scope2.environment));if(release2&&prompts().note(releasedNote(release2.version)),release2){let shared=[...opts.path===void 0?[]:["--path"],...opts.packageId===void 0?[]:["--package-id"]];shared.length>0&&fail(EXIT.USAGE,"USAGE_ERROR",`${shared.join(" and ")} cannot be changed in an environment with a release deployed \u2014 the import path and the package belong to the API connection and are shared by every environment. Target a HEAD environment, or pass only --connector-id.`)}let path2=release2?void 0:opts.path===void 0?await askPath(current.data.path):assertApiConnectionPath(opts.path),packageId=release2?void 0:opts.packageId??await askKeepOrChange({client:scope2.client,key:"apiConnectionPackage",deps:{app:current.data.app.id,apiConnectionType:current.data.apiConnectionTypeId},message:"Package:",current:{value:current.data.package?.id,label:packageCell(current.data.package,"")}}),connectorId=opts.connectorId??await askConnector(scope2,globals,{appId:current.data.app.id,apiConnectionTypeId:current.data.apiConnectionTypeId,connectorId:current.data.connector?.id,label:current.data.connector?.name,owner:current.data.connector?.owner});!current.data.connector?.id&&connectorId===void 0&&fail(EXIT.USAGE,"CONNECTOR_REQUIRED",`This API connection has no connector attached in this environment, and the API refuses every update to one that has none. Attach one with --connector-id <id>, from \`${CLI} connector list\`.`);let renamed=path2===void 0||path2===current.data.path?void 0:path2;if(renamed===void 0&&packageId===void 0&&connectorId===void 0){prompts().note("Nothing to update \u2014 the API connection was left as it is.");return}return stripUndefined({path:renamed,connectorId,packageId})}function apiConnectionCommand(){let conn=new Command("api-connection").alias("ac").description("Manage workspace API connections");return conn.command("create").description("Create an API connection in a workspace").option("-w, --workspace <workspaceId>",SCOPE_WORKSPACE).option("--team <teamId>",SCOPE_TEAM_FILTER).option("--app-id <id>","App ID (required unless --input, interactive)").option("--api-connection-type-id <id>","API connection type ID (required unless --input, interactive)").option("--path <path>",`Import path scripts use to reference the connection as ${importSpecifier("<path>")}, ${API_CONNECTION_PATH_FORMAT} (required unless --input, interactive)`).option("--package-id <id>","Package ID (optional, interactive, API default: the recommended or first non-deprecated package)").option("--connector-id <id>","Connector to authorize the connection with (optional, interactive, requires -e/--env, refused in a non-HEAD environment)").option("-e, --env <environmentId>","Environment ID (required with --connector-id unless --input, interactive, session default, env SR_CONNECT_CLI_ENVIRONMENT, ignored with --input)").option("--input <file>",INPUT_BODY).option("--explain",EXPLAIN).action(async(opts,cmd)=>{if(explained(cmd,CREATE_DOC))return;let globals=cmd.optsWithGlobals(),client=await apiClient(globals.instance),interactive=canPrompt(),scope2=await resolveParams(["workspace"],{team:opts.team??globals.team,workspace:opts.workspace??globals.workspace,environment:opts.env??globals.env},{client,interactive,offerSession:!1,needs:["workspace","environment"]}),workspaceId=scope2.workspace??"",rawBody=opts.input?readInput(opts.input):await buildCreateBody(client,workspaceId,scope2,opts,interactive),parsed=validate(createBodySchema,rawBody),body={...parsed,path:assertApiConnectionPath(parsed.path)};body.connectorId&&!body.environmentId&&fail(EXIT.USAGE,"USAGE_ERROR",opts.input?"connectorId needs environmentId in the same body \u2014 -e/--env does not fill it, an --input body superseding every body flag (a connector is attached per environment).":"--connector-id needs an environment \u2014 pass -e/--env (a connector is attached per environment)."),opts.input&&assertExplicitEnvironmentAgrees(opts.env,body.environmentId);let{data,response,error:error51}=await withSpinner("Creating API connection",()=>client.POST("/v1/workspace/{workspaceId}/apiConnection",{params:{path:{workspaceId}},body}));(!response.ok||!data)&&apiFail(response.status,error51),await syncApiConnections(client,{workspaceId}),await syncPackages(client,workspaceId),okMutation("API connection created",data,{...data,path:body.path,import:importSpecifier(body.path)})}),withScope(conn.command("list").description("List API connections in a workspace")).option("--explain",EXPLAIN).action(async(_opts,cmd)=>{if(explained(cmd,LIST_DOC))return;let globals=cmd.optsWithGlobals(),scope2=await resolveScope(globals),{data,response,error:error51}=await withSpinner("Fetching API connections",()=>scope2.client.GET("/v1/workspace/{workspaceId}/environment/{environmentId}/apiConnections",{params:{path:{workspaceId:scope2.workspace,environmentId:scope2.environment}}}));(!response.ok||!data)&&apiFail(response.status,error51),ok(data,{human:d=>({apiConnections:d.apiConnections.map(c=>({id:c.id,path:c.path??"\u2014",app:`${c.app.name} (${c.app.id})`,connector:connectorCell(c),package:packageDetail(c.package,"\u2014")}))})})}),withScope(conn.command("get").description("Get a single API connection as the environment sees it").argument("[apiConnectionId]","API connection ID (required, interactive)")).option("--explain",EXPLAIN).action(async(idArg,_opts,cmd)=>{if(explained(cmd,GET_DOC))return;let globals=cmd.optsWithGlobals(),scope2=await resolveScope(globals),connection=await resolveApiConnection(scope2,idArg),{data,response,error:error51}=await withSpinner("Fetching API connection",()=>scope2.client.GET("/v1/workspace/{workspaceId}/environment/{environmentId}/apiConnection/{apiConnectionId}",{params:{path:{workspaceId:scope2.workspace,environmentId:scope2.environment,apiConnectionId:connection.id}}}));(!response.ok||!data)&&apiFail(response.status,error51),ok(data,{human:d=>({id:d.id,path:d.path??"(none)",import:d.path?importSpecifier(d.path):"(none)",app:`${d.app.name} (${d.app.id})`,apiConnectionTypeId:d.apiConnectionTypeId,connector:connectorCell(d,"(none)"),...d.connector?.owner?{connectorOwner:personCell(d.connector.owner)}:{},package:packageDetail(d.package)})})}),withScope(conn.command("update").description("Update an API connection").argument("[apiConnectionId]","API connection ID (required, interactive)")).option("--path <path>",`New import path, used by scripts as ${importSpecifier("<path>")}, ${API_CONNECTION_PATH_FORMAT} (optional, interactive on HEAD only, refused when it differs from what a non-HEAD environment reports)`).option("--package-id <id>","Vendor API package to use, as reported in package.id (optional, interactive on HEAD only, refused when it differs from what a non-HEAD environment reports)").option("--connector-id <id>","Connector to attach in the specified environment \u2014 there is no way to detach one (optional, interactive, required when the specified environment has no connector attached)").option("--input <file>",INPUT_BODY).option("--explain",EXPLAIN).action(async(idArg,opts,cmd)=>{if(explained(cmd,UPDATE_DOC))return;let globals=cmd.optsWithGlobals(),scope2=await resolveScope(globals),connection=await resolveApiConnection(scope2,idArg),rawBody=await buildUpdateBody(scope2,globals,connection.id,opts);if(rawBody===void 0)return;let parsed=validate(updateBodySchema,rawBody),body=parsed.path===void 0?parsed:{...parsed,path:assertApiConnectionPath(parsed.path)},{response,error:error51}=await withSpinner("Updating API connection",()=>scope2.client.PUT("/v1/workspace/{workspaceId}/environment/{environmentId}/apiConnection/{apiConnectionId}",{params:{path:{workspaceId:scope2.workspace,environmentId:scope2.environment,apiConnectionId:connection.id}},body}));response.ok||updateFail(response.status,error51,scope2),await syncApiConnections(scope2.client,{workspaceId:scope2.workspace,environmentId:scope2.environment}),await syncPackages(scope2.client,scope2.workspace);let echoed=body.path?{path:body.path,import:importSpecifier(body.path)}:void 0;okMutation("API connection updated",{updated:!0,id:connection.id},echoed)}),withScope(conn.command("delete").description("Delete an API connection from a workspace").argument("[apiConnectionId]","API connection ID (required, interactive)"),{destructive:!0,gate:!0}).option("--yes",CONFIRM_YES).option("--explain",EXPLAIN).action(async(idArg,opts,cmd)=>{if(explained(cmd,DELETE_DOC))return;let globals=cmd.optsWithGlobals(),scope2=await resolveScope(globals,{useSession:canPrompt()}),connection=await resolveApiConnection(scope2,idArg);if(!opts.yes){canPrompt()||failNeedsYes(`API connection ${connection.id}`);let current=await withSpinner("Fetching API connection",()=>scope2.client.GET("/v1/workspace/{workspaceId}/environment/{environmentId}/apiConnection/{apiConnectionId}",{params:{path:{workspaceId:scope2.workspace,environmentId:scope2.environment,apiConnectionId:connection.id}}}));(!current.response.ok||!current.data)&&apiFail(current.response.status,current.error);let path2=current.data.path,pkg=current.data.package;prompts().note(["Deleting removes the API connection from the whole workspace, not just this environment.",path2?`Scripts importing "${importSpecifier(path2)}" stop working.`:"Scripts importing it stop working.",pkg?`The vendor API package ${packageDetail(pkg)} is removed from the workspace unless another API connection still uses it.`:"The vendor API package it uses is removed from the workspace unless another API connection still uses it.","An environment with a release deployed keeps running the API connection captured in that release until the release is replaced."].join(`
|
|
@@ -1362,7 +1363,7 @@ ${renderResponse(data)}`:detail}function renderResponse(data){return data.respon
|
|
|
1362
1363
|
${JSON.stringify(data.response,null,2)}`}function consoleLogsHint(invocationId,workspaceId,finished=!1){return`Read console logs with${finished?"":" (once the script has finished executing)"}: ${CLI} log list-console-logs ${invocationId} -w ${workspaceId}`}function printConsoleLogsHint(invocationId,workspaceId,finished=!1){let hint=consoleLogsHint(invocationId,workspaceId,finished);isRaw()?noteLine(hint):prompts().note(hint)}function failInvocation(status,error51,workspaceId){let body=error51,reason=body?.errorMessage??`Request failed with HTTP status ${status}.`,invocationId=body?.invocationId,suffix=invocationId?` (invocation ${invocationId})`:"",[code,message]=status===422?["SCRIPT_ERROR",`The script threw: ${reason}${suffix}`]:status===504?["SCRIPT_TIMEOUT",`The script was still running when the 20 second cap on waiting expired, and the invocation was ended as timed out: ${reason}${suffix}`]:["INVOCATION_ABORTED",`The invocation was aborted before it finished: ${reason}${suffix}`];fail(EXIT.API_ERROR,code,message,{status,expected:!0,...invocationId?{hint:consoleLogsHint(invocationId,workspaceId)}:{}})}async function askStreamLogs(){return prompts().confirm("Stream console logs back to this terminal while the script runs?",!0)}async function startLogStream(client,opts,explicit2){let stream=await openLogStream(client,{timestamps:assertChoice("--timestamps",opts.timestamps,TIMESTAMP_MODES)??"time",...opts.rawStream?{rawFrames:!0}:{}});if(stream)return stream;explicit2&&fail(EXIT.API_ERROR,"STREAMING_UNAVAILABLE","Live log streaming is not available in this deployment.",{hint:`Read the output after the run instead: ${CLI} log list-console-logs <invocationId> -w <workspaceId>`}),prompts().note("\u26A0 Live log streaming is not available in this deployment \u2014 continuing without it.")}var STREAM_DRAIN_MS=5e3;async function drainLogStream(stream,invocationId){stream.identify(invocationId),await Promise.race([stream.done(),new Promise(resolve8=>setTimeout(resolve8,STREAM_DRAIN_MS))]),stream.close()}function failStreamOutcome(result,invocationId,workspaceId){let hint=consoleLogsHint(invocationId,workspaceId),outcome=result.outcome;if(!outcome||outcome.status==="FINISHED")return;let known=outcome.status in OUTCOME_FAILURES,failure=OUTCOME_FAILURES[outcome.status],sentence=known?failure?.sentence:`The invocation ended as ${outcome.status}`,reason=outcome.message??result.lastError??"no detail was reported";fail(EXIT.API_ERROR,failure?.code??"INVOCATION_FAILED",`${sentence?`${sentence}: `:""}${reason} (invocation ${invocationId})`,{hint,...failure?.status===void 0?{}:{status:failure.status}})}var REPLAYABLE_TRIGGER_TYPES=["EXTERNAL","MANUAL_EVENT_LISTENER","CHAINED"];async function resolveReplayTarget(client,teamId,invocationIdArg,opts,interactive){if(!invocationIdArg){interactive||fail(EXIT.USAGE,"USAGE_ERROR",`<invocationId> is required. ${supplyHint()}`);let picked=await askInvocation(client,teamId,{query:{...opts.workspace?{workspaces:[opts.workspace]}:{},triggerTypes:[...REPLAYABLE_TRIGGER_TYPES]},browseFilters:()=>askBrowseScopeFilters(client,teamId,opts.workspace),browseHint:`newest ${MIN_INVOCATION_PAGE_SIZE} that can be replayed`,emptyNote:"No recent replayable invocations in this team \u2014 enter an invocation ID instead.",hint:invocation2=>`${invocation2.triggerType} \xB7 ${invocation2.executionStatus}`});if(picked.workspaceId&&picked.environmentId&&picked.scriptId)return{invocationId:picked.invocationId,workspaceId:picked.workspaceId,environmentName:picked.environmentName??picked.environmentId,environmentId:picked.environmentId,scriptId:picked.scriptId,scriptName:picked.scriptName??picked.scriptId};invocationIdArg=picked.invocationId}invocationIdArg=assertResourceId(invocationIdArg,"invocationId");let invocation=await findInvocation(client,teamId,invocationIdArg);return invocation||fail(EXIT.NOT_FOUND,"INVOCATION_NOT_FOUND",`No invocation ${invocationIdArg} in this team.`,{hint:`List what is there with: ${CLI} log list-invocation-logs --invocation-id ${invocationIdArg}`}),replayTarget(invocation)}function replayTarget(invocation){return{invocationId:invocation.invocationId,workspaceId:invocation.workspace.id,environmentId:invocation.environment.id,environmentName:invocation.environment.name,scriptId:invocation.script.id,scriptName:invocation.script.name}}var replayBodySchema=external_exports.object({environmentId:external_exports.string().min(1),scriptId:external_exports.string().min(1),eventPayload:external_exports.unknown().optional(),silent:external_exports.boolean().optional(),streamSubscriptionId:external_exports.string().min(1).optional()}).strict(),REPLAY_DOC=defineCommandDoc("script replay-invocation",{schema:replayBodySchema,body:{environmentId:"<environmentId>",scriptId:"<scriptId>",eventPayload:{issue:{key:"TEST-1"}},silent:!1},hidden:["streamSubscriptionId"],rules:["environmentId and scriptId must be the invocation's own, as reported by log list-invocation-logs; any other value is a 400. Without --input they are filled from the invocation record and there is nothing to pass, so they are required only in an --input body.",`eventPayload: any JSON value replacing the original event \u2014 an object, but an array or a scalar too, handed to the function as it is sent, up to ${CONTENT_CAP}. Spelled --payload or --payload-file <path> as a flag; omitted, the original event is delivered again.`,"silent: true withholds the live console stream from everything except a socket the caller is already holding open for the replay (--stream-logs); the replay is still recorded and its logs readable either way. A replay asked for through the API is addressed to its caller alone, so it never reaches the web application whichever value this carries.","Parameter values come from the environment as they are now, and the release deployed there is what runs. The workspace is the invocation's; --team is where the invocation is looked up.","The invocation is the positional argument or --invocation-id, and passing both is exit 2.",INVOCATION_SCOPE_RULE],notes:["Only an invocation triggered by a stored event can be replayed: EXTERNAL, MANUAL_EVENT_LISTENER and CHAINED. script trigger produces MANUAL, which is none of them, so nothing this CLI starts can be replayed afterwards \u2014 the invocation has to have arrived from outside.","There is no --wait here: --stream-logs is the way to see the outcome in one command. Beside it, --raw-stream prints every received frame verbatim as one JSON document per line instead of a rendered console, and --timestamps is time, iso, relative or off. Both are ignored without --stream-logs.","Streamed rows print in the order the frames arrive, and the order they are sent in is not guaranteed: a row can print after one stamped later than it. The stored file is ordered, so where the order of two lines carries meaning read log list-console-logs once the run has ended rather than the live view.","There is no --yes either: a terminal confirms and a script does not. -w only narrows the list the invocation is looked up in."]});function queuedAbortWarning(){return"This invocation is QUEUED, so aborting it is best effort: the request eventually lapses, and an invocation still waiting by then runs to completion. Even before it lapses it starts and is then stopped, rather than being prevented from starting."}function abortQuestion(target){return`Request that ${target.scriptName?`${target.scriptName} (${target.invocationId})`:target.invocationId} be aborted?`}function abortHint(invocationId,workspaceId){return`Aborting is a request, not a command \u2014 the invocation may still finish on its own. Confirm what it did with: ${CLI} log list-invocation-logs --invocation-id ${invocationId}
|
|
1363
1364
|
${consoleLogsHint(invocationId,workspaceId)}`}function failInvocationMissing(invocationId,workspaceId){fail(EXIT.NOT_FOUND,"INVOCATION_NOT_FOUND",`No invocation ${invocationId} in workspace ${workspaceId}.`,{hint:"An invocation triggered moments ago may not be recorded yet \u2014 retry briefly before treating this as a wrong ID."})}function failNotAbortable(invocationId,error51){let message=error51?.errorMessage??"The invocation has already finished.";fail(EXIT.API_ERROR,"INVOCATION_NOT_ABORTABLE",message,{hint:`Read what it did with: ${CLI} log list-invocation-logs --invocation-id ${invocationId}`})}async function abortInvocation(client,target){target.executionStatus==="QUEUED"&&prompts().note(`\u26A0 ${queuedAbortWarning()}`),canPrompt()&&!await prompts().confirm(abortQuestion(target),!1)&&fail(EXIT.CANCELLED,"CANCELLED","Abort not requested.");let{data,response,error:error51}=await withSpinner("Requesting the abort",()=>client.POST("/v1/workspace/{workspaceId}/invocation/{invocationId}/abort",{params:{path:{workspaceId:target.workspaceId,invocationId:target.invocationId}}}));response.status===404&&(warnInheritedWorkspace(target.workspaceFrom,target.workspaceId),failInvocationMissing(target.invocationId,target.workspaceId)),response.status===409&&failNotAbortable(target.invocationId,error51),(!response.ok||!data)&&apiFail(response.status,error51),okMutation("Abort requested",data,renderDetail({invocationId:data.invocationId})),isRaw()?noteLine(abortHint(data.invocationId,target.workspaceId)):prompts().note(abortHint(data.invocationId,target.workspaceId))}async function resolveScriptScope(globals,opts){let client=await apiClient(globals.instance),labels={},keys=opts.script?["workspace","environment","script"]:["workspace","environment"],resolved=await resolveParams(keys,{team:opts.team??globals.team,workspace:opts.workspace??globals.workspace,environment:opts.env??globals.env,...opts.script?{script:opts.scriptId}:{}},{client,interactive:canPrompt(),offerSession:opts.offerSession??!0,useSession:opts.useSession,labels});return{client,workspaceId:resolved.workspace??"",environmentId:resolved.environment??"",scriptId:resolved.script??"",labels}}async function askRunAfterSave(when){return prompts().confirm(`Run the script once ${when}?`,!1)}var SILENT_AFTER_SAVE="Mark the run offered after saving as silenced and withhold its live console stream from everything but --stream-logs; the invocation is still recorded, and its logs still readable (optional, refused without a TTY)";function assertSilentIsUsable(silent,interactive){!silent||interactive||fail(EXIT.USAGE,"USAGE_ERROR","--silent applies to the run offered after saving, which is only offered interactively \u2014 it does not quieten this command's own output.")}async function askTriggerRequest(client,path2,opts,interactive){let rawBody,wantStream=opts.streamLogs===!0;if(opts.input)rawBody=readInput(opts.input);else{let source={};opts.payload!==void 0?source={payload:assertEventPayload(opts.payload,"--payload")}:opts.payloadFile!==void 0?source={payload:assertEventPayload(readContentFile(opts.payloadFile,PAYLOAD_KIND),opts.payloadFile)}:opts.testPayloadId!==void 0?source={testPayloadId:opts.testPayloadId}:interactive&&(source=await askEventPayload(client,path2));let wait=opts.wait||interactive&&await prompts().confirm("Wait for the response? The wait is capped at 20 seconds and the return value is shown.",!1);!wantStream&&interactive&&(wantStream=await askStreamLogs()),rawBody=stripUndefined({functionName:opts.functionName,...source,waitForResponse:wait||void 0,silent:opts.silent||void 0})}let body=validate(triggerBodySchema,rawBody);return assertPayloadSize(body.payload),{body,wantStream}}async function runTrigger(client,path2,request,opts){let{body,wantStream}=request,waited=body.waitForResponse===!0,stream;wantStream&&(stream=await startLogStream(client,opts,opts.streamLogs===!0),stream&&(body.streamSubscriptionId=stream.subscriptionId)),stream?.start(path2.workspaceId,invocationId=>{!isRaw()&&!opts.responseOnly&&okText(`Script triggered:
|
|
1364
1365
|
${renderDetail({invocationId})}`)});let send2=()=>client.POST("/v1/workspace/{workspaceId}/environment/{environmentId}/script/{scriptId}/trigger",{params:{path:path2},body}),{data,response,error:error51}=stream?await send2():await withSpinner(waited?"Running the script (waiting up to 20 seconds)":"Triggering the script",send2);if(response.status===409||response.status===422||response.status===504){let failed2=error51?.invocationId;stream&&failed2?await drainLogStream(stream,failed2):stream?.close(),failInvocation(response.status,error51,path2.workspaceId)}(!response.ok||!data)&&(stream?.close(),apiFail(response.status,error51));let result=data;if(stream){stream.identify(result.invocationId);let streamed=await stream.done();failStreamOutcome(streamed,result.invocationId,path2.workspaceId),opts.responseOnly?okText(isRaw()?JSON.stringify(result.response??null):JSON.stringify(result.response??null,null,2)):isRaw()?okMutation("Script triggered",result):waited&&okText(renderResponse(result));return}opts.responseOnly?okText(isRaw()?JSON.stringify(result.response??null):JSON.stringify(result.response??null,null,2)):okMutation("Script triggered",result,renderTrigger(result,waited)),printConsoleLogsHint(result.invocationId,path2.workspaceId,waited)}function scriptCommand(){let script=new Command("script").description("Manage workspace scripts");return script.command("create").description("Create a script in a workspace").option("-w, --workspace <workspaceId>",SCOPE_WORKSPACE).option("-e, --env <environmentId>",SCOPE_ENVIRONMENT).option("--team <teamId>",SCOPE_TEAM_FILTER).option("--name <name>",`Script name, ${SCRIPT_NAME_FORMAT} (required unless --input, interactive)`).option("--file <path>","Read the script source from a file, or - for stdin (required unless --content or --input, interactive, exclusive with --content)").option("--content <source>","Script source inline (required unless --file or --input, interactive, exclusive with --file)").option("--silent",SILENT_AFTER_SAVE).option("--input <file>",INPUT_BODY).option("--explain",EXPLAIN).action(async(opts,cmd)=>{if(explained(cmd,CREATE_DOC5))return;let globals=cmd.optsWithGlobals(),interactive=canPrompt();opts.file!==void 0&&opts.content!==void 0&&fail(EXIT.USAGE,"USAGE_ERROR","--file and --content cannot be combined."),assertSilentIsUsable(opts.silent,interactive);let{client,workspaceId,environmentId}=await resolveScriptScope(globals,{...opts,offerSession:!opts.input}),rawBody;if(opts.input)rawBody=readInput(opts.input);else{let content=opts.content,sourcePath=opts.file;if(content===void 0&&sourcePath!==void 0&&(content=readScriptFile(sourcePath)),content===void 0){interactive||fail(EXIT.USAGE,"USAGE_ERROR","--file or --content is required.");let source=await askSource();content=source.content,sourcePath=source.path}let name=opts.name;name===void 0&&(interactive||fail(EXIT.USAGE,"USAGE_ERROR","--name is required."),name=await askScriptName2(sourcePath?suggestNameFromPath(sourcePath):void 0)),rawBody={name,content}}let body=validate(createBodySchema5,rawBody);body.name=assertScriptName(body.name),body.content||fail(EXIT.USAGE,"INVALID_BODY","Script content cannot be empty."),assertSize(Buffer.byteLength(body.content,"utf8"),SCRIPT_KIND);let run;interactive&&await askRunAfterSave("it is saved")&&(run=await askTriggerRequest(client,void 0,{silent:opts.silent},!0));let{data,response,error:error51}=await withSpinner("Creating script (the workspace is compiled and bundled)",()=>client.POST("/v1/workspace/{workspaceId}/environment/{environmentId}/script",{params:{path:{workspaceId,environmentId}},body}));(response.status===502||response.status===504)&&failBundleTimeout(response.status),(!response.ok||!data)&&apiFail(response.status,error51),syncScript({workspaceId,environmentId},{name:data.name,content:body.content,id:data.id}),okMutation("Script created",data,renderScriptMutation(data)),run&&await runTrigger(client,{workspaceId,environmentId,scriptId:data.id},run,{silent:opts.silent})}),script.command("update").description("Update a script").argument("[scriptId]","Script to update (required, interactive)").option("-w, --workspace <workspaceId>",SCOPE_WORKSPACE).option("-e, --env <environmentId>",SCOPE_ENVIRONMENT).option("--team <teamId>",SCOPE_TEAM_FILTER).option("--name <name>",`Rename the script, ${SCRIPT_NAME_FORMAT} (optional, interactive)`).option("--file <path>","Read the new source from a file, or - for stdin (optional, interactive, exclusive with --content)").option("--content <source>","New source inline (optional, interactive, exclusive with --file)").option("--silent",SILENT_AFTER_SAVE).option("--input <file>",INPUT_BODY).option("--explain",EXPLAIN).action(async(scriptIdArg,opts,cmd)=>{if(explained(cmd,UPDATE_DOC5))return;let globals=cmd.optsWithGlobals(),interactive=canPrompt();opts.file!==void 0&&opts.content!==void 0&&fail(EXIT.USAGE,"USAGE_ERROR","--file and --content cannot be combined."),assertSilentIsUsable(opts.silent,interactive);let{client,labels,...ids}=await resolveScriptScope(globals,{...opts,script:!0,scriptId:scriptIdArg,offerSession:!opts.input}),path2=ids,rawBody,editSource;if(opts.input)rawBody=readInput(opts.input);else{let name=opts.name,content=opts.content;content===void 0&&opts.file!==void 0&&(content=readScriptFile(opts.file));let fetched,currentScript=()=>fetched??=fetchScript(client,path2);if(interactive&&(name===void 0&&await prompts().confirm("Rename the script?",!1)&&(name=await askScriptName2(labels.script??(await currentScript()).name)),content===void 0&&await prompts().confirm("Edit the script content?",!0)&&({content}=await askSource({inlineLabel:"Edit it here",currentContent:async()=>{let fetchedScript=await currentScript();return editSource=await localEditSource(client,{workspaceId:path2.workspaceId,environmentId:path2.environmentId},{kind:"script",name:fetchedScript.name},fetchedScript.content),editSource.content}}))),name===void 0&&content===void 0){if(interactive){prompts().note("Nothing to update \u2014 neither the name nor the content changed.");return}failNothingToUpdate(["--name to rename","--file/--content to replace the source","--input"])}content??=(await currentScript()).content,rawBody=stripUndefined({name,content})}let body=validate(updateBodySchema5,rawBody);body.name!==void 0&&(body.name=assertScriptName(body.name)),body.content||fail(EXIT.USAGE,"INVALID_BODY","Script content cannot be empty."),assertSize(Buffer.byteLength(body.content,"utf8"),SCRIPT_KIND);let run;interactive&&await askRunAfterSave("the change is saved")&&(run=await askTriggerRequest(client,path2,{silent:opts.silent},!0));let{data,response,error:error51}=await withSpinner("Updating script (the workspace is compiled and bundled)",()=>client.PUT("/v1/workspace/{workspaceId}/environment/{environmentId}/script/{scriptId}",{params:{path:path2},body}));(response.status===502||response.status===504)&&failBundleTimeout(response.status),(!response.ok||!data)&&apiFail(response.status,error51),syncScript({workspaceId:path2.workspaceId,environmentId:path2.environmentId},{name:data.name,content:body.content,id:data.id,...editSource===void 0?{}:{mode:editSource.mode}}),okMutation("Script updated",data,renderScriptMutation(data)),run&&await runTrigger(client,path2,run,{silent:opts.silent})}),script.command("list").description("List scripts in a workspace").option("-w, --workspace <workspaceId>",SCOPE_WORKSPACE).option("-e, --env <environmentId>",SCOPE_ENVIRONMENT).option("--team <teamId>",SCOPE_TEAM_FILTER).option("--explain",EXPLAIN).action(async(opts,cmd)=>{if(explained(cmd,LIST_DOC6))return;let globals=cmd.optsWithGlobals(),{client,workspaceId,environmentId}=await resolveScriptScope(globals,opts),{data,response,error:error51}=await withSpinner("Fetching scripts",()=>client.GET("/v1/workspace/{workspaceId}/environment/{environmentId}/scripts",{params:{path:{workspaceId,environmentId}}}));(!response.ok||!data)&&apiFail(response.status,error51),ok(data,{human:d=>({scripts:d.scripts.map(s=>({id:s.id,name:s.name}))})})}),script.command("get").description("Get a single script as the environment sees it").argument("[scriptId]","Script to get (required, interactive)").option("-w, --workspace <workspaceId>",SCOPE_WORKSPACE).option("-e, --env <environmentId>",SCOPE_ENVIRONMENT).option("--team <teamId>",SCOPE_TEAM_FILTER).option("--content-only","Print just the script source, verbatim, for redirecting it into a file; the same bytes with or without --raw (optional)").option("--explain",EXPLAIN).action(async(scriptIdArg,opts,cmd)=>{if(explained(cmd,GET_DOC5))return;let globals=cmd.optsWithGlobals(),{client,labels:_labels,...path2}=await resolveScriptScope(globals,{...opts,script:!0,scriptId:scriptIdArg}),found2=await fetchScript(client,path2);if(opts.contentOnly){okFile(found2.content);return}ok(found2,{human:renderScript})}),script.command("delete").description("Delete a script from a workspace").argument("[scriptId]","Script to delete (required, interactive)").option("-w, --workspace <workspaceId>",SCOPE_WORKSPACE_DESTRUCTIVE).option("-e, --env <environmentId>",SCOPE_ENVIRONMENT_GATE_DESTRUCTIVE).option("--team <teamId>",SCOPE_TEAM_FILTER_DESTRUCTIVE).option("--yes",CONFIRM_YES).option("--force","Delete even when event listeners or scheduled triggers still use the script, which are then deactivated (optional, interactive)").option("--explain",EXPLAIN).action(async(scriptIdArg,opts,cmd)=>{if(explained(cmd,DELETE_DOC5))return;let globals=cmd.optsWithGlobals(),interactive=canPrompt(),{client,labels,...path2}=await resolveScriptScope(globals,{...opts,script:!0,scriptId:scriptIdArg,useSession:interactive}),named=labels.script??path2.scriptId;opts.yes||(interactive||failNeedsYes(`script ${named}`),await prompts().confirm(`Delete ${named}? It is removed from the whole workspace, not just this environment. This is irreversible.`,!1)||fail(EXIT.CANCELLED,"CANCELLED","Deletion cancelled.")),await deleteScriptWithConflict(client,path2,{force:!!opts.force,interactive}),syncScriptDeleted({workspaceId:path2.workspaceId,environmentId:path2.environmentId},{id:path2.scriptId,...labels.script?{name:labels.script}:{}}),okMutation("Script deleted",{deleted:!0,id:path2.scriptId})}),script.command("trigger").description("Run a script in a workspace").argument("[scriptId]","Script to run (required, interactive)").option("-w, --workspace <workspaceId>",SCOPE_WORKSPACE).option("-e, --env <environmentId>",SCOPE_ENVIRONMENT).option("--team <teamId>",SCOPE_TEAM_FILTER).option("--function-name <name>","Function to invoke (optional, default: the script's default export)").option("--payload <json>","Event payload as a JSON object (optional, interactive, exclusive with --payload-file and --test-payload-id)").option("--payload-file <path>","Read the event payload from a JSON file, or - for stdin (optional, interactive, exclusive with --payload and --test-payload-id)").option("--test-payload-id <testPayloadId>","Run an event listener test payload as the event; offered only when a listener targeting the script has one (optional, interactive, exclusive with --payload and --payload-file)").option("--wait","Wait for the script to return \u2014 the wait is capped at 20 seconds, and a script still running then is ended as timed out (optional, interactive, ignored with --input)").option("--response-only","Print just the value the script returned, verbatim; null when it returned nothing (optional, requires --wait or waitForResponse: true in the --input body)").option("--silent","Withhold the live console stream from everything except --stream-logs, and mark the run as silenced in the audit trail; the invocation is still recorded, and its logs still readable. A run started here is addressed to you and to nobody else regardless, so this changes nothing the web application would have seen (optional)").option("--stream-logs","Watch the script's console output live over a WebSocket until it finishes; printed on stderr, and the exit code then reflects the script's own outcome (optional, interactive)").option("--raw-stream","Print every received frame verbatim as JSON, one per line, instead of a rendered console (optional, requires --stream-logs)").option("--timestamps <mode>",`Timestamp gutter for the streamed console: ${TIMESTAMP_MODES.join(" | ")} (optional, default: time, ignored without --stream-logs)`).option("--input <file>",INPUT_BODY).option("--explain",EXPLAIN).action(async(scriptIdArg,opts,cmd)=>{if(explained(cmd,TRIGGER_DOC))return;let globals=cmd.optsWithGlobals(),interactive=canPrompt();[opts.payload,opts.payloadFile,opts.testPayloadId].filter(v2=>v2!==void 0).length>1&&fail(EXIT.USAGE,"USAGE_ERROR","--payload, --payload-file and --test-payload-id cannot be combined."),opts.responseOnly&&!opts.wait&&!opts.input&&fail(EXIT.USAGE,"USAGE_ERROR","--response-only requires --wait."),opts.rawStream&&!opts.streamLogs&&fail(EXIT.USAGE,"USAGE_ERROR","--raw-stream requires --stream-logs.");let{client,labels:_labels,...path2}=await resolveScriptScope(globals,{...opts,script:!0,scriptId:scriptIdArg,offerSession:!opts.input}),request=await askTriggerRequest(client,path2,opts,interactive);opts.responseOnly&&request.body.waitForResponse!==!0&&fail(EXIT.USAGE,"USAGE_ERROR","--response-only needs a waited run: the --input body must carry waitForResponse: true (--wait is a body flag, and the body supersedes it)."),await runTrigger(client,path2,request,opts)}),script.command("replay-invocation").description("Replay a past invocation through its own script, optionally with another payload").argument("[invocationId]","Invocation to replay (required unless --invocation-id, interactive)").option("--invocation-id <invocationId>",INVOCATION_ID_FLAG).option("--team <teamId>","Team ID \u2014 the invocation is looked up in it (required, interactive, session default, env SR_CONNECT_CLI_TEAM)").option("-w, --workspace <workspaceId>","Narrow the interactive invocation list (optional, ignored when the invocation is given)").option("--payload <json>","Replace the event payload with any JSON value, an array or a scalar included (optional, interactive, exclusive with --payload-file)").option("--payload-file <path>","Read the replacement event payload from a JSON file, or - for stdin (optional, interactive, exclusive with --payload)").option("--silent","Withhold the live console stream from everything except --stream-logs; the replay is still recorded, and its logs still readable. A replay asked for here is addressed to you and to nobody else regardless, so this changes nothing the web application would have seen (optional)").option("--stream-logs","Watch the replayed invocation's console output live over a WebSocket until it finishes; printed on stderr, and the exit code then reflects the script's own outcome (optional, interactive)").option("--raw-stream","Print every received frame verbatim as JSON, one per line, instead of a rendered console (optional, requires --stream-logs)").option("--timestamps <mode>",`Timestamp gutter for the streamed console: ${TIMESTAMP_MODES.join(" | ")} (optional, default: time, ignored without --stream-logs)`).option("--input <file>",INPUT_BODY).option("--explain",EXPLAIN).action(async(invocationIdArg,opts,cmd)=>{if(explained(cmd,REPLAY_DOC))return;let globals=cmd.optsWithGlobals(),interactive=canPrompt();opts.payload!==void 0&&opts.payloadFile!==void 0&&fail(EXIT.USAGE,"USAGE_ERROR","--payload and --payload-file cannot be combined."),opts.rawStream&&!opts.streamLogs&&fail(EXIT.USAGE,"USAGE_ERROR","--raw-stream requires --stream-logs.");let flagPayload,payloadChoice="the original invocation's payload";opts.payload!==void 0?(flagPayload=assertEventPayload(opts.payload,"--payload","any"),payloadChoice="a replacement payload from --payload"):opts.payloadFile!==void 0&&(flagPayload=assertEventPayload(readContentFile(opts.payloadFile,PAYLOAD_KIND),opts.payloadFile,"any"),payloadChoice=`a replacement payload from ${opts.payloadFile}`);let client=await apiClient(globals.instance),typedInvocation=invocationFromArgs(invocationIdArg,opts.invocationId),teamId=(await resolveParams(["team"],{team:opts.team??globals.team},{client,interactive,offerSession:!1})).team??"",target=await resolveReplayTarget(client,teamId,typedInvocation,opts,interactive),rawBody,wantStream=opts.streamLogs===!0;if(opts.input)rawBody=readInput(opts.input),payloadChoice="the payload in --input";else{let eventPayload=flagPayload;eventPayload===void 0&&interactive&&(eventPayload=await askReplayPayload(),eventPayload!==void 0&&(payloadChoice="a replacement payload")),!wantStream&&interactive&&(wantStream=await askStreamLogs()),rawBody=stripUndefined({environmentId:target.environmentId,scriptId:target.scriptId,eventPayload,silent:opts.silent||void 0})}let body=validate(replayBodySchema,rawBody);if(assertPayloadSize(body.eventPayload),interactive){let namedEnvironment=body.environmentId===target.environmentId?target.environmentName:body.environmentId,namedScript=body.scriptId===target.scriptId?target.scriptName:body.scriptId;await prompts().confirm(`Replay in ${namedEnvironment} environment, through ${namedScript} script, with ${payloadChoice}? The original event is delivered again, and parameter values come from that environment as they are now.`,!0)||fail(EXIT.CANCELLED,"CANCELLED","Replay cancelled.")}let stream;wantStream&&(stream=await startLogStream(client,opts,opts.streamLogs===!0),stream&&(body.streamSubscriptionId=stream.subscriptionId)),stream?.start(target.workspaceId,invocationId=>{isRaw()||okText(`Invocation replayed:
|
|
1365
|
-
${renderDetail({invocationId})}`)});let send2=()=>client.POST("/v1/workspace/{workspaceId}/invocation/{invocationId}/replay",{params:{path:{workspaceId:target.workspaceId,invocationId:target.invocationId}},body}),{data,response,error:error51}=stream?await send2():await withSpinner("Replaying the invocation",send2);if((!response.ok||!data)&&(stream?.close(),apiFail(response.status,error51)),stream){stream.identify(data.invocationId);let streamed=await stream.done();failStreamOutcome(streamed,data.invocationId,target.workspaceId),isRaw()&&okMutation("Invocation replayed",data);return}okMutation("Invocation replayed",data,renderDetail({invocationId:data.invocationId})),printConsoleLogsHint(data.invocationId,target.workspaceId)}),script.command("abort-invocation").description("Request that a queued or running invocation be aborted").argument("[invocationId]","Invocation to abort (required unless --invocation-id, interactive)").option("--invocation-id <invocationId>",INVOCATION_ID_FLAG).option("--team <teamId>","Team ID \u2014 only needed to browse invocations or pick a workspace (optional, interactive, session default, env SR_CONNECT_CLI_TEAM, ignored when the invocation and workspace are both given)").option("-w, --workspace <workspaceId>","Workspace the invocation belongs to (required unless the invocation is browsed, interactive, session default, env SR_CONNECT_CLI_WORKSPACE)").option("--explain",EXPLAIN).action(async(invocationIdArg,opts,cmd)=>{if(explained(cmd,ABORT_DOC))return;let globals=cmd.optsWithGlobals(),client=await apiClient(globals.instance),target=await resolveInvocationScope(client,invocationFromArgs(invocationIdArg,opts.invocationId),opts,globals.team,ABORT_SCOPE);await abortInvocation(client,target)}),script}var HTTP_ENDPOINT="HTTP_ENDPOINT";function withScope3(cmd,opts={}){let env=opts.gate?opts.destructive?SCOPE_ENVIRONMENT_GATE_DESTRUCTIVE:SCOPE_ENVIRONMENT_GATE:opts.destructive?SCOPE_ENVIRONMENT_DESTRUCTIVE:SCOPE_ENVIRONMENT;return cmd.option("-w, --workspace <workspaceId>",opts.destructive?SCOPE_WORKSPACE_DESTRUCTIVE:SCOPE_WORKSPACE).option("-e, --env <environmentId>",env).option("--team <teamId>",opts.destructive?SCOPE_TEAM_FILTER_DESTRUCTIVE:SCOPE_TEAM_FILTER)}async function resolveScope5(globals,opts={}){let client=await apiClient(globals.instance),resolved=await resolveParams(["workspace","environment"],{team:globals.team,workspace:globals.workspace,environment:globals.env},{client,interactive:canPrompt(),useSession:opts.useSession});return{client,workspace:resolved.workspace??"",environment:resolved.environment??"",team:resolved.team}}async function resolveListenerId(scope2,provided){return provided?assertResourceId(provided,"eventListenerId"):(canPrompt()||fail(EXIT.USAGE,"USAGE_ERROR",`<eventListenerId> is required. ${supplyHint()}`),(await resolveParams(["eventListener"],{workspace:scope2.workspace,environment:scope2.environment},{client:scope2.client,interactive:!0})).eventListener??"")}var MAX_QUEUE_GROUPINGS=10,createBodySchema6=external_exports.object({appId:external_exports.string().min(1),eventListenerTypeId:external_exports.string().min(1),eventTypeId:external_exports.string().min(1),scriptId:external_exports.string().min(1).optional(),scriptName:external_exports.string().min(1).optional(),connectorId:external_exports.string().optional(),urlPath:external_exports.string().optional(),disabled:external_exports.boolean().optional(),eventQueueId:external_exports.string().optional(),eventQueueGroupings:external_exports.array(external_exports.string()).max(MAX_QUEUE_GROUPINGS).optional()}).strict().refine(body=>!(body.scriptId&&body.scriptName),{error:"scriptId and scriptName cannot be combined.",path:["scriptId"]}).refine(body=>!!(body.scriptId??body.scriptName),{error:"Either scriptId or scriptName is required.",path:["scriptId"]}),updateBodySchema6=external_exports.object({eventTypeId:external_exports.string().min(1).optional(),connectorId:external_exports.string().optional(),scriptId:external_exports.string().min(1).optional(),scriptName:external_exports.string().min(1).optional(),urlPath:external_exports.string().optional(),disabled:external_exports.boolean().optional(),eventQueueId:external_exports.string().nullable().optional(),eventQueueGroupings:external_exports.array(external_exports.string()).max(MAX_QUEUE_GROUPINGS).optional()}).strict().refine(body=>!(body.scriptId&&body.scriptName),{error:"scriptId and scriptName cannot be combined.",path:["scriptId"]}).refine(body=>Object.keys(body).length>0,{error:"At least one of eventTypeId, scriptId, scriptName, connectorId, urlPath, disabled, eventQueueId or eventQueueGroupings is required."}),SCRIPT_KEYS_RULE=`scriptId names an existing script; scriptName makes the API create one (${SCRIPT_NAME_RULE}) and attach it.`,CONNECTOR_RULE="connectorId: a connector of the same app that you may use in the team. Some listener types need one and app list does not mark which; event-listener get reports connectionRequired for a listener that already exists. A connector fits when its connectionType, as connector list reports it, is the app's connectionType in app list.",MAX_URL_PATH=200,URL_PATH_CHARSET=/^[A-Za-z0-9_-]+$/,URL_PATH_FORMAT=`letters, digits, underscores and dashes, up to ${MAX_URL_PATH} characters, stored lower-cased and unique across the deployment`;function assertUrlPath(path2){let normalized=path2.trim().toLowerCase();return normalized||fail(EXIT.USAGE,"INVALID_URL_PATH","A URL path is required."),normalized.length>MAX_URL_PATH&&fail(EXIT.USAGE,"INVALID_URL_PATH",`A URL path can be at most ${MAX_URL_PATH} characters (that one is ${normalized.length}).`),URL_PATH_CHARSET.test(normalized)||fail(EXIT.USAGE,"INVALID_URL_PATH",`Use letters, digits, underscores and dashes \u2014 '${path2}' has a character the API refuses.`),normalized}var LIST_DOC7=defineCommandDoc("event-listener list",{rules:["The workspace is -w and the environment -e; there is no positional argument."],notes:["A listener reads through the environment named: its URL path, connector and enabled state are per-environment, and the event type and script it triggers are the workspace's."]}),GET_DOC6=defineCommandDoc("event-listener get",{rules:["The event listener is the positional argument; the workspace is -w and the environment -e."],notes:["Reports the URL path, the webhook URL to register in the external application, and the setup URL, when the listener has a path in the environment named.",'It also reports connectionRequired, which is the only place the CLI can tell you whether a listener type needs a connector at all \u2014 app list does not mark which do. It reads as "a connector must be attached", never as "a connector may not be": a false there makes one optional, and such a listener still accepts a connectorId on create and update and reports it afterwards.',"In a non-HEAD environment the read reports what that release captured and nothing else: the script and the event type are absent when the release captured none, rather than borrowing the workspace's current ones. So what get shows there is safe to send straight back to update.","An absent script means the listener has nothing to run, in either kind of environment: it was never given one, or the one it had was deleted with script delete --force. The read never names a script that is gone, so what it reports is what the listener would run."]}),DELETE_DOC6=defineCommandDoc("event-listener delete",{rules:["The event listener is the positional argument; the workspace is -w and the environment -e, which gates the write rather than choosing what is deleted.","--yes skips the confirmation, and is required without a terminal."],notes:["Deletes the listener from the whole workspace. The script it triggered is left in place, as are its test payloads' only reason to exist."]}),CREATE_DOC6=defineCommandDoc("event-listener create",{schema:createBodySchema6,conditional:["scriptId","scriptName"],body:{appId:"<appId>",eventListenerTypeId:"<eventListenerTypeId>",eventTypeId:"<eventTypeId>",scriptId:"<scriptId>",scriptName:"OnIssueCreated",connectorId:"<connectorId>",urlPath:"jira-issues",disabled:!1,eventQueueId:"<eventQueueId>",eventQueueGroupings:["issue.key"]},rules:[`appId, eventListenerTypeId (spelled --listener-type-id as a flag) and eventTypeId come from ${CLI} app list: the listener type must be one of the app's and the event type one of the listener type's.`,`Exactly one of scriptId or scriptName is required. ${SCRIPT_KEYS_RULE}`,CONNECTOR_RULE,`urlPath: the path an HTTP_ENDPOINT listener answers on: ${URL_PATH_FORMAT}; omitted, the API generates one, and every other listener type gets a generated one whatever is sent. The full address comes back as webhookUrl.`,"disabled: true creates the listener disabled in the environment -e names; omitted means enabled.","eventQueueId: an event queue of the workspace; the team's plan must include event queues, which team get reports as features.eventQueues.",`eventQueueGroupings: up to ${MAX_QUEUE_GROUPINGS} field paths into the event, spelled --event-queue-grouping as a repeatable flag; events sharing the values at those paths are handed to the script in arrival order. Ignored without eventQueueId: the API answers 201 and the listener comes back with no grouping at all.`,"A new listener arrives with a seeded Default test payload, sampling the event type it was created for.","Refused in a non-HEAD environment: create in a HEAD one."],notes:[SCRIPT_NAME_BUNDLE_REPORT]}),UPDATE_DOC6=defineCommandDoc("event-listener update",{schema:updateBodySchema6,body:{eventTypeId:"<eventTypeId>",scriptId:"<scriptId>",scriptName:"OnIssueCreated",connectorId:"<connectorId>",urlPath:"jira-issues",disabled:!1,eventQueueId:"<eventQueueId>",eventQueueGroupings:["issue.key"]},rules:["An omitted key keeps the current value.",'eventTypeId moves the listener to a different event type; omitted, the current one is kept. Only a listener that has never been configured with one requires it, and a body naming neither it nor a current value is refused with 400 "Event type is required." there.',`${SCRIPT_KEYS_RULE} The two cannot be combined, and omitting both keeps the script the listener already triggers. In a non-HEAD environment the script cannot change at all, so a scriptId sent there must be the one that environment reports.`,CONNECTOR_RULE,`urlPath moves the endpoint an HTTP_ENDPOINT listener answers on, and whatever was registered with the old path stops arriving: ${URL_PATH_FORMAT}. Omitted, the path is kept where the environment has one of its own, and a non-HEAD environment that has never had one gets a generated path from the first update that touches the listener, as the notes below set out. On every other listener type it is ignored: the listener keeps the path it has.`,"disabled: true stops the listener in the environment named by -e, false starts it there (--disabled and --enabled as flags), omitted keeps the current state.","eventQueueId: an ID attaches that queue, null detaches the listener and drops the grouping with it (--no-event-queue as a flag), omitted keeps the queue as it is; attaching needs the team's plan to include event queues.",`eventQueueGroupings applies to the queue the listener is on, up to ${MAX_QUEUE_GROUPINGS} paths, spelled --event-queue-grouping as a repeatable flag; [] clears the grouping and leaves the listener queued (--no-event-queue-grouping as a flag), and on a listener with no queue it is ignored the way it is on create.`,"In a non-HEAD environment only connectorId, urlPath and disabled can change. eventTypeId, scriptId, eventQueueId and eventQueueGroupings are read-only rather than refused there: omit them, or echo back what that environment's own get reports, and only a differing value is a 400 naming it. Omitting eventTypeId is the only way to write that environment's own fields when its release captured the listener before an event type was chosen, there being nothing to echo. scriptName is refused whenever it is sent, creating a script being a shared change by definition.","Changing eventTypeId leaves the existing test payloads sampling the old event; --replace-test-payloads, a flag rather than a key, replaces them."],notes:["The URL path is per environment, and an environment that has never had one of its own gets a generated path from the first update that touches the listener there \u2014 --disabled alone included. Its webhookUrl then differs from HEAD's, and get through that environment reports no urlPath until that has happened.","--replace-test-payloads deletes the payloads that still sample the old event and seeds one from the new type; a run that passes neither it nor --no-replace-test-payloads gets a warning. An update not carrying eventTypeId cannot have moved the type, so it costs nothing; one that does could be echoing the current value, so the listener is read first to tell a move from an echo \u2014 a read --no-replace-test-payloads skips, neither outcome being possible there. In a local copy the payload files follow.",SCRIPT_NAME_BUNDLE_REPORT]});async function askUrlPath(ask){if(ask.provided!==void 0)return ask.provided;if(!ask.interactive||ask.listenerType!==HTTP_ENDPOINT)return;let typed=(await prompts().text("URL path (must be unique; edit or keep the suggestion)",{initial:ask.current??ulid(),allowEmpty:!0})).trim()||void 0;return typed===ask.current?void 0:typed}async function listenerTypeName(client,appId,listenerTypeId,known){return known||(!appId||!listenerTypeId?void 0:(await resolverChoices(client,"listenerType",{app:appId})).find(choice=>choice.value===listenerTypeId)?.label)}function suggestScriptName(eventTypeName){let pascal=(eventTypeName??"").split(/[^A-Za-z0-9]+/).filter(Boolean).map(word=>word.charAt(0).toUpperCase()+word.slice(1)).join("");return pascal?`On${pascal}`.slice(0,MAX_SCRIPT_NAME):void 0}async function askQueueGroupings(current){let paths=[];for(let existing of current??[]){if(!await prompts().confirm(`Change field path "${existing}"?`,!1)){paths.push(existing);continue}let answer=(await prompts().text(`Field path (empty to remove "${existing}")`,{allowEmpty:!0,initial:existing})).trim();answer&&paths.push(answer)}for(;;){if(paths.length>=MAX_QUEUE_GROUPINGS){prompts().note(`\u2714 ${MAX_QUEUE_GROUPINGS} field paths \u2014 that is the maximum.`);break}let opening=paths.length===0&&!current?.length;if(!opening&&!await prompts().confirm("Add another field path?",!1))break;let answer=(await prompts().text(opening?"Field path to group events by (empty for no grouping)":"Field path",{allowEmpty:!0})).trim();if(!answer){opening||prompts().note("\u2716 A field path cannot be empty \u2014 skipping it.");break}paths.push(answer)}return paths}async function askGroupingChoice(current){return await prompts().confirm(`Group queued events by a field? (events sharing a value are processed in order, max ${MAX_QUEUE_GROUPINGS} paths)`,!1)?askQueueGroupings(current):current?.length?[]:void 0}async function askQueueAttachment(scope2,current){let eventQueueId;try{eventQueueId=(await resolveParams(["eventQueue"],{workspace:scope2.workspace,environment:scope2.environment},{client:scope2.client,interactive:!0})).eventQueue}catch(err){if(!(err instanceof CliError)||err.code!=="NO_RESULTS")throw err;return prompts().note(`\u26A0 No event queues in this environment \u2014 continuing unqueued. Create one with '${CLI} event-queue create'.`),{}}return stripUndefined({eventQueueId,eventQueueGroupings:await askGroupingChoice(current?.groupings)})}function queueCell(listener){if(!listener.eventQueueId)return"\u2014";let name=listener.eventQueueName??listener.eventQueueId,groupings=listener.eventQueueGroupings;return groupings?.length?`${name} \xB7 ${groupings.join(", ")}`:name}function connectorCell2(id,name){return id?name&&name!==id?`${name} (${id})`:id:name??"\u2014"}async function askQueueOnUpdate(scope2,globals,current){let teamId=await teamForQuestions(scope2,globals);if(!teamId)return{};if(!(await withSpinner("Checking plan features",()=>teamFeatures(scope2.client,teamId))).eventQueues)return{};if(!current.eventQueueId)return await prompts().select("Event queue: not queued",[{value:"keep",label:"Leave it unqueued (current)"},{value:"attach",label:"Queue incoming events",hint:"events are held in an event queue and processed one at a time"}],{initial:"keep"})==="attach"?askQueueAttachment(scope2):{};let grouped2=current.eventQueueGroupings?.length?` \u2014 grouped by ${current.eventQueueGroupings.join(", ")}`:"",answer=await prompts().select(`Event queue: ${current.eventQueueName??current.eventQueueId}${grouped2}`,[{value:"keep",label:"Keep it as it is"},{value:"move",label:"Use a different event queue"},{value:"regroup",label:"Change what the events are grouped by"},{value:"detach",label:"Detach",hint:"deliver events straight to the script"}],{initial:"keep"});return answer==="keep"?{}:answer==="move"?askQueueAttachment(scope2,{groupings:current.eventQueueGroupings}):answer==="detach"?{eventQueueId:null}:{eventQueueGroupings:await askQueueGroupings(current.eventQueueGroupings)}}async function askQueueOnCreate(scope2,globals,opts){if(opts.eventQueueId)return stripUndefined({eventQueueId:opts.eventQueueId,eventQueueGroupings:opts.eventQueueGrouping});let teamId=await teamForQuestions(scope2,globals);return teamId?(await withSpinner("Checking plan features",()=>teamFeatures(scope2.client,teamId))).eventQueues?await prompts().confirm("Queue incoming events? (events are held in an event queue and processed one at a time)",!1)?askQueueAttachment(scope2):{}:{}:{}}var CREATE_SCRIPT="\0create-script",ENVIRONMENT_OWNED="the connector, the URL path and the enabled state";function releasedNote2(version2,environmentName){return[`${environmentName} has ${version2?`release ${version2}`:"a release"} deployed.`,`Only ${ENVIRONMENT_OWNED} can be changed there; the event type, the script and the`,"event queue belong to the event listener and are shared by every environment."].join(" ")}async function askConnectorOnUpdate(scope2,globals,current){let team=await teamForQuestions(scope2,globals);if(!team)return;let choices;try{choices=await resolverChoices(scope2.client,"connector",{team,app:current.appId,listenerType:current.listenerTypeId,workspace:scope2.workspace,environment:scope2.environment})}catch(err){if(!(err instanceof CliError))throw err;return}if(choices.length===0)return;let currentId=current.connectorId,listed=currentId?choices.some(choice=>choice.value===currentId):!1,me2=current.connectorOwner?await currentUserId(scope2.client):void 0,someoneElse=!current.connectorOwner||!me2||current.connectorOwner.id!==me2,implicit=!!currentId&&!listed&&someoneElse,KEEP="\0keep-connector",keepLabel=current.connectionName??currentId,offered=listed?choices.map(choice=>choice.value===currentId?{...choice,display:`${choice.display??choice.label} (current)`}:choice):[currentId&&keepLabel?{value:KEEP,label:keepLabel,display:`${keepLabel} (${implicit?implicitShareMark(current.connectorOwner):"current"})`}:{value:KEEP,label:"No connector",display:"No connector (current)"},...choices],initial=listed?currentId:KEEP;for(;;){let picked=await prompts().select("Connector:",offered,initial?{initial}:{});if(picked===KEEP||listed&&picked===currentId)return;if(!implicit)return picked;let replacement=choices.find(choice=>choice.value===picked)?.label??picked;if(await confirmImplicitReplacement(keepLabel??"",replacement,current.connectorOwner))return picked}}async function askScriptOnUpdate(scope2,current,suggestedName){let picked=await askKeepOrChange({client:scope2.client,key:"script",deps:{workspace:scope2.workspace,environment:scope2.environment},message:"Script:",current:{value:current.id,label:current.name},extra:[{value:CREATE_SCRIPT,label:"Create a new script\u2026"}]});return picked===CREATE_SCRIPT?{scriptName:await askScriptName(suggestedName)}:picked===void 0?{}:{scriptId:picked}}var NO_CONNECTOR2="\0no-connector";async function askConnectorOnCreate2(scope2,globals,current){let team=await teamForQuestions(scope2,globals);if(!team)return;let choices;try{choices=await resolverChoices(scope2.client,"connector",{team,app:current.appId,listenerType:current.listenerTypeId,workspace:scope2.workspace,environment:scope2.environment})}catch(err){if(!(err instanceof CliError))throw err;return}if(choices.length===0){prompts().note("\u26A0 No connector compatible with the selected app exists in the team \u2014 continuing without one.");return}let picked=await prompts().select("Connector:",[{value:NO_CONNECTOR2,label:"No connector",hint:"required by some listener types; attach one later"},...choices],{initial:choices[0]?.value??NO_CONNECTOR2});return picked===NO_CONNECTOR2?void 0:picked}var RECOMMEND_CREATE="recommended \u2014 the entry function is generated for the event type";async function fillCreateBody2(scope2,globals,opts){let labels={},resolved=await resolveParams(["app","listenerType","eventType"],{app:opts.appId,listenerType:opts.listenerTypeId,eventType:opts.eventTypeId,workspace:scope2.workspace,environment:scope2.environment,team:globals.team},{client:scope2.client,interactive:!0,labels,registry:listenerAppRegistry()}),script=opts.scriptId??opts.scriptName?{scriptId:opts.scriptId,scriptName:opts.scriptName}:await askScript({client:scope2.client,workspace:scope2.workspace,environment:scope2.environment,message:"Script to handle the event:",suggestedName:suggestScriptName(labels.eventType),recommendCreate:RECOMMEND_CREATE}),urlPath=await askUrlPath({provided:opts.urlPath,listenerType:opts.urlPath===void 0?await listenerTypeName(scope2.client,resolved.app,resolved.listenerType,labels.listenerType):void 0,interactive:!0}),connectorId=opts.connectorId??await askConnectorOnCreate2(scope2,globals,{appId:resolved.app??"",listenerTypeId:resolved.listenerType??""}),queue=await askQueueOnCreate(scope2,globals,opts);return stripUndefined({appId:resolved.app,eventListenerTypeId:resolved.listenerType,eventTypeId:resolved.eventType,scriptId:script.scriptId,scriptName:script.scriptName,connectorId,urlPath,disabled:opts.disabled,...queue})}var DEFAULT_PAYLOAD_NAME="Default",PAYLOAD_CONCURRENCY=5;function plural3(count,noun){return`${count} ${noun}${count===1?"":"s"}`}function eventTypeMoved(plan){return plan.eventTypeChanged??!1}async function refreshTestPayloads(scope2,eventListenerId){let path2={workspaceId:scope2.workspace,environmentId:scope2.environment,eventListenerId},list=await withSpinner("Fetching test payloads",()=>scope2.client.GET("/v1/workspace/{workspaceId}/environment/{environmentId}/eventListener/{eventListenerId}/testPayloads",{params:{path:path2}}));(!list.response.ok||!list.data)&&apiFail(list.response.status,list.error);let existing=list.data.testPayloads;if(existing.length===0)return{deleted:[]};let taken=new Set(existing.map(payload=>payload.name)),name=DEFAULT_PAYLOAD_NAME;for(let n=2;taken.has(name);n+=1)name=`${DEFAULT_PAYLOAD_NAME} ${n}`;let created=await withSpinner("Creating test payload for the new event type",()=>scope2.client.POST("/v1/workspace/{workspaceId}/environment/{environmentId}/eventListener/{eventListenerId}/testPayload",{params:{path:path2},body:{name}}));(!created.response.ok||!created.data)&&apiFail(created.response.status,created.error),await withSpinner(`Deleting ${plural3(existing.length,"old test payload")}`,()=>throttleAll(PAYLOAD_CONCURRENCY,existing.map(payload=>async()=>{let{response,error:error51}=await scope2.client.DELETE("/v1/workspace/{workspaceId}/environment/{environmentId}/eventListener/{eventListenerId}/testPayload/{testPayloadId}",{params:{path:{...path2,testPayloadId:payload.id}}});response.ok||apiFail(response.status,error51)})));let final=created.data;if(final.name!==DEFAULT_PAYLOAD_NAME){let renamed=await withSpinner("Renaming the new test payload",()=>scope2.client.PUT("/v1/workspace/{workspaceId}/environment/{environmentId}/eventListener/{eventListenerId}/testPayload/{testPayloadId}",{params:{path:{...path2,testPayloadId:created.data.id}},body:{name:DEFAULT_PAYLOAD_NAME}}));renamed.response.ok&&renamed.data&&(final=renamed.data)}return{created:final,deleted:existing}}async function buildUpdateBody3(scope2,globals,eventListenerId,opts,plan={}){let interactive=!opts.input&&canPrompt();opts.eventQueue===!1&&opts.eventQueueId&&fail(EXIT.USAGE,"USAGE_ERROR","--no-event-queue cannot be combined with --event-queue-id.");let listenerType,currentUrlPath,currentQueue={},eventTypeId=opts.eventTypeId,scriptId=opts.scriptId,scriptName=opts.scriptName,connectorId=opts.connectorId,disabled=disabledFromFlags(opts),queue={},releasedEnvironment=!1;if(interactive){let current=await withSpinner("Fetching event listener",()=>scope2.client.GET("/v1/workspace/{workspaceId}/environment/{environmentId}/eventListener/{eventListenerId}",{params:{path:{workspaceId:scope2.workspace,environmentId:scope2.environment,eventListenerId}}}));(!current.response.ok||!current.data)&&apiFail(current.response.status,current.error),listenerType=current.data.eventListenerType.name,currentUrlPath=current.data.urlPath,currentQueue={eventQueueId:current.data.eventQueueId,eventQueueName:current.data.eventQueueName,eventQueueGroupings:current.data.eventQueueGroupings};let release2=await withSpinner("Checking the environment",()=>environmentRelease(scope2.client,scope2.workspace,scope2.environment));if(releasedEnvironment=!!release2,release2?prompts().note(`\u26A0 ${releasedNote2(release2.version,"This environment")}`):eventTypeId||(eventTypeId=await askKeepOrChange({client:scope2.client,key:"eventType",deps:{app:current.data.app.id,listenerType:current.data.eventListenerType.id},message:"Event type:",current:{value:current.data.eventType?.id,label:current.data.eventType?.name}})),plan.eventTypeChanged=eventTypeId!==void 0&&eventTypeId!==current.data.eventType?.id,plan.eventTypeChanged&&(plan.replace=opts.replaceTestPayloads??await prompts().confirm("The event type changed. Replace the test payloads with a fresh sample of the new event? Existing payloads are deleted, edits included.",!1)),!release2&&!scriptId&&!scriptName){let picked=await askScriptOnUpdate(scope2,{id:current.data.script?.id,name:current.data.script?.name},suggestScriptName(current.data.eventType?.name));scriptId=picked.scriptId,scriptName=picked.scriptName}connectorId??=await askConnectorOnUpdate(scope2,globals,{connectorId:current.data.connectorId,connectionName:current.data.connectionName,connectorOwner:current.data.connectorOwner,appId:current.data.app.id,listenerTypeId:current.data.eventListenerType.id}),disabled??=await askStatus(current.data.disabled,"the event listener")}let urlPath=await askUrlPath({provided:opts.urlPath,listenerType,current:currentUrlPath,interactive}),groupingFlag=opts.eventQueueGrouping===!1?[]:opts.eventQueueGrouping??void 0;return opts.eventQueue===!1?queue={eventQueueId:null}:opts.eventQueueId||groupingFlag?queue=stripUndefined({eventQueueId:opts.eventQueueId,eventQueueGroupings:groupingFlag}):interactive&&!releasedEnvironment&&(queue=await askQueueOnUpdate(scope2,globals,currentQueue)),opts.input?readInput(opts.input):{...stripUndefined({eventTypeId,connectorId,scriptId,scriptName,urlPath,disabled}),...queue}}async function recordEventTypeMove(scope2,eventListenerId,body,opts,plan){if(plan.eventTypeChanged!==void 0||opts.replaceTestPayloads===!1||body.eventTypeId===void 0)return;let current=await withSpinner("Fetching event listener",()=>scope2.client.GET("/v1/workspace/{workspaceId}/environment/{environmentId}/eventListener/{eventListenerId}",{params:{path:{workspaceId:scope2.workspace,environmentId:scope2.environment,eventListenerId}}}));current.response.ok&¤t.data&&(plan.eventTypeChanged=body.eventTypeId!==current.data.eventType?.id)}function eventListenerCommand(){let el=new Command("event-listener").alias("el").description("Manage workspace event listeners");return withScope3(el.command("list").description("List event listeners in a workspace")).option("--explain",EXPLAIN).action(async(_opts,cmd)=>{if(explained(cmd,LIST_DOC7))return;let globals=cmd.optsWithGlobals(),scope2=await resolveScope5(globals),{data,response,error:error51}=await withSpinner("Fetching event listeners",()=>scope2.client.GET("/v1/workspace/{workspaceId}/environment/{environmentId}/eventListeners",{params:{path:{workspaceId:scope2.workspace,environmentId:scope2.environment}}}));(!response.ok||!data)&&apiFail(response.status,error51),ok(data,{human:d=>({eventListeners:tableRows(["id","app","eventListenerType","disabled","script","eventType","connector","urlPath","queue"],d.eventListeners.map(listener=>({...listener,connector:listener.connectionName??"\u2014",urlPath:listener.urlPath??"\u2014",queue:queueCell(listener)})))})})}),withScope3(el.command("get").description("Get a single event listener as the environment sees it").argument("[eventListenerId]","Event listener ID (required, interactive)")).option("--explain",EXPLAIN).action(async(idArg,_opts,cmd)=>{if(explained(cmd,GET_DOC6))return;let globals=cmd.optsWithGlobals(),scope2=await resolveScope5(globals),eventListenerId=await resolveListenerId(scope2,idArg),{data,response,error:error51}=await withSpinner("Fetching event listener",()=>scope2.client.GET("/v1/workspace/{workspaceId}/environment/{environmentId}/eventListener/{eventListenerId}",{params:{path:{workspaceId:scope2.workspace,environmentId:scope2.environment,eventListenerId}}}));(!response.ok||!data)&&apiFail(response.status,error51),ok(data,{human:({eventQueueId:_id,eventQueueName:_name,eventQueueGroupings:_g,connectorId,connectionName,connectorOwner,...rest})=>({...rest,...connectorId||connectionName?{connector:connectorCell2(connectorId,connectionName)}:{},...connectorOwner?{connectorOwner:personCell(connectorOwner)}:{},queue:queueCell(data)})})}),withScope3(el.command("create").description("Create an event listener in a workspace")).option("--app-id <id>",`App ID, see ${CLI} app list (required unless --input, interactive)`).option("--listener-type-id <id>","Event listener type ID for the app (required unless --input, interactive)").option("--event-type-id <id>","Event type ID for the listener type (required unless --input, interactive)").option("--script-id <id>","Existing script ID to attach (required unless --script-name or --input, interactive, exclusive with --script-name)").option("--script-name <name>","Script name to create and attach (required unless --script-id or --input, interactive, exclusive with --script-id)").option("--connector-id <id>","Connector ID, required by some listener types, which app list does not mark (optional, interactive)").option("--url-path <path>","Custom URL path an HTTP_ENDPOINT listener answers on (optional, interactive for HTTP_ENDPOINT only, API default: a generated path, ignored on every other listener type)").option("--disabled","Create the listener disabled (optional, API default: enabled)").option("--event-queue-id <id>","Event queue ID to attach (optional, interactive on a plan with event queues)").option("--event-queue-grouping <fieldPath>",`Event queue grouping field path, max ${MAX_QUEUE_GROUPINGS}; repeat the flag or comma-separate (optional, interactive, repeatable, ignored without --event-queue-id)`,collect).option("--input <file>",INPUT_BODY).option("--explain",EXPLAIN).action(async(opts,cmd)=>{if(explained(cmd,CREATE_DOC6))return;let globals=cmd.optsWithGlobals(),scope2=await resolveScope5(globals),interactive=!opts.input&&canPrompt(),hasAllRequired=opts.appId&&opts.listenerTypeId&&opts.eventTypeId&&(opts.scriptId??opts.scriptName),rawBody;if(opts.input)rawBody=readInput(opts.input);else if(interactive&&!hasAllRequired)rawBody=await fillCreateBody2(scope2,globals,opts);else{let urlPath=await askUrlPath({provided:opts.urlPath,listenerType:interactive&&opts.urlPath===void 0?await listenerTypeName(scope2.client,opts.appId,opts.listenerTypeId):void 0,interactive});rawBody=stripUndefined({appId:opts.appId,eventListenerTypeId:opts.listenerTypeId,eventTypeId:opts.eventTypeId,scriptId:opts.scriptId,scriptName:opts.scriptName,connectorId:opts.connectorId,urlPath,disabled:opts.disabled,eventQueueId:opts.eventQueueId,eventQueueGroupings:opts.eventQueueGrouping})}let parsed=validate(createBodySchema6,rawBody),body={...parsed,...parsed.scriptName===void 0?{}:{scriptName:assertScriptName(parsed.scriptName)},...parsed.urlPath===void 0?{}:{urlPath:assertUrlPath(parsed.urlPath)}},{data,response,error:error51}=await withSpinner("Creating event listener",()=>scope2.client.POST("/v1/workspace/{workspaceId}/environment/{environmentId}/eventListener",{params:{path:{workspaceId:scope2.workspace,environmentId:scope2.environment}},body}));(!response.ok||!data)&&apiFail(response.status,error51),await syncNewEventListener(scope2.client,{workspaceId:scope2.workspace,environmentId:scope2.environment},data.eventListenerId),await syncPackages(scope2.client,scope2.workspace),body.scriptName!==void 0&&await syncScriptFromServer(scope2.client,{workspaceId:scope2.workspace,environmentId:scope2.environment},data.scriptId),okMutation("Event listener created",data,bundleReportDetail(data,data))}),withScope3(el.command("update").description("Update an event listener").argument("[eventListenerId]","Event listener ID (required, interactive)")).option("--event-type-id <id>","Event type ID for the listener type (optional, interactive on HEAD only, default: the current event type, refused when it differs from what a non-HEAD environment reports)").option("--connector-id <id>","Connector ID, required by some listener types, which app list does not mark (optional, interactive)").option("--script-id <id>","Existing script ID to attach (optional, interactive on HEAD only, exclusive with --script-name, refused when it differs from what a non-HEAD environment reports)").option("--script-name <name>","Script name to create and attach (optional, interactive on HEAD only, exclusive with --script-id, refused in a non-HEAD environment)").option("--url-path <path>","Custom URL path an HTTP_ENDPOINT listener answers on (optional, interactive for HTTP_ENDPOINT only, default: the current path, ignored on every other listener type)").option("--disabled","Disable the listener (optional, interactive, exclusive with --enabled)").option("--enabled","Enable the listener (optional, interactive, exclusive with --disabled)").option("--event-queue-id <id>","Event queue ID to attach; omitting it keeps the current queue (optional, interactive on HEAD only, exclusive with --no-event-queue, refused when it differs from what a non-HEAD environment reports)").option("--no-event-queue","Detach the event queue so events go straight to the script, also dropping the grouping (optional, interactive on HEAD only, exclusive with --event-queue-id, refused when it differs from what a non-HEAD environment reports)").option("--event-queue-grouping <fieldPath>",`Event queue grouping field path, max ${MAX_QUEUE_GROUPINGS}; repeat the flag or comma-separate, applies to the queue the listener is on (optional, interactive on HEAD only, repeatable, refused when it differs from what a non-HEAD environment reports)`,collect).option("--no-event-queue-grouping","Clear the grouping, leaving the listener queued (optional, interactive on HEAD only, refused when it differs from what a non-HEAD environment reports)").option("--replace-test-payloads","When the event type changes, delete the existing test payloads and create one seeded from the new event (optional, interactive, exclusive with --no-replace-test-payloads, ignored when the event type does not change)").option("--no-replace-test-payloads","Keep the existing test payloads even though they sample the old event (optional, interactive, exclusive with --replace-test-payloads, ignored when the event type does not change)").option("--input <file>",INPUT_BODY).option("--explain",EXPLAIN).action(async(idArg,opts,cmd)=>{if(explained(cmd,UPDATE_DOC6))return;let globals=cmd.optsWithGlobals(),scope2=await resolveScope5(globals),eventListenerId=await resolveListenerId(scope2,idArg),payloads={},rawBody=await buildUpdateBody3(scope2,globals,eventListenerId,opts,payloads),empty=typeof rawBody=="object"&&Object.keys(rawBody??{}).length===0;if(canPrompt()&&!opts.input&&empty){prompts().note("Nothing to update \u2014 the event listener was left as it is.");return}empty&&!opts.input&&failNothingToUpdate(["--event-type-id","--script-id/--script-name","--connector-id","--url-path","--disabled/--enabled","a queue flag","--input"]);let parsed=validate(updateBodySchema6,rawBody),body={...parsed,...parsed.scriptName===void 0?{}:{scriptName:assertScriptName(parsed.scriptName)},...parsed.urlPath===void 0?{}:{urlPath:assertUrlPath(parsed.urlPath)}};await recordEventTypeMove(scope2,eventListenerId,body,opts,payloads);let{data,response,error:error51}=await withSpinner("Updating event listener",()=>scope2.client.PUT("/v1/workspace/{workspaceId}/environment/{environmentId}/eventListener/{eventListenerId}",{params:{path:{workspaceId:scope2.workspace,environmentId:scope2.environment,eventListenerId}},body}));(!response.ok||!data)&&apiFail(response.status,error51),await syncEventListenerFolder(scope2.client,{workspaceId:scope2.workspace,environmentId:scope2.environment},eventListenerId,"rename"),await syncPackages(scope2.client,scope2.workspace),body.scriptName!==void 0&&data.scriptId!==void 0&&await syncScriptFromServer(scope2.client,{workspaceId:scope2.workspace,environmentId:scope2.environment},data.scriptId);let syncScope={workspaceId:scope2.workspace,environmentId:scope2.environment},typeChanged=eventTypeMoved(payloads);if(payloads.replace??(typeChanged&&opts.replaceTestPayloads)){let refreshed2=await refreshTestPayloads(scope2,eventListenerId);for(let gone of refreshed2.deleted)await syncTestPayloadDeleted(scope2.client,syncScope,eventListenerId,{id:gone.id});refreshed2.created&&await syncTestPayloadById(scope2.client,syncScope,eventListenerId,refreshed2.created.id)}else if(typeChanged&&opts.replaceTestPayloads!==!1){let movedTo=body.eventTypeId??"<eventTypeId>";warnLine(`\u26A0 The event listener's test payloads still sample the previous event type. Replace them with \`${CLI} event-listener update ${eventListenerId} --event-type-id ${movedTo} --replace-test-payloads\`.`)}okMutation("Event listener updated",{updated:!0,id:eventListenerId,...data},bundleReportDetail({id:eventListenerId,...data},data))}),withScope3(el.command("delete").description("Delete an event listener from a workspace").argument("[eventListenerId]","Event listener ID (required, interactive)"),{destructive:!0,gate:!0}).option("--yes",CONFIRM_YES).option("--explain",EXPLAIN).action(async(idArg,opts,cmd)=>{if(explained(cmd,DELETE_DOC6))return;let globals=cmd.optsWithGlobals(),scope2=await resolveScope5(globals,{useSession:canPrompt()}),eventListenerId=await resolveListenerId(scope2,idArg);opts.yes||(canPrompt()||failNeedsYes(`event listener ${eventListenerId}`),await prompts().confirm(`Delete event listener ${eventListenerId}? This is irreversible.`)||fail(EXIT.CANCELLED,"CANCELLED","Deletion cancelled."));let{response,error:error51}=await withSpinner("Deleting event listener",()=>scope2.client.DELETE("/v1/workspace/{workspaceId}/environment/{environmentId}/eventListener/{eventListenerId}",{params:{path:{workspaceId:scope2.workspace,environmentId:scope2.environment,eventListenerId}}}));response.ok||apiFail(response.status,error51),await syncEventListenerFolder(scope2.client,{workspaceId:scope2.workspace,environmentId:scope2.environment},eventListenerId,"delete"),await syncPackages(scope2.client,scope2.workspace),okMutation("Event listener deleted",{deleted:!0,id:eventListenerId})}),el}import{basename as basename4,extname as extname2}from"path";var TEST_PAYLOAD_NAME_FORMAT="up to 50 characters",MAX_TEST_PAYLOAD_NAME=50;function normalizeTestPayloadName(name){return name.trim()}function testPayloadNameError(name){let normalized=normalizeTestPayloadName(name);if(!normalized)return"A test payload name is required.";if(normalized.length>MAX_TEST_PAYLOAD_NAME)return`A test payload name can be at most ${MAX_TEST_PAYLOAD_NAME} characters (that one is ${normalized.length}).`}function assertTestPayloadName(name){let error51=testPayloadNameError(name);return error51&&fail(EXIT.USAGE,"INVALID_TEST_PAYLOAD_NAME",error51),normalizeTestPayloadName(name)}function suggestPayloadNameFromPath(path2){let cleaned=normalizeTestPayloadName(basename4(path2,extname2(path2)));return testPayloadNameError(cleaned)?void 0:cleaned}var PAYLOAD_KIND2={noun:"Test payload",tooLargeCode:"TEST_PAYLOAD_TOO_LARGE",language:"json"},NAME_PROMPT2=`Test payload name (${TEST_PAYLOAD_NAME_FORMAT})`,SOURCE_PROMPT="How do you want to provide the payload content?",SEED_CHOICE={label:"Edit the sample event here",hint:"recommended \u2014 seeded from the event type, opens in the editor"};function withScope4(cmd,opts={}){return cmd.option("-w, --workspace <workspaceId>",opts.destructive?SCOPE_WORKSPACE_DESTRUCTIVE:SCOPE_WORKSPACE).option("-e, --env <environmentId>",opts.destructive?SCOPE_ENVIRONMENT_DESTRUCTIVE:SCOPE_ENVIRONMENT).option("--team <teamId>",opts.destructive?SCOPE_TEAM_FILTER_DESTRUCTIVE:SCOPE_TEAM_FILTER).option("--event-listener-id <eventListenerId>","Event listener ID (required, interactive)")}async function resolveScope6(globals,opts,extra={}){let client=await apiClient(globals.instance),resolved=await resolveParams(["workspace","environment"],{team:opts.team??globals.team,workspace:opts.workspace??globals.workspace,environment:opts.env??globals.env},{client,interactive:canPrompt(),useSession:extra.useSession});return{client,workspace:resolved.workspace??"",environment:resolved.environment??""}}async function resolveListener(scope2,provided){return provided?assertResourceId(provided,"eventListenerId"):(canPrompt()||fail(EXIT.USAGE,"USAGE_ERROR","--event-listener-id is required."),(await resolveParams(["eventListener"],{workspace:scope2.workspace,environment:scope2.environment},{client:scope2.client,interactive:!0})).eventListener??"")}async function resolvePayload(scope2,eventListenerId,provided){if(provided)return{id:assertResourceId(provided,"testPayloadId")};canPrompt()||fail(EXIT.USAGE,"USAGE_ERROR",`<testPayloadId> is required. ${supplyHint()}`);let labels={};return{id:(await resolveParams(["testPayload"],{workspace:scope2.workspace,environment:scope2.environment,eventListener:eventListenerId},{client:scope2.client,interactive:!0,labels})).testPayload??"",label:labels.testPayload}}var createBodySchema7=external_exports.object({name:external_exports.string().min(1),content:external_exports.string().optional(),default:external_exports.boolean().optional()}).strict(),updateBodySchema7=external_exports.object({content:external_exports.string().optional(),name:external_exports.string().min(1).optional()}).strict().refine(body=>body.content!==void 0||body.name!==void 0,{error:"Either content or name is required.",path:["name"]}),CONTENT_CAP2=`${MAX_CONTENT_BYTES/1024/1024} MiB`,LIST_DOC8=defineCommandDoc("event-listener-test-payload list",{rules:["The listener is --event-listener-id; the workspace is -w and the environment -e. There is no positional argument."],notes:["A listener's payloads are the same in every environment. Which one is the default is user-specific and environment-specific, so the default column is yours and not a colleague's."]}),GET_DOC7=defineCommandDoc("event-listener-test-payload get",{rules:["The payload is the positional argument and the listener is --event-listener-id; the workspace is -w and the environment -e.","--content-only prints the stored bytes alone, identically with or without --raw, so `\u2026 --content-only > payload.json` writes the file."],notes:["The content is stored verbatim and never parsed, so a payload saved as something other than a JSON object reads back unchanged and only fails when a trigger runs it."]}),SET_DEFAULT_DOC=defineCommandDoc("event-listener-test-payload set-default",{rules:["The payload is the positional argument and the listener is --event-listener-id; the workspace is -w and the environment -e, which is the environment the choice is made in."],notes:["User-specific and environment-specific: a colleague's manual trigger still runs whatever they picked."]}),DELETE_DOC7=defineCommandDoc("event-listener-test-payload delete",{rules:["The payload is the positional argument and the listener is --event-listener-id; the workspace is -w and the environment -e.","--yes skips the confirmation, and is required without a terminal."],notes:["The last remaining payload of a listener cannot be deleted.","Anyone who had chosen this one falls back to the payload named Default."]}),CREATE_DOC7=defineCommandDoc("event-listener-test-payload create",{schema:createBodySchema7,body:{name:"Issue created",content:'{ "issue": { "key": "TEST-1" } }',default:!0},rules:[`name: ${TEST_PAYLOAD_NAME_FORMAT}, trimmed, no charset rule, unique within the listener.`,`content: the event as text, spelled --content or --file <path> as a flag, up to ${CONTENT_CAP2}, stored verbatim and never parsed; omitted, the API seeds the payload with the sample event for the listener's event type; "" is refused.`,"default: true also makes it the payload a manual trigger runs, for your user in the environment -e names.","The listener is --event-listener-id, not a body key; a listener's payloads are shared by every environment of the workspace."]}),UPDATE_DOC7=defineCommandDoc("event-listener-test-payload update",{schema:updateBodySchema7,body:{name:"Issue created",content:'{ "issue": { "key": "TEST-1" } }'},rules:["At least one of content or name is required; an omitted key keeps the current value, and a rename travels without content.",`name: ${TEST_PAYLOAD_NAME_FORMAT}, trimmed, unique within the listener.`,`content: the whole new event as text, spelled --content or --file <path> as a flag, up to ${CONTENT_CAP2}, stored verbatim; "" is refused.`,"The listener is --event-listener-id and the payload the positional argument; neither is a body key."]});async function askPayloadName(suggested){for(;;){let answer=await prompts().text(NAME_PROMPT2,{...suggested?{initial:suggested}:{},allowEmpty:!0}),error51=testPayloadNameError(answer);if(!error51)return normalizeTestPayloadName(answer);prompts().note(`\u2716 ${error51}`)}}function askPayloadSource(opts){return askContentSource({kind:PAYLOAD_KIND2,message:SOURCE_PROMPT,pathMessage:"Path to the payload file",extensions:[".json"],placeholder:PAYLOAD_PLACEHOLDER2,...opts.allowSeed?{omitChoice:SEED_CHOICE}:{},...opts.inlineLabel?{inlineLabel:opts.inlineLabel}:{},...opts.currentContent?{currentContent:opts.currentContent}:{}})}var PAYLOAD_PLACEHOLDER2='{ "issue": { "key": "TEST-1" } }';async function fetchPayload(client,path2,label="Fetching test payload"){let{data,response,error:error51}=await withSpinner(label,()=>client.GET("/v1/workspace/{workspaceId}/environment/{environmentId}/eventListener/{eventListenerId}/testPayload/{testPayloadId}",{params:{path:path2}}));return(!response.ok||!data)&&apiFail(response.status,error51),data}async function setDefaultPayload(client,path2){let{response,error:error51}=await withSpinner("Setting default test payload",()=>client.PUT("/v1/workspace/{workspaceId}/environment/{environmentId}/eventListener/{eventListenerId}/testPayload/{testPayloadId}/default",{params:{path:path2}}));response.ok||apiFail(response.status,error51)}async function editSeededContent(client,path2){let seeded=await fetchPayload(client,path2,"Fetching the seeded sample event"),edited=await askInlineContent(PAYLOAD_KIND2,{initial:seeded.content,placeholder:PAYLOAD_PLACEHOLDER2});if(edited===seeded.content)return{changed:!1};assertSize(Buffer.byteLength(edited,"utf8"),PAYLOAD_KIND2);let{response,error:error51}=await withSpinner("Saving the edited sample event",()=>client.PUT("/v1/workspace/{workspaceId}/environment/{environmentId}/eventListener/{eventListenerId}/testPayload/{testPayloadId}",{params:{path:path2},body:{content:edited}}));return response.ok||apiFail(response.status,error51),{changed:!0}}function formatContent(content){try{return JSON.stringify(JSON.parse(content),null,2)}catch{return content}}function renderPayload(payload){return`${renderDetail({id:payload.id,name:payload.name})}
|
|
1366
|
+
${renderDetail({invocationId})}`)});let send2=()=>client.POST("/v1/workspace/{workspaceId}/invocation/{invocationId}/replay",{params:{path:{workspaceId:target.workspaceId,invocationId:target.invocationId}},body}),{data,response,error:error51}=stream?await send2():await withSpinner("Replaying the invocation",send2);if((!response.ok||!data)&&(stream?.close(),apiFail(response.status,error51)),stream){stream.identify(data.invocationId);let streamed=await stream.done();failStreamOutcome(streamed,data.invocationId,target.workspaceId),isRaw()&&okMutation("Invocation replayed",data);return}okMutation("Invocation replayed",data,renderDetail({invocationId:data.invocationId})),printConsoleLogsHint(data.invocationId,target.workspaceId)}),script.command("abort-invocation").description("Request that a queued or running invocation be aborted").argument("[invocationId]","Invocation to abort (required unless --invocation-id, interactive)").option("--invocation-id <invocationId>",INVOCATION_ID_FLAG).option("--team <teamId>","Team ID \u2014 only needed to browse invocations or pick a workspace (optional, interactive, session default, env SR_CONNECT_CLI_TEAM, ignored when the invocation and workspace are both given)").option("-w, --workspace <workspaceId>","Workspace the invocation belongs to (required unless the invocation is browsed, interactive, session default, env SR_CONNECT_CLI_WORKSPACE)").option("--explain",EXPLAIN).action(async(invocationIdArg,opts,cmd)=>{if(explained(cmd,ABORT_DOC))return;let globals=cmd.optsWithGlobals(),client=await apiClient(globals.instance),target=await resolveInvocationScope(client,invocationFromArgs(invocationIdArg,opts.invocationId),opts,globals.team,ABORT_SCOPE);await abortInvocation(client,target)}),script}var HTTP_ENDPOINT="HTTP_ENDPOINT";function withScope3(cmd,opts={}){let env=opts.gate?opts.destructive?SCOPE_ENVIRONMENT_GATE_DESTRUCTIVE:SCOPE_ENVIRONMENT_GATE:opts.destructive?SCOPE_ENVIRONMENT_DESTRUCTIVE:SCOPE_ENVIRONMENT;return cmd.option("-w, --workspace <workspaceId>",opts.destructive?SCOPE_WORKSPACE_DESTRUCTIVE:SCOPE_WORKSPACE).option("-e, --env <environmentId>",env).option("--team <teamId>",opts.destructive?SCOPE_TEAM_FILTER_DESTRUCTIVE:SCOPE_TEAM_FILTER)}async function resolveScope5(globals,opts={}){let client=await apiClient(globals.instance),resolved=await resolveParams(["workspace","environment"],{team:globals.team,workspace:globals.workspace,environment:globals.env},{client,interactive:canPrompt(),useSession:opts.useSession});return{client,workspace:resolved.workspace??"",environment:resolved.environment??"",team:resolved.team}}async function resolveListenerId(scope2,provided){return provided?assertResourceId(provided,"eventListenerId"):(canPrompt()||fail(EXIT.USAGE,"USAGE_ERROR",`<eventListenerId> is required. ${supplyHint()}`),(await resolveParams(["eventListener"],{workspace:scope2.workspace,environment:scope2.environment},{client:scope2.client,interactive:!0})).eventListener??"")}var MAX_QUEUE_GROUPINGS=10,createBodySchema6=external_exports.object({appId:external_exports.string().min(1),eventListenerTypeId:external_exports.string().min(1),eventTypeId:external_exports.string().min(1),scriptId:external_exports.string().min(1).optional(),scriptName:external_exports.string().min(1).optional(),connectorId:external_exports.string().optional(),urlPath:external_exports.string().optional(),disabled:external_exports.boolean().optional(),eventQueueId:external_exports.string().optional(),eventQueueGroupings:external_exports.array(external_exports.string()).max(MAX_QUEUE_GROUPINGS).optional()}).strict().refine(body=>!(body.scriptId&&body.scriptName),{error:"scriptId and scriptName cannot be combined.",path:["scriptId"]}).refine(body=>!!(body.scriptId??body.scriptName),{error:"Either scriptId or scriptName is required.",path:["scriptId"]}),updateBodySchema6=external_exports.object({eventTypeId:external_exports.string().min(1).optional(),connectorId:external_exports.string().optional(),scriptId:external_exports.string().min(1).optional(),scriptName:external_exports.string().min(1).optional(),urlPath:external_exports.string().optional(),disabled:external_exports.boolean().optional(),eventQueueId:external_exports.string().nullable().optional(),eventQueueGroupings:external_exports.array(external_exports.string()).max(MAX_QUEUE_GROUPINGS).optional()}).strict().refine(body=>!(body.scriptId&&body.scriptName),{error:"scriptId and scriptName cannot be combined.",path:["scriptId"]}),SCRIPT_KEYS_RULE=`scriptId names an existing script; scriptName makes the API create one (${SCRIPT_NAME_RULE}) and attach it.`,CONNECTOR_RULE="connectorId: a connector of the same app that you may use in the team. Some listener types need one and app list does not mark which; event-listener get reports connectionRequired for a listener that already exists. A connector fits when its connectionType, as connector list reports it, is the app's connectionType in app list.",MAX_URL_PATH=200,URL_PATH_CHARSET=/^[A-Za-z0-9_-]+$/,URL_PATH_FORMAT=`letters, digits, underscores and dashes, up to ${MAX_URL_PATH} characters, stored lower-cased and unique across the deployment`;function assertUrlPath(path2){let normalized=path2.trim().toLowerCase();return normalized||fail(EXIT.USAGE,"INVALID_URL_PATH","A URL path is required."),normalized.length>MAX_URL_PATH&&fail(EXIT.USAGE,"INVALID_URL_PATH",`A URL path can be at most ${MAX_URL_PATH} characters (that one is ${normalized.length}).`),URL_PATH_CHARSET.test(normalized)||fail(EXIT.USAGE,"INVALID_URL_PATH",`Use letters, digits, underscores and dashes \u2014 '${path2}' has a character the API refuses.`),normalized}var LIST_DOC7=defineCommandDoc("event-listener list",{rules:["The workspace is -w and the environment -e; there is no positional argument."],notes:["A listener reads through the environment named: its URL path, connector and enabled state are per-environment, and the event type and script it triggers are the workspace's."]}),GET_DOC6=defineCommandDoc("event-listener get",{rules:["The event listener is the positional argument; the workspace is -w and the environment -e."],notes:["Reports the URL path, the webhook URL to register in the external application, and the setup URL, when the listener has a path in the environment named.",'It also reports connectionRequired, which is the only place the CLI can tell you whether a listener type needs a connector at all \u2014 app list does not mark which do. It reads as "a connector must be attached", never as "a connector may not be": a false there makes one optional, and such a listener still accepts a connectorId on create and update and reports it afterwards.',"In a non-HEAD environment the read reports what that release captured and nothing else: the script and the event type are absent when the release captured none, rather than borrowing the workspace's current ones. So what get shows there is safe to send straight back to update.","An absent script means the listener has nothing to run, in either kind of environment: it was never given one, or the one it had was deleted with script delete --force. The read never names a script that is gone, so what it reports is what the listener would run."]}),DELETE_DOC6=defineCommandDoc("event-listener delete",{rules:["The event listener is the positional argument; the workspace is -w and the environment -e, which gates the write rather than choosing what is deleted.","--yes skips the confirmation, and is required without a terminal."],notes:["Deletes the listener from the whole workspace. The script it triggered is left in place, as are its test payloads' only reason to exist."]}),CREATE_DOC6=defineCommandDoc("event-listener create",{schema:createBodySchema6,conditional:["scriptId","scriptName"],body:{appId:"<appId>",eventListenerTypeId:"<eventListenerTypeId>",eventTypeId:"<eventTypeId>",scriptId:"<scriptId>",scriptName:"OnIssueCreated",connectorId:"<connectorId>",urlPath:"jira-issues",disabled:!1,eventQueueId:"<eventQueueId>",eventQueueGroupings:["issue.key"]},rules:[`appId, eventListenerTypeId (spelled --listener-type-id as a flag) and eventTypeId come from ${CLI} app list: the listener type must be one of the app's and the event type one of the listener type's.`,`Exactly one of scriptId or scriptName is required. ${SCRIPT_KEYS_RULE}`,CONNECTOR_RULE,`urlPath: the path an HTTP_ENDPOINT listener answers on: ${URL_PATH_FORMAT}; omitted, the API generates one, and every other listener type gets a generated one whatever is sent. The full address comes back as webhookUrl.`,"disabled: true creates the listener disabled in the environment -e names; omitted means enabled.","eventQueueId: an event queue of the workspace; the team's plan must include event queues, which team get reports as features.eventQueues.",`eventQueueGroupings: up to ${MAX_QUEUE_GROUPINGS} field paths into the event, spelled --event-queue-grouping as a repeatable flag; events sharing the values at those paths are handed to the script in arrival order. Ignored without eventQueueId: the API answers 201 and the listener comes back with no grouping at all.`,"A new listener arrives with a seeded Default test payload, sampling the event type it was created for.","Refused in a non-HEAD environment: create in a HEAD one."],notes:[SCRIPT_NAME_BUNDLE_REPORT]}),UPDATE_DOC6=defineCommandDoc("event-listener update",{schema:updateBodySchema6,body:{eventTypeId:"<eventTypeId>",scriptId:"<scriptId>",scriptName:"OnIssueCreated",connectorId:"<connectorId>",urlPath:"jira-issues",disabled:!1,eventQueueId:"<eventQueueId>",eventQueueGroupings:["issue.key"]},rules:["An omitted key keeps the current value.",'eventTypeId moves the listener to a different event type; omitted, the current one is kept. Only a listener that has never been configured with one requires it, and a body naming neither it nor a current value is refused with 400 "Event type is required." there.',`${SCRIPT_KEYS_RULE} The two cannot be combined, and omitting both keeps the script the listener already triggers. In a non-HEAD environment the script cannot change at all, so a scriptId sent there must be the one that environment reports.`,CONNECTOR_RULE,`urlPath moves the endpoint an HTTP_ENDPOINT listener answers on, and whatever was registered with the old path stops arriving: ${URL_PATH_FORMAT}. Omitted, the path is kept where the environment has one of its own, and a non-HEAD environment that has never had one gets a generated path from the first update that touches the listener, as the notes below set out. On every other listener type it is ignored: the listener keeps the path it has.`,"disabled: true stops the listener in the environment named by -e, false starts it there (--disabled and --enabled as flags), omitted keeps the current state.","eventQueueId: an ID attaches that queue, null detaches the listener and drops the grouping with it (--no-event-queue as a flag), omitted keeps the queue as it is; attaching needs the team's plan to include event queues.",`eventQueueGroupings applies to the queue the listener is on, up to ${MAX_QUEUE_GROUPINGS} paths, spelled --event-queue-grouping as a repeatable flag; [] clears the grouping and leaves the listener queued (--no-event-queue-grouping as a flag), and on a listener with no queue it is ignored the way it is on create.`,"In a non-HEAD environment only connectorId, urlPath and disabled can change. eventTypeId, scriptId, eventQueueId and eventQueueGroupings are read-only rather than refused there: omit them, or echo back what that environment's own get reports, and only a differing value is a 400 naming it. Omitting eventTypeId is the only way to write that environment's own fields when its release captured the listener before an event type was chosen, there being nothing to echo. scriptName is refused whenever it is sent, creating a script being a shared change by definition.","Changing eventTypeId leaves the existing test payloads sampling the old event; --replace-test-payloads, a flag rather than a key, replaces them."],notes:["A body with no keys at all is accepted, and unlike every other update verb this one sends it: nothing changes, and the update still touches the listener, which is what makes an environment with no URL path of its own generate one. A run passing no flags does the same, there being no other way to reach that state on a listener with no connector to re-attach.","The URL path is per environment, and an environment that has never had one of its own gets a generated path from the first update that touches the listener there \u2014 --disabled alone and an empty body included. Its webhookUrl then differs from HEAD's, and get through that environment reports no urlPath until that has happened.","--replace-test-payloads deletes the payloads that still sample the old event and seeds one from the new type; a run that passes neither it nor --no-replace-test-payloads gets a warning. An update not carrying eventTypeId cannot have moved the type, so it costs nothing; one that does could be echoing the current value, so the listener is read first to tell a move from an echo \u2014 a read --no-replace-test-payloads skips, neither outcome being possible there. In a local copy the payload files follow.",SCRIPT_NAME_BUNDLE_REPORT]});async function askUrlPath(ask){if(ask.provided!==void 0)return ask.provided;if(!ask.interactive||ask.listenerType!==HTTP_ENDPOINT)return;let typed=(await prompts().text("URL path (must be unique; edit or keep the suggestion)",{initial:ask.current??ulid(),allowEmpty:!0})).trim()||void 0;return typed===ask.current?void 0:typed}async function listenerTypeName(client,appId,listenerTypeId,known){return known||(!appId||!listenerTypeId?void 0:(await resolverChoices(client,"listenerType",{app:appId})).find(choice=>choice.value===listenerTypeId)?.label)}function suggestScriptName(eventTypeName){let pascal=(eventTypeName??"").split(/[^A-Za-z0-9]+/).filter(Boolean).map(word=>word.charAt(0).toUpperCase()+word.slice(1)).join("");return pascal?`On${pascal}`.slice(0,MAX_SCRIPT_NAME):void 0}async function askQueueGroupings(current){let paths=[];for(let existing of current??[]){if(!await prompts().confirm(`Change field path "${existing}"?`,!1)){paths.push(existing);continue}let answer=(await prompts().text(`Field path (empty to remove "${existing}")`,{allowEmpty:!0,initial:existing})).trim();answer&&paths.push(answer)}for(;;){if(paths.length>=MAX_QUEUE_GROUPINGS){prompts().note(`\u2714 ${MAX_QUEUE_GROUPINGS} field paths \u2014 that is the maximum.`);break}let opening=paths.length===0&&!current?.length;if(!opening&&!await prompts().confirm("Add another field path?",!1))break;let answer=(await prompts().text(opening?"Field path to group events by (empty for no grouping)":"Field path",{allowEmpty:!0})).trim();if(!answer){opening||prompts().note("\u2716 A field path cannot be empty \u2014 skipping it.");break}paths.push(answer)}return paths}async function askGroupingChoice(current){return await prompts().confirm(`Group queued events by a field? (events sharing a value are processed in order, max ${MAX_QUEUE_GROUPINGS} paths)`,!1)?askQueueGroupings(current):current?.length?[]:void 0}async function askQueueAttachment(scope2,current){let eventQueueId;try{eventQueueId=(await resolveParams(["eventQueue"],{workspace:scope2.workspace,environment:scope2.environment},{client:scope2.client,interactive:!0})).eventQueue}catch(err){if(!(err instanceof CliError)||err.code!=="NO_RESULTS")throw err;return prompts().note(`\u26A0 No event queues in this environment \u2014 continuing unqueued. Create one with '${CLI} event-queue create'.`),{}}return stripUndefined({eventQueueId,eventQueueGroupings:await askGroupingChoice(current?.groupings)})}function queueCell(listener){if(!listener.eventQueueId)return"\u2014";let name=listener.eventQueueName??listener.eventQueueId,groupings=listener.eventQueueGroupings;return groupings?.length?`${name} \xB7 ${groupings.join(", ")}`:name}function connectorCell2(id,name){return id?name&&name!==id?`${name} (${id})`:id:name??"\u2014"}async function askQueueOnUpdate(scope2,globals,current){let teamId=await teamForQuestions(scope2,globals);if(!teamId)return{};if(!(await withSpinner("Checking plan features",()=>teamFeatures(scope2.client,teamId))).eventQueues)return{};if(!current.eventQueueId)return await prompts().select("Event queue: not queued",[{value:"keep",label:"Leave it unqueued (current)"},{value:"attach",label:"Queue incoming events",hint:"events are held in an event queue and processed one at a time"}],{initial:"keep"})==="attach"?askQueueAttachment(scope2):{};let grouped2=current.eventQueueGroupings?.length?` \u2014 grouped by ${current.eventQueueGroupings.join(", ")}`:"",answer=await prompts().select(`Event queue: ${current.eventQueueName??current.eventQueueId}${grouped2}`,[{value:"keep",label:"Keep it as it is"},{value:"move",label:"Use a different event queue"},{value:"regroup",label:"Change what the events are grouped by"},{value:"detach",label:"Detach",hint:"deliver events straight to the script"}],{initial:"keep"});return answer==="keep"?{}:answer==="move"?askQueueAttachment(scope2,{groupings:current.eventQueueGroupings}):answer==="detach"?{eventQueueId:null}:{eventQueueGroupings:await askQueueGroupings(current.eventQueueGroupings)}}async function askQueueOnCreate(scope2,globals,opts){if(opts.eventQueueId)return stripUndefined({eventQueueId:opts.eventQueueId,eventQueueGroupings:opts.eventQueueGrouping});let teamId=await teamForQuestions(scope2,globals);return teamId?(await withSpinner("Checking plan features",()=>teamFeatures(scope2.client,teamId))).eventQueues?await prompts().confirm("Queue incoming events? (events are held in an event queue and processed one at a time)",!1)?askQueueAttachment(scope2):{}:{}:{}}var CREATE_SCRIPT="\0create-script",ENVIRONMENT_OWNED="the connector, the URL path and the enabled state";function releasedNote2(version2,environmentName){return[`${environmentName} has ${version2?`release ${version2}`:"a release"} deployed.`,`Only ${ENVIRONMENT_OWNED} can be changed there; the event type, the script and the`,"event queue belong to the event listener and are shared by every environment."].join(" ")}async function askConnectorOnUpdate(scope2,globals,current){let team=await teamForQuestions(scope2,globals);if(!team)return;let choices;try{choices=await resolverChoices(scope2.client,"connector",{team,app:current.appId,listenerType:current.listenerTypeId,workspace:scope2.workspace,environment:scope2.environment})}catch(err){if(!(err instanceof CliError))throw err;return}if(choices.length===0)return;let currentId=current.connectorId,listed=currentId?choices.some(choice=>choice.value===currentId):!1,me2=current.connectorOwner?await currentUserId(scope2.client):void 0,someoneElse=!current.connectorOwner||!me2||current.connectorOwner.id!==me2,implicit=!!currentId&&!listed&&someoneElse,KEEP="\0keep-connector",keepLabel=current.connectionName??currentId,offered=listed?choices.map(choice=>choice.value===currentId?{...choice,display:`${choice.display??choice.label} (current)`}:choice):[currentId&&keepLabel?{value:KEEP,label:keepLabel,display:`${keepLabel} (${implicit?implicitShareMark(current.connectorOwner):"current"})`}:{value:KEEP,label:"No connector",display:"No connector (current)"},...choices],initial=listed?currentId:KEEP;for(;;){let picked=await prompts().select("Connector:",offered,initial?{initial}:{});if(picked===KEEP||listed&&picked===currentId)return;if(!implicit)return picked;let replacement=choices.find(choice=>choice.value===picked)?.label??picked;if(await confirmImplicitReplacement(keepLabel??"",replacement,current.connectorOwner))return picked}}async function askScriptOnUpdate(scope2,current,suggestedName){let picked=await askKeepOrChange({client:scope2.client,key:"script",deps:{workspace:scope2.workspace,environment:scope2.environment},message:"Script:",current:{value:current.id,label:current.name},extra:[{value:CREATE_SCRIPT,label:"Create a new script\u2026"}]});return picked===CREATE_SCRIPT?{scriptName:await askScriptName(suggestedName)}:picked===void 0?{}:{scriptId:picked}}var NO_CONNECTOR2="\0no-connector";async function askConnectorOnCreate2(scope2,globals,current){let team=await teamForQuestions(scope2,globals);if(!team)return;let choices;try{choices=await resolverChoices(scope2.client,"connector",{team,app:current.appId,listenerType:current.listenerTypeId,workspace:scope2.workspace,environment:scope2.environment})}catch(err){if(!(err instanceof CliError))throw err;return}if(choices.length===0){prompts().note("\u26A0 No connector compatible with the selected app exists in the team \u2014 continuing without one.");return}let picked=await prompts().select("Connector:",[{value:NO_CONNECTOR2,label:"No connector",hint:"required by some listener types; attach one later"},...choices],{initial:choices[0]?.value??NO_CONNECTOR2});return picked===NO_CONNECTOR2?void 0:picked}var RECOMMEND_CREATE="recommended \u2014 the entry function is generated for the event type";async function fillCreateBody2(scope2,globals,opts){let labels={},resolved=await resolveParams(["app","listenerType","eventType"],{app:opts.appId,listenerType:opts.listenerTypeId,eventType:opts.eventTypeId,workspace:scope2.workspace,environment:scope2.environment,team:globals.team},{client:scope2.client,interactive:!0,labels,registry:listenerAppRegistry()}),script=opts.scriptId??opts.scriptName?{scriptId:opts.scriptId,scriptName:opts.scriptName}:await askScript({client:scope2.client,workspace:scope2.workspace,environment:scope2.environment,message:"Script to handle the event:",suggestedName:suggestScriptName(labels.eventType),recommendCreate:RECOMMEND_CREATE}),urlPath=await askUrlPath({provided:opts.urlPath,listenerType:opts.urlPath===void 0?await listenerTypeName(scope2.client,resolved.app,resolved.listenerType,labels.listenerType):void 0,interactive:!0}),connectorId=opts.connectorId??await askConnectorOnCreate2(scope2,globals,{appId:resolved.app??"",listenerTypeId:resolved.listenerType??""}),queue=await askQueueOnCreate(scope2,globals,opts);return stripUndefined({appId:resolved.app,eventListenerTypeId:resolved.listenerType,eventTypeId:resolved.eventType,scriptId:script.scriptId,scriptName:script.scriptName,connectorId,urlPath,disabled:opts.disabled,...queue})}var DEFAULT_PAYLOAD_NAME="Default",PAYLOAD_CONCURRENCY=5;function plural3(count,noun){return`${count} ${noun}${count===1?"":"s"}`}function eventTypeMoved(plan){return plan.eventTypeChanged??!1}async function refreshTestPayloads(scope2,eventListenerId){let path2={workspaceId:scope2.workspace,environmentId:scope2.environment,eventListenerId},list=await withSpinner("Fetching test payloads",()=>scope2.client.GET("/v1/workspace/{workspaceId}/environment/{environmentId}/eventListener/{eventListenerId}/testPayloads",{params:{path:path2}}));(!list.response.ok||!list.data)&&apiFail(list.response.status,list.error);let existing=list.data.testPayloads;if(existing.length===0)return{deleted:[]};let taken=new Set(existing.map(payload=>payload.name)),name=DEFAULT_PAYLOAD_NAME;for(let n=2;taken.has(name);n+=1)name=`${DEFAULT_PAYLOAD_NAME} ${n}`;let created=await withSpinner("Creating test payload for the new event type",()=>scope2.client.POST("/v1/workspace/{workspaceId}/environment/{environmentId}/eventListener/{eventListenerId}/testPayload",{params:{path:path2},body:{name}}));(!created.response.ok||!created.data)&&apiFail(created.response.status,created.error),await withSpinner(`Deleting ${plural3(existing.length,"old test payload")}`,()=>throttleAll(PAYLOAD_CONCURRENCY,existing.map(payload=>async()=>{let{response,error:error51}=await scope2.client.DELETE("/v1/workspace/{workspaceId}/environment/{environmentId}/eventListener/{eventListenerId}/testPayload/{testPayloadId}",{params:{path:{...path2,testPayloadId:payload.id}}});response.ok||apiFail(response.status,error51)})));let final=created.data;if(final.name!==DEFAULT_PAYLOAD_NAME){let renamed=await withSpinner("Renaming the new test payload",()=>scope2.client.PUT("/v1/workspace/{workspaceId}/environment/{environmentId}/eventListener/{eventListenerId}/testPayload/{testPayloadId}",{params:{path:{...path2,testPayloadId:created.data.id}},body:{name:DEFAULT_PAYLOAD_NAME}}));renamed.response.ok&&renamed.data&&(final=renamed.data)}return{created:final,deleted:existing}}async function buildUpdateBody3(scope2,globals,eventListenerId,opts,plan={}){let interactive=!opts.input&&canPrompt();opts.eventQueue===!1&&opts.eventQueueId&&fail(EXIT.USAGE,"USAGE_ERROR","--no-event-queue cannot be combined with --event-queue-id.");let listenerType,currentUrlPath,currentQueue={},eventTypeId=opts.eventTypeId,scriptId=opts.scriptId,scriptName=opts.scriptName,connectorId=opts.connectorId,disabled=disabledFromFlags(opts),queue={},releasedEnvironment=!1;if(interactive){let current=await withSpinner("Fetching event listener",()=>scope2.client.GET("/v1/workspace/{workspaceId}/environment/{environmentId}/eventListener/{eventListenerId}",{params:{path:{workspaceId:scope2.workspace,environmentId:scope2.environment,eventListenerId}}}));(!current.response.ok||!current.data)&&apiFail(current.response.status,current.error),listenerType=current.data.eventListenerType.name,currentUrlPath=current.data.urlPath,currentQueue={eventQueueId:current.data.eventQueueId,eventQueueName:current.data.eventQueueName,eventQueueGroupings:current.data.eventQueueGroupings};let release2=await withSpinner("Checking the environment",()=>environmentRelease(scope2.client,scope2.workspace,scope2.environment));if(releasedEnvironment=!!release2,release2?prompts().note(`\u26A0 ${releasedNote2(release2.version,"This environment")}`):eventTypeId||(eventTypeId=await askKeepOrChange({client:scope2.client,key:"eventType",deps:{app:current.data.app.id,listenerType:current.data.eventListenerType.id},message:"Event type:",current:{value:current.data.eventType?.id,label:current.data.eventType?.name}})),plan.eventTypeChanged=eventTypeId!==void 0&&eventTypeId!==current.data.eventType?.id,plan.eventTypeChanged&&(plan.replace=opts.replaceTestPayloads??await prompts().confirm("The event type changed. Replace the test payloads with a fresh sample of the new event? Existing payloads are deleted, edits included.",!1)),!release2&&!scriptId&&!scriptName){let picked=await askScriptOnUpdate(scope2,{id:current.data.script?.id,name:current.data.script?.name},suggestScriptName(current.data.eventType?.name));scriptId=picked.scriptId,scriptName=picked.scriptName}connectorId??=await askConnectorOnUpdate(scope2,globals,{connectorId:current.data.connectorId,connectionName:current.data.connectionName,connectorOwner:current.data.connectorOwner,appId:current.data.app.id,listenerTypeId:current.data.eventListenerType.id}),disabled??=await askStatus(current.data.disabled,"the event listener")}let urlPath=await askUrlPath({provided:opts.urlPath,listenerType,current:currentUrlPath,interactive}),groupingFlag=opts.eventQueueGrouping===!1?[]:opts.eventQueueGrouping??void 0;return opts.eventQueue===!1?queue={eventQueueId:null}:opts.eventQueueId||groupingFlag?queue=stripUndefined({eventQueueId:opts.eventQueueId,eventQueueGroupings:groupingFlag}):interactive&&!releasedEnvironment&&(queue=await askQueueOnUpdate(scope2,globals,currentQueue)),opts.input?readInput(opts.input):{...stripUndefined({eventTypeId,connectorId,scriptId,scriptName,urlPath,disabled}),...queue}}async function recordEventTypeMove(scope2,eventListenerId,body,opts,plan){if(plan.eventTypeChanged!==void 0||opts.replaceTestPayloads===!1||body.eventTypeId===void 0)return;let current=await withSpinner("Fetching event listener",()=>scope2.client.GET("/v1/workspace/{workspaceId}/environment/{environmentId}/eventListener/{eventListenerId}",{params:{path:{workspaceId:scope2.workspace,environmentId:scope2.environment,eventListenerId}}}));current.response.ok&¤t.data&&(plan.eventTypeChanged=body.eventTypeId!==current.data.eventType?.id)}function eventListenerCommand(){let el=new Command("event-listener").alias("el").description("Manage workspace event listeners");return withScope3(el.command("list").description("List event listeners in a workspace")).option("--explain",EXPLAIN).action(async(_opts,cmd)=>{if(explained(cmd,LIST_DOC7))return;let globals=cmd.optsWithGlobals(),scope2=await resolveScope5(globals),{data,response,error:error51}=await withSpinner("Fetching event listeners",()=>scope2.client.GET("/v1/workspace/{workspaceId}/environment/{environmentId}/eventListeners",{params:{path:{workspaceId:scope2.workspace,environmentId:scope2.environment}}}));(!response.ok||!data)&&apiFail(response.status,error51),ok(data,{human:d=>({eventListeners:tableRows(["id","app","eventListenerType","disabled","script","eventType","connector","urlPath","queue"],d.eventListeners.map(listener=>({...listener,connector:listener.connectionName??"\u2014",urlPath:listener.urlPath??"\u2014",queue:queueCell(listener)})))})})}),withScope3(el.command("get").description("Get a single event listener as the environment sees it").argument("[eventListenerId]","Event listener ID (required, interactive)")).option("--explain",EXPLAIN).action(async(idArg,_opts,cmd)=>{if(explained(cmd,GET_DOC6))return;let globals=cmd.optsWithGlobals(),scope2=await resolveScope5(globals),eventListenerId=await resolveListenerId(scope2,idArg),{data,response,error:error51}=await withSpinner("Fetching event listener",()=>scope2.client.GET("/v1/workspace/{workspaceId}/environment/{environmentId}/eventListener/{eventListenerId}",{params:{path:{workspaceId:scope2.workspace,environmentId:scope2.environment,eventListenerId}}}));(!response.ok||!data)&&apiFail(response.status,error51),ok(data,{human:({eventQueueId:_id,eventQueueName:_name,eventQueueGroupings:_g,connectorId,connectionName,connectorOwner,...rest})=>({...rest,...connectorId||connectionName?{connector:connectorCell2(connectorId,connectionName)}:{},...connectorOwner?{connectorOwner:personCell(connectorOwner)}:{},queue:queueCell(data)})})}),withScope3(el.command("create").description("Create an event listener in a workspace")).option("--app-id <id>",`App ID, see ${CLI} app list (required unless --input, interactive)`).option("--listener-type-id <id>","Event listener type ID for the app (required unless --input, interactive)").option("--event-type-id <id>","Event type ID for the listener type (required unless --input, interactive)").option("--script-id <id>","Existing script ID to attach (required unless --script-name or --input, interactive, exclusive with --script-name)").option("--script-name <name>","Script name to create and attach (required unless --script-id or --input, interactive, exclusive with --script-id)").option("--connector-id <id>","Connector ID, required by some listener types, which app list does not mark (optional, interactive)").option("--url-path <path>","Custom URL path an HTTP_ENDPOINT listener answers on (optional, interactive for HTTP_ENDPOINT only, API default: a generated path, ignored on every other listener type)").option("--disabled","Create the listener disabled (optional, API default: enabled)").option("--event-queue-id <id>","Event queue ID to attach (optional, interactive on a plan with event queues)").option("--event-queue-grouping <fieldPath>",`Event queue grouping field path, max ${MAX_QUEUE_GROUPINGS}; repeat the flag or comma-separate (optional, interactive, repeatable, ignored without --event-queue-id)`,collect).option("--input <file>",INPUT_BODY).option("--explain",EXPLAIN).action(async(opts,cmd)=>{if(explained(cmd,CREATE_DOC6))return;let globals=cmd.optsWithGlobals(),scope2=await resolveScope5(globals),interactive=!opts.input&&canPrompt(),hasAllRequired=opts.appId&&opts.listenerTypeId&&opts.eventTypeId&&(opts.scriptId??opts.scriptName),rawBody;if(opts.input)rawBody=readInput(opts.input);else if(interactive&&!hasAllRequired)rawBody=await fillCreateBody2(scope2,globals,opts);else{let urlPath=await askUrlPath({provided:opts.urlPath,listenerType:interactive&&opts.urlPath===void 0?await listenerTypeName(scope2.client,opts.appId,opts.listenerTypeId):void 0,interactive});rawBody=stripUndefined({appId:opts.appId,eventListenerTypeId:opts.listenerTypeId,eventTypeId:opts.eventTypeId,scriptId:opts.scriptId,scriptName:opts.scriptName,connectorId:opts.connectorId,urlPath,disabled:opts.disabled,eventQueueId:opts.eventQueueId,eventQueueGroupings:opts.eventQueueGrouping})}let parsed=validate(createBodySchema6,rawBody),body={...parsed,...parsed.scriptName===void 0?{}:{scriptName:assertScriptName(parsed.scriptName)},...parsed.urlPath===void 0?{}:{urlPath:assertUrlPath(parsed.urlPath)}},{data,response,error:error51}=await withSpinner("Creating event listener",()=>scope2.client.POST("/v1/workspace/{workspaceId}/environment/{environmentId}/eventListener",{params:{path:{workspaceId:scope2.workspace,environmentId:scope2.environment}},body}));(!response.ok||!data)&&apiFail(response.status,error51),await syncNewEventListener(scope2.client,{workspaceId:scope2.workspace,environmentId:scope2.environment},data.eventListenerId),await syncPackages(scope2.client,scope2.workspace),body.scriptName!==void 0&&await syncScriptFromServer(scope2.client,{workspaceId:scope2.workspace,environmentId:scope2.environment},data.scriptId),okMutation("Event listener created",data,bundleReportDetail(data,data))}),withScope3(el.command("update").description("Update an event listener").argument("[eventListenerId]","Event listener ID (required, interactive)")).option("--event-type-id <id>","Event type ID for the listener type (optional, interactive on HEAD only, default: the current event type, refused when it differs from what a non-HEAD environment reports)").option("--connector-id <id>","Connector ID, required by some listener types, which app list does not mark (optional, interactive)").option("--script-id <id>","Existing script ID to attach (optional, interactive on HEAD only, exclusive with --script-name, refused when it differs from what a non-HEAD environment reports)").option("--script-name <name>","Script name to create and attach (optional, interactive on HEAD only, exclusive with --script-id, refused in a non-HEAD environment)").option("--url-path <path>","Custom URL path an HTTP_ENDPOINT listener answers on (optional, interactive for HTTP_ENDPOINT only, default: the current path, ignored on every other listener type)").option("--disabled","Disable the listener (optional, interactive, exclusive with --enabled)").option("--enabled","Enable the listener (optional, interactive, exclusive with --disabled)").option("--event-queue-id <id>","Event queue ID to attach; omitting it keeps the current queue (optional, interactive on HEAD only, exclusive with --no-event-queue, refused when it differs from what a non-HEAD environment reports)").option("--no-event-queue","Detach the event queue so events go straight to the script, also dropping the grouping (optional, interactive on HEAD only, exclusive with --event-queue-id, refused when it differs from what a non-HEAD environment reports)").option("--event-queue-grouping <fieldPath>",`Event queue grouping field path, max ${MAX_QUEUE_GROUPINGS}; repeat the flag or comma-separate, applies to the queue the listener is on (optional, interactive on HEAD only, repeatable, refused when it differs from what a non-HEAD environment reports)`,collect).option("--no-event-queue-grouping","Clear the grouping, leaving the listener queued (optional, interactive on HEAD only, refused when it differs from what a non-HEAD environment reports)").option("--replace-test-payloads","When the event type changes, delete the existing test payloads and create one seeded from the new event (optional, interactive, exclusive with --no-replace-test-payloads, ignored when the event type does not change)").option("--no-replace-test-payloads","Keep the existing test payloads even though they sample the old event (optional, interactive, exclusive with --replace-test-payloads, ignored when the event type does not change)").option("--input <file>",INPUT_BODY).option("--explain",EXPLAIN).action(async(idArg,opts,cmd)=>{if(explained(cmd,UPDATE_DOC6))return;let globals=cmd.optsWithGlobals(),scope2=await resolveScope5(globals),eventListenerId=await resolveListenerId(scope2,idArg),payloads={},rawBody=await buildUpdateBody3(scope2,globals,eventListenerId,opts,payloads),parsed=validate(updateBodySchema6,rawBody);Object.keys(parsed).length===0&¬eLine("\u2139 No fields to change \u2014 sending an empty update, which is what makes an environment with no URL path of its own generate one.");let body={...parsed,...parsed.scriptName===void 0?{}:{scriptName:assertScriptName(parsed.scriptName)},...parsed.urlPath===void 0?{}:{urlPath:assertUrlPath(parsed.urlPath)}};await recordEventTypeMove(scope2,eventListenerId,body,opts,payloads);let{data,response,error:error51}=await withSpinner("Updating event listener",()=>scope2.client.PUT("/v1/workspace/{workspaceId}/environment/{environmentId}/eventListener/{eventListenerId}",{params:{path:{workspaceId:scope2.workspace,environmentId:scope2.environment,eventListenerId}},body}));(!response.ok||!data)&&apiFail(response.status,error51),await syncEventListenerFolder(scope2.client,{workspaceId:scope2.workspace,environmentId:scope2.environment},eventListenerId,"rename"),await syncPackages(scope2.client,scope2.workspace),body.scriptName!==void 0&&data.scriptId!==void 0&&await syncScriptFromServer(scope2.client,{workspaceId:scope2.workspace,environmentId:scope2.environment},data.scriptId);let syncScope={workspaceId:scope2.workspace,environmentId:scope2.environment},typeChanged=eventTypeMoved(payloads);if(payloads.replace??(typeChanged&&opts.replaceTestPayloads)){let refreshed2=await refreshTestPayloads(scope2,eventListenerId);for(let gone of refreshed2.deleted)await syncTestPayloadDeleted(scope2.client,syncScope,eventListenerId,{id:gone.id});refreshed2.created&&await syncTestPayloadById(scope2.client,syncScope,eventListenerId,refreshed2.created.id)}else if(typeChanged&&opts.replaceTestPayloads!==!1){let movedTo=body.eventTypeId??"<eventTypeId>";warnLine(`\u26A0 The event listener's test payloads still sample the previous event type. Replace them with \`${CLI} event-listener update ${eventListenerId} --event-type-id ${movedTo} --replace-test-payloads\`.`)}okMutation("Event listener updated",{updated:!0,id:eventListenerId,...data},bundleReportDetail({id:eventListenerId,...data},data))}),withScope3(el.command("delete").description("Delete an event listener from a workspace").argument("[eventListenerId]","Event listener ID (required, interactive)"),{destructive:!0,gate:!0}).option("--yes",CONFIRM_YES).option("--explain",EXPLAIN).action(async(idArg,opts,cmd)=>{if(explained(cmd,DELETE_DOC6))return;let globals=cmd.optsWithGlobals(),scope2=await resolveScope5(globals,{useSession:canPrompt()}),eventListenerId=await resolveListenerId(scope2,idArg);opts.yes||(canPrompt()||failNeedsYes(`event listener ${eventListenerId}`),await prompts().confirm(`Delete event listener ${eventListenerId}? This is irreversible.`)||fail(EXIT.CANCELLED,"CANCELLED","Deletion cancelled."));let{response,error:error51}=await withSpinner("Deleting event listener",()=>scope2.client.DELETE("/v1/workspace/{workspaceId}/environment/{environmentId}/eventListener/{eventListenerId}",{params:{path:{workspaceId:scope2.workspace,environmentId:scope2.environment,eventListenerId}}}));response.ok||apiFail(response.status,error51),await syncEventListenerFolder(scope2.client,{workspaceId:scope2.workspace,environmentId:scope2.environment},eventListenerId,"delete"),await syncPackages(scope2.client,scope2.workspace),okMutation("Event listener deleted",{deleted:!0,id:eventListenerId})}),el}import{basename as basename4,extname as extname2}from"path";var TEST_PAYLOAD_NAME_FORMAT="up to 50 characters",MAX_TEST_PAYLOAD_NAME=50;function normalizeTestPayloadName(name){return name.trim()}function testPayloadNameError(name){let normalized=normalizeTestPayloadName(name);if(!normalized)return"A test payload name is required.";if(normalized.length>MAX_TEST_PAYLOAD_NAME)return`A test payload name can be at most ${MAX_TEST_PAYLOAD_NAME} characters (that one is ${normalized.length}).`}function assertTestPayloadName(name){let error51=testPayloadNameError(name);return error51&&fail(EXIT.USAGE,"INVALID_TEST_PAYLOAD_NAME",error51),normalizeTestPayloadName(name)}function suggestPayloadNameFromPath(path2){let cleaned=normalizeTestPayloadName(basename4(path2,extname2(path2)));return testPayloadNameError(cleaned)?void 0:cleaned}var PAYLOAD_KIND2={noun:"Test payload",tooLargeCode:"TEST_PAYLOAD_TOO_LARGE",language:"json"},NAME_PROMPT2=`Test payload name (${TEST_PAYLOAD_NAME_FORMAT})`,SOURCE_PROMPT="How do you want to provide the payload content?",SEED_CHOICE={label:"Edit the sample event here",hint:"recommended \u2014 seeded from the event type, opens in the editor"};function withScope4(cmd,opts={}){return cmd.option("-w, --workspace <workspaceId>",opts.destructive?SCOPE_WORKSPACE_DESTRUCTIVE:SCOPE_WORKSPACE).option("-e, --env <environmentId>",opts.destructive?SCOPE_ENVIRONMENT_DESTRUCTIVE:SCOPE_ENVIRONMENT).option("--team <teamId>",opts.destructive?SCOPE_TEAM_FILTER_DESTRUCTIVE:SCOPE_TEAM_FILTER).option("--event-listener-id <eventListenerId>","Event listener ID (required, interactive)")}async function resolveScope6(globals,opts,extra={}){let client=await apiClient(globals.instance),resolved=await resolveParams(["workspace","environment"],{team:opts.team??globals.team,workspace:opts.workspace??globals.workspace,environment:opts.env??globals.env},{client,interactive:canPrompt(),useSession:extra.useSession});return{client,workspace:resolved.workspace??"",environment:resolved.environment??""}}async function resolveListener(scope2,provided){return provided?assertResourceId(provided,"eventListenerId"):(canPrompt()||fail(EXIT.USAGE,"USAGE_ERROR","--event-listener-id is required."),(await resolveParams(["eventListener"],{workspace:scope2.workspace,environment:scope2.environment},{client:scope2.client,interactive:!0})).eventListener??"")}async function resolvePayload(scope2,eventListenerId,provided){if(provided)return{id:assertResourceId(provided,"testPayloadId")};canPrompt()||fail(EXIT.USAGE,"USAGE_ERROR",`<testPayloadId> is required. ${supplyHint()}`);let labels={};return{id:(await resolveParams(["testPayload"],{workspace:scope2.workspace,environment:scope2.environment,eventListener:eventListenerId},{client:scope2.client,interactive:!0,labels})).testPayload??"",label:labels.testPayload}}var createBodySchema7=external_exports.object({name:external_exports.string().min(1),content:external_exports.string().optional(),default:external_exports.boolean().optional()}).strict(),updateBodySchema7=external_exports.object({content:external_exports.string().optional(),name:external_exports.string().min(1).optional()}).strict().refine(body=>body.content!==void 0||body.name!==void 0,{error:"Either content or name is required.",path:["name"]}),CONTENT_CAP2=`${MAX_CONTENT_BYTES/1024/1024} MiB`,LIST_DOC8=defineCommandDoc("event-listener-test-payload list",{rules:["The listener is --event-listener-id; the workspace is -w and the environment -e. There is no positional argument."],notes:["A listener's payloads are the same in every environment. Which one is the default is user-specific and environment-specific, so the default column is yours and not a colleague's."]}),GET_DOC7=defineCommandDoc("event-listener-test-payload get",{rules:["The payload is the positional argument and the listener is --event-listener-id; the workspace is -w and the environment -e.","--content-only prints the stored bytes alone, identically with or without --raw, so `\u2026 --content-only > payload.json` writes the file."],notes:["The content is stored verbatim and never parsed, so a payload saved as something other than a JSON object reads back unchanged and only fails when a trigger runs it."]}),SET_DEFAULT_DOC=defineCommandDoc("event-listener-test-payload set-default",{rules:["The payload is the positional argument and the listener is --event-listener-id; the workspace is -w and the environment -e, which is the environment the choice is made in."],notes:["User-specific and environment-specific: a colleague's manual trigger still runs whatever they picked."]}),DELETE_DOC7=defineCommandDoc("event-listener-test-payload delete",{rules:["The payload is the positional argument and the listener is --event-listener-id; the workspace is -w and the environment -e.","--yes skips the confirmation, and is required without a terminal."],notes:["The last remaining payload of a listener cannot be deleted.","Anyone who had chosen this one falls back to the payload named Default."]}),CREATE_DOC7=defineCommandDoc("event-listener-test-payload create",{schema:createBodySchema7,body:{name:"Issue created",content:'{ "issue": { "key": "TEST-1" } }',default:!0},rules:[`name: ${TEST_PAYLOAD_NAME_FORMAT}, trimmed, no charset rule, unique within the listener.`,`content: the event as text, spelled --content or --file <path> as a flag, up to ${CONTENT_CAP2}, stored verbatim and never parsed; omitted, the API seeds the payload with the sample event for the listener's event type; "" is refused.`,"default: true also makes it the payload a manual trigger runs, for your user in the environment -e names.","The listener is --event-listener-id, not a body key; a listener's payloads are shared by every environment of the workspace."]}),UPDATE_DOC7=defineCommandDoc("event-listener-test-payload update",{schema:updateBodySchema7,body:{name:"Issue created",content:'{ "issue": { "key": "TEST-1" } }'},rules:["At least one of content or name is required; an omitted key keeps the current value, and a rename travels without content.",`name: ${TEST_PAYLOAD_NAME_FORMAT}, trimmed, unique within the listener.`,`content: the whole new event as text, spelled --content or --file <path> as a flag, up to ${CONTENT_CAP2}, stored verbatim; "" is refused.`,"The listener is --event-listener-id and the payload the positional argument; neither is a body key."]});async function askPayloadName(suggested){for(;;){let answer=await prompts().text(NAME_PROMPT2,{...suggested?{initial:suggested}:{},allowEmpty:!0}),error51=testPayloadNameError(answer);if(!error51)return normalizeTestPayloadName(answer);prompts().note(`\u2716 ${error51}`)}}function askPayloadSource(opts){return askContentSource({kind:PAYLOAD_KIND2,message:SOURCE_PROMPT,pathMessage:"Path to the payload file",extensions:[".json"],placeholder:PAYLOAD_PLACEHOLDER2,...opts.allowSeed?{omitChoice:SEED_CHOICE}:{},...opts.inlineLabel?{inlineLabel:opts.inlineLabel}:{},...opts.currentContent?{currentContent:opts.currentContent}:{}})}var PAYLOAD_PLACEHOLDER2='{ "issue": { "key": "TEST-1" } }';async function fetchPayload(client,path2,label="Fetching test payload"){let{data,response,error:error51}=await withSpinner(label,()=>client.GET("/v1/workspace/{workspaceId}/environment/{environmentId}/eventListener/{eventListenerId}/testPayload/{testPayloadId}",{params:{path:path2}}));return(!response.ok||!data)&&apiFail(response.status,error51),data}async function setDefaultPayload(client,path2){let{response,error:error51}=await withSpinner("Setting default test payload",()=>client.PUT("/v1/workspace/{workspaceId}/environment/{environmentId}/eventListener/{eventListenerId}/testPayload/{testPayloadId}/default",{params:{path:path2}}));response.ok||apiFail(response.status,error51)}async function editSeededContent(client,path2){let seeded=await fetchPayload(client,path2,"Fetching the seeded sample event"),edited=await askInlineContent(PAYLOAD_KIND2,{initial:seeded.content,placeholder:PAYLOAD_PLACEHOLDER2});if(edited===seeded.content)return{changed:!1};assertSize(Buffer.byteLength(edited,"utf8"),PAYLOAD_KIND2);let{response,error:error51}=await withSpinner("Saving the edited sample event",()=>client.PUT("/v1/workspace/{workspaceId}/environment/{environmentId}/eventListener/{eventListenerId}/testPayload/{testPayloadId}",{params:{path:path2},body:{content:edited}}));return response.ok||apiFail(response.status,error51),{changed:!0}}function formatContent(content){try{return JSON.stringify(JSON.parse(content),null,2)}catch{return content}}function renderPayload(payload){return`${renderDetail({id:payload.id,name:payload.name})}
|
|
1366
1367
|
CONTENT
|
|
1367
1368
|
${formatContent(payload.content)}`}function assertOneSource(opts){opts.file!==void 0&&opts.content!==void 0&&fail(EXIT.USAGE,"USAGE_ERROR","--file and --content cannot be combined.")}function eventListenerTestPayloadCommand(){let tp=new Command("event-listener-test-payload").alias("tp").description("Manage the test payloads a manual event listener trigger runs");return withScope4(tp.command("list").description("List an event listener's test payloads")).option("--explain",EXPLAIN).action(async(opts,cmd)=>{if(explained(cmd,LIST_DOC8))return;let globals=cmd.optsWithGlobals(),scope2=await resolveScope6(globals,opts),eventListenerId=await resolveListener(scope2,opts.eventListenerId),{data,response,error:error51}=await withSpinner("Fetching test payloads",()=>scope2.client.GET("/v1/workspace/{workspaceId}/environment/{environmentId}/eventListener/{eventListenerId}/testPayloads",{params:{path:{workspaceId:scope2.workspace,environmentId:scope2.environment,eventListenerId}}}));(!response.ok||!data)&&apiFail(response.status,error51),ok(data,{human:d=>({testPayloads:d.testPayloads.map(p=>({id:p.id,name:p.name,default:p.id===d.defaultTestPayloadId?"\u2714":""}))})})}),withScope4(tp.command("get").description("Get a single test payload with its content").argument("[testPayloadId]","Test payload ID (required, interactive)")).option("--content-only","Print just the payload content, verbatim, for redirecting it into a file; the same bytes with or without --raw (optional)").option("--explain",EXPLAIN).action(async(idArg,opts,cmd)=>{if(explained(cmd,GET_DOC7))return;let globals=cmd.optsWithGlobals(),scope2=await resolveScope6(globals,opts),eventListenerId=await resolveListener(scope2,opts.eventListenerId),picked=await resolvePayload(scope2,eventListenerId,idArg),payload=await fetchPayload(scope2.client,{workspaceId:scope2.workspace,environmentId:scope2.environment,eventListenerId,testPayloadId:picked.id});if(opts.contentOnly){okFile(payload.content);return}ok(payload,{human:renderPayload})}),withScope4(tp.command("create").description("Create a test payload for an event listener")).option("--name <name>",`Test payload name, ${TEST_PAYLOAD_NAME_FORMAT} (required unless --input, interactive)`).option("--file <path>","Read the payload content from a file, or - for stdin (optional, interactive, exclusive with --content, API default: the sample event for the event type)").option("--content <json>","Payload content inline (optional, interactive, exclusive with --file, API default: the sample event for the event type)").option("--default","Also make it the payload a manual trigger runs (optional, interactive)").option("--input <file>",INPUT_BODY).option("--explain",EXPLAIN).action(async(opts,cmd)=>{if(explained(cmd,CREATE_DOC7))return;let globals=cmd.optsWithGlobals();assertOneSource(opts);let scope2=await resolveScope6(globals,opts),eventListenerId=await resolveListener(scope2,opts.eventListenerId),seedThenEdit=!1,rawBody;if(opts.input)rawBody=readInput(opts.input);else{let content=opts.content,sourcePath=opts.file;if(content===void 0&&sourcePath!==void 0&&(content=readContentFile(sourcePath,PAYLOAD_KIND2)),opts.name===void 0&&canPrompt()){if(content===void 0){let source=await askPayloadSource({allowSeed:!0});content=source.content,sourcePath=source.path,seedThenEdit=content===void 0}let name=await askPayloadName(sourcePath?suggestPayloadNameFromPath(sourcePath):void 0),asDefault=seedThenEdit?opts.default:opts.default??await prompts().confirm("Make this the payload a manual trigger runs?",!1);rawBody=stripUndefined({name,content,default:asDefault||void 0})}else opts.name===void 0&&fail(EXIT.USAGE,"USAGE_ERROR","--name is required."),rawBody=stripUndefined({name:opts.name,content,default:opts.default})}let body=validate(createBodySchema7,rawBody);body.name=assertTestPayloadName(body.name),body.content!==void 0&&(body.content||fail(EXIT.USAGE,"INVALID_BODY","Test payload content cannot be empty \u2014 omit it to seed the sample event instead."),assertSize(Buffer.byteLength(body.content,"utf8"),PAYLOAD_KIND2));let{data,response,error:error51}=await withSpinner("Creating test payload",()=>scope2.client.POST("/v1/workspace/{workspaceId}/environment/{environmentId}/eventListener/{eventListenerId}/testPayload",{params:{path:{workspaceId:scope2.workspace,environmentId:scope2.environment,eventListenerId}},body}));if((!response.ok||!data)&&apiFail(response.status,error51),seedThenEdit){let path2={workspaceId:scope2.workspace,environmentId:scope2.environment,eventListenerId,testPayloadId:data.id};await editSeededContent(scope2.client,path2),opts.default===void 0&&await prompts().confirm("Make this the payload a manual trigger runs?",!1)&&await setDefaultPayload(scope2.client,path2)}let payloadScope={workspaceId:scope2.workspace,environmentId:scope2.environment};body.content===void 0?await syncTestPayloadById(scope2.client,payloadScope,eventListenerId,data.id):await syncTestPayload(scope2.client,payloadScope,eventListenerId,{name:data.name,content:body.content,id:data.id}),okMutation("Test payload created",data,data),body.content===void 0&&!seedThenEdit&&canPrompt()&&prompts().note(`Seeded with the sample event \u2014 read it with \`get ${data.id}\`.`)}),withScope4(tp.command("update").description("Replace a test payload's content and/or rename it").argument("[testPayloadId]","Test payload ID (required, interactive)")).option("--name <name>",`Rename the test payload, ${TEST_PAYLOAD_NAME_FORMAT} (optional, interactive)`).option("--file <path>","Read the new content from a file, or - for stdin (optional, interactive, exclusive with --content)").option("--content <json>","New content inline (optional, interactive, exclusive with --file)").option("--input <file>",INPUT_BODY).option("--explain",EXPLAIN).action(async(idArg,opts,cmd)=>{if(explained(cmd,UPDATE_DOC7))return;let globals=cmd.optsWithGlobals(),interactive=!opts.input&&canPrompt();assertOneSource(opts);let scope2=await resolveScope6(globals,opts),eventListenerId=await resolveListener(scope2,opts.eventListenerId),picked=await resolvePayload(scope2,eventListenerId,idArg),path2={workspaceId:scope2.workspace,environmentId:scope2.environment,eventListenerId,testPayloadId:picked.id},editSource,rawBody;if(opts.input)rawBody=readInput(opts.input);else{let name=opts.name,content=opts.content;if(content===void 0&&opts.file!==void 0&&(content=readContentFile(opts.file,PAYLOAD_KIND2)),interactive&&(name===void 0&&await prompts().confirm("Rename the test payload?",!1)&&(name=await askPayloadName(picked.label)),content===void 0&&await prompts().confirm("Replace the payload content?",!0)&&({content}=await askPayloadSource({inlineLabel:"Edit it here",currentContent:async()=>{let current=await fetchPayload(scope2.client,path2);return editSource=await localEditSource(scope2.client,{workspaceId:scope2.workspace,environmentId:scope2.environment},{kind:"payload",eventListenerId,name:current.name},current.content),editSource.content}}))),name===void 0&&content===void 0){if(interactive){prompts().note("Nothing to update \u2014 neither the name nor the content changed.");return}failNothingToUpdate(["--name to rename","--file/--content to replace the content","--input"])}rawBody=stripUndefined({name,content})}let body=validate(updateBodySchema7,rawBody);body.name!==void 0&&(body.name=assertTestPayloadName(body.name)),body.content!==void 0&&(body.content||fail(EXIT.USAGE,"INVALID_BODY","Test payload content cannot be empty."),assertSize(Buffer.byteLength(body.content,"utf8"),PAYLOAD_KIND2));let{data,response,error:error51}=await withSpinner("Updating test payload",()=>scope2.client.PUT("/v1/workspace/{workspaceId}/environment/{environmentId}/eventListener/{eventListenerId}/testPayload/{testPayloadId}",{params:{path:path2},body}));(!response.ok||!data)&&apiFail(response.status,error51);let payloadScope={workspaceId:scope2.workspace,environmentId:scope2.environment};body.content===void 0?await syncTestPayloadRenamed(scope2.client,payloadScope,eventListenerId,{id:data.id,name:data.name}):await syncTestPayload(scope2.client,payloadScope,eventListenerId,{name:data.name,content:body.content,id:data.id,...editSource===void 0?{}:{mode:editSource.mode}}),okMutation("Test payload updated",data,data)}),withScope4(tp.command("set-default").description("Make a test payload the one a manual trigger runs").argument("[testPayloadId]","Test payload ID (required, interactive)")).option("--explain",EXPLAIN).action(async(idArg,opts,cmd)=>{if(explained(cmd,SET_DEFAULT_DOC))return;let globals=cmd.optsWithGlobals(),scope2=await resolveScope6(globals,opts),eventListenerId=await resolveListener(scope2,opts.eventListenerId),picked=await resolvePayload(scope2,eventListenerId,idArg);await setDefaultPayload(scope2.client,{workspaceId:scope2.workspace,environmentId:scope2.environment,eventListenerId,testPayloadId:picked.id}),okMutation("Default test payload set for your user in this environment",{updated:!0,id:picked.id})}),withScope4(tp.command("delete").description("Delete a test payload").argument("[testPayloadId]","Test payload ID (required, interactive)"),{destructive:!0}).option("--yes",CONFIRM_YES).option("--explain",EXPLAIN).action(async(idArg,opts,cmd)=>{if(explained(cmd,DELETE_DOC7))return;let globals=cmd.optsWithGlobals(),scope2=await resolveScope6(globals,opts,{useSession:canPrompt()}),eventListenerId=await resolveListener(scope2,opts.eventListenerId),picked=await resolvePayload(scope2,eventListenerId,idArg),named=picked.label??picked.id;opts.yes||(canPrompt()||failNeedsYes(`test payload ${named}`),await prompts().confirm(`Delete ${named}? It is removed from the whole workspace, along with every user's choice of it as the payload a manual trigger runs. This is irreversible.`,!1)||fail(EXIT.CANCELLED,"CANCELLED","Deletion cancelled."));let{response,error:error51}=await withSpinner("Deleting test payload",()=>scope2.client.DELETE("/v1/workspace/{workspaceId}/environment/{environmentId}/eventListener/{eventListenerId}/testPayload/{testPayloadId}",{params:{path:{workspaceId:scope2.workspace,environmentId:scope2.environment,eventListenerId,testPayloadId:picked.id}}}));response.ok||apiFail(response.status,error51),await syncTestPayloadDeleted(scope2.client,{workspaceId:scope2.workspace,environmentId:scope2.environment},eventListenerId,{id:picked.id,...picked.label?{name:picked.label}:{}}),okMutation("Test payload deleted",{deleted:!0,id:picked.id})}),tp}var EVENT_QUEUE_NAME_FORMAT="up to 100 characters",MAX_EVENT_QUEUE_NAME=100;function normalizeEventQueueName(name){return name.trim()}function eventQueueNameError(name){let normalized=normalizeEventQueueName(name);if(!normalized)return"An event queue name is required.";if(normalized.length>MAX_EVENT_QUEUE_NAME)return`An event queue name can be at most ${MAX_EVENT_QUEUE_NAME} characters (that one is ${normalized.length}).`}function assertEventQueueName(name){let error51=eventQueueNameError(name);return error51&&fail(EXIT.USAGE,"INVALID_EVENT_QUEUE_NAME",error51),normalizeEventQueueName(name)}function evictionThresholdError(minutes){if(!Number.isInteger(minutes)||minutes<=0)return"The eviction threshold must be a whole number of minutes greater than zero."}function assertEvictionThreshold(minutes){let error51=evictionThresholdError(minutes);return error51&&fail(EXIT.USAGE,"INVALID_EVICTION_THRESHOLD",error51),minutes}var DEFAULT_EVICTION_THRESHOLD=30;var EVICTION_ACTIONS=["PROCESS_EVENT","DROP_EVENT"],NAME_PROMPT3=`Event queue name (${EVENT_QUEUE_NAME_FORMAT})`;function withScope5(cmd,opts={}){let env=opts.gate?opts.destructive?SCOPE_ENVIRONMENT_GATE_DESTRUCTIVE:SCOPE_ENVIRONMENT_GATE_HEAD:opts.destructive?SCOPE_ENVIRONMENT_DESTRUCTIVE:SCOPE_ENVIRONMENT;return cmd.option("-w, --workspace <workspaceId>",opts.destructive?SCOPE_WORKSPACE_DESTRUCTIVE:SCOPE_WORKSPACE).option("-e, --env <environmentId>",env).option("--team <teamId>",opts.destructive?SCOPE_TEAM_FILTER_DESTRUCTIVE:SCOPE_TEAM_FILTER)}async function resolveScope7(globals,opts={}){let client=await apiClient(globals.instance),resolved=await resolveParams(["workspace","environment"],{team:globals.team,workspace:globals.workspace,environment:globals.env},{client,interactive:canPrompt(),useSession:opts.useSession});return{client,workspace:resolved.workspace??"",environment:resolved.environment??"",...resolved.team===void 0?{}:{team:resolved.team}}}async function resolveQueue(scope2,provided){if(provided)return{id:assertResourceId(provided,"eventQueueId")};canPrompt()||fail(EXIT.USAGE,"USAGE_ERROR",`<eventQueueId> is required. ${supplyHint()}`);let labels={};return{id:(await resolveParams(["eventQueue"],{workspace:scope2.workspace,environment:scope2.environment},{client:scope2.client,interactive:!0,labels})).eventQueue??"",label:labels.eventQueue}}var PLAN_GATE_SENTENCE="Event queues are not available on this team plan.";function queueFail(status,body,team){let message=body?.errorMessage;if(status===403&&message===PLAN_GATE_SENTENCE){let hint=team===void 0?`Whether the plan includes them is features.eventQueues on \`${CLI} team get <teamId>\`, for a team from \`${CLI} team list\`.`:`Whether the plan includes them is features.eventQueues on \`${CLI} team get ${team}\`.`;fail(EXIT.API_ERROR,"FORBIDDEN",message,{status,hint})}apiFail(status,body)}async function assertQueuesAvailable(scope2){if(!scope2.team)return;let team=scope2.team;(await withSpinner("Checking plan features",()=>teamFeaturesIfKnown(scope2.client,team)))?.eventQueues===!1&&queueFail(403,{errorMessage:PLAN_GATE_SENTENCE},team)}var evictionPolicySchema=external_exports.object({evictionAction:external_exports.enum(EVICTION_ACTIONS),evictionThresholdInMinutes:external_exports.number().optional()}).strict(),createBodySchema8=external_exports.object({name:external_exports.string().min(1),evictionPolicy:evictionPolicySchema.optional()}).strict(),updateBodySchema8=external_exports.object({name:external_exports.string().min(1).optional(),disabled:external_exports.boolean().optional(),evictionPolicy:evictionPolicySchema.nullable().optional()}).strict().refine(body=>Object.keys(body).length>0,{message:"At least one of name, disabled or evictionPolicy is required."});function assertQueueRules(body){body.name!==void 0&&(body.name=assertEventQueueName(body.name));let threshold=body.evictionPolicy?.evictionThresholdInMinutes;return threshold!==void 0&&assertEvictionThreshold(threshold),body}var EVICTION_ACTION_EFFECT={PROCESS_EVENT:"hands it to the script regardless",DROP_EVENT:"discards it"},EVICTION_ACTION_EFFECTS=EVICTION_ACTIONS.map(a=>`${a} ${EVICTION_ACTION_EFFECT[a]}`).join(", "),EXAMPLE_POLICY={evictionAction:"PROCESS_EVENT",evictionThresholdInMinutes:DEFAULT_EVICTION_THRESHOLD},LIST_DOC9=defineCommandDoc("event-queue list",{rules:["The workspace is -w and the environment -e, which decides only which enabled state is reported; there is no positional argument."],notes:["A queue belongs to the whole workspace, so every environment lists the same queues. Only the enabled state is per-environment. Event queues need the team's plan to include them; without it every verb in this group is refused."]}),GET_DOC8=defineCommandDoc("event-queue get",{rules:["The event queue is the positional argument; the workspace is -w and the environment -e."],notes:["Reports the listeners attached to the queue beside its own fields.","Event queues need the team's plan to include them; without it every verb in this group is refused."]}),DELETE_DOC8=defineCommandDoc("event-queue delete",{rules:["The event queue is the positional argument; the workspace is -w and the environment -e, which gates the write rather than choosing what is deleted.","--yes skips the confirmation, and is required without a terminal."],notes:["Deleting detaches every listener on the queue, which then runs unqueued and loses its grouping. Nothing refuses it; the confirmation is the only warning.","A listener that loses its queue reads the same way whichever route it took, a queue delete and event-listener update --no-event-queue alike: event-listener get reports no eventQueueId key at all, and no eventQueueGroupings beside it. Absence is the whole signal, and there is no null to branch on.","Event queues need the team's plan to include them; without it every verb in this group is refused."]}),CREATE_DOC8=defineCommandDoc("event-queue create",{schema:createBodySchema8,body:{name:"Orders",evictionPolicy:EXAMPLE_POLICY},rules:[`name: ${EVENT_QUEUE_NAME_FORMAT}, trimmed, unique within the workspace.`,`evictionPolicy: what happens to an event that has waited longer than evictionThresholdInMinutes: ${EVICTION_ACTION_EFFECTS}; omitted, events wait indefinitely. The block has no flag of its own.`,"evictionPolicy.evictionAction is required whenever the block is sent, spelled --eviction-action as a flag.",`evictionPolicy.evictionThresholdInMinutes: a positive integer, spelled --eviction-threshold as a flag; API default ${DEFAULT_EVICTION_THRESHOLD}.`,"The queue is created for the whole workspace and enabled in every environment; refused in a non-HEAD environment. Event queues need the team's plan to include them."]}),UPDATE_DOC8=defineCommandDoc("event-queue update",{schema:updateBodySchema8,body:{name:"Orders",disabled:!1,evictionPolicy:EXAMPLE_POLICY},rules:["An omitted key keeps the current value, and a body with no keys is refused: at least one of name, disabled or evictionPolicy is required.","disabled: true disables the queue in the environment named by -e and false enables it there (--disabled and --enabled as flags), omitted keeps the current state; name and evictionPolicy apply to every environment.","evictionPolicy: an object replaces the policy, null removes it so events wait indefinitely (--no-eviction-policy as a flag), omitted keeps it. The block itself has no flag for setting one.",`evictionPolicy.evictionAction is required whenever an object is sent, spelled --eviction-action as a flag: ${EVICTION_ACTION_EFFECTS}.`,`evictionPolicy.evictionThresholdInMinutes: a positive integer, spelled --eviction-threshold as a flag; API default ${DEFAULT_EVICTION_THRESHOLD}.`,"In a non-HEAD environment only disabled can change. name and evictionPolicy are read-only rather than refused there: echo back what that environment's own get reports, or omit them, and only a differing value is a 400 naming it. null counts as differing when there is a policy to remove, and is accepted when there is not, removing nothing.","Event queues need the team's plan to include them; without it every verb in this group is refused."]});function evictionCell(policy){if(!policy)return"\u2014";let minutes=policy.evictionThresholdInMinutes;return minutes===void 0?policy.evictionAction:`${policy.evictionAction} after ${minutes} min`}function policyFromFlags(opts){if(opts.evictionThreshold!==void 0&&!opts.evictionAction&&fail(EXIT.USAGE,"USAGE_ERROR","--eviction-threshold needs --eviction-action (PROCESS_EVENT or DROP_EVENT)."),!opts.evictionAction)return;let action=opts.evictionAction.toUpperCase();return EVICTION_ACTIONS.includes(action)||fail(EXIT.USAGE,"INVALID_EVICTION_ACTION",`--eviction-action must be one of: ${EVICTION_ACTIONS.join(", ")}.`),{evictionAction:action,...opts.evictionThreshold===void 0?{}:{evictionThresholdInMinutes:assertEvictionThreshold(opts.evictionThreshold)}}}async function askQueueName(initial){for(;;){let answer=await prompts().text(NAME_PROMPT3,{initial}),error51=eventQueueNameError(answer);if(!error51)return normalizeEventQueueName(answer);prompts().note(`\u2716 ${error51}`)}}async function askEvictionPolicy(current){let choices=[{value:"PROCESS_EVENT",label:"Process it anyway",hint:"PROCESS_EVENT"},{value:"DROP_EVENT",label:"Drop it",hint:"DROP_EVENT"}],evictionAction=await prompts().select("When an event has waited too long:",choices,{initial:current?.evictionAction});for(;;){let answer=await prompts().text("Wait limit in minutes",{initial:String(current?.evictionThresholdInMinutes??DEFAULT_EVICTION_THRESHOLD)}),minutes=Number(answer.trim()),error51=evictionThresholdError(minutes);if(!error51)return{evictionAction,evictionThresholdInMinutes:minutes};prompts().note(`\u2716 ${error51}`)}}function eventQueueCommand(){let eq=new Command("event-queue").alias("eq").description("Manage workspace event queues");return withScope5(eq.command("list").description("List event queues in a workspace")).option("--explain",EXPLAIN).action(async(_opts,cmd)=>{if(explained(cmd,LIST_DOC9))return;let globals=cmd.optsWithGlobals(),scope2=await resolveScope7(globals),{data,response,error:error51}=await withSpinner("Fetching event queues",()=>scope2.client.GET("/v1/workspace/{workspaceId}/environment/{environmentId}/eventQueues",{params:{path:{workspaceId:scope2.workspace,environmentId:scope2.environment}}}));(!response.ok||!data)&&queueFail(response.status,error51,scope2.team),ok(data,{human:d=>({eventQueues:d.eventQueues.map(q2=>({id:q2.id,name:q2.name,disabled:q2.disabled,eviction:evictionCell(q2.evictionPolicy)}))})})}),withScope5(eq.command("get").description("Get a single event queue").argument("[eventQueueId]","Event queue ID (required, interactive)")).option("--explain",EXPLAIN).action(async(idArg,_opts,cmd)=>{if(explained(cmd,GET_DOC8))return;let globals=cmd.optsWithGlobals(),scope2=await resolveScope7(globals),queue=await resolveQueue(scope2,idArg),{data,response,error:error51}=await withSpinner("Fetching event queue",()=>scope2.client.GET("/v1/workspace/{workspaceId}/environment/{environmentId}/eventQueue/{eventQueueId}",{params:{path:{workspaceId:scope2.workspace,environmentId:scope2.environment,eventQueueId:queue.id}}}));(!response.ok||!data)&&queueFail(response.status,error51,scope2.team),ok(data,{human:d=>({id:d.id,name:d.name,disabled:d.disabled,eviction:evictionCell(d.evictionPolicy),eventListeners:d.eventListeners.length===0?"(none)":d.eventListeners.map(el=>`${el.name} (${el.id})`).join(`
|
|
1368
1369
|
`)})})}),withScope5(eq.command("create").description("Create an event queue in a workspace"),{gate:!0}).option("--name <name>",`Event queue name, ${EVENT_QUEUE_NAME_FORMAT} (required unless --input, interactive)`).option("--eviction-action <action>",`What happens to an event that waited too long: ${EVICTION_ACTIONS.join(" | ")} (optional, interactive)`).option("--eviction-threshold <minutes>",`How long an event may wait before that applies (optional, interactive, API default: ${DEFAULT_EVICTION_THRESHOLD}, requires --eviction-action)`,v2=>Number(v2)).option("--input <file>",INPUT_BODY).option("--explain",EXPLAIN).action(async(opts,cmd)=>{if(explained(cmd,CREATE_DOC8))return;let globals=cmd.optsWithGlobals(),scope2=await resolveScope7(globals);await assertQueuesAvailable(scope2);let rawBody;if(opts.input)rawBody=readInput(opts.input);else if(!opts.name&&canPrompt()){let name=await askQueueName(),policy=opts.evictionAction!==void 0||opts.evictionThreshold!==void 0?policyFromFlags(opts):await prompts().confirm("Add an eviction policy? (without one, events wait indefinitely)",!1)?await askEvictionPolicy():void 0;rawBody=stripUndefined({name,evictionPolicy:policy})}else rawBody=stripUndefined({name:opts.name===void 0?void 0:assertEventQueueName(opts.name),evictionPolicy:policyFromFlags(opts)});let body=assertQueueRules(validate(createBodySchema8,rawBody)),{data,response,error:error51}=await withSpinner("Creating event queue",()=>scope2.client.POST("/v1/workspace/{workspaceId}/environment/{environmentId}/eventQueue",{params:{path:{workspaceId:scope2.workspace,environmentId:scope2.environment}},body}));(!response.ok||!data)&&queueFail(response.status,error51,scope2.team),okMutation("Event queue created",data,{...data,availability:"every environment of this workspace, enabled"})}),withScope5(eq.command("update").description("Update an event queue").argument("[eventQueueId]","Event queue ID (required, interactive)")).option("--name <name>","New name, applies to every environment (optional, interactive on HEAD only, refused when it differs from what a non-HEAD environment reports)").option("--disabled","Disable the queue in the specified environment (optional, interactive, exclusive with --enabled)").option("--enabled","Enable the queue in the specified environment (optional, interactive, exclusive with --disabled)").option("--eviction-action <action>",`Eviction action: ${EVICTION_ACTIONS.join(" | ")} (optional, interactive on HEAD only, refused when it differs from what a non-HEAD environment reports)`).option("--eviction-threshold <minutes>","Eviction threshold in minutes (optional, interactive on HEAD only, requires --eviction-action, refused when it differs from what a non-HEAD environment reports)",v2=>Number(v2)).option("--no-eviction-policy","Remove the eviction policy so events wait indefinitely (optional, interactive on HEAD only, exclusive with --eviction-action and --eviction-threshold, refused when it differs from what a non-HEAD environment reports)").option("--input <file>",INPUT_BODY).option("--explain",EXPLAIN).action(async(idArg,opts,cmd)=>{if(explained(cmd,UPDATE_DOC8))return;let globals=cmd.optsWithGlobals(),scope2=await resolveScope7(globals),queue=await resolveQueue(scope2,idArg),interactive=!opts.input&&canPrompt(),removePolicy=opts.evictionPolicy===!1;removePolicy&&(opts.evictionAction||opts.evictionThreshold!==void 0)&&fail(EXIT.USAGE,"USAGE_ERROR","--no-eviction-policy cannot be combined with --eviction-action or --eviction-threshold.");let rawBody;if(opts.input)rawBody=readInput(opts.input);else if(interactive){let current=await withSpinner("Fetching event queue",()=>scope2.client.GET("/v1/workspace/{workspaceId}/environment/{environmentId}/eventQueue/{eventQueueId}",{params:{path:{workspaceId:scope2.workspace,environmentId:scope2.environment,eventQueueId:queue.id}}}));(!current.response.ok||!current.data)&&queueFail(current.response.status,current.error,scope2.team);let release2=await withSpinner("Checking the environment",()=>environmentRelease(scope2.client,scope2.workspace,scope2.environment));release2&&(opts.name!==void 0||removePolicy||opts.evictionAction!==void 0||opts.evictionThreshold!==void 0)&&fail(EXIT.USAGE,"USAGE_ERROR","The name and the eviction policy belong to the event queue and are shared by every environment, so they cannot be changed in an environment with a release deployed. Target a HEAD environment, or pass only --disabled/--enabled."),release2&&prompts().note(`\u26A0 This environment has ${release2.version?`release ${release2.version}`:"a release"} deployed. Only the enabled state can be changed there; the name and the eviction policy belong to the event queue and are shared by every environment.`);let name=release2?void 0:opts.name??await askQueueName(current.data.name),disabled=disabledFromFlags(opts)??await askStatus(current.data.disabled,"the event queue"),evictionPolicy;if(release2)evictionPolicy=void 0;else if(removePolicy)evictionPolicy=null;else if(opts.evictionAction||opts.evictionThreshold!==void 0)evictionPolicy=policyFromFlags(opts);else{let choices=[{value:"keep",label:evictionCell(current.data.evictionPolicy),display:`${evictionCell(current.data.evictionPolicy)} (current)`},{value:"set",label:current.data.evictionPolicy?"Change the eviction policy":"Add an eviction policy"},...current.data.evictionPolicy?[{value:"remove",label:"Remove it",hint:"events then wait indefinitely"}]:[]],answer=await prompts().select("Eviction policy:",choices,{initial:"keep"});answer==="set"?evictionPolicy=await askEvictionPolicy(current.data.evictionPolicy):answer==="remove"&&(evictionPolicy=null)}let renamed=name===void 0||name===current.data.name?void 0:name;if(renamed===void 0&&disabled===void 0&&evictionPolicy===void 0){prompts().note("Nothing to update \u2014 the event queue was left as it is.");return}rawBody=stripUndefined({name:renamed,disabled,evictionPolicy})}else rawBody=stripUndefined({name:opts.name===void 0?void 0:assertEventQueueName(opts.name),disabled:disabledFromFlags(opts),evictionPolicy:removePolicy?null:policyFromFlags(opts)}),Object.keys(rawBody).length===0&&failNothingToUpdate(["--name","--disabled/--enabled","an eviction policy","--input"]);let body=assertQueueRules(validate(updateBodySchema8,rawBody)),{data,response,error:error51}=await withSpinner("Updating event queue",()=>scope2.client.PUT("/v1/workspace/{workspaceId}/environment/{environmentId}/eventQueue/{eventQueueId}",{params:{path:{workspaceId:scope2.workspace,environmentId:scope2.environment,eventQueueId:queue.id}},body}));(!response.ok||!data)&&queueFail(response.status,error51,scope2.team);let{evictionPolicy:_policy,...detail}=data;okMutation("Event queue updated",data,{...detail,eviction:evictionCell(data.evictionPolicy)})}),withScope5(eq.command("delete").description("Delete an event queue from a workspace").argument("[eventQueueId]","Event queue ID (required, interactive)"),{destructive:!0,gate:!0}).option("--yes",CONFIRM_YES).option("--explain",EXPLAIN).action(async(idArg,opts,cmd)=>{if(explained(cmd,DELETE_DOC8))return;let globals=cmd.optsWithGlobals(),scope2=await resolveScope7(globals,{useSession:canPrompt()}),queue=await resolveQueue(scope2,idArg);if(!opts.yes){canPrompt()||failNeedsYes(`event queue ${queue.id}`);let current=await withSpinner("Fetching event queue",()=>scope2.client.GET("/v1/workspace/{workspaceId}/environment/{environmentId}/eventQueue/{eventQueueId}",{params:{path:{workspaceId:scope2.workspace,environmentId:scope2.environment,eventQueueId:queue.id}}}));(!current.response.ok||!current.data)&&queueFail(current.response.status,current.error,scope2.team);let attached=current.data.eventListeners;prompts().note(["Deleting removes the event queue from the whole workspace, not just this environment.",attached.length===0?"No event listeners are attached to it.":`${attached.length} event listener${attached.length===1?"":"s"} ${attached.length===1?"is":"are"} attached and will be detached, losing ${attached.length===1?"its":"their"} grouping, and will then run unqueued:
|
|
@@ -1385,9 +1386,9 @@ CONTENT
|
|
|
1385
1386
|
${readme.content}`}function sizeCell(content){if(content==="")return"empty";let bytes=Buffer.byteLength(content,"utf8"),size=bytes<1024?`${bytes} B`:bytes<1024*1024?`${(bytes/1024).toFixed(1)} KB`:`${(bytes/(1024*1024)).toFixed(1)} MB`,lines=content.replace(/\n$/,"").split(`
|
|
1386
1387
|
`).length;return`${size} (${lines} line${lines===1?"":"s"})`}async function askReadmeContent(client,path2){let release2=await withSpinner("Checking the environment",()=>environmentRelease(client,path2.workspaceId,path2.environmentId));release2&&fail(EXIT.USAGE,"RELEASED_ENVIRONMENT",`This environment runs ${release2.version?`release ${release2.version}`:"a release"} \u2014 the README is shared by every environment and can only be replaced through a HEAD (non-deployed) environment.`);let fetched,current=()=>fetched??=fetchReadme(client,path2),editSource;return{content:(await askContentSource({kind:README_KIND,message:"How do you want to provide the README?",pathMessage:"Path to the markdown file",inlineLabel:"Edit it here",extensions:[".md",".markdown"],placeholder:"# My workspace",currentContent:async()=>{let server=(await current()).content;return editSource=await localEditSource(client,{workspaceId:path2.workspaceId,environmentId:path2.environmentId},{kind:"readme"},server),editSource.content},emptyConfirm:"Save an empty README? This clears the stored one."})).content??"",...editSource?{mode:editSource.mode}:{}}}function workspaceReadmeCommand(){let readme=new Command("readme").description("Manage workspace READMEs");return withScope7(readme.command("get").description("Get the workspace's README")).option("--content-only","Print just the markdown, rendered for the terminal; with --raw, the stored source verbatim (optional)").option("--explain",EXPLAIN).action(async(opts,cmd)=>{if(explained(cmd,GET_DOC11))return;let globals=cmd.optsWithGlobals(),scope2=await resolveScope10(globals),stored=await fetchReadme(scope2.client,{workspaceId:scope2.workspace,environmentId:scope2.environment});if(opts.contentOnly){isRaw()?okFile(stored.content):okText(renderMarkdown(stored.content));return}ok(stored,{human:renderReadme})}),withScope7(readme.command("update").description("Update the workspace's README")).option("--file <path>","Read the new README from a file, or - for stdin (optional, interactive, exclusive with --content)").option("--content <markdown>",'New README markdown inline; "" empties the README (optional, interactive, exclusive with --file)').option("--input <file>",INPUT_BODY).option("--explain",EXPLAIN).action(async(opts,cmd)=>{if(explained(cmd,UPDATE_DOC11))return;let globals=cmd.optsWithGlobals(),interactive=canPrompt();opts.file!==void 0&&opts.content!==void 0&&fail(EXIT.USAGE,"USAGE_ERROR","--file and --content cannot be combined.");let scope2=await resolveScope10(globals),path2={workspaceId:scope2.workspace,environmentId:scope2.environment},rawBody,editMode;if(opts.input)rawBody=readInput(opts.input);else{let content=opts.content;content===void 0&&opts.file!==void 0&&(content=readContentFile(opts.file,README_KIND)),content===void 0&&interactive&&({content,mode:editMode}=await askReadmeContent(scope2.client,path2)),content===void 0&&failNothingToUpdate(["--file","--content","--input"]),rawBody={content}}let body=validate(updateBodySchema11,rawBody);assertSize(Buffer.byteLength(body.content,"utf8"),README_KIND);let{data,response,error:error51}=await withSpinner("Updating README",()=>scope2.client.PUT("/v1/workspace/{workspaceId}/environment/{environmentId}/readme",{params:{path:path2},body}));(!response.ok||!data)&&apiFail(response.status,error51),syncReadme({workspaceId:path2.workspaceId,environmentId:path2.environmentId},data.content,editMode),okMutation("README updated",data,{name:data.name,size:sizeCell(data.content)})}),readme}var LANGUAGES=["js","ts","ts-strict"],VISIBILITIES=["public","private"],LANGUAGE_CHOICES=[{value:"ts",label:"TypeScript"},{value:"ts-strict",label:"TypeScript (strict)"},{value:"js",label:"JavaScript"}],VISIBILITY_CHOICES=[{value:"private",label:"Private \u2014 admins of the team and you"},{value:"public",label:"Public \u2014 all members of the team"}],VISIBILITY_MEANING={public:"every member of the team",private:"the team's admins and you"},VISIBILITY_MEANINGS=VISIBILITIES.map(v2=>`${v2} (${VISIBILITY_MEANING[v2]})`).join(" or "),MAX_WORKSPACE_NAME=200,WORKSPACE_NAME_CHARSET=/^[A-Za-z0-9 .-]+$/,WORKSPACE_NAME_FORMAT=`letters, digits, spaces, hyphens and periods, up to ${MAX_WORKSPACE_NAME} characters, and unique within the team`,MAX_WORKSPACE_DESCRIPTION=1e3;function assertWorkspaceName(name){let trimmed=name.trim();return trimmed||fail(EXIT.USAGE,"INVALID_WORKSPACE_NAME","A workspace name is required."),trimmed.length>MAX_WORKSPACE_NAME&&fail(EXIT.USAGE,"INVALID_WORKSPACE_NAME",`A workspace name can be at most ${MAX_WORKSPACE_NAME} characters (that one is ${trimmed.length}).`),WORKSPACE_NAME_CHARSET.test(trimmed)||fail(EXIT.USAGE,"INVALID_WORKSPACE_NAME",`Use letters, digits, spaces, hyphens and periods \u2014 '${name}' has a character the API refuses. No underscores or slashes, unlike a script name.`),trimmed}function assertWorkspaceDescription(description){return description.length>MAX_WORKSPACE_DESCRIPTION&&fail(EXIT.USAGE,"INVALID_WORKSPACE_DESCRIPTION",`A workspace description can be at most ${MAX_WORKSPACE_DESCRIPTION} characters (that one is ${description.length}).`),description}function assertWorkspaceBody(body){return body.name!==void 0&&(body.name=assertWorkspaceName(body.name)),body.description!==void 0&&assertWorkspaceDescription(body.description),body}var createBodySchema12=external_exports.object({name:external_exports.string(),description:external_exports.string().optional(),sourceWorkspaceId:external_exports.string().optional(),sourceTemplateId:external_exports.string().optional(),language:external_exports.enum(LANGUAGES).optional(),visibility:external_exports.enum(VISIBILITIES).optional()}).strict().refine(body=>!(body.sourceWorkspaceId&&body.sourceTemplateId),{message:"sourceWorkspaceId and sourceTemplateId cannot both be set.",path:["sourceTemplateId"]}),updateBodySchema12=external_exports.object({name:external_exports.string(),description:external_exports.string().optional(),language:external_exports.enum(LANGUAGES).optional(),visibility:external_exports.enum(VISIBILITIES).optional()}).strict(),MISSING_WORKSPACE={workspace:`<workspaceId> is required. ${supplyHint({env:"SR_CONNECT_CLI_WORKSPACE"})}`},BLAME_WORKSPACE={workspace:"<workspaceId>"},CONFIRM_MOVE_YES="Confirm moving the workspace when --team names another team, the one change here that clears connector attachments and remote file system access (optional on a TTY, required for a move otherwise, ignored when no move is involved)";function teamLabel(moving){return moving.teamName?`${moving.teamName} (${moving.teamId})`:moving.teamId}async function confirmMove(moving,teamId,yes){let from=teamLabel(moving);noteLine(`\u2139 Workspace "${moving.workspace.name}" is in team ${from}. This update moves it to ${teamId}.`),warnLine(`\u26A0 Moving clears every connector attachment in every environment \u2014 each event listener
|
|
1387
1388
|
and API connection has to be pointed at a connector in the new team.
|
|
1388
|
-
Remote file system access is turned off with it, and any temporary credentials stop working.`),!yes&&(canPrompt()||fail(EXIT.USAGE,"CONFIRMATION_REQUIRED",`Moving workspace "${moving.workspace.name}" from team ${from} to ${teamId} clears every connector attachment in every environment and turns remote file system access off, and moving it back undoes neither. Re-run with --yes to confirm.`,{hint:`Pass --team ${moving.teamId} to update it where it is instead.`}),await prompts().confirm("Move it to that team?",!1)||fail(EXIT.CANCELLED,"CANCELLED","Cancelled."))}var LIST_DOC13=defineCommandDoc("workspace list",{rules:["The team is --team; the workspace is this group's resource, so there is no -w here and no positional argument."],notes:["Every workspace of the team, yours and the public ones you are not a member of alike."]}),GET_DOC12=defineCommandDoc("workspace get",{rules:["The workspace is the positional argument and there is no -w here, the workspace being what this verb reads rather than where it looks. --team is optional: every workspace read is keyed by team, and a team that was not given is found by searching the ones you are a member of, which is one request per team until the workspace turns up."],notes:["Reports the language, which is worth reading after creating from a template or another workspace: either brings its own, and ts-strict is the one to prefer.","Also reports remoteWorkspaceEnabled, which a move between teams turns off."]}),DELETE_DOC11=defineCommandDoc("workspace delete",{rules:["The workspace is the positional argument and the team is --team.","--yes skips the confirmation, and is required without a terminal."],notes:["Deletes the workspace with its environments, scripts, API connections, event listeners, scheduled triggers and releases; anything running from a release stops.","The lock this shell holds is presented and never stands in the way. Another holder is exit 1 WORKSPACE_LOCKED naming them, with workspace-lock check and workspace-lock take --force in the hint.","Dropped from this shell's session defaults afterwards, along with the environment the record named."]}),CREATE_DOC12=defineCommandDoc("workspace create",{schema:createBodySchema12,body:{name:"Order sync",description:"Keeps Jira and the order system in step.",sourceWorkspaceId:"<workspaceId>",sourceTemplateId:"<templateId>",language:"ts-strict",visibility:"private"},rules:[`name: ${WORKSPACE_NAME_FORMAT}.`,`description: free text, up to ${MAX_WORKSPACE_DESCRIPTION} characters.`,`sourceWorkspaceId (--source-workspace-id as a flag) copies another workspace; sourceTemplateId (--source-template-id) creates from a published template, as listed by ${CLI} template list; at most one of the two. Either brings its own language, and language is then ignored: read the language back with ${CLI} workspace get and upgrade it with update. A copy has one environment, the default one, holding the source's default environment's parameters with each default value as the value; parameter values, other environments and releases are not copied.`,`language: ${LANGUAGES.join(", ")}; API default ts; ts-strict is the one to prefer.`,`visibility: ${VISIBILITY_MEANINGS}; API default private. Creating a public one needs you to be an admin of the team, and a member who is not gets exit 1 "User is not in any of the required roles: ADMIN,SUPER_ADMIN"; seeing one needs nothing, which is what public means.`,"The team is --team, never a body key."]}),UPDATE_DOC12=defineCommandDoc("workspace update",{schema:updateBodySchema12,body:{name:"Order sync",description:"Keeps Jira and the order system in step.",language:"ts-strict",visibility:"private"},rules:[`name is required even when it does not change: send the current one back. ${WORKSPACE_NAME_FORMAT}.`,`description is cleared when the body omits it, so send the current one back to keep it; "" clears it too. Up to ${MAX_WORKSPACE_DESCRIPTION} characters. The flags path reads the workspace and carries it forward, so only a body given here has to.`,`language: ${LANGUAGES.join(", ")}; omitted, the current one is kept.`,`visibility: ${VISIBILITIES.join(" or ")}; omitted, the current one is kept, except when --team moves the workspace to another team, where a body that does not name one makes it private. Changing it needs you to be an admin of the team.`,"The sources a workspace was created from cannot change. --team names the workspace's team, or a new team to move it to; it is not a body key.","A --team that names another team moves the workspace, which clears every connector attachment in every environment and turns remote file system access off \u2014 neither undone by moving it back. So it takes --yes without a terminal (exit 2 CONFIRMATION_REQUIRED otherwise) and a confirmation with one, and only a typed flag can move at all: a team from an environment variable, a clone or the session record is exit 2 TEAM_MISMATCH. An --input body is held to both, the team being resolved outside it."],notes:["--yes is for the move alone: an ordinary update never needs it, and passing it to one is accepted and ignored.","The workspace is found by looking through your teams for the one holding it, which is named on stderr. Only a move pays for that search \u2014 an ordinary update reads the workspace once. An ID in none of your teams is exit 4.","A workspace published as a template stays one: the template flag is not part of this request, and editing such a workspace needs permission to author templates, which the API answers 403 for when you do not have it."]});function assertOneSource2(opts){opts.sourceWorkspaceId&&opts.sourceTemplateId&&fail(EXIT.USAGE,"USAGE_ERROR","--source-workspace-id and --source-template-id cannot be combined.")}async function fillCreateBody4(client,teamId,opts){let sourceWorkspaceId=opts.sourceWorkspaceId;!sourceWorkspaceId&&!opts.sourceTemplateId&&await prompts().confirm("Clone from an existing workspace?",!1)&&(sourceWorkspaceId=(await resolveParams(["workspace"],{team:teamId},{client,interactive:!0})).workspace);let name=opts.name??await prompts().text("Workspace name"),description=opts.description;description===void 0&&(description=await prompts().text("Workspace description, optional (empty for none)",{allowEmpty:!0})||void 0);let language=opts.language??(sourceWorkspaceId||opts.sourceTemplateId?void 0:await prompts().select("Scripting language",LANGUAGE_CHOICES)),visibility=opts.visibility??await prompts().select("Visibility",VISIBILITY_CHOICES);return stripUndefined({name,description,sourceWorkspaceId,sourceTemplateId:opts.sourceTemplateId,language,visibility})}async function locateWorkspace(client,teamId,workspaceId){let direct=teamId===void 0?void 0:await withSpinner("Fetching workspace",()=>client.GET("/v1/team/{teamId}/workspace/{workspaceId}",{params:{path:{teamId,workspaceId}}}));return direct?.response.ok&&direct.data?{workspace:direct.data,teamId:teamId??""}:(direct&&direct.response.status!==404&&apiFail(direct.response.status,direct.error),withSpinner("Looking for the workspace in your other teams",async()=>{let teams=await client.GET("/v1/teams");(!teams.response.ok||!teams.data)&&apiFail(teams.response.status,teams.error);for(let team of teams.data.teams){if(!team.id||team.id===teamId)continue;let list=await client.GET("/v1/team/{teamId}/workspaces",{params:{path:{teamId:team.id}}});(!list.response.ok||!list.data)&&apiFail(list.response.status,list.error);let found2=list.data.workspaces.find(w=>w.id===workspaceId);if(found2)return{workspace:found2,teamId:team.id,...team.name?{teamName:team.name}:{}}}}))}async function fetchWorkspace(client,teamId,workspaceId){let{data,response,error:error51}=await withSpinner("Fetching workspace",()=>client.GET("/v1/team/{teamId}/workspace/{workspaceId}",{params:{path:{teamId,workspaceId}}}));return(!response.ok||!data)&&apiFail(response.status,error51),data}async function fillUpdateBody2(current,moving){let name=await prompts().text("Workspace name",{initial:current.name}),description=current.description,currently=current.description?`(currently "${current.description}")`:"(currently unset)";await prompts().confirm(`Change the description? ${currently}`,!1)&&(description=await prompts().text("Description",{allowEmpty:!0}));let language;await prompts().confirm("Change the scripting language?",!1)&&(language=await prompts().select("Scripting language",LANGUAGE_CHOICES));let visibility;return moving?visibility=await prompts().select("Visibility",VISIBILITY_CHOICES,{initial:current.visibility}):await prompts().confirm("Change the visibility?",!1)&&(visibility=await prompts().select("Visibility",VISIBILITY_CHOICES)),{name,...description===void 0?{}:{description},...language===void 0?{}:{language},...visibility===void 0?{}:{visibility}}}async function confirmDeletion4(client,teamId,workspaceId){let current=await fetchWorkspace(client,teamId,workspaceId);prompts().note(["Deleting removes the workspace from the whole team, and everything in it goes with it:","environments, scripts, API connections, event listeners, scheduled triggers \u2014 and releases,","so anything still running from one stops immediately.",`It disappears from ${CLI} workspace list, and every later request naming it is a 404.`].join(`
|
|
1389
|
-
`)),await prompts().confirm(`Delete workspace "${current.name}" (${workspaceId})? This is irreversible.`)||fail(EXIT.CANCELLED,"CANCELLED","Deletion cancelled.")}async function failDeletion2(client,status,error51,workspaceId){if(status===409){let holder=error51?.lockedBy;lockedFail(holder,workspaceId,`See who holds it with \`${CLI} workspace-lock check -w ${workspaceId}\`, then take it with \`${CLI} workspace-lock take -w ${workspaceId} --force\` and delete again.`,await currentUser(client))}apiFail(status,error51)}function workspaceCommand(){let ws=new Command("workspace").description("Manage workspaces");return ws.command("list").description("List workspaces").option("--team <teamId>",SCOPE_TEAM).option("--explain",EXPLAIN).action(async(opts,cmd)=>{if(explained(cmd,LIST_DOC13))return;let globals=cmd.optsWithGlobals(),client=await apiClient(globals.instance),resolved=await resolveParams(["team"],{team:opts.team},{client,interactive:canPrompt()}),{data,response,error:error51}=await withSpinner("Fetching workspaces",()=>client.GET("/v1/team/{teamId}/workspaces",{params:{path:{teamId:resolved.team??""}}}));(!response.ok||!data)&&apiFail(response.status,error51),ok(data,{human:d=>({workspaces:tableRows(["id","name","description","language","remoteWorkspaceEnabled","visibility","incomingApps","outgoingApps","createdFromTemplate"],d.workspaces.map(w=>({...w,incomingApps:w.incomingApps.join(", "),outgoingApps:w.outgoingApps.join(", ")})))})})}),ws.command("create").description("Create a workspace, optionally from another workspace or a published template").option("--team <teamId>",SCOPE_TEAM).option("--name <name>","Workspace name (required unless --input, interactive)").option("--description <text>","Workspace description (optional, interactive)").option("--source-workspace-id <id>","Clone from the specified workspace, whose language is used (optional, interactive, exclusive with --source-template-id)").option("--source-template-id <id>",`Create from the specified published template, whose language is used, as listed by ${CLI} template list (optional, exclusive with --source-workspace-id)`).option("--language <lang>","Scripting language: js, ts, or ts-strict (optional, interactive, API default: ts, ignored with --source-workspace-id or --source-template-id)").option("--visibility <mode>","Sharing mode: public or private (optional, interactive, API default: private)").option("--input <file>",INPUT_BODY).option("--explain",EXPLAIN).action(async(opts,cmd)=>{if(explained(cmd,CREATE_DOC12))return;let globals=cmd.optsWithGlobals();assertOneSource2(opts);let client=await apiClient(globals.instance),teamId=(await resolveParams(["team"],{team:opts.team??globals.team},{client,interactive:canPrompt()})).team??"",rawBody=opts.input?readInput(opts.input):!opts.name&&canPrompt()?await fillCreateBody4(client,teamId,opts):stripUndefined({name:opts.name,description:opts.description,sourceWorkspaceId:opts.sourceWorkspaceId,sourceTemplateId:opts.sourceTemplateId,language:assertChoice("--language",opts.language,LANGUAGES),visibility:assertChoice("--visibility",opts.visibility,VISIBILITIES)}),body=assertWorkspaceBody(validate(createBodySchema12,rawBody)),{data,response,error:error51}=await withSpinner("Creating workspace",()=>client.POST("/v1/team/{teamId}/workspace",{params:{path:{teamId}},body}));(!response.ok||!data)&&apiFail(response.status,error51),okMutation("Workspace created",data,data)}),ws.command("get").description("Get a single workspace").argument("[workspaceId]",SCOPE_WORKSPACE).option("--team <teamId>",SCOPE_TEAM_SEARCHED).option("--explain",EXPLAIN).action(async(idArg,opts,cmd)=>{if(explained(cmd,GET_DOC12))return;let globals=cmd.optsWithGlobals(),client=await apiClient(globals.instance),resolved=await resolveParams(["workspace"],{team:opts.team??globals.team,workspace:idArg??globals.workspace},{client,interactive:canPrompt(),missing:MISSING_WORKSPACE,...idArg===void 0?{}:{blame:BLAME_WORKSPACE}}),workspaceId=resolved.workspace??"",teamId=resolved.team,located=teamId===void 0?await locateWorkspace(client,void 0,workspaceId):void 0;teamId===void 0&&!located&&fail(EXIT.NOT_FOUND,"NOT_FOUND",`No workspace ${workspaceId} in any of your teams.`,{status:404});let data=located?located.workspace:await fetchWorkspace(client,teamId??"",workspaceId);ok(data,{human:d=>({...d,incomingApps:d.incomingApps.join(", "),outgoingApps:d.outgoingApps.join(", ")})})}),ws.command("update").description("Update a workspace").argument("[workspaceId]","Workspace ID (required, interactive, session default, env SR_CONNECT_CLI_WORKSPACE)").option("--team <teamId>","Team ID \u2014 the workspace's team, or a new team to move it to; only the flag itself can move, a session default or environment variable never does (required, interactive, session default, env SR_CONNECT_CLI_TEAM)").option("--name <name>","New workspace name (optional, interactive, default: the current name)").option("--description <text>",'New workspace description; "" clears it (optional, interactive, default: the current description)').option("--language <lang>","Scripting language: js, ts, or ts-strict (optional, interactive, default: the current language)").option("--visibility <mode>","Sharing mode: public or private; a move to another team makes the workspace private unless this says otherwise (optional, interactive, default: the current mode)").option("--yes",CONFIRM_MOVE_YES).option("--input <file>",INPUT_BODY).option("--explain",EXPLAIN).action(async(idArg,opts,cmd)=>{if(explained(cmd,UPDATE_DOC12))return;let globals=cmd.optsWithGlobals(),client=await apiClient(globals.instance),resolved=await resolveParams(["team","workspace"],{team:opts.team??globals.team,workspace:idArg??globals.workspace},{client,interactive:canPrompt(),missing:MISSING_WORKSPACE,...idArg===void 0?{}:{blame:BLAME_WORKSPACE}}),teamId=resolved.team??"",workspaceId=resolved.workspace??"",{name,description,language,visibility}=opts,interactive=[name,description,language,visibility].every(v2=>v2===void 0)&&opts.input===void 0&&canPrompt(),located=await locateWorkspace(client,teamId,workspaceId);located||fail(EXIT.NOT_FOUND,"NOT_FOUND",`Workspace '${workspaceId}' is not in team '${teamId}', or in any other team you are a member of.`,{status:404});let current=located.workspace,moving=located.teamId!==teamId?located:void 0;moving&&(opts.team===void 0&&fail(EXIT.USAGE,"TEAM_MISMATCH",`Workspace "${moving.workspace.name}" is in team ${teamLabel(moving)}, but this run took --team ${teamId} from a default rather than the flag, and only the flag can move a workspace.`,{hint:`Pass --team ${moving.teamId} to update it where it is, or --team ${teamId} to move it there.`}),await confirmMove(moving,teamId,opts.yes===!0));let body;if(opts.input)body=assertWorkspaceBody(validate(updateBodySchema12,readInput(opts.input)));else{if(interactive){let walked=await fillUpdateBody2(current,!!moving);name=walked.name,description=walked.description,language=walked.language,visibility=walked.visibility}else!moving&&!name&&description===void 0&&!language&&!visibility&&failNothingToUpdate(["--name","--description","--language","--visibility","--input"]),name||(name=current.name),description??=current.description;body=assertWorkspaceBody(validate(updateBodySchema12,stripUndefined({name,description,language,visibility})))}moving&¤t.visibility==="public"&&body.visibility===void 0&&warnLine(`\u26A0 Moving a workspace makes it private unless the update names a visibility.
|
|
1390
|
-
Pass --visibility public to keep it public.`);let{response,error:error51}=await withSpinner("Updating workspace",()=>client.PUT("/v1/team/{teamId}/workspace/{workspaceId}",{params:{path:{teamId,workspaceId}},body}));response.ok||apiFail(response.status,error51);let sent=body;await syncWorkspaceSettings(workspaceId,{...sent.name===void 0?{}:{name:sent.name},...sent.language===void 0?{}:{language:sent.language}}),okMutation("Workspace updated",{updated:!0,id:workspaceId})}),ws.command("delete").description("Delete a workspace").argument("[workspaceId]",SCOPE_WORKSPACE_DESTRUCTIVE).option("--team <teamId>",SCOPE_TEAM_DESTRUCTIVE).option("--yes",CONFIRM_YES).option("--explain",EXPLAIN).action(async(idArg,opts,cmd)=>{if(explained(cmd,DELETE_DOC11))return;let globals=cmd.optsWithGlobals(),client=await apiClient(globals.instance),resolved=await resolveParams(["team","workspace"],{team:opts.team??globals.team,workspace:idArg??globals.workspace},{client,interactive:canPrompt(),useSession:canPrompt(),missing:MISSING_WORKSPACE,...idArg===void 0?{}:{blame:BLAME_WORKSPACE}}),teamId=resolved.team??"",workspaceId=resolved.workspace??"";opts.yes||(canPrompt()||failNeedsYes(`workspace ${workspaceId}`),await confirmDeletion4(client,teamId,workspaceId));let{response,error:error51}=await withSpinner("Deleting workspace",()=>client.DELETE("/v1/team/{teamId}/workspace/{workspaceId}",{params:{path:{teamId,workspaceId}}}));response.ok||await failDeletion2(client,response.status,error51,workspaceId),forgetWorkspaceLock(workspaceId);let removed=forgetScopeValue("workspace",workspaceId,["environment"]);if(removed.length>0){let what=removed.includes("environment")?"workspace and its environment":"workspace";prompts().note(`Removed the deleted ${what} from this shell's session defaults (${CLI} cli set-session to store another).`)}okMutation("Workspace deleted",{deleted:!0,id:workspaceId})}),ws}var CHECK_DOC=defineCommandDoc("workspace-lock check",{rules:["The workspace is -w and there is no positional argument: a workspace holds at most one lock, so there is nothing to name."],notes:["Reports who holds the lock, how they took it, and when the lease lapses. A held lock is exit 0 \u2014 the read succeeded \u2014 and leads with a neutral `\u2139 Workspace lock is taken.` above the rows.","Nobody holding it is exit 4 NO_WORKSPACE_LOCK, printed green with a \u2714: for a script polling for a free workspace that is the good answer, and the code is what to branch on."]}),TAKE_DOC=defineCommandDoc("workspace-lock take",{rules:["--force takes the lock even though another session holds it, which makes a browser tab lose edit control at once. Never pass it on your own when the holder is somebody else: stop and ask. A refusal naming you as the holder is the exception, and its hint says so.","--lock-id names the ID to take or renew rather than generating one, and it is the one place an explicit ID is stored for the rest of the shell session; every other command presents it and stores nothing."],notes:["Takes the lock and keeps it for the rest of the shell session, so the writes that follow renew it rather than taking their own. Re-running renews rather than replaces.","The document adds lockId, which no read reports, for --lock-id elsewhere.","Another holder is exit 1 WORKSPACE_LOCKED without --force.","A lock renews only through writes and lapses without them. Trust the lapse time the command prints over any number written down elsewhere."]}),RELEASE_DOC=defineCommandDoc("workspace-lock release",{rules:["--lock-id releases the lock of that ID rather than the one this shell took; the same flag every command accepts, read here whichever side of the verb it is on. Required when this shell holds none."],notes:["Only the session that took a lock can release it. A workspace nobody holds is exit 4; an ID that is not what holds the workspace is exit 1 WORKSPACE_LOCK_NOT_HELD, which means either another session of yours has it under a different ID or another user does \u2014 the refusal says which. Nothing is released either way.","Releasing early is the polite thing to do: the alternative is leaving somebody locked out until the lease lapses."]});function withScope8(cmd){return cmd.option("-w, --workspace <workspaceId>",SCOPE_WORKSPACE).option("--team <teamId>",SCOPE_TEAM_FILTER)}async function resolveScope11(globals){let client=await apiClient(globals.instance),resolved=await resolveParams(["workspace"],{workspace:globals.workspace,team:globals.team},{client,interactive:canPrompt()});return{client,workspace:resolved.workspace??""}}function lockReadFail(status,error51,workspaceId){let message=error51?.errorMessage??"";status===404&&/lock not found/i.test(message)&&fail(EXIT.NOT_FOUND,"NO_WORKSPACE_LOCK","Nobody holds the lock on this workspace.",{status,tone:"ok",hint:`Take it with \`${CLI} workspace-lock take -w ${workspaceId}\`.`}),apiFail(status,error51)}function renderLock(lock,me2,extra={}){return renderDetail({workspaceId:lock.workspaceId,source:lock.source,acquiredAt:lock.acquiredAt,expiresAt:expiryCell(lock.expiresAt),holder:holderCell(lock.holder,me2),...extra})}function workspaceLockCommand(){let lock=new Command("workspace-lock").alias("wl").description("Manage workspace locks");return withScope8(lock.command("check").description("Check who holds the workspace lock (exit 4 when nobody does)")).option("--explain",EXPLAIN).action(async(opts,cmd)=>{if(explained(cmd,CHECK_DOC))return;let globals=cmd.optsWithGlobals(),scope2=await resolveScope11(globals),result=await withSpinner("Reading the workspace lock",()=>readLock(scope2.client,scope2.workspace));result.lock||lockReadFail(result.status,result.error,scope2.workspace);let me2=isRaw()?void 0:await currentUser(scope2.client),lockDoc=result.lock;isRaw()||console.error("\u2139 Workspace lock is taken."),ok(lockDoc,{human:()=>renderLock(lockDoc,me2)})}),withScope8(lock.command("take").description("Take the workspace lock, or renew one this shell already holds; kept for the rest of the shell session")).option("--force","Take the lock even though another session holds it \u2014 a web application session loses edit control and is warned about unsaved changes (optional, interactive)").option("--explain",EXPLAIN).action(async(opts,cmd)=>{if(explained(cmd,TAKE_DOC))return;let globals=cmd.optsWithGlobals(),scope2=await resolveScope11(globals),lockId=explicitLockId()??ownStoredLock(scope2.workspace)?.lockId??newLockId(),result=await withSpinner("Taking the workspace lock",()=>takeLock(scope2.client,scope2.workspace,{lockId,force:opts.force}));if(result.conflict){let holder=result.conflict===!0?void 0:result.conflict;canPrompt()||lockedFail(holder,scope2.workspace,void 0,await currentUser(scope2.client)),await askLockConflict(holder,await currentUser(scope2.client),{allowUnlocked:!1})!=="force"&&fail(EXIT.CANCELLED,"CANCELLED","Cancelled."),result=await withSpinner("Taking the workspace lock",()=>takeLock(scope2.client,scope2.workspace,{lockId,force:!0}))}result.lock||apiFail(result.status,result.error),storeTaken(scope2.workspace,lockId,result.lock.expiresAt);let human=isRaw()?"":renderLock(result.lock,await currentUser(scope2.client),{lockId});okMutation("Workspace lock taken",{...result.lock,lockId},human),isRaw()||console.error(`Held for this shell session. Release it with \`${CLI} workspace-lock release -w ${scope2.workspace}\`.`)}),withScope8(lock.command("release").description("Release the workspace lock, rather than waiting for the lease to lapse")).option("--lock-id <lockId>","Lock ID to release; the same flag every command accepts, read here whichever side of the verb it is on (required unless this shell holds one, env SR_CONNECT_CLI_LOCK_ID, default: the lock this shell took)").option("--explain",EXPLAIN).action(async(opts,cmd)=>{if(explained(cmd,RELEASE_DOC))return;let globals=cmd.optsWithGlobals(),scope2=await resolveScope11(globals),stored=ownStoredLock(scope2.workspace,"read")?.lockId,lockId=opts.lockId??explicitLockId()??stored;lockId||fail(EXIT.USAGE,"USAGE_ERROR","No workspace lock to release: this shell holds none. Pass --lock-id, or set SR_CONNECT_CLI_LOCK_ID.");let result=await withSpinner("Releasing the workspace lock",()=>releaseLock(scope2.client,scope2.workspace,lockId));if(lockId===stored&&(result.ok||result.status===404)&&forgetWorkspaceLock(scope2.workspace),result.status===409){let holder=result.error?.lockedBy;releaseFail(holder,scope2.workspace,lockId,await currentUser(scope2.client))}result.ok||apiFail(result.status,result.error),okMutation("Workspace lock released",{deleted:!0,id:lockId,workspaceId:scope2.workspace},renderDetail({workspaceId:scope2.workspace}))}),lock}var refusedBy;function positionalNamed(cmd,flag){let named=cmd?.registeredArguments.find(argument=>`--${argument.name().replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase()}`===flag)?.name();if(named!==void 0)return named;let asPositional=SCOPE_POSITIONALS[flag];return asPositional!==void 0&&cmd?.registeredArguments.some(argument=>argument.name()===asPositional)?asPositional:void 0}var SCOPE_POSITIONALS={"-w":"workspaceId","--workspace":"workspaceId","-e":"environmentId","--env":"environmentId","--environment":"environmentId","--team":"teamId"};function scopeNamed(cmd,flag){if(SCOPE_POSITIONALS[flag]===void 0)return;let declared=(cmd?.options??[]).flatMap(option=>option.long!==void 0&&SCOPE_POSITIONALS[option.long]!==void 0?[option.long]:[]);return declared.length>0?declared:void 0}var MIN_SUFFIX_STEM=4;function suffixNamed(cmd,flag){let stem=flag.replace(/^--/,"");if(stem.length<MIN_SUFFIX_STEM)return;let matches=(cmd?.options??[]).map(option=>option.long).filter(long=>long!==void 0&&long!==flag&&long.endsWith(`-${stem}`));return matches.length===1?matches[0]:void 0}function nounOf2(name){return name.replace(/Id$/,"").replace(/([a-z0-9])([A-Z])/g,"$1 $2").toLowerCase()}function valuedOptions(cmd){return(cmd?.options??[]).filter(option=>(option.required||option.optional)&&option.long!==void 0).map(option=>option.long??"")}function usageErrorOf(err,cmd=refusedBy){let raw=err.message.replace(/^error: /,""),quoted=/'([^']+)'/.exec(raw)?.[1],flag=quoted===void 0?void 0:/--[a-z][a-z-]*/.exec(quoted)?.[0]??quoted,path2=cmd===void 0?void 0:commandPath2(cmd);switch(err.code){case"commander.missingMandatoryOptionValue":return new CliError(EXIT.USAGE,"USAGE_ERROR",`${flag??"An option"} is required.`,{hint:supplyHint({ask:"be asked for it"})});case"commander.optionMissingArgument":{let value=quoted===void 0?void 0:/<[^>]+>/.exec(quoted)?.[0];return new CliError(EXIT.USAGE,"USAGE_ERROR",`${flag??"The option"} needs a value${value?` (${value})`:""}.`)}case"commander.unknownOption":{let suggestion=/\(Did you mean ([^?]+)\?\)/.exec(raw)?.[1],options="Add --help to the command to list its options.",positional=quoted===void 0?void 0:positionalNamed(cmd,quoted),suffix=quoted===void 0?void 0:suffixNamed(cmd,quoted),scope2=quoted===void 0?void 0:scopeNamed(cmd,quoted),lead=positional!==void 0&&path2!==void 0?`The ${nounOf2(positional)} is the positional argument: ${path2} <${positional}>.`:scope2!==void 0?`This verb's scope ${scope2.length===1?"flag is":"flags are"} ${scope2.join(" and ")}.`:(suffix??suggestion)!==void 0?`Did you mean ${suffix??suggestion}?`:void 0;return new CliError(EXIT.USAGE,"USAGE_ERROR",`'${quoted??""}' is not an option here.`,{hint:lead===void 0?options:`${lead} ${options}`})}case"commander.excessArguments":{let options="Add --help to the command to list its options.";if(cmd!==void 0&&cmd.registeredArguments.length===0){let valued=valuedOptions(cmd),named=valued.length>0?`Name it with ${valued.join(" or ")}. `:"";return new CliError(EXIT.USAGE,"USAGE_ERROR",`'${path2??"The command"}' takes no positional arguments.`,{hint:`${named}${options}`})}return new CliError(EXIT.USAGE,"USAGE_ERROR",raw.charAt(0).toUpperCase()+raw.slice(1),{hint:options})}case"commander.unknownCommand":{let suggestion=/\(Did you mean ([^?]+)\?\)/.exec(raw)?.[1],groups=`\`${CLI}\` lists the groups, and a group run alone lists its verbs.`;return new CliError(EXIT.USAGE,"USAGE_ERROR",`'${quoted??""}' is not a command.`,{hint:suggestion?`Did you mean ${suggestion}? ${groups}`:groups})}case"commander.missingArgument":return new CliError(EXIT.USAGE,"USAGE_ERROR",`<${quoted??"argument"}> is required.`,{hint:supplyHint()});default:return new CliError(EXIT.USAGE,"USAGE_ERROR",raw.charAt(0).toUpperCase()+raw.slice(1))}}var program2=addGlobalOptions(new Command(CLI).description("CLI for ScriptRunner Connect")).exitOverride();program2.addCommand(apiConnectionCommand());program2.addCommand(appCommand());program2.addCommand(authCommand());program2.addCommand(cliCommand());program2.addCommand(connectorCommand());program2.addCommand(connectorSharingCommand());program2.addCommand(environmentCommand());program2.addCommand(environmentParameterCommand());program2.addCommand(eventListenerCommand());program2.addCommand(eventListenerTestPayloadCommand());program2.addCommand(eventQueueCommand());program2.addCommand(feedbackCommand());program2.addCommand(localWorkspaceCommand());program2.addCommand(logsCommand());program2.addCommand(packageCommand());program2.addCommand(workspaceReadmeCommand());program2.addCommand(workspaceReleaseCommand());program2.addCommand(scheduledTriggerCommand());program2.addCommand(scriptCommand());program2.addCommand(teamCommand());program2.addCommand(tempRemoteWorkspaceCommand());program2.addCommand(templateCommand());program2.addCommand(workspaceCommand());program2.addCommand(workspaceLockCommand());function overrideExits(cmd){cmd.exitOverride(err=>{throw refusedBy=cmd,err}),cmd.configureOutput({outputError:()=>{},writeErr:str=>{process.stdout.write(str)}});for(let sub of cmd.commands)overrideExits(sub)}overrideExits(program2);applyHelpConventions(program2);program2.addHelpText("after",rootHelpFooter());function commandPath2(cmd){let names=[];for(let c=cmd;c.parent;c=c.parent)names.unshift(c.name());return names.join(" ")}program2.hook("preAction",(thisCommand,actionCommand)=>{let globals=thisCommand.optsWithGlobals();configureRawMode({enabled:!!globals.raw}),setCommandPath(commandPath2(actionCommand)),configureAgentMode({enabled:!!globals.agent}),setPromptsAllowed(globals.prompts!==!1&&!process.env.SR_CONNECT_CLI_NO_PROMPTS),setOutputCopy(globals.copyOutputToFile),configureSession({instance:globals.instance,enabled:globals.session!==!1}),configureRecorder({enabled:globals.recordApiCalls!==!1,instance:globals.instance}),configureWorkspaceLocking({enabled:globals.lock!==!1,lockId:globals.lockId}),configureLocalSync({enabled:globals.localSync!==!1,instance:globals.instance}),configureLocalWorkspaceScope({enabled:globals.localWorkspace!==!1,instance:globals.instance}),configureVersionGate({enabled:globals.versionGate!==!1}),configureCrashReports({enabled:globals.crashReports!==!1,instance:globals.instance}),configureAgenticFeedback({enabled:globals.agenticFeedback!==!1})});try{ignoreBrokenPipe(),warnIfNodeUnsupported(),configureRawMode({enabled:process.argv.includes("--raw")});let commandNames=program2.commands.flatMap(c=>[c.name(),...c.aliases()]);assertOutputCopyValue(process.argv,commandNames),assertVersionFlagIsRoot(process.argv,commandNames),configureUpdateCheck({enabled:!process.argv.includes("--no-update-check")}),configureCrashReports({enabled:!process.argv.includes("--no-crash-reports")}),asksForUpdates(process.argv)||(printUpdateNotice(),startUpdateCheck()),await program2.parseAsync(process.argv),reportOutputCopy(),await flushOutput(),process.exit(EXIT.OK)}catch(err){if(err instanceof CliError){err.exitCode===EXIT.NOT_FOUND&&warnInheritedWorkspace();let code2=reportError(err);reportOutputCopy(),await offerCrashReport(err),await flushOutput(),process.exit(code2)}if(err instanceof CommanderError){(err.code==="commander.helpDisplayed"||err.code==="commander.version"||err.code==="commander.help")&&(await flushOutput(),process.exit(err.exitCode===1?0:err.exitCode));let code2=reportError(usageErrorOf(err));reportOutputCopy(),await flushOutput(),process.exit(code2)}let message=err instanceof Error?err.message:String(err),code=reportError(new CliError(EXIT.API_ERROR,"UNEXPECTED_ERROR",message));reportOutputCopy(),await offerCrashReport(err),await flushOutput(),process.exit(code)}
|
|
1389
|
+
Remote file system access is turned off with it, and any temporary credentials stop working.`),!yes&&(canPrompt()||fail(EXIT.USAGE,"CONFIRMATION_REQUIRED",`Moving workspace "${moving.workspace.name}" from team ${from} to ${teamId} clears every connector attachment in every environment and turns remote file system access off, and moving it back undoes neither. Re-run with --yes to confirm.`,{hint:`Pass --team ${moving.teamId} to update it where it is instead.`}),await prompts().confirm("Move it to that team?",!1)||fail(EXIT.CANCELLED,"CANCELLED","Cancelled."))}var LIST_DOC13=defineCommandDoc("workspace list",{rules:["The team is --team; the workspace is this group's resource, so there is no -w here and no positional argument."],notes:["Every workspace of the team, yours and the public ones you are not a member of alike."]}),GET_DOC12=defineCommandDoc("workspace get",{rules:["The workspace is the positional argument and there is no -w here, the workspace being what this verb reads rather than where it looks. --team is optional: every workspace read is keyed by team, and a team that was not given is found by searching the ones you are a member of, which is one request per team until the workspace turns up."],notes:["Reports the language, which is worth reading after creating from a template or another workspace: either brings its own, and ts-strict is the one to prefer.","Also reports remoteWorkspaceEnabled, which a move between teams turns off."]}),CHECK_PACKAGE_VERSIONS_DOC=defineCommandDoc("workspace check-package-versions",{rules:["The workspace is -w and the team is --team, which is only the way to reach it; there is no positional argument.","--outdated-only keeps the packages a newer version was found for. The summary counts the whole workspace either way.","--include-prereleases compares against the newest version published at all rather than the newest stable one."],notes:["One request to the API for the packages, then one lookup per package on the public NPM registry, unauthenticated and throttled. Nothing is written and no version is changed.","Every row carries status: outdated (a newer version is published), current (nothing newer is), unknown (the registry did not answer, or a version on either side cannot be ranked) or unpublished (the registry has no package by that name, which is what a private one looks like from here). updateAvailable is true for outdated and for nothing else.","A registry nobody could reach is exit 0 with a warning and unknown rows: the packages and the versions the workspace stores are still the answer, and silence is never reported as up to date.","The versions reported are the workspace's own, which are HEAD's. An environment running a release keeps the dependencies that release captured, and nothing here reports those.","Reading is all this does. The version of one package is moved with package update."]}),DELETE_DOC11=defineCommandDoc("workspace delete",{rules:["The workspace is the positional argument and the team is --team.","--yes skips the confirmation, and is required without a terminal."],notes:["Deletes the workspace with its environments, scripts, API connections, event listeners, scheduled triggers and releases; anything running from a release stops.","The lock this shell holds is presented and never stands in the way. Another holder is exit 1 WORKSPACE_LOCKED naming them, with workspace-lock check and workspace-lock take --force in the hint.","Dropped from this shell's session defaults afterwards, along with the environment the record named."]}),CREATE_DOC12=defineCommandDoc("workspace create",{schema:createBodySchema12,body:{name:"Order sync",description:"Keeps Jira and the order system in step.",sourceWorkspaceId:"<workspaceId>",sourceTemplateId:"<templateId>",language:"ts-strict",visibility:"private"},rules:[`name: ${WORKSPACE_NAME_FORMAT}.`,`description: free text, up to ${MAX_WORKSPACE_DESCRIPTION} characters.`,`sourceWorkspaceId (--source-workspace-id as a flag) copies another workspace; sourceTemplateId (--source-template-id) creates from a published template, as listed by ${CLI} template list; at most one of the two. Either brings its own language, and language is then ignored: read the language back with ${CLI} workspace get and upgrade it with update. A copy has one environment, the default one, holding the source's default environment's parameters with each default value as the value; parameter values, other environments and releases are not copied.`,`language: ${LANGUAGES.join(", ")}; API default ts; ts-strict is the one to prefer.`,`visibility: ${VISIBILITY_MEANINGS}; API default private. Creating a public one needs you to be an admin of the team, and a member who is not gets exit 1 "User is not in any of the required roles: ADMIN,SUPER_ADMIN"; seeing one needs nothing, which is what public means.`,"The team is --team, never a body key."]}),UPDATE_DOC12=defineCommandDoc("workspace update",{schema:updateBodySchema12,body:{name:"Order sync",description:"Keeps Jira and the order system in step.",language:"ts-strict",visibility:"private"},rules:[`name is required even when it does not change: send the current one back. ${WORKSPACE_NAME_FORMAT}.`,`description is cleared when the body omits it, so send the current one back to keep it; "" clears it too. Up to ${MAX_WORKSPACE_DESCRIPTION} characters. The flags path reads the workspace and carries it forward, so only a body given here has to.`,`language: ${LANGUAGES.join(", ")}; omitted, the current one is kept.`,`visibility: ${VISIBILITIES.join(" or ")}; omitted, the current one is kept, except when --team moves the workspace to another team, where a body that does not name one makes it private. Changing it needs you to be an admin of the team.`,"The sources a workspace was created from cannot change. --team names the workspace's team, or a new team to move it to; it is not a body key.","A --team that names another team moves the workspace, which clears every connector attachment in every environment and turns remote file system access off \u2014 neither undone by moving it back. So it takes --yes without a terminal (exit 2 CONFIRMATION_REQUIRED otherwise) and a confirmation with one, and only a typed flag can move at all: a team from an environment variable, a clone or the session record is exit 2 TEAM_MISMATCH. An --input body is held to both, the team being resolved outside it."],notes:["--yes is for the move alone: an ordinary update never needs it, and passing it to one is accepted and ignored.","The workspace is found by looking through your teams for the one holding it, which is named on stderr. Only a move pays for that search \u2014 an ordinary update reads the workspace once. An ID in none of your teams is exit 4.","A workspace published as a template stays one: the template flag is not part of this request, and editing such a workspace needs permission to author templates, which the API answers 403 for when you do not have it."]});function assertOneSource2(opts){opts.sourceWorkspaceId&&opts.sourceTemplateId&&fail(EXIT.USAGE,"USAGE_ERROR","--source-workspace-id and --source-template-id cannot be combined.")}async function fillCreateBody4(client,teamId,opts){let sourceWorkspaceId=opts.sourceWorkspaceId;!sourceWorkspaceId&&!opts.sourceTemplateId&&await prompts().confirm("Clone from an existing workspace?",!1)&&(sourceWorkspaceId=(await resolveParams(["workspace"],{team:teamId},{client,interactive:!0})).workspace);let name=opts.name??await prompts().text("Workspace name"),description=opts.description;description===void 0&&(description=await prompts().text("Workspace description, optional (empty for none)",{allowEmpty:!0})||void 0);let language=opts.language??(sourceWorkspaceId||opts.sourceTemplateId?void 0:await prompts().select("Scripting language",LANGUAGE_CHOICES)),visibility=opts.visibility??await prompts().select("Visibility",VISIBILITY_CHOICES);return stripUndefined({name,description,sourceWorkspaceId,sourceTemplateId:opts.sourceTemplateId,language,visibility})}async function locateWorkspace(client,teamId,workspaceId){let direct=teamId===void 0?void 0:await withSpinner("Fetching workspace",()=>client.GET("/v1/team/{teamId}/workspace/{workspaceId}",{params:{path:{teamId,workspaceId}}}));return direct?.response.ok&&direct.data?{workspace:direct.data,teamId:teamId??""}:(direct&&direct.response.status!==404&&apiFail(direct.response.status,direct.error),withSpinner("Looking for the workspace in your other teams",async()=>{let teams=await client.GET("/v1/teams");(!teams.response.ok||!teams.data)&&apiFail(teams.response.status,teams.error);for(let team of teams.data.teams){if(!team.id||team.id===teamId)continue;let list=await client.GET("/v1/team/{teamId}/workspaces",{params:{path:{teamId:team.id}}});(!list.response.ok||!list.data)&&apiFail(list.response.status,list.error);let found2=list.data.workspaces.find(w=>w.id===workspaceId);if(found2)return{workspace:found2,teamId:team.id,...team.name?{teamName:team.name}:{}}}}))}async function fetchWorkspace(client,teamId,workspaceId){let{data,response,error:error51}=await withSpinner("Fetching workspace",()=>client.GET("/v1/team/{teamId}/workspace/{workspaceId}",{params:{path:{teamId,workspaceId}}}));return(!response.ok||!data)&&apiFail(response.status,error51),data}async function fillUpdateBody2(current,moving){let name=await prompts().text("Workspace name",{initial:current.name}),description=current.description,currently=current.description?`(currently "${current.description}")`:"(currently unset)";await prompts().confirm(`Change the description? ${currently}`,!1)&&(description=await prompts().text("Description",{allowEmpty:!0}));let language;await prompts().confirm("Change the scripting language?",!1)&&(language=await prompts().select("Scripting language",LANGUAGE_CHOICES));let visibility;return moving?visibility=await prompts().select("Visibility",VISIBILITY_CHOICES,{initial:current.visibility}):await prompts().confirm("Change the visibility?",!1)&&(visibility=await prompts().select("Visibility",VISIBILITY_CHOICES)),{name,...description===void 0?{}:{description},...language===void 0?{}:{language},...visibility===void 0?{}:{visibility}}}async function confirmDeletion4(client,teamId,workspaceId){let current=await fetchWorkspace(client,teamId,workspaceId);prompts().note(["Deleting removes the workspace from the whole team, and everything in it goes with it:","environments, scripts, API connections, event listeners, scheduled triggers \u2014 and releases,","so anything still running from one stops immediately.",`It disappears from ${CLI} workspace list, and every later request naming it is a 404.`].join(`
|
|
1390
|
+
`)),await prompts().confirm(`Delete workspace "${current.name}" (${workspaceId})? This is irreversible.`)||fail(EXIT.CANCELLED,"CANCELLED","Deletion cancelled.")}async function failDeletion2(client,status,error51,workspaceId){if(status===409){let holder=error51?.lockedBy;lockedFail(holder,workspaceId,`See who holds it with \`${CLI} workspace-lock check -w ${workspaceId}\`, then take it with \`${CLI} workspace-lock take -w ${workspaceId} --force\` and delete again.`,await currentUser(client))}apiFail(status,error51)}var REGISTRY_CONCURRENCY=5;function packageCount(count){return`${count} ${count===1?"package":"packages"}`}function workspaceCommand(){let ws=new Command("workspace").description("Manage workspaces");return ws.command("list").description("List workspaces").option("--team <teamId>",SCOPE_TEAM).option("--explain",EXPLAIN).action(async(opts,cmd)=>{if(explained(cmd,LIST_DOC13))return;let globals=cmd.optsWithGlobals(),client=await apiClient(globals.instance),resolved=await resolveParams(["team"],{team:opts.team},{client,interactive:canPrompt()}),{data,response,error:error51}=await withSpinner("Fetching workspaces",()=>client.GET("/v1/team/{teamId}/workspaces",{params:{path:{teamId:resolved.team??""}}}));(!response.ok||!data)&&apiFail(response.status,error51),ok(data,{human:d=>({workspaces:tableRows(["id","name","description","language","remoteWorkspaceEnabled","visibility","incomingApps","outgoingApps","createdFromTemplate"],d.workspaces.map(w=>({...w,incomingApps:w.incomingApps.join(", "),outgoingApps:w.outgoingApps.join(", ")})))})})}),ws.command("create").description("Create a workspace, optionally from another workspace or a published template").option("--team <teamId>",SCOPE_TEAM).option("--name <name>","Workspace name (required unless --input, interactive)").option("--description <text>","Workspace description (optional, interactive)").option("--source-workspace-id <id>","Clone from the specified workspace, whose language is used (optional, interactive, exclusive with --source-template-id)").option("--source-template-id <id>",`Create from the specified published template, whose language is used, as listed by ${CLI} template list (optional, exclusive with --source-workspace-id)`).option("--language <lang>","Scripting language: js, ts, or ts-strict (optional, interactive, API default: ts, ignored with --source-workspace-id or --source-template-id)").option("--visibility <mode>","Sharing mode: public or private (optional, interactive, API default: private)").option("--input <file>",INPUT_BODY).option("--explain",EXPLAIN).action(async(opts,cmd)=>{if(explained(cmd,CREATE_DOC12))return;let globals=cmd.optsWithGlobals();assertOneSource2(opts);let client=await apiClient(globals.instance),teamId=(await resolveParams(["team"],{team:opts.team??globals.team},{client,interactive:canPrompt()})).team??"",rawBody=opts.input?readInput(opts.input):!opts.name&&canPrompt()?await fillCreateBody4(client,teamId,opts):stripUndefined({name:opts.name,description:opts.description,sourceWorkspaceId:opts.sourceWorkspaceId,sourceTemplateId:opts.sourceTemplateId,language:assertChoice("--language",opts.language,LANGUAGES),visibility:assertChoice("--visibility",opts.visibility,VISIBILITIES)}),body=assertWorkspaceBody(validate(createBodySchema12,rawBody)),{data,response,error:error51}=await withSpinner("Creating workspace",()=>client.POST("/v1/team/{teamId}/workspace",{params:{path:{teamId}},body}));(!response.ok||!data)&&apiFail(response.status,error51),okMutation("Workspace created",data,data)}),ws.command("get").description("Get a single workspace").argument("[workspaceId]",SCOPE_WORKSPACE).option("--team <teamId>",SCOPE_TEAM_SEARCHED).option("--explain",EXPLAIN).action(async(idArg,opts,cmd)=>{if(explained(cmd,GET_DOC12))return;let globals=cmd.optsWithGlobals(),client=await apiClient(globals.instance),resolved=await resolveParams(["workspace"],{team:opts.team??globals.team,workspace:idArg??globals.workspace},{client,interactive:canPrompt(),missing:MISSING_WORKSPACE,...idArg===void 0?{}:{blame:BLAME_WORKSPACE}}),workspaceId=resolved.workspace??"",teamId=resolved.team,located=teamId===void 0?await locateWorkspace(client,void 0,workspaceId):void 0;teamId===void 0&&!located&&fail(EXIT.NOT_FOUND,"NOT_FOUND",`No workspace ${workspaceId} in any of your teams.`,{status:404});let data=located?located.workspace:await fetchWorkspace(client,teamId??"",workspaceId);ok(data,{human:d=>({...d,incomingApps:d.incomingApps.join(", "),outgoingApps:d.outgoingApps.join(", ")})})}),ws.command("update").description("Update a workspace").argument("[workspaceId]","Workspace ID (required, interactive, session default, env SR_CONNECT_CLI_WORKSPACE)").option("--team <teamId>","Team ID \u2014 the workspace's team, or a new team to move it to; only the flag itself can move, a session default or environment variable never does (required, interactive, session default, env SR_CONNECT_CLI_TEAM)").option("--name <name>","New workspace name (optional, interactive, default: the current name)").option("--description <text>",'New workspace description; "" clears it (optional, interactive, default: the current description)').option("--language <lang>","Scripting language: js, ts, or ts-strict (optional, interactive, default: the current language)").option("--visibility <mode>","Sharing mode: public or private; a move to another team makes the workspace private unless this says otherwise (optional, interactive, default: the current mode)").option("--yes",CONFIRM_MOVE_YES).option("--input <file>",INPUT_BODY).option("--explain",EXPLAIN).action(async(idArg,opts,cmd)=>{if(explained(cmd,UPDATE_DOC12))return;let globals=cmd.optsWithGlobals(),client=await apiClient(globals.instance),resolved=await resolveParams(["team","workspace"],{team:opts.team??globals.team,workspace:idArg??globals.workspace},{client,interactive:canPrompt(),missing:MISSING_WORKSPACE,...idArg===void 0?{}:{blame:BLAME_WORKSPACE}}),teamId=resolved.team??"",workspaceId=resolved.workspace??"",{name,description,language,visibility}=opts,interactive=[name,description,language,visibility].every(v2=>v2===void 0)&&opts.input===void 0&&canPrompt(),located=await locateWorkspace(client,teamId,workspaceId);located||fail(EXIT.NOT_FOUND,"NOT_FOUND",`Workspace '${workspaceId}' is not in team '${teamId}', or in any other team you are a member of.`,{status:404});let current=located.workspace,moving=located.teamId!==teamId?located:void 0;moving&&(opts.team===void 0&&fail(EXIT.USAGE,"TEAM_MISMATCH",`Workspace "${moving.workspace.name}" is in team ${teamLabel(moving)}, but this run took --team ${teamId} from a default rather than the flag, and only the flag can move a workspace.`,{hint:`Pass --team ${moving.teamId} to update it where it is, or --team ${teamId} to move it there.`}),await confirmMove(moving,teamId,opts.yes===!0));let body;if(opts.input)body=assertWorkspaceBody(validate(updateBodySchema12,readInput(opts.input)));else{if(interactive){let walked=await fillUpdateBody2(current,!!moving);name=walked.name,description=walked.description,language=walked.language,visibility=walked.visibility}else!moving&&!name&&description===void 0&&!language&&!visibility&&failNothingToUpdate(["--name","--description","--language","--visibility","--input"]),name||(name=current.name),description??=current.description;body=assertWorkspaceBody(validate(updateBodySchema12,stripUndefined({name,description,language,visibility})))}moving&¤t.visibility==="public"&&body.visibility===void 0&&warnLine(`\u26A0 Moving a workspace makes it private unless the update names a visibility.
|
|
1391
|
+
Pass --visibility public to keep it public.`);let{response,error:error51}=await withSpinner("Updating workspace",()=>client.PUT("/v1/team/{teamId}/workspace/{workspaceId}",{params:{path:{teamId,workspaceId}},body}));response.ok||apiFail(response.status,error51);let sent=body;await syncWorkspaceSettings(workspaceId,{...sent.name===void 0?{}:{name:sent.name},...sent.language===void 0?{}:{language:sent.language}}),okMutation("Workspace updated",{updated:!0,id:workspaceId})}),ws.command("delete").description("Delete a workspace").argument("[workspaceId]",SCOPE_WORKSPACE_DESTRUCTIVE).option("--team <teamId>",SCOPE_TEAM_DESTRUCTIVE).option("--yes",CONFIRM_YES).option("--explain",EXPLAIN).action(async(idArg,opts,cmd)=>{if(explained(cmd,DELETE_DOC11))return;let globals=cmd.optsWithGlobals(),client=await apiClient(globals.instance),resolved=await resolveParams(["team","workspace"],{team:opts.team??globals.team,workspace:idArg??globals.workspace},{client,interactive:canPrompt(),useSession:canPrompt(),missing:MISSING_WORKSPACE,...idArg===void 0?{}:{blame:BLAME_WORKSPACE}}),teamId=resolved.team??"",workspaceId=resolved.workspace??"";opts.yes||(canPrompt()||failNeedsYes(`workspace ${workspaceId}`),await confirmDeletion4(client,teamId,workspaceId));let{response,error:error51}=await withSpinner("Deleting workspace",()=>client.DELETE("/v1/team/{teamId}/workspace/{workspaceId}",{params:{path:{teamId,workspaceId}}}));response.ok||await failDeletion2(client,response.status,error51,workspaceId),forgetWorkspaceLock(workspaceId);let removed=forgetScopeValue("workspace",workspaceId,["environment"]);if(removed.length>0){let what=removed.includes("environment")?"workspace and its environment":"workspace";prompts().note(`Removed the deleted ${what} from this shell's session defaults (${CLI} cli set-session to store another).`)}okMutation("Workspace deleted",{deleted:!0,id:workspaceId})}),ws.command("check-package-versions").description("Check the packages a workspace depends on against the versions NPM publishes").option("-w, --workspace <workspaceId>",SCOPE_WORKSPACE).option("--team <teamId>",SCOPE_TEAM_FILTER).option("--outdated-only","Report only the packages a newer version was found for (optional)").option("--include-prereleases","Compare against the newest version published at all rather than the newest stable one (optional)").option("--explain",EXPLAIN).action(async(opts,cmd)=>{if(explained(cmd,CHECK_PACKAGE_VERSIONS_DOC))return;let globals=cmd.optsWithGlobals(),client=await apiClient(globals.instance),workspaceId=(await resolveParams(["workspace"],{workspace:globals.workspace,team:globals.team},{client,interactive:canPrompt()})).workspace??"",{data,response,error:error51}=await withSpinner("Fetching packages",()=>client.GET("/v1/workspace/{workspaceId}/packages",{params:{path:{workspaceId}}}));(!response.ok||!data)&&apiFail(response.status,error51);let rows2=data.packages.length===0?[]:await withSpinner("Checking the NPM registry",()=>throttleAll(REGISTRY_CONCURRENCY,data.packages.map(pkg=>async()=>({id:pkg.id,name:pkg.name,type:pkg.type,required:pkg.required,version:pkg.version,...versionCheck(pkg.version,await fetchVersions(pkg.name),{includePrereleases:!!opts.includePrereleases})})))),count=status=>rows2.filter(row=>row.status===status).length,summary={checked:rows2.length,outdated:count("outdated"),current:count("current"),unknown:count("unknown"),unpublished:count("unpublished")},packages=opts.outdatedOnly?rows2.filter(row=>row.updateAvailable):rows2;if(ok({workspaceId,packages,summary},{human:d=>({packages:d.packages.map(row=>({id:row.id,name:row.name,version:row.version,latest:row.latest??"\u2014",update:row.updateAvailable?"yes":"no",status:row.status,type:row.type,required:row.required?"yes":"no"}))})}),summary.unknown>0){let them=summary.unknown===1?"it":"them";warnLine(`\u26A0 ${packageCount(summary.unknown)} could not be checked \u2014 the NPM registry did not answer for ${them}.`)}if(!isRaw()&&summary.checked>0){let have=summary.outdated===1?"has":"have",compared=summary.checked-summary.unknown;summary.outdated>0?noteLine(`\u2714 ${summary.outdated} of ${packageCount(summary.checked)} ${have} a newer version published (${CLI} package update moves one).`):summary.unknown===0?noteLine("\u2714 Nothing checked is behind what the NPM registry publishes."):compared>0&¬eLine(`\u2139 Nothing the registry answered for is behind what it publishes \u2014 ${packageCount(compared)} of ${summary.checked}.`)}}),ws}var CHECK_DOC=defineCommandDoc("workspace-lock check",{rules:["The workspace is -w and there is no positional argument: a workspace holds at most one lock, so there is nothing to name."],notes:["Reports who holds the lock, how they took it, and when the lease lapses. A held lock is exit 0 \u2014 the read succeeded \u2014 and leads with a neutral `\u2139 Workspace lock is taken.` above the rows.","Nobody holding it is exit 4 NO_WORKSPACE_LOCK, printed green with a \u2714: for a script polling for a free workspace that is the good answer, and the code is what to branch on."]}),TAKE_DOC=defineCommandDoc("workspace-lock take",{rules:["--force takes the lock even though another session holds it, which makes a browser tab lose edit control at once. Never pass it on your own when the holder is somebody else: stop and ask. A refusal naming you as the holder is the exception, and its hint says so.","--lock-id names the ID to take or renew rather than generating one, and it is the one place an explicit ID is stored for the rest of the shell session; every other command presents it and stores nothing."],notes:["Takes the lock and keeps it for the rest of the shell session, so the writes that follow renew it rather than taking their own. Re-running renews rather than replaces.","The document adds lockId, which no read reports, for --lock-id elsewhere.","Another holder is exit 1 WORKSPACE_LOCKED without --force.","A lock renews only through writes and lapses without them. Trust the lapse time the command prints over any number written down elsewhere."]}),RELEASE_DOC=defineCommandDoc("workspace-lock release",{rules:["--lock-id releases the lock of that ID rather than the one this shell took; the same flag every command accepts, read here whichever side of the verb it is on. Required when this shell holds none."],notes:["Only the session that took a lock can release it. A workspace nobody holds is exit 4; an ID that is not what holds the workspace is exit 1 WORKSPACE_LOCK_NOT_HELD, which means either another session of yours has it under a different ID or another user does \u2014 the refusal says which. Nothing is released either way.","Releasing early is the polite thing to do: the alternative is leaving somebody locked out until the lease lapses."]});function withScope8(cmd){return cmd.option("-w, --workspace <workspaceId>",SCOPE_WORKSPACE).option("--team <teamId>",SCOPE_TEAM_FILTER)}async function resolveScope11(globals){let client=await apiClient(globals.instance),resolved=await resolveParams(["workspace"],{workspace:globals.workspace,team:globals.team},{client,interactive:canPrompt()});return{client,workspace:resolved.workspace??""}}function lockReadFail(status,error51,workspaceId){let message=error51?.errorMessage??"";status===404&&/lock not found/i.test(message)&&fail(EXIT.NOT_FOUND,"NO_WORKSPACE_LOCK","Nobody holds the lock on this workspace.",{status,tone:"ok",hint:`Take it with \`${CLI} workspace-lock take -w ${workspaceId}\`.`}),apiFail(status,error51)}function renderLock(lock,me2,extra={}){return renderDetail({workspaceId:lock.workspaceId,source:lock.source,acquiredAt:lock.acquiredAt,expiresAt:expiryCell(lock.expiresAt),holder:holderCell(lock.holder,me2),...extra})}function workspaceLockCommand(){let lock=new Command("workspace-lock").alias("wl").description("Manage workspace locks");return withScope8(lock.command("check").description("Check who holds the workspace lock (exit 4 when nobody does)")).option("--explain",EXPLAIN).action(async(opts,cmd)=>{if(explained(cmd,CHECK_DOC))return;let globals=cmd.optsWithGlobals(),scope2=await resolveScope11(globals),result=await withSpinner("Reading the workspace lock",()=>readLock(scope2.client,scope2.workspace));result.lock||lockReadFail(result.status,result.error,scope2.workspace);let me2=isRaw()?void 0:await currentUser(scope2.client),lockDoc=result.lock;isRaw()||console.error("\u2139 Workspace lock is taken."),ok(lockDoc,{human:()=>renderLock(lockDoc,me2)})}),withScope8(lock.command("take").description("Take the workspace lock, or renew one this shell already holds; kept for the rest of the shell session")).option("--force","Take the lock even though another session holds it \u2014 a web application session loses edit control and is warned about unsaved changes (optional, interactive)").option("--explain",EXPLAIN).action(async(opts,cmd)=>{if(explained(cmd,TAKE_DOC))return;let globals=cmd.optsWithGlobals(),scope2=await resolveScope11(globals),lockId=explicitLockId()??ownStoredLock(scope2.workspace)?.lockId??newLockId(),result=await withSpinner("Taking the workspace lock",()=>takeLock(scope2.client,scope2.workspace,{lockId,force:opts.force}));if(result.conflict){let holder=result.conflict===!0?void 0:result.conflict;canPrompt()||lockedFail(holder,scope2.workspace,void 0,await currentUser(scope2.client)),await askLockConflict(holder,await currentUser(scope2.client),{allowUnlocked:!1})!=="force"&&fail(EXIT.CANCELLED,"CANCELLED","Cancelled."),result=await withSpinner("Taking the workspace lock",()=>takeLock(scope2.client,scope2.workspace,{lockId,force:!0}))}result.lock||apiFail(result.status,result.error),storeTaken(scope2.workspace,lockId,result.lock.expiresAt);let human=isRaw()?"":renderLock(result.lock,await currentUser(scope2.client),{lockId});okMutation("Workspace lock taken",{...result.lock,lockId},human),isRaw()||console.error(`Held for this shell session. Release it with \`${CLI} workspace-lock release -w ${scope2.workspace}\`.`)}),withScope8(lock.command("release").description("Release the workspace lock, rather than waiting for the lease to lapse")).option("--lock-id <lockId>","Lock ID to release; the same flag every command accepts, read here whichever side of the verb it is on (required unless this shell holds one, env SR_CONNECT_CLI_LOCK_ID, default: the lock this shell took)").option("--explain",EXPLAIN).action(async(opts,cmd)=>{if(explained(cmd,RELEASE_DOC))return;let globals=cmd.optsWithGlobals(),scope2=await resolveScope11(globals),stored=ownStoredLock(scope2.workspace,"read")?.lockId,lockId=opts.lockId??explicitLockId()??stored;lockId||fail(EXIT.USAGE,"USAGE_ERROR","No workspace lock to release: this shell holds none. Pass --lock-id, or set SR_CONNECT_CLI_LOCK_ID.");let result=await withSpinner("Releasing the workspace lock",()=>releaseLock(scope2.client,scope2.workspace,lockId));if(lockId===stored&&(result.ok||result.status===404)&&forgetWorkspaceLock(scope2.workspace),result.status===409){let holder=result.error?.lockedBy;releaseFail(holder,scope2.workspace,lockId,await currentUser(scope2.client))}result.ok||apiFail(result.status,result.error),okMutation("Workspace lock released",{deleted:!0,id:lockId,workspaceId:scope2.workspace},renderDetail({workspaceId:scope2.workspace}))}),lock}var refusedBy;function positionalNamed(cmd,flag){let named=cmd?.registeredArguments.find(argument=>`--${argument.name().replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase()}`===flag)?.name();if(named!==void 0)return named;let asPositional=SCOPE_POSITIONALS[flag];return asPositional!==void 0&&cmd?.registeredArguments.some(argument=>argument.name()===asPositional)?asPositional:void 0}var SCOPE_POSITIONALS={"-w":"workspaceId","--workspace":"workspaceId","-e":"environmentId","--env":"environmentId","--environment":"environmentId","--team":"teamId"};function scopeNamed(cmd,flag){if(SCOPE_POSITIONALS[flag]===void 0)return;let declared=(cmd?.options??[]).flatMap(option=>option.long!==void 0&&SCOPE_POSITIONALS[option.long]!==void 0?[option.long]:[]);return declared.length>0?declared:void 0}var MIN_SUFFIX_STEM=4;function suffixNamed(cmd,flag){let stem=flag.replace(/^--/,"");if(stem.length<MIN_SUFFIX_STEM)return;let matches=(cmd?.options??[]).map(option=>option.long).filter(long=>long!==void 0&&long!==flag&&long.endsWith(`-${stem}`));return matches.length===1?matches[0]:void 0}function nounOf2(name){return name.replace(/Id$/,"").replace(/([a-z0-9])([A-Z])/g,"$1 $2").toLowerCase()}function valuedOptions(cmd){return(cmd?.options??[]).filter(option=>(option.required||option.optional)&&option.long!==void 0).map(option=>option.long??"")}function usageErrorOf(err,cmd=refusedBy){let raw=err.message.replace(/^error: /,""),quoted=/'([^']+)'/.exec(raw)?.[1],flag=quoted===void 0?void 0:/--[a-z][a-z-]*/.exec(quoted)?.[0]??quoted,path2=cmd===void 0?void 0:commandPath2(cmd);switch(err.code){case"commander.missingMandatoryOptionValue":return new CliError(EXIT.USAGE,"USAGE_ERROR",`${flag??"An option"} is required.`,{hint:supplyHint({ask:"be asked for it"})});case"commander.optionMissingArgument":{let value=quoted===void 0?void 0:/<[^>]+>/.exec(quoted)?.[0];return new CliError(EXIT.USAGE,"USAGE_ERROR",`${flag??"The option"} needs a value${value?` (${value})`:""}.`)}case"commander.unknownOption":{let suggestion=/\(Did you mean ([^?]+)\?\)/.exec(raw)?.[1],options="Add --help to the command to list its options.",positional=quoted===void 0?void 0:positionalNamed(cmd,quoted),suffix=quoted===void 0?void 0:suffixNamed(cmd,quoted),scope2=quoted===void 0?void 0:scopeNamed(cmd,quoted),lead=positional!==void 0&&path2!==void 0?`The ${nounOf2(positional)} is the positional argument: ${path2} <${positional}>.`:scope2!==void 0?`This verb's scope ${scope2.length===1?"flag is":"flags are"} ${scope2.join(" and ")}.`:(suffix??suggestion)!==void 0?`Did you mean ${suffix??suggestion}?`:void 0;return new CliError(EXIT.USAGE,"USAGE_ERROR",`'${quoted??""}' is not an option here.`,{hint:lead===void 0?options:`${lead} ${options}`})}case"commander.excessArguments":{let options="Add --help to the command to list its options.";if(cmd!==void 0&&cmd.registeredArguments.length===0){let valued=valuedOptions(cmd),named=valued.length>0?`Name it with ${valued.join(" or ")}. `:"";return new CliError(EXIT.USAGE,"USAGE_ERROR",`'${path2??"The command"}' takes no positional arguments.`,{hint:`${named}${options}`})}return new CliError(EXIT.USAGE,"USAGE_ERROR",raw.charAt(0).toUpperCase()+raw.slice(1),{hint:options})}case"commander.unknownCommand":{let suggestion=/\(Did you mean ([^?]+)\?\)/.exec(raw)?.[1],groups=`\`${CLI}\` lists the groups, and a group run alone lists its verbs.`;return new CliError(EXIT.USAGE,"USAGE_ERROR",`'${quoted??""}' is not a command.`,{hint:suggestion?`Did you mean ${suggestion}? ${groups}`:groups})}case"commander.missingArgument":return new CliError(EXIT.USAGE,"USAGE_ERROR",`<${quoted??"argument"}> is required.`,{hint:supplyHint()});default:return new CliError(EXIT.USAGE,"USAGE_ERROR",raw.charAt(0).toUpperCase()+raw.slice(1))}}var program2=addGlobalOptions(new Command(CLI).description("CLI for ScriptRunner Connect")).exitOverride();program2.addCommand(apiConnectionCommand());program2.addCommand(appCommand());program2.addCommand(authCommand());program2.addCommand(cliCommand());program2.addCommand(connectorCommand());program2.addCommand(connectorSharingCommand());program2.addCommand(environmentCommand());program2.addCommand(environmentParameterCommand());program2.addCommand(eventListenerCommand());program2.addCommand(eventListenerTestPayloadCommand());program2.addCommand(eventQueueCommand());program2.addCommand(feedbackCommand());program2.addCommand(localWorkspaceCommand());program2.addCommand(logsCommand());program2.addCommand(packageCommand());program2.addCommand(workspaceReadmeCommand());program2.addCommand(workspaceReleaseCommand());program2.addCommand(scheduledTriggerCommand());program2.addCommand(scriptCommand());program2.addCommand(teamCommand());program2.addCommand(tempRemoteWorkspaceCommand());program2.addCommand(templateCommand());program2.addCommand(workspaceCommand());program2.addCommand(workspaceLockCommand());function overrideExits(cmd){cmd.exitOverride(err=>{throw refusedBy=cmd,err}),cmd.configureOutput({outputError:()=>{},writeErr:str=>{process.stdout.write(str)}});for(let sub of cmd.commands)overrideExits(sub)}overrideExits(program2);applyHelpConventions(program2);program2.addHelpText("after",rootHelpFooter());function commandPath2(cmd){let names=[];for(let c=cmd;c.parent;c=c.parent)names.unshift(c.name());return names.join(" ")}program2.hook("preAction",(thisCommand,actionCommand)=>{let globals=thisCommand.optsWithGlobals();configureRawMode({enabled:!!globals.raw}),setCommandPath(commandPath2(actionCommand)),configureAgentMode({enabled:!!globals.agent}),setPromptsAllowed(globals.prompts!==!1&&!process.env.SR_CONNECT_CLI_NO_PROMPTS),setOutputCopy(globals.copyOutputToFile),configureSession({instance:globals.instance,enabled:globals.session!==!1}),configureRecorder({enabled:globals.recordApiCalls!==!1,instance:globals.instance}),configureWorkspaceLocking({enabled:globals.lock!==!1,lockId:globals.lockId}),configureLocalSync({enabled:globals.localSync!==!1,instance:globals.instance}),configureLocalWorkspaceScope({enabled:globals.localWorkspace!==!1,instance:globals.instance}),configureVersionGate({enabled:globals.versionGate!==!1}),configureCrashReports({enabled:globals.crashReports!==!1,instance:globals.instance}),configureAgenticFeedback({enabled:globals.agenticFeedback!==!1})});try{ignoreBrokenPipe(),warnIfNodeUnsupported(),configureRawMode({enabled:process.argv.includes("--raw")});let commandNames=program2.commands.flatMap(c=>[c.name(),...c.aliases()]);assertOutputCopyValue(process.argv,commandNames),assertVersionFlagIsRoot(process.argv,commandNames),configureUpdateCheck({enabled:!process.argv.includes("--no-update-check")}),configureCrashReports({enabled:!process.argv.includes("--no-crash-reports")}),asksForUpdates(process.argv)||(printUpdateNotice(),startUpdateCheck()),await program2.parseAsync(process.argv),reportOutputCopy(),await flushOutput(),process.exit(EXIT.OK)}catch(err){if(err instanceof CliError){err.exitCode===EXIT.NOT_FOUND&&warnInheritedWorkspace();let code2=reportError(err);reportOutputCopy(),await offerCrashReport(err),await flushOutput(),process.exit(code2)}if(err instanceof CommanderError){(err.code==="commander.helpDisplayed"||err.code==="commander.version"||err.code==="commander.help")&&(await flushOutput(),process.exit(err.exitCode===1?0:err.exitCode));let code2=reportError(usageErrorOf(err));reportOutputCopy(),await flushOutput(),process.exit(code2)}let message=err instanceof Error?err.message:String(err),code=reportError(new CliError(EXIT.API_ERROR,"UNEXPECTED_ERROR",message));reportOutputCopy(),await offerCrashReport(err),await flushOutput(),process.exit(code)}
|
|
1391
1392
|
/*! Bundled license information:
|
|
1392
1393
|
|
|
1393
1394
|
promise-throttle-all/dist/index.mjs:
|