@sinch/cli 0.3.1 → 0.3.2
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/dist/index.js +112 -108
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,45 +1,49 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
"use strict";var Bs=Object.create;var on=Object.defineProperty;var Ks=Object.getOwnPropertyDescriptor;var Hs=Object.getOwnPropertyNames;var Ws=Object.getPrototypeOf,zs=Object.prototype.hasOwnProperty;var W=(i,e)=>()=>(i&&(e=i(i=0)),e);var T=(i,e)=>()=>(e||i((e={exports:{}}).exports,e),e.exports),Te=(i,e)=>{for(var t in e)on(i,t,{get:e[t],enumerable:!0})},Ni=(i,e,t,o)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of Hs(e))!zs.call(i,r)&&r!==t&&on(i,r,{get:()=>e[r],enumerable:!(o=Ks(e,r))||o.enumerable});return i};var y=(i,e,t)=>(t=i!=null?Bs(Ws(i)):{},Ni(e||!i||!i.__esModule?on(t,"default",{value:i,enumerable:!0}):t,i)),L=i=>Ni(on({},"__esModule",{value:!0}),i);var Dt=T((rl,Gs)=>{Gs.exports={name:"@sinch/cli",version:"0.3.1",description:"Official Sinch CLI - Manage all Sinch products from your terminal",main:"dist/index.js",bin:{sinch:"bin/sinch"},scripts:{start:"tsx src/index.ts",dev:"tsx watch src/index.ts",build:"tsc && node scripts/post-build.js","build:prod":"tsup src/index.ts --format cjs --dts --clean --minify",typecheck:"tsc --noEmit",test:"jest --config jest.config.js && jest --config tests/e2e/jest.config.js","test:unit":"jest --config jest.config.js","test:e2e":"jest --config tests/e2e/jest.config.js","test:e2e:staging":"jest --config tests/e2e/jest.config.js --env=staging",prepublishOnly:"npm run build:prod",format:"prettier --write .","format:check":"prettier --check ."},keywords:[],author:"Sinch <support@sinch.com> (https://www.sinch.com)",license:"MIT",private:!1,publishConfig:{access:"public",registry:"https://registry.npmjs.org/"},homepage:"https://www.sinch.com/products/apis/voice/",files:["dist/","bin/","README.md","LICENSE"],dependencies:{"@inquirer/prompts":"^8.2.0","@opentelemetry/api":"^1.9.0","@opentelemetry/auto-instrumentations-node":"^0.69.0","@opentelemetry/exporter-trace-otlp-http":"^0.212.0","@opentelemetry/resources":"^2.5.1","@opentelemetry/sdk-node":"^0.212.0","@opentelemetry/semantic-conventions":"^1.39.0","@sinch/fax":"^1.0.0","@sinch/sdk-core":"^1.2.1","adm-zip":"^0.5.10",axios:"^1.13.3","axios-retry":"^4.5.0",blessed:"^0.1.81",chalk:"^4.1.2",chokidar:"^3.6.0","cli-spinners":"^2.9.2","cli-table3":"^0.6.3",clipboardy:"^5.1.0",commander:"^14.0.0",eventsource:"^4.0.0","form-data":"^4.0.0","fs-extra":"^11.3.3","google-libphonenumber":"^3.2.44",inquirer:"8.2.7",keytar:"^7.9.0",ora:"^4.1.1"},devDependencies:{"@types/adm-zip":"^0.5.7","@types/blessed":"^0.1.25","@types/fs-extra":"^11.0.4","@types/google-libphonenumber":"^7.4.30","@types/inquirer":"^9.0.9","@types/jest":"^30.0.0","@types/keytar":"^4.4.0","@types/node":"24.10.9",execa:"^5.1.1",jest:"^30.0.0",nodemon:"^3.0.1",prettier:"^3.8.1","ts-jest":"^29.4.6",tsup:"^8.5.0",tsx:"^4.20.4",typescript:"^5.9.2"},engines:{node:">=20.0.0",npm:">=9.0.0"}}});var $,D,pt=W(()=>{"use strict";$={SUCCESS:0,FAILURE:1,USAGE:2,USAGE_ERROR:64,DATA_ERROR:65,NO_INPUT:66,UNAVAILABLE:69,SOFTWARE:70,CANT_CREATE:73,IO_ERROR:74,NO_PERMISSION:77,CONFIG_ERROR:78,AUTH_REQUIRED:100,AUTH_FAILED:101,NOT_FOUND:102,CONFLICT:103,TIMEOUT:104},D=class extends Error{exitCode;constructor(e,t=$.FAILURE){super(e),this.name="CLIError",this.exitCode=t}}});function an(i){if(!i)return i;let e=i;for(let t of ga)e=e.replace(t,o=>{let r=o.match(/^[A-Za-z]+\s+/)?.[0]||"";return r?`${r}[REDACTED]`:"[REDACTED]"});return e}function qi(i){let e={...i};if(e.Authorization){let r=e.Authorization.match(/^([A-Za-z]+)\s+/),s=r?r[1]:"Bearer";e.Authorization=`${s} [REDACTED]`}let t=["x-api-key","x-auth-token","api-key","token"];for(let o of t){let r=Object.keys(e).find(s=>s.toLowerCase()===o);r&&(e[r]="[REDACTED]")}return e}var ga,Vi=W(()=>{"use strict";ga=[/Bearer\s+[A-Za-z0-9\-_.]+/g,/Basic\s+[A-Za-z0-9+/=]+/g,/[Aa]uthorization["\s:=]+["']?[^"'\s]+/g]});var Bi={};Te(Bi,{DebugLevel:()=>Ot,debugLog:()=>ue,getDebugLevel:()=>se,setConfigDebugLevel:()=>ha});function ha(i){Nn=Math.max(0,Math.min(i,3))}function se(){let i=process.env.SINCH_DEBUG;if(i){let e=parseInt(i,10);if(!isNaN(e))return Math.max(0,Math.min(e,3));if(i.toLowerCase()==="true")return 1}return Nn!==null?Nn:0}function ue(i,e,...t){se()>=i&&console.log(Ji.default.gray(`[DEBUG:${i}]`),e,...t)}var Ji,Ot,Nn,jt=W(()=>{"use strict";Ji=y(require("chalk")),Ot=(r=>(r[r.NONE=0]="NONE",r[r.INFO=1]="INFO",r[r.HTTP=2]="HTTP",r[r.VERBOSE=3]="VERBOSE",r))(Ot||{}),Nn=null});var Qe={};Te(Qe,{SinchAPI:()=>V});var cn,ln,On,jn,V,X=W(()=>{"use strict";cn=y(require("axios")),ln=y(require("axios-retry")),On=y(require("form-data")),jn=y(require("chalk"));Vi();pt();jt();V=class{baseUrl;oauthUrl;projectId;timeout;credentials;client;constructor(e={}){this.baseUrl=e.apiUrl||"https://functions.api.sinch.com/",this.oauthUrl=e.oauthUrl||"https://auth.sinch.com/oauth2/token",this.projectId=e.projectId||"",this.timeout=6e4,this.credentials=e.credentials||null,this.client=cn.default.create({baseURL:this.baseUrl,timeout:this.timeout,headers:{"User-Agent":"sinch-functions-cli/1.0.0"}}),(0,ln.default)(this.client,{retries:3,retryDelay:(t,o)=>{let r=o.response?.headers?.["retry-after"];return r?parseInt(r,10)*1e3:ln.default.exponentialDelay(t)},retryCondition:t=>{if(ln.default.isNetworkError(t))return!0;let o=t.response?.status;return!!(o&&o>=500||o===429)},onRetry:(t,o)=>{ue(1,`Retry ${t}/3: ${o.message}`)}}),this.client.interceptors.request.use(async t=>{if(this.credentials){let o=await this.getValidToken();o&&(t.headers.Authorization=`${o.token_type} ${o.access_token}`)}if(se()>=2){let o=an(t.url||"");if(ue(2,`\u2192 ${t.method?.toUpperCase()} ${o}`),se()>=3){let r=qi(t.headers);ue(3," Headers:",JSON.stringify(r,null,2))}}return t},t=>Promise.reject(t)),this.client.interceptors.response.use(t=>{if(se()>=2){let o=an(t.config.url||"");ue(2,`\u2190 ${t.status} ${o}`)}return t},async t=>{if(se()>=2){let o=an(t.config?.url||"");ue(2,`\u2190 ${t.response?.status||"ERROR"} ${o}`)}if(t.response?.status===401&&this.credentials&&t.config){let o=t.config;if(!o._retry){o._retry=!0;try{let r=await this.getValidToken();if(r)return o.headers.Authorization=`${r.token_type} ${r.access_token}`,this.client.request(o)}catch{console.error(jn.default.yellow("Token refresh failed during retry"))}}}return Promise.reject(t)})}async listAllTemplates(e=null){try{let t=e?{category:e}:{};return(await this.client.get(`/v1/projects/${this.projectId}/templates`,{params:t})).data}catch(t){throw this._handleError(t,"Failed to list templates")}}async listRuntimeTemplates(e,t=null){try{let o=t?{category:t}:{};return(await this.client.get(`/v1/projects/${this.projectId}/templates/${e}`,{params:o})).data}catch(o){throw this._handleError(o,`Failed to list ${e} templates`)}}async getTemplateDetails(e,t){try{return(await this.client.get(`/v1/projects/${this.projectId}/templates/${e}/${t}`)).data}catch(o){throw this._handleError(o,`Failed to get template details for ${e}/${t}`)}}async downloadTemplate(e,t){try{let o=await this.client.get(`/v1/projects/${this.projectId}/templates/${e}/${t}/download`,{responseType:"arraybuffer"});return Buffer.from(o.data)}catch(o){throw this._handleError(o,`Failed to download template ${e}/${t}`)}}async listFunctions(){try{return(await this.client.get(`/v1/projects/${this.projectId}/functions`)).data}catch(e){throw this._handleError(e,"Failed to list functions")}}async getFunction(e){try{return(await this.client.get(`/v1/projects/${this.projectId}/functions/${e}`)).data}catch(t){throw this._handleError(t,`Failed to get function ${e}`)}}async deployFunction(e,t,o,r,s="public"){try{let a=new On.default;return a.append("name",e),a.append("runtime",t),a.append("code",o,{filename:"function.zip"}),a.append("accessLevel",s),r&&a.append("configuration",JSON.stringify(r)),(await this.client.post(`/v1/projects/${this.projectId}/functions`,a,{headers:{...a.getHeaders()},maxContentLength:1/0,maxBodyLength:1/0})).data}catch(a){throw this._handleError(a,"Failed to deploy function")}}async updateFunction(e,t,o){try{let r=new On.default;return r.append("code",t,{filename:"function.zip"}),o&&r.append("configuration",JSON.stringify(o)),(await this.client.put(`/v1/projects/${this.projectId}/functions/${e}`,r,{headers:{...r.getHeaders()},maxContentLength:1/0,maxBodyLength:1/0})).data}catch(r){throw this._handleError(r,`Failed to update function ${e}`)}}async deleteFunction(e){try{await this.client.delete(`/v1/projects/${this.projectId}/functions/${e}`)}catch(t){throw this._handleError(t,`Failed to delete function ${e}`)}}async downloadFunction(e){try{let t=await this.client.get(`/v1/projects/${this.projectId}/functions/${e}/download`,{responseType:"arraybuffer"});return Buffer.from(t.data)}catch(t){throw this._handleError(t,`Failed to download function ${e}`)}}async getFunctionLogs(e,t={}){try{return(await this.client.get(`/v1/projects/${this.projectId}/functions/${e}/logs`,{params:t})).data}catch(o){throw this._handleError(o,`Failed to get logs for function ${e}`)}}async getFunctionStatus(e){try{return(await this.client.get(`/v1/projects/${this.projectId}/functions/${e}/deployment/status`)).data}catch(t){throw this._handleError(t,`Failed to get status for function ${e}`)}}async generateDocumentationFromCode(e,t="node",o="function"){try{return(await this.client.post(`/v1/projects/${this.projectId}/test/documentation`,{Code:e,Runtime:t,Name:o})).data}catch(r){throw this._handleError(r,"Failed to generate documentation from code")}}async generateDocumentationForFunction(e,t){try{let o=t?{MarkdownOverride:t}:{};return(await this.client.post(`/v1/projects/${this.projectId}/functions/${e}/documentation`,o)).data}catch(o){throw this._handleError(o,`Failed to generate documentation for function ${e}`)}}async getDocumentationForFunction(e){try{return(await this.client.get(`/v1/projects/${this.projectId}/functions/${e}/documentation`)).data}catch(t){throw this._handleError(t,`Failed to get documentation for function ${e}`)}}async streamDeployment(e,t,o){let r=p=>p.status?"status":p.progress?"progress":p.completed?"completed":p.failed||p.error?"failed":p.connected?"connected":"message",s=new URL(`v1/projects/${this.projectId}/functions/${e}/deployment/stream`,this.baseUrl).href,a={Accept:"text/event-stream","Cache-Control":"no-cache"};if(this.credentials)try{let p=await this.credentials.retrieve();if(p&&p.keyId&&p.keySecret){let d=Buffer.from(`${p.keyId}:${p.keySecret}`).toString("base64");a.Authorization=`Basic ${d}`}}catch(p){console.error("Failed to add authentication:",p)}let l=null;try{l=new AbortController;let p=await fetch(s,{method:"GET",headers:a,signal:l.signal});if(!p.ok)throw new Error(`SSE connection failed: ${p.status} ${p.statusText}`);if(!p.body)throw new Error("Response body is null");let d=p.body.getReader(),u=new TextDecoder,m="";return(async()=>{let h="";try{for(;;){let{done:C,value:v}=await d.read();if(C)break;let R=u.decode(v,{stream:!0});m+=R;let ee=m.split(`
|
|
3
|
-
`);m=
|
|
4
|
-
\u26A0\uFE0F OS keychain not available (Docker/CI environment detected)`)),console.log(
|
|
5
|
-
For better security, export as environment variables instead:`)),console.log(
|
|
6
|
-
\u26A0\uFE0F OS keychain not available (Docker/CI environment detected)`)),console.log(
|
|
7
|
-
For better security, export as environment variable instead:`)),console.log(ae.default.cyan(' export SINCH_FAX_KEY_SECRET="'+r+'"')),this.config.set("faxKeySecretPlaintext",r)),this.config.set("faxProjectId",t),this.config.set("faxKeyId",o),this.config.set("faxCredentialsStored",!0),await this.config.save()}async retrieveFax(){let e=process.env.SINCH_FAX_KEY_ID,t=process.env.SINCH_FAX_KEY_SECRET;if(e&&t)return{projectId:process.env.SINCH_FAX_PROJECT_ID||this.config.get("faxProjectId")||"",keyId:e,keySecret:t};if(!this.config.get("faxCredentialsStored"))return null;let r=this.config.get("faxProjectId"),s=this.config.get("faxKeyId"),a=await this.getPassword(`${this.accountPrefix}-fax-keySecret`);return a||(a=t||null),a||(a=this.config.get("faxKeySecretPlaintext")),a?{projectId:r,keyId:s,keySecret:a}:null}async hasFaxCredentials(){return process.env.SINCH_FAX_KEY_ID&&process.env.SINCH_FAX_KEY_SECRET?!0:this.config.get("faxCredentialsStored")?this.config.get("faxKeySecretPlaintext")?!0:!!await this.getPassword(`${this.accountPrefix}-fax-keySecret`):!1}async clearFax(){await this.deletePassword(`${this.accountPrefix}-fax-keySecret`),this.config.set("faxProjectId",null),this.config.set("faxKeyId",null),this.config.set("faxCredentialsStored",!1),this.config.set("faxKeySecretPlaintext",null),await this.config.save()}getFaxPublicInfo(){return process.env.SINCH_FAX_KEY_ID&&process.env.SINCH_FAX_KEY_SECRET?{projectId:process.env.SINCH_FAX_PROJECT_ID||this.config.get("faxProjectId"),keyId:process.env.SINCH_FAX_KEY_ID,hasCredentials:!0,source:"environment"}:{projectId:this.config.get("faxProjectId"),keyId:this.config.get("faxKeyId"),hasCredentials:this.config.get("faxCredentialsStored",!1),source:"config"}}}});var Lt={};Te(Lt,{ProfileManager:()=>un,profileManager:()=>mt});var U,ye,Wi,un,mt,gt=W(()=>{"use strict";U=y(require("fs-extra")),ye=y(require("path")),Wi=y(require("os")),un=class{configDir;profilesDir;metaFile;constructor(){this.configDir=ye.join(Wi.homedir(),".sinch"),this.profilesDir=ye.join(this.configDir,"profiles"),this.metaFile=ye.join(this.configDir,"config.json")}async init(){await U.ensureDir(this.profilesDir),(await this.list()).length===0&&await this.migrateFromLegacy()}async migrateFromLegacy(){if(!await U.pathExists(this.metaFile)){await this.create("default");return}try{let e=await U.readJson(this.metaFile),t={name:"default",projectId:e.projectId,keyId:e.keyId,apiUrl:e.apiUrl,oauthUrl:e.oauthUrl,defaultApplicationKey:e.defaultApplicationKey,credentialsStored:e.credentialsStored,created:e.created||new Date().toISOString()};await U.writeJson(ye.join(this.profilesDir,"default.json"),t,{spaces:2}),e.activeProfile="default",await U.writeJson(this.metaFile,e,{spaces:2})}catch{await this.create("default")}}async create(e){let t=ye.join(this.profilesDir,`${e}.json`);if(await U.pathExists(t))throw new Error(`Profile '${e}' already exists`);let o={name:e,created:new Date().toISOString()};await U.ensureDir(this.profilesDir),await U.writeJson(t,o,{spaces:2})}async delete(e){let t=await this.getActive();if(e===t)throw new Error(`Cannot delete the active profile '${e}'. Switch to another profile first.`);let o=ye.join(this.profilesDir,`${e}.json`);if(!await U.pathExists(o))throw new Error(`Profile '${e}' does not exist`);await U.remove(o)}async use(e){let t=ye.join(this.profilesDir,`${e}.json`);if(!await U.pathExists(t))throw new Error(`Profile '${e}' does not exist`);let o=await this.getMeta();o.activeProfile=e,await U.writeJson(this.metaFile,o,{spaces:2})}async list(){if(!await U.pathExists(this.profilesDir))return[];let e=await U.readdir(this.profilesDir),t=await this.getActive(),o=[];for(let r of e)if(r.endsWith(".json"))try{let s=await U.readJson(ye.join(this.profilesDir,r));o.push({name:s.name,projectId:s.projectId,keyId:s.keyId,active:s.name===t,created:s.created})}catch{}return o}async getActive(){return(await this.getMeta()).activeProfile||"default"}async loadProfile(e){let t=e||await this.getActive(),o=ye.join(this.profilesDir,`${t}.json`);return await U.pathExists(o)?await U.readJson(o):(await this.create(t),{name:t,created:new Date().toISOString()})}async saveProfile(e){let t=ye.join(this.profilesDir,`${e.name}.json`);await U.ensureDir(this.profilesDir),await U.writeJson(t,e,{spaces:2})}async getMeta(){try{if(await U.pathExists(this.metaFile))return await U.readJson(this.metaFile)}catch{}return{activeProfile:"default"}}get profilesDirPath(){return this.profilesDir}},mt=new un});var xe={};Te(xe,{config:()=>f});var we,_t,zi,_n,Un,f,A=W(()=>{"use strict";we=y(require("fs-extra")),_t=y(require("path")),zi=y(require("os")),_n=y(require("chalk"));Hi();gt();Un=class{configDir;configFile;projectConfigFile;_config=null;_projectConfig=null;_credentials=null;_profileName="default";_profileOverride=null;constructor(){this.configDir=_t.join(zi.homedir(),".sinch"),this.configFile=_t.join(this.configDir,"config.json"),this.projectConfigFile=_t.join(process.cwd(),"sinch.json")}setProfileOverride(e){this._profileOverride=e}getActiveProfileName(){return this._profileName}async load(){await mt.init(),this._profileName=this._profileOverride||await mt.getActive();try{let t=await mt.loadProfile(this._profileName);this._config=this._profileDataToConfig(t)}catch(t){console.warn(_n.default.yellow(`Warning: Could not load profile '${this._profileName}': ${t.message}`)),this._config=this._getDefaultConfig()}this._credentials=new pn(this,this._profileName);let e=this.get("debug",0);if(e>0){let{setConfigDebugLevel:t}=(jt(),L(Bi));t(e)}try{await we.pathExists(this.projectConfigFile)&&(this._projectConfig=await we.readJson(this.projectConfigFile))}catch(t){console.warn(_n.default.yellow(`Warning: Could not load project config: ${t.message}`))}}async save(){try{let e=this._configToProfileData(this._config);await mt.saveProfile(e),await we.ensureDir(this.configDir);let t=await we.pathExists(this.configFile)?await we.readJson(this.configFile):{};t.activeProfile=this._profileName,t.apiUrl=this._config?.apiUrl,t.projectId=this._config?.projectId,await we.writeJson(this.configFile,t,{spaces:2})}catch(e){throw new Error(`Could not save config: ${e.message}`)}}_profileDataToConfig(e){return{apiUrl:e.apiUrl||"https://functions.api.sinch.com",oauthUrl:e.oauthUrl||"https://auth.sinch.com/oauth2/token",projectId:e.projectId||"default-project",created:e.created,keyId:e.keyId,defaultApplicationKey:e.defaultApplicationKey,credentialsStored:e.credentialsStored,...e}}_configToProfileData(e){return{name:this._profileName,projectId:e.projectId,keyId:e.keyId,apiUrl:e.apiUrl,oauthUrl:e.oauthUrl,defaultApplicationKey:e.defaultApplicationKey,credentialsStored:e.credentialsStored,created:e.created,...e}}async saveProjectConfig(){try{if(this._projectConfig){let e=_t.join(process.cwd(),"sinch.json");await we.writeJson(e,this._projectConfig,{spaces:2})}}catch(e){throw new Error(`Could not save project config: ${e.message}`)}}get(e,t=null){if(!this._config)throw new Error("Config not loaded. Call load() first.");return this._projectConfig&&this._projectConfig[e]!==void 0?this._projectConfig[e]:this._config[e]!==void 0?this._config[e]:t}set(e,t,o=!1){if(!this._config)throw new Error("Config not loaded. Call load() first.");o?(this._projectConfig||(this._projectConfig={}),this._projectConfig[e]=t):this._config[e]=t}getApiConfig(){return{apiUrl:this.get("apiUrl"),oauthUrl:this.get("oauthUrl","https://auth.sinch.com/oauth2/token"),projectId:this.get("projectId"),credentials:this._credentials}}async initProject(e,t="node",o={},r=null){let s={name:e,runtime:t,description:`Sinch Functions project: ${e}`,created:new Date().toISOString()};return o&&Object.keys(o).length>0&&(s.variables=o),r&&(s.applicationKey=r),this._projectConfig=s,await this.saveProjectConfig(),s}isInProject(){return this._projectConfig!==null}getProjectConfig(){return this._projectConfig}_getDefaultConfig(){return{apiUrl:"https://functions.api.sinch.com",oauthUrl:"https://auth.sinch.com/oauth2/token",projectId:"default-project",created:new Date().toISOString()}}async storeCredentials(e){if(!this._credentials)throw new Error("Config not loaded. Call load() first.");return await this._credentials.store(e)}async getCredentials(){if(!this._credentials)throw new Error("Config not loaded. Call load() first.");return await this._credentials.retrieve()}async clearCredentials(){if(!this._credentials)throw new Error("Config not loaded. Call load() first.");return await this._credentials.clear()}async hasCredentials(){if(!this._credentials)throw new Error("Config not loaded. Call load() first.");return await this._credentials.hasCredentials()}getPublicCredentialInfo(){if(!this._credentials)throw new Error("Config not loaded. Call load() first.");return this._credentials.getPublicInfo()}async createSinchClient(e=null){if(!this._credentials)throw new Error("Config not loaded. Call load() first.");return!e&&this.isInProject()&&(e=this._projectConfig?.applicationKey||null),await this._credentials.createSinchClient(e)}async getApplicationCredentials(e=null){if(!this._credentials)throw new Error("Config not loaded. Call load() first.");return!e&&this.isInProject()&&(e=this._projectConfig?.applicationKey||null),await this._credentials.getApplicationCredentials(e)}async storeApplicationSecret(e,t){if(!this._credentials)throw new Error("Config not loaded. Call load() first.");return await this._credentials.storeApplicationSecret(e,t)}getTunnelPreference(){return this._projectConfig&&this._projectConfig.tunnel?.preference||null}async setTunnelPreference(e){if(!this._projectConfig)throw new Error("Not in a project directory");this._projectConfig.tunnel||(this._projectConfig.tunnel={}),this._projectConfig.tunnel.preference=e,this._projectConfig.tunnel.lastUpdated=new Date().toISOString(),await this.saveProjectConfig()}getTunnelSubdomain(){return this._projectConfig&&this._projectConfig.tunnel?.subdomain||null}async setTunnelSubdomain(e){if(!this._projectConfig)throw new Error("Not in a project directory");this._projectConfig.tunnel||(this._projectConfig.tunnel={}),this._projectConfig.tunnel.subdomain=e,this._projectConfig.tunnel.lastUpdated=new Date().toISOString(),await this.saveProjectConfig()}getTunnelUrl(){return this._projectConfig&&this._projectConfig.tunnel?.lastUrl||null}async setTunnelUrl(e){if(!this._projectConfig)throw new Error("Not in a project directory");this._projectConfig.tunnel||(this._projectConfig.tunnel={}),this._projectConfig.tunnel.lastUrl=e,this._projectConfig.tunnel.lastUpdated=new Date().toISOString(),await this.saveProjectConfig()}async setFaxServiceId(e){this.set("faxServiceId",e),await this.save()}getFaxServiceId(){return this.get("faxServiceId",null)}async setFaxSenderNumber(e){this.set("faxSenderNumber",e),await this.save()}getFaxSenderNumber(){return this.get("faxSenderNumber",null)}async storeFaxCredentials(e){if(!this._credentials)throw new Error("Config not loaded. Call load() first.");return await this._credentials.storeFax(e)}async getFaxCredentials(){if(!this._credentials)throw new Error("Config not loaded. Call load() first.");return await this._credentials.retrieveFax()}async hasFaxCredentials(){if(!this._credentials)throw new Error("Config not loaded. Call load() first.");return await this._credentials.hasFaxCredentials()}async clearFaxCredentials(){if(!this._credentials)throw new Error("Config not loaded. Call load() first.");return await this._credentials.clearFax()}getFaxPublicCredentialInfo(){if(!this._credentials)throw new Error("Config not loaded. Call load() first.");return this._credentials.getFaxPublicInfo()}},f=new Un});var Yi={};Te(Yi,{logger:()=>n});var ne,Ue,Mn,Gi,qn,n,E=W(()=>{"use strict";ne=y(require("chalk")),Ue=y(require("fs")),Mn=y(require("path")),Gi=y(require("os"));jt();qn=class{logFile;constructor(){let e="cli";try{let t=Mn.join(process.cwd(),"sinch.json");Ue.existsSync(t)&&(e=JSON.parse(Ue.readFileSync(t,"utf8")).name||"cli")}catch{}this.logFile=Mn.join(Gi.tmpdir(),`sinch-${e}.log`);try{Ue.writeFileSync(this.logFile,`=== Sinch CLI Debug Log - ${new Date().toISOString()} ===
|
|
2
|
+
"use strict";var zs=Object.create;var an=Object.defineProperty;var Gs=Object.getOwnPropertyDescriptor;var Ys=Object.getOwnPropertyNames;var Xs=Object.getPrototypeOf,Zs=Object.prototype.hasOwnProperty;var G=(i,e)=>()=>(i&&(e=i(i=0)),e);var N=(i,e)=>()=>(e||i((e={exports:{}}).exports,e),e.exports),xe=(i,e)=>{for(var t in e)an(i,t,{get:e[t],enumerable:!0})},Li=(i,e,t,o)=>{if(e&&typeof e=="object"||typeof e=="function")for(let r of Ys(e))!Zs.call(i,r)&&r!==t&&an(i,r,{get:()=>e[r],enumerable:!(o=Gs(e,r))||o.enumerable});return i};var y=(i,e,t)=>(t=i!=null?zs(Xs(i)):{},Li(e||!i||!i.__esModule?an(t,"default",{value:i,enumerable:!0}):t,i)),F=i=>Li(an({},"__esModule",{value:!0}),i);var Ot=N((pl,Qs)=>{Qs.exports={name:"@sinch/cli",version:"0.3.2",description:"Official Sinch CLI - Manage all Sinch products from your terminal",main:"dist/index.js",bin:{sinch:"bin/sinch"},scripts:{start:"tsx src/index.ts",dev:"tsx watch src/index.ts",build:"tsc && node scripts/post-build.js","build:prod":"tsup src/index.ts --format cjs --dts --clean --minify",typecheck:"tsc --noEmit",test:"jest --config jest.config.js && jest --config tests/e2e/jest.config.js","test:unit":"jest --config jest.config.js","test:e2e":"jest --config tests/e2e/jest.config.js","test:e2e:staging":"jest --config tests/e2e/jest.config.js --env=staging",prepublishOnly:"npm run build:prod",format:"prettier --write .","format:check":"prettier --check ."},keywords:[],author:"Sinch <support@sinch.com> (https://www.sinch.com)",license:"MIT",private:!1,publishConfig:{access:"public",registry:"https://registry.npmjs.org/"},homepage:"https://www.sinch.com/products/apis/voice/",files:["dist/","bin/","README.md","LICENSE"],dependencies:{"@inquirer/prompts":"^8.2.0","@opentelemetry/api":"^1.9.0","@opentelemetry/auto-instrumentations-node":"^0.69.0","@opentelemetry/exporter-trace-otlp-http":"^0.212.0","@opentelemetry/resources":"^2.5.1","@opentelemetry/sdk-node":"^0.212.0","@opentelemetry/semantic-conventions":"^1.39.0","@sinch/fax":"^1.0.0","@sinch/sdk-core":"^1.2.1","adm-zip":"^0.5.10",axios:"^1.13.3","axios-retry":"^4.5.0",blessed:"^0.1.81",chalk:"^4.1.2",chokidar:"^3.6.0","cli-spinners":"^2.9.2","cli-table3":"^0.6.3",clipboardy:"^5.1.0",commander:"^14.0.0",eventsource:"^4.0.0","form-data":"^4.0.0","fs-extra":"^11.3.3","google-libphonenumber":"^3.2.44",inquirer:"8.2.7",keytar:"^7.9.0",ora:"^4.1.1"},devDependencies:{"@types/adm-zip":"^0.5.7","@types/blessed":"^0.1.25","@types/fs-extra":"^11.0.4","@types/google-libphonenumber":"^7.4.30","@types/inquirer":"^9.0.9","@types/jest":"^30.0.0","@types/keytar":"^4.4.0","@types/node":"24.10.9",execa:"^5.1.1",jest:"^30.0.0",nodemon:"^3.0.1",prettier:"^3.8.1","ts-jest":"^29.4.6",tsup:"^8.5.0",tsx:"^4.20.4",typescript:"^5.9.2"},engines:{node:">=20.0.0",npm:">=9.0.0"}}});var I,D,ut=G(()=>{"use strict";I={SUCCESS:0,FAILURE:1,USAGE:2,USAGE_ERROR:64,DATA_ERROR:65,NO_INPUT:66,UNAVAILABLE:69,SOFTWARE:70,CANT_CREATE:73,IO_ERROR:74,NO_PERMISSION:77,CONFIG_ERROR:78,AUTH_REQUIRED:100,AUTH_FAILED:101,NOT_FOUND:102,CONFLICT:103,TIMEOUT:104},D=class extends Error{exitCode;constructor(e,t=I.FAILURE){super(e),this.name="CLIError",this.exitCode=t}}});function dn(i){if(!i)return i;let e=i;for(let t of Ca)e=e.replace(t,o=>{let r=o.match(/^[A-Za-z]+\s+/)?.[0]||"";return r?`${r}[REDACTED]`:"[REDACTED]"});return e}function Ki(i){let e={...i};if(e.Authorization){let r=e.Authorization.match(/^([A-Za-z]+)\s+/),s=r?r[1]:"Bearer";e.Authorization=`${s} [REDACTED]`}let t=["x-api-key","x-auth-token","api-key","token"];for(let o of t){let r=Object.keys(e).find(s=>s.toLowerCase()===o);r&&(e[r]="[REDACTED]")}return e}var Ca,Hi=G(()=>{"use strict";Ca=[/Bearer\s+[A-Za-z0-9\-_.]+/g,/Basic\s+[A-Za-z0-9+/=]+/g,/[Aa]uthorization["\s:=]+["']?[^"'\s]+/g]});var zi={};xe(zi,{DebugLevel:()=>jt,debugLog:()=>Ce,getDebugLevel:()=>ae,setConfigDebugLevel:()=>va});function va(i){jn=Math.max(0,Math.min(i,3))}function ae(){let i=process.env.SINCH_DEBUG;if(i){let e=parseInt(i,10);if(!isNaN(e))return Math.max(0,Math.min(e,3));if(i.toLowerCase()==="true")return 1}return jn!==null?jn:0}function Ce(i,e,...t){ae()>=i&&console.log(Wi.default.gray(`[DEBUG:${i}]`),e,...t)}var Wi,jt,jn,Lt=G(()=>{"use strict";Wi=y(require("chalk")),jt=(r=>(r[r.NONE=0]="NONE",r[r.INFO=1]="INFO",r[r.HTTP=2]="HTTP",r[r.VERBOSE=3]="VERBOSE",r))(jt||{}),jn=null});var et={};xe(et,{SinchAPI:()=>J});var pn,un,Ln,_n,J,Q=G(()=>{"use strict";pn=y(require("axios")),un=y(require("axios-retry")),Ln=y(require("form-data")),_n=y(require("chalk"));Hi();ut();Lt();J=class{baseUrl;oauthUrl;projectId;timeout;credentials;client;constructor(e={}){this.baseUrl=e.apiUrl||"https://functions.api.sinch.com/",this.oauthUrl=e.oauthUrl||"https://auth.sinch.com/oauth2/token",this.projectId=e.projectId||"",this.timeout=6e4,this.credentials=e.credentials||null,this.client=pn.default.create({baseURL:this.baseUrl,timeout:this.timeout,headers:{"User-Agent":"sinch-functions-cli/1.0.0"}}),(0,un.default)(this.client,{retries:3,retryDelay:(t,o)=>{let r=o.response?.headers?.["retry-after"];return r?parseInt(r,10)*1e3:un.default.exponentialDelay(t)},retryCondition:t=>{if(un.default.isNetworkError(t))return!0;let o=t.response?.status;return!!(o&&o>=500||o===429)},onRetry:(t,o)=>{Ce(1,`Retry ${t}/3: ${o.message}`)}}),this.client.interceptors.request.use(async t=>{if(this.credentials){let o=await this.getValidToken();o&&(t.headers.Authorization=`${o.token_type} ${o.access_token}`)}if(ae()>=2){let o=dn(t.url||"");if(Ce(2,`\u2192 ${t.method?.toUpperCase()} ${o}`),ae()>=3){let r=Ki(t.headers);Ce(3," Headers:",JSON.stringify(r,null,2))}}return t},t=>Promise.reject(t)),this.client.interceptors.response.use(t=>{if(ae()>=2){let o=dn(t.config.url||"");Ce(2,`\u2190 ${t.status} ${o}`)}return t},async t=>{if(ae()>=2){let o=dn(t.config?.url||"");Ce(2,`\u2190 ${t.response?.status||"ERROR"} ${o}`)}if(t.response?.status===401&&this.credentials&&t.config){let o=t.config;if(!o._retry){o._retry=!0;try{let r=await this.getValidToken();if(r)return o.headers.Authorization=`${r.token_type} ${r.access_token}`,this.client.request(o)}catch{console.error(_n.default.yellow("Token refresh failed during retry"))}}}return Promise.reject(t)})}async listAllTemplates(e=null){try{let t=e?{category:e}:{};return(await this.client.get(`/v1/projects/${this.projectId}/templates`,{params:t})).data}catch(t){throw this._handleError(t,"Failed to list templates")}}async listRuntimeTemplates(e,t=null){try{let o=t?{category:t}:{};return(await this.client.get(`/v1/projects/${this.projectId}/templates/${e}`,{params:o})).data}catch(o){throw this._handleError(o,`Failed to list ${e} templates`)}}async getTemplateDetails(e,t){try{return(await this.client.get(`/v1/projects/${this.projectId}/templates/${e}/${t}`)).data}catch(o){throw this._handleError(o,`Failed to get template details for ${e}/${t}`)}}async downloadTemplate(e,t){try{let o=await this.client.get(`/v1/projects/${this.projectId}/templates/${e}/${t}/download`,{responseType:"arraybuffer"});return Buffer.from(o.data)}catch(o){throw this._handleError(o,`Failed to download template ${e}/${t}`)}}async listFunctions(){try{return(await this.client.get(`/v1/projects/${this.projectId}/functions`)).data}catch(e){throw this._handleError(e,"Failed to list functions")}}async getFunction(e){try{return(await this.client.get(`/v1/projects/${this.projectId}/functions/${e}`)).data}catch(t){throw this._handleError(t,`Failed to get function ${e}`)}}async deployFunction(e,t,o,r,s="public"){try{let a=new Ln.default;return a.append("name",e),a.append("runtime",t),a.append("code",o,{filename:"function.zip"}),a.append("accessLevel",s),r&&a.append("configuration",JSON.stringify(r)),(await this.client.post(`/v1/projects/${this.projectId}/functions`,a,{headers:{...a.getHeaders()},maxContentLength:1/0,maxBodyLength:1/0})).data}catch(a){throw this._handleError(a,"Failed to deploy function")}}async updateFunction(e,t,o){try{let r=new Ln.default;return r.append("code",t,{filename:"function.zip"}),o&&r.append("configuration",JSON.stringify(o)),(await this.client.put(`/v1/projects/${this.projectId}/functions/${e}`,r,{headers:{...r.getHeaders()},maxContentLength:1/0,maxBodyLength:1/0})).data}catch(r){throw this._handleError(r,`Failed to update function ${e}`)}}async deleteFunction(e){try{await this.client.delete(`/v1/projects/${this.projectId}/functions/${e}`)}catch(t){throw this._handleError(t,`Failed to delete function ${e}`)}}async downloadFunction(e){try{let t=await this.client.get(`/v1/projects/${this.projectId}/functions/${e}/download`,{responseType:"arraybuffer"});return Buffer.from(t.data)}catch(t){throw this._handleError(t,`Failed to download function ${e}`)}}async getFunctionLogs(e,t={}){try{return(await this.client.get(`/v1/projects/${this.projectId}/functions/${e}/logs`,{params:t})).data}catch(o){throw this._handleError(o,`Failed to get logs for function ${e}`)}}async getFunctionStatus(e){try{return(await this.client.get(`/v1/projects/${this.projectId}/functions/${e}/deployment/status`)).data}catch(t){throw this._handleError(t,`Failed to get status for function ${e}`)}}async generateDocumentationFromCode(e,t="node",o="function"){try{return(await this.client.post(`/v1/projects/${this.projectId}/test/documentation`,{Code:e,Runtime:t,Name:o})).data}catch(r){throw this._handleError(r,"Failed to generate documentation from code")}}async generateDocumentationForFunction(e,t){try{let o=t?{MarkdownOverride:t}:{};return(await this.client.post(`/v1/projects/${this.projectId}/functions/${e}/documentation`,o)).data}catch(o){throw this._handleError(o,`Failed to generate documentation for function ${e}`)}}async getDocumentationForFunction(e){try{return(await this.client.get(`/v1/projects/${this.projectId}/functions/${e}/documentation`)).data}catch(t){throw this._handleError(t,`Failed to get documentation for function ${e}`)}}async streamDeployment(e,t,o){let r=p=>p.status?"status":p.progress?"progress":p.completed?"completed":p.failed||p.error?"failed":p.connected?"connected":"message",s=new URL(`v1/projects/${this.projectId}/functions/${e}/deployment/stream`,this.baseUrl).href,a={Accept:"text/event-stream","Cache-Control":"no-cache"};if(this.credentials)try{let p=await this.credentials.retrieve();if(p&&p.keyId&&p.keySecret){let d=Buffer.from(`${p.keyId}:${p.keySecret}`).toString("base64");a.Authorization=`Basic ${d}`}}catch(p){console.error("Failed to add authentication:",p)}let l=null;try{l=new AbortController;let p=await fetch(s,{method:"GET",headers:a,signal:l.signal});if(!p.ok)throw new Error(`SSE connection failed: ${p.status} ${p.statusText}`);if(!p.body)throw new Error("Response body is null");let d=p.body.getReader(),u=new TextDecoder,m="";return(async()=>{let h="";try{for(;;){let{done:C,value:v}=await d.read();if(C)break;let k=u.decode(v,{stream:!0});m+=k;let re=m.split(`
|
|
3
|
+
`);m=re.pop()||"";for(let j of re){if(j.startsWith("event:")){h=j.substring(6).trim();continue}if(j.startsWith("data:")){let M=j.substring(5).trim();if(M)try{let fe=JSON.parse(M),H=h||r(fe);t({type:H,data:fe}),h=""}catch{t({type:h||"message",data:M}),h=""}}j===""&&(h="")}}}catch(C){C.name!=="AbortError"&&o&&o(C)}})(),()=>{l&&l.abort()}}catch(p){throw console.error("Failed to create SSE stream:",p),o&&o(p),p}}async checkHealth(){try{return(await this.client.get("/health")).data}catch(e){throw this._handleError(e,"Health check failed")}}async getValidToken(){if(!this.credentials)return null;try{let e=await this.credentials.getOAuthToken();if(e)return{access_token:e,token_type:"Bearer",expires_in:3600};let t=await this.credentials.getBasicAuthToken();return t?{access_token:t,token_type:"Basic",expires_in:3600}:null}catch(e){return console.error(_n.default.yellow("Failed to get authentication token:",e.message)),null}}async authenticateOAuth(e,t){try{let o=this.oauthUrl,r=new URLSearchParams;r.append("grant_type","client_credentials");let a=(await pn.default.post(o,r,{headers:{"Content-Type":"application/x-www-form-urlencoded",Authorization:"Basic "+Buffer.from(`${e}:${t}`).toString("base64")},timeout:this.timeout})).data;return this.credentials&&await this.credentials.storeOAuthToken(a),a}catch(o){throw this._handleError(o,"OAuth authentication failed")}}async getTosStatus(){try{return(await this.client.get(`/v1/projects/${this.projectId}/terms-of-service`)).data}catch(e){throw this._handleError(e,"Failed to check Terms of Service status")}}async acceptTos(e,t){try{let o={acceptedBy:e};return t&&(o.version=t),(await this.client.post(`/v1/projects/${this.projectId}/terms-of-service`,o)).data}catch(o){throw this._handleError(o,"Failed to accept Terms of Service")}}_handleError(e,t){if(pn.default.isAxiosError(e)){let o=e;if(o.response){let r=o.response.status,s=o.response.data,a=s?.message||s?.error||o.message;throw r===401?new D('Authentication required. Please run "sinch auth login" first.',I.AUTH_REQUIRED):r===403?new D(`Permission denied: ${a}`,I.NO_PERMISSION):r===404?new D(`Resource not found: ${a}`,I.NOT_FOUND):r===409?new D(`Conflict: ${a}`,I.CONFLICT):r===429?new D(`Rate limited: ${a}`,I.UNAVAILABLE):r>=500?new D(`Server error: ${a}`,I.UNAVAILABLE):new D(`${t}: ${a}`,I.FAILURE)}else throw o.request?o.code==="ECONNREFUSED"?new D(`Cannot connect to API at ${this.baseUrl}. Is the server running?`,I.UNAVAILABLE):o.code==="ETIMEDOUT"?new D(`Request timeout after ${this.timeout}ms`,I.TIMEOUT):new D(`${t}: No response from server (${o.code||"unknown error"})`,I.IO_ERROR):new D(`${t}: ${o.message}`,I.FAILURE)}else throw new D(`${t}: ${e.message||e}`,I.FAILURE)}}});function fn(){if(!Un)try{Un=require("keytar")}catch{return null}return Un}var Gi,ce,Un,_t,Mn,mn,Yi=G(()=>{"use strict";Gi=y(require("os")),ce=y(require("chalk")),Un=null;_t="sinch-functions-cli",Mn=Gi.userInfo().username,mn=class{config;keychainAvailable=null;accountPrefix;constructor(e,t="default"){this.config=e,this.accountPrefix=t==="default"?Mn:`${t}-${Mn}`}async isKeychainAvailable(){if(this.keychainAvailable!==null)return this.keychainAvailable;if(this.config.get("keySecretPlaintext"))return this.keychainAvailable=!1,!1;try{let e=fn();if(!e)return this.keychainAvailable=!1,!1;let t=`${Mn}-test-${Date.now()}`;return await e.setPassword(_t,t,"test"),await e.deletePassword(_t,t),this.keychainAvailable=!0,!0}catch{return this.keychainAvailable=!1,!1}}async setPassword(e,t){if(!await this.isKeychainAvailable())return!1;let r=fn();return r?(await r.setPassword(_t,e,t),!0):!1}async getPassword(e){if(!await this.isKeychainAvailable())return null;let o=fn();return o?await o.getPassword(_t,e):null}async deletePassword(e){if(!await this.isKeychainAvailable())return!1;try{let o=fn();return o?(await o.deletePassword(_t,e),!0):!1}catch{return!0}}async store(e){let{projectId:t,keyId:o,keySecret:r,applicationKey:s,applicationSecret:a}=e,l=await this.setPassword(`${this.accountPrefix}-keySecret`,r),p=!0;s&&a&&(p=await this.setPassword(s,a)),l&&p?(this.config.set("keySecretPlaintext",null),a&&this.config.set("applicationSecretPlaintext",null)):(console.log(ce.default.yellow(`
|
|
4
|
+
\u26A0\uFE0F OS keychain not available (Docker/CI environment detected)`)),console.log(ce.default.yellow("\u26A0\uFE0F Storing secrets in plaintext config file")),console.log(ce.default.gray("Location: ~/.sinch/config.json")),console.log(ce.default.gray(`
|
|
5
|
+
For better security, export as environment variables instead:`)),console.log(ce.default.cyan(' export SINCH_KEY_SECRET="'+r+'"')),a&&console.log(ce.default.cyan(' export SINCH_APPLICATION_SECRET="'+a+'"')),this.config.set("keySecretPlaintext",r),a&&this.config.set("applicationSecretPlaintext",a)),this.config.set("projectId",t),this.config.set("keyId",o),s&&this.config.set("defaultApplicationKey",s),this.config.set("credentialsStored",!0),await this.config.save()}async storeOAuthToken(e){let{access_token:t,refresh_token:o,expires_in:r,token_type:s}=e,a=new Date(Date.now()+r*1e3).toISOString(),l=await this.setPassword(`${this.accountPrefix}-oauth-access`,t),p=!0;o&&(p=await this.setPassword(`${this.accountPrefix}-oauth-refresh`,o)),this.config.set("oauthTokenType",s),this.config.set("oauthExpiresAt",a),this.config.set("oauthStored",l&&p),await this.config.save()}async reAuthenticateOAuth(){try{let e=await this.retrieve();if(!e)return null;let{SinchAPI:t}=(Q(),F(et)),r=await new t({apiUrl:this.config.get("apiUrl")||"https://api.functions.dev.sinchvoice.org",projectId:e.projectId,credentials:null}).authenticateOAuth(e.keyId,e.keySecret);return await this.storeOAuthToken(r),r.access_token}catch{return null}}async getOAuthToken(){if(!this.config.get("oauthStored"))return await this.reAuthenticateOAuth();let t=this.config.get("oauthExpiresAt");if(t&&new Date(t)<new Date){console.log(ce.default.gray("Token expired, re-authenticating..."));let o=await this.reAuthenticateOAuth();return o?console.log(ce.default.green("\u2713 Token renewed successfully")):console.warn(ce.default.yellow("Failed to renew OAuth token. Please login again.")),o}return await this.getPassword(`${this.accountPrefix}-oauth-access`)}async storeApplicationSecret(e,t){await this.setPassword(e,t),this.config.get("defaultApplicationKey")||(this.config.set("defaultApplicationKey",e),await this.config.save())}async retrieve(){let e=process.env.SINCH_KEY_ID,t=process.env.SINCH_KEY_SECRET,o=process.env.SINCH_APPLICATION_KEY,r=process.env.SINCH_APPLICATION_SECRET;if(e&&t)return{projectId:process.env.SINCH_PROJECT_ID||this.config.get("projectId")||"",keyId:e,keySecret:t,applicationKey:o||void 0,applicationSecret:r||void 0};if(!this.config.get("credentialsStored"))return null;let a=this.config.get("projectId"),l=this.config.get("keyId"),p=this.config.get("defaultApplicationKey"),d=await this.getPassword(`${this.accountPrefix}-keySecret`);if(d||(d=t||null),d||(d=this.config.get("keySecretPlaintext")),!d)return null;let u=null;return p&&(u=await this.getPassword(p),u||(u=r||null),u||(u=this.config.get("applicationSecretPlaintext"))),{projectId:a,keyId:l,keySecret:d,applicationKey:p||void 0,applicationSecret:u||void 0}}async getApplicationCredentials(e=null){if(e||(e=this.config.get("defaultApplicationKey")),!e)return null;let t=await this.getPassword(e);return t||(t=process.env.SINCH_APPLICATION_SECRET||null),t||(t=this.config.get("applicationSecretPlaintext")),t?{applicationKey:e,applicationSecret:t}:null}async clear(){let e=this.config.get("defaultApplicationKey");await this.deletePassword(`${this.accountPrefix}-keySecret`),await this.deletePassword(`${this.accountPrefix}-oauth-access`),await this.deletePassword(`${this.accountPrefix}-oauth-refresh`),e&&await this.deletePassword(e),this.config.set("projectId",null),this.config.set("keyId",null),this.config.set("defaultApplicationKey",null),this.config.set("credentialsStored",!1),this.config.set("oauthStored",!1),this.config.set("oauthTokenType",null),this.config.set("oauthExpiresAt",null),this.config.set("keySecretPlaintext",null),this.config.set("applicationSecretPlaintext",null),await this.config.save()}async hasCredentials(){return process.env.SINCH_KEY_ID&&process.env.SINCH_KEY_SECRET?!0:this.config.get("credentialsStored")?this.config.get("keySecretPlaintext")?!0:!!await this.getPassword(`${this.accountPrefix}-keySecret`):!1}async hasVoiceCredentials(){let e=process.env.SINCH_APPLICATION_KEY,t=process.env.SINCH_APPLICATION_SECRET;if(e&&t)return!0;let o=this.config.get("defaultApplicationKey");return o?await this.getPassword(o)?!0:!!this.config.get("applicationSecretPlaintext"):!1}async hasOAuthToken(){return this.config.get("oauthStored")?!!await this.getPassword(`${this.accountPrefix}-oauth-access`):!1}getPublicInfo(){return process.env.SINCH_KEY_ID&&process.env.SINCH_KEY_SECRET?{projectId:process.env.SINCH_PROJECT_ID||this.config.get("projectId"),keyId:process.env.SINCH_KEY_ID,applicationKey:process.env.SINCH_APPLICATION_KEY||this.config.get("defaultApplicationKey"),hasCredentials:!0,hasOAuth:!1,oauthExpiresAt:null,source:"environment"}:{projectId:this.config.get("projectId"),keyId:this.config.get("keyId"),applicationKey:this.config.get("defaultApplicationKey"),hasCredentials:this.config.get("credentialsStored",!1),hasOAuth:this.config.get("oauthStored",!1),oauthExpiresAt:this.config.get("oauthExpiresAt"),source:"config"}}async createSinchClient(e=null){let t=await this.retrieve();if(!t)throw new Error('No credentials found. Please run "sinch auth login" first.');let o=await this.getApplicationCredentials(e),{SinchClient:r}=require("@sinch/sdk-core");return new r({applicationKey:o?.applicationKey||t.applicationKey,applicationSecret:o?.applicationSecret||t.applicationSecret,projectId:t.projectId,keyId:t.keyId,keySecret:t.keySecret,conversationRegion:"us"})}async storeBasicAuthToken(e){await this.setPassword(`${this.accountPrefix}-basic-auth`,e)&&(this.config.set("basicAuthStored",!0),await this.config.save())}async getBasicAuthToken(){return this.config.get("basicAuthStored")?await this.getPassword(`${this.accountPrefix}-basic-auth`):null}async clearBasicAuthToken(){await this.deletePassword(`${this.accountPrefix}-basic-auth`),this.config.set("basicAuthStored",!1),await this.config.save()}async storeFax(e){let{projectId:t,keyId:o,keySecret:r}=e;await this.setPassword(`${this.accountPrefix}-fax-keySecret`,r)?this.config.set("faxKeySecretPlaintext",null):(console.log(ce.default.yellow(`
|
|
6
|
+
\u26A0\uFE0F OS keychain not available (Docker/CI environment detected)`)),console.log(ce.default.yellow("\u26A0\uFE0F Storing fax secret in plaintext config file")),console.log(ce.default.gray("Location: ~/.sinch/config.json")),console.log(ce.default.gray(`
|
|
7
|
+
For better security, export as environment variable instead:`)),console.log(ce.default.cyan(' export SINCH_FAX_KEY_SECRET="'+r+'"')),this.config.set("faxKeySecretPlaintext",r)),this.config.set("faxProjectId",t),this.config.set("faxKeyId",o),this.config.set("faxCredentialsStored",!0),await this.config.save()}async retrieveFax(){let e=process.env.SINCH_FAX_KEY_ID,t=process.env.SINCH_FAX_KEY_SECRET;if(e&&t)return{projectId:process.env.SINCH_FAX_PROJECT_ID||this.config.get("faxProjectId")||"",keyId:e,keySecret:t};if(!this.config.get("faxCredentialsStored"))return null;let r=this.config.get("faxProjectId"),s=this.config.get("faxKeyId"),a=await this.getPassword(`${this.accountPrefix}-fax-keySecret`);return a||(a=t||null),a||(a=this.config.get("faxKeySecretPlaintext")),a?{projectId:r,keyId:s,keySecret:a}:null}async hasFaxCredentials(){return process.env.SINCH_FAX_KEY_ID&&process.env.SINCH_FAX_KEY_SECRET?!0:this.config.get("faxCredentialsStored")?this.config.get("faxKeySecretPlaintext")?!0:!!await this.getPassword(`${this.accountPrefix}-fax-keySecret`):!1}async clearFax(){await this.deletePassword(`${this.accountPrefix}-fax-keySecret`),this.config.set("faxProjectId",null),this.config.set("faxKeyId",null),this.config.set("faxCredentialsStored",!1),this.config.set("faxKeySecretPlaintext",null),await this.config.save()}getFaxPublicInfo(){return process.env.SINCH_FAX_KEY_ID&&process.env.SINCH_FAX_KEY_SECRET?{projectId:process.env.SINCH_FAX_PROJECT_ID||this.config.get("faxProjectId"),keyId:process.env.SINCH_FAX_KEY_ID,hasCredentials:!0,source:"environment"}:{projectId:this.config.get("faxProjectId"),keyId:this.config.get("faxKeyId"),hasCredentials:this.config.get("faxCredentialsStored",!1),source:"config"}}}});var Ut={};xe(Ut,{ProfileManager:()=>gn,profileManager:()=>gt});var L,Se,Xi,gn,gt,ht=G(()=>{"use strict";L=y(require("fs-extra")),Se=y(require("path")),Xi=y(require("os")),gn=class{configDir;profilesDir;metaFile;constructor(){this.configDir=Se.join(Xi.homedir(),".sinch"),this.profilesDir=Se.join(this.configDir,"profiles"),this.metaFile=Se.join(this.configDir,"config.json")}async init(){await L.ensureDir(this.profilesDir),(await this.list()).length===0&&await this.migrateFromLegacy()}async migrateFromLegacy(){if(!await L.pathExists(this.metaFile)){await this.create("default");return}try{let e=await L.readJson(this.metaFile),t={name:"default",projectId:e.projectId,keyId:e.keyId,apiUrl:e.apiUrl,oauthUrl:e.oauthUrl,defaultApplicationKey:e.defaultApplicationKey,credentialsStored:e.credentialsStored,created:e.created||new Date().toISOString()};await L.writeJson(Se.join(this.profilesDir,"default.json"),t,{spaces:2}),e.activeProfile="default",await L.writeJson(this.metaFile,e,{spaces:2})}catch{await this.create("default")}}async create(e){let t=Se.join(this.profilesDir,`${e}.json`);if(await L.pathExists(t))throw new Error(`Profile '${e}' already exists`);let o={name:e,created:new Date().toISOString()};await L.ensureDir(this.profilesDir),await L.writeJson(t,o,{spaces:2})}async delete(e){let t=await this.getActive();if(e===t)throw new Error(`Cannot delete the active profile '${e}'. Switch to another profile first.`);let o=Se.join(this.profilesDir,`${e}.json`);if(!await L.pathExists(o))throw new Error(`Profile '${e}' does not exist`);await L.remove(o)}async use(e){let t=Se.join(this.profilesDir,`${e}.json`);if(!await L.pathExists(t))throw new Error(`Profile '${e}' does not exist`);let o=await this.getMeta();o.activeProfile=e,await L.writeJson(this.metaFile,o,{spaces:2})}async list(){if(!await L.pathExists(this.profilesDir))return[];let e=await L.readdir(this.profilesDir),t=await this.getActive(),o=[];for(let r of e)if(r.endsWith(".json"))try{let s=await L.readJson(Se.join(this.profilesDir,r));o.push({name:s.name,projectId:s.projectId,keyId:s.keyId,active:s.name===t,created:s.created})}catch{}return o}async getActive(){return(await this.getMeta()).activeProfile||"default"}async loadProfile(e){let t=e||await this.getActive(),o=Se.join(this.profilesDir,`${t}.json`);return await L.pathExists(o)?await L.readJson(o):(await this.create(t),{name:t,created:new Date().toISOString()})}async saveProfile(e){let t=Se.join(this.profilesDir,`${e.name}.json`);await L.ensureDir(this.profilesDir),await L.writeJson(t,e,{spaces:2})}async getMeta(){try{if(await L.pathExists(this.metaFile))return await L.readJson(this.metaFile)}catch{}return{activeProfile:"default"}}get profilesDirPath(){return this.profilesDir}},gt=new gn});var Oe={};xe(Oe,{config:()=>f});var be,Mt,Zi,qn,Jn,f,E=G(()=>{"use strict";be=y(require("fs-extra")),Mt=y(require("path")),Zi=y(require("os")),qn=y(require("chalk"));Yi();ht();Jn=class{configDir;configFile;projectConfigFile;_config=null;_projectConfig=null;_credentials=null;_profileName="default";_profileOverride=null;constructor(){this.configDir=Mt.join(Zi.homedir(),".sinch"),this.configFile=Mt.join(this.configDir,"config.json"),this.projectConfigFile=Mt.join(process.cwd(),"sinch.json")}setProfileOverride(e){this._profileOverride=e}getActiveProfileName(){return this._profileName}async load(){await gt.init(),this._profileName=this._profileOverride||await gt.getActive();try{let t=await gt.loadProfile(this._profileName);this._config=this._profileDataToConfig(t)}catch(t){console.warn(qn.default.yellow(`Warning: Could not load profile '${this._profileName}': ${t.message}`)),this._config=this._getDefaultConfig()}this._credentials=new mn(this,this._profileName);let e=this.get("debug",0);if(e>0){let{setConfigDebugLevel:t}=(Lt(),F(zi));t(e)}try{await be.pathExists(this.projectConfigFile)&&(this._projectConfig=await be.readJson(this.projectConfigFile))}catch(t){console.warn(qn.default.yellow(`Warning: Could not load project config: ${t.message}`))}}async save(){try{let e=this._configToProfileData(this._config);await gt.saveProfile(e),await be.ensureDir(this.configDir);let t=await be.pathExists(this.configFile)?await be.readJson(this.configFile):{};t.activeProfile=this._profileName,t.apiUrl=this._config?.apiUrl,t.projectId=this._config?.projectId,await be.writeJson(this.configFile,t,{spaces:2})}catch(e){throw new Error(`Could not save config: ${e.message}`)}}_profileDataToConfig(e){return{apiUrl:e.apiUrl||"https://functions.api.sinch.com",oauthUrl:e.oauthUrl||"https://auth.sinch.com/oauth2/token",projectId:e.projectId||"default-project",created:e.created,keyId:e.keyId,defaultApplicationKey:e.defaultApplicationKey,credentialsStored:e.credentialsStored,...e}}_configToProfileData(e){return{name:this._profileName,projectId:e.projectId,keyId:e.keyId,apiUrl:e.apiUrl,oauthUrl:e.oauthUrl,defaultApplicationKey:e.defaultApplicationKey,credentialsStored:e.credentialsStored,created:e.created,...e}}async saveProjectConfig(){try{if(this._projectConfig){let e=Mt.join(process.cwd(),"sinch.json");await be.writeJson(e,this._projectConfig,{spaces:2})}}catch(e){throw new Error(`Could not save project config: ${e.message}`)}}get(e,t=null){if(!this._config)throw new Error("Config not loaded. Call load() first.");return this._projectConfig&&this._projectConfig[e]!==void 0?this._projectConfig[e]:this._config[e]!==void 0?this._config[e]:t}set(e,t,o=!1){if(!this._config)throw new Error("Config not loaded. Call load() first.");o?(this._projectConfig||(this._projectConfig={}),this._projectConfig[e]=t):this._config[e]=t}getApiConfig(){return{apiUrl:this.get("apiUrl"),oauthUrl:this.get("oauthUrl","https://auth.sinch.com/oauth2/token"),projectId:this.get("projectId"),credentials:this._credentials}}async initProject(e,t="node",o={},r=null){let s={name:e,runtime:t,description:`Sinch Functions project: ${e}`,created:new Date().toISOString()};return o&&Object.keys(o).length>0&&(s.variables=o),r&&(s.applicationKey=r),this._projectConfig=s,await this.saveProjectConfig(),s}isInProject(){return this._projectConfig!==null}getProjectConfig(){return this._projectConfig}_getDefaultConfig(){return{apiUrl:"https://functions.api.sinch.com",oauthUrl:"https://auth.sinch.com/oauth2/token",projectId:"default-project",created:new Date().toISOString()}}async storeCredentials(e){if(!this._credentials)throw new Error("Config not loaded. Call load() first.");return await this._credentials.store(e)}async getCredentials(){if(!this._credentials)throw new Error("Config not loaded. Call load() first.");return await this._credentials.retrieve()}async clearCredentials(){if(!this._credentials)throw new Error("Config not loaded. Call load() first.");return await this._credentials.clear()}async hasCredentials(){if(!this._credentials)throw new Error("Config not loaded. Call load() first.");return await this._credentials.hasCredentials()}getPublicCredentialInfo(){if(!this._credentials)throw new Error("Config not loaded. Call load() first.");return this._credentials.getPublicInfo()}async createSinchClient(e=null){if(!this._credentials)throw new Error("Config not loaded. Call load() first.");return!e&&this.isInProject()&&(e=this._projectConfig?.applicationKey||null),await this._credentials.createSinchClient(e)}async getApplicationCredentials(e=null){if(!this._credentials)throw new Error("Config not loaded. Call load() first.");return!e&&this.isInProject()&&(e=this._projectConfig?.applicationKey||null),await this._credentials.getApplicationCredentials(e)}async storeApplicationSecret(e,t){if(!this._credentials)throw new Error("Config not loaded. Call load() first.");return await this._credentials.storeApplicationSecret(e,t)}getTunnelPreference(){return this._projectConfig&&this._projectConfig.tunnel?.preference||null}async setTunnelPreference(e){if(!this._projectConfig)throw new Error("Not in a project directory");this._projectConfig.tunnel||(this._projectConfig.tunnel={}),this._projectConfig.tunnel.preference=e,this._projectConfig.tunnel.lastUpdated=new Date().toISOString(),await this.saveProjectConfig()}getTunnelSubdomain(){return this._projectConfig&&this._projectConfig.tunnel?.subdomain||null}async setTunnelSubdomain(e){if(!this._projectConfig)throw new Error("Not in a project directory");this._projectConfig.tunnel||(this._projectConfig.tunnel={}),this._projectConfig.tunnel.subdomain=e,this._projectConfig.tunnel.lastUpdated=new Date().toISOString(),await this.saveProjectConfig()}getTunnelUrl(){return this._projectConfig&&this._projectConfig.tunnel?.lastUrl||null}async setTunnelUrl(e){if(!this._projectConfig)throw new Error("Not in a project directory");this._projectConfig.tunnel||(this._projectConfig.tunnel={}),this._projectConfig.tunnel.lastUrl=e,this._projectConfig.tunnel.lastUpdated=new Date().toISOString(),await this.saveProjectConfig()}async setFaxServiceId(e){this.set("faxServiceId",e),await this.save()}getFaxServiceId(){return this.get("faxServiceId",null)}async setFaxSenderNumber(e){this.set("faxSenderNumber",e),await this.save()}getFaxSenderNumber(){return this.get("faxSenderNumber",null)}async storeFaxCredentials(e){if(!this._credentials)throw new Error("Config not loaded. Call load() first.");return await this._credentials.storeFax(e)}async getFaxCredentials(){if(!this._credentials)throw new Error("Config not loaded. Call load() first.");return await this._credentials.retrieveFax()}async hasFaxCredentials(){if(!this._credentials)throw new Error("Config not loaded. Call load() first.");return await this._credentials.hasFaxCredentials()}async clearFaxCredentials(){if(!this._credentials)throw new Error("Config not loaded. Call load() first.");return await this._credentials.clearFax()}getFaxPublicCredentialInfo(){if(!this._credentials)throw new Error("Config not loaded. Call load() first.");return this._credentials.getFaxPublicInfo()}},f=new Jn});var eo={};xe(eo,{logger:()=>n});var ne,Ve,Vn,Qi,Bn,n,T=G(()=>{"use strict";ne=y(require("chalk")),Ve=y(require("fs")),Vn=y(require("path")),Qi=y(require("os"));Lt();Bn=class{logFile;constructor(){let e="cli";try{let t=Vn.join(process.cwd(),"sinch.json");Ve.existsSync(t)&&(e=JSON.parse(Ve.readFileSync(t,"utf8")).name||"cli")}catch{}this.logFile=Vn.join(Qi.tmpdir(),`sinch-${e}.log`);try{Ve.writeFileSync(this.logFile,`=== Sinch CLI Debug Log - ${new Date().toISOString()} ===
|
|
8
8
|
`,{flag:"w"})}catch{}}writeToFile(e,t,...o){try{let s=`[${new Date().toISOString()}] ${e}: ${t} ${o.length>0?JSON.stringify(o):""}
|
|
9
|
-
`;
|
|
9
|
+
`;Ve.appendFileSync(this.logFile,s)}catch{}}info(e,...t){console.log(ne.default.blue("\u2139"),e,...t),this.writeToFile("INFO",e,...t)}success(e,...t){console.log(ne.default.green("\u2705"),e,...t),this.writeToFile("SUCCESS",e,...t)}warn(e,...t){console.log(ne.default.yellow("\u26A0\uFE0F "),e,...t),this.writeToFile("WARN",e,...t)}error(e,...t){console.log(ne.default.red("\u274C"),e,...t),this.writeToFile("ERROR",e,...t)}debug(e,...t){this.writeToFile("DEBUG",e,...t),ae()>=1&&console.log(ne.default.gray("\u{1F41B}"),ne.default.gray(e),...t)}httpDebug(e,...t){this.writeToFile("HTTP",e,...t),ae()>=2&&console.log(ne.default.gray("\u{1F310}"),ne.default.gray(e),...t)}verboseDebug(e,...t){this.writeToFile("VERBOSE",e,...t),ae()>=3&&console.log(ne.default.gray("\u{1F4CB}"),ne.default.gray(e),...t)}log(e,...t){console.log(e,...t)}title(e){console.log(ne.default.blue.bold(`
|
|
10
10
|
\u{1F3AF} ${e}`))}subtitle(e){console.log(ne.default.gray(`
|
|
11
|
-
${e}`))}list(e,t={}){let{indent:o=" ",bullet:r="\u2022"}=t;e.forEach(s=>{console.log(`${o}${ne.default.gray(r)} ${s}`)})}calculateColumnWidths(e,t){let o=e.map(r=>r.length);return t.forEach(r=>{r.forEach((s,a)=>{o[a]=Math.max(o[a]??0,String(s).length)})}),o}table(e,t){let o=this.calculateColumnWidths(e,t),r=e.map((s,a)=>s.padEnd(o[a]??0)).join(" ");console.log(ne.default.bold(r)),console.log(ne.default.gray("-".repeat(r.length))),t.forEach(s=>{let a=s.map((l,p)=>String(l).padEnd(o[p]??0)).join(" ");console.log(a)})}newline(){console.log()}},n=new
|
|
12
|
-
`));let
|
|
13
|
-
|
|
11
|
+
${e}`))}list(e,t={}){let{indent:o=" ",bullet:r="\u2022"}=t;e.forEach(s=>{console.log(`${o}${ne.default.gray(r)} ${s}`)})}calculateColumnWidths(e,t){let o=e.map(r=>r.length);return t.forEach(r=>{r.forEach((s,a)=>{o[a]=Math.max(o[a]??0,String(s).length)})}),o}table(e,t){let o=this.calculateColumnWidths(e,t),r=e.map((s,a)=>s.padEnd(o[a]??0)).join(" ");console.log(ne.default.bold(r)),console.log(ne.default.gray("-".repeat(r.length))),t.forEach(s=>{let a=s.map((l,p)=>String(l).padEnd(o[p]??0)).join(" ");console.log(a)})}newline(){console.log()}},n=new Bn});var yt={};xe(yt,{spinner:()=>c});var to,no,Kn,c,R=G(()=>{"use strict";to=y(require("ora")),no=y(require("cli-spinners")),Kn=class{spinner=null;spinnerType=no.default.dots;start(e){return this.spinner=(0,to.default)({text:e,spinner:this.spinnerType}).start(),this}succeed(e){return this.spinner&&(this.spinner.succeed(e),this.spinner=null),this}fail(e){return this.spinner&&(this.spinner.fail(e),this.spinner=null),this}info(e){return this.spinner&&(this.spinner.info(e),this.spinner=null),this}warn(e){return this.spinner&&(this.spinner.warn(e),this.spinner=null),this}stop(){return this.spinner&&(this.spinner.stop(),this.spinner=null),this}update(e){return this.spinner&&(this.spinner.text=e),this}get isSpinning(){return this.spinner?.isSpinning??!1}get text(){return this.spinner?.text??""}set text(e){this.spinner&&(this.spinner.text=e)}},c=new Kn});var ao=N((Ll,so)=>{"use strict";var X=y(require("fs-extra")),Be=y(require("path")),ee=y(require("chalk")),Fe=y(require("inquirer")),io=require("commander");E();T();R();Q();var wt=require("child_process"),oo=y(require("adm-zip")),Hn=y(require("keytar")),ro=new io.Command("init");ro.description("Initialize a new Sinch Functions project").argument("[template]","Template to use (simple-ivr, customer-lookup, smart-routing)").option("--name <name>","Function name (default: template name)").option("--runtime <runtime>","Runtime to use (node, csharp)").option("--skip-install","Skip npm install for Node.js projects").option("--non-interactive","Use default values without prompting").action(async(i,e)=>{try{await f.load();let t=process.cwd(),o=new J(f.getApiConfig()),r=e.runtime;r||(e.nonInteractive?r="node":r=(await Fe.default.prompt([{type:"list",name:"runtime",message:"Choose a runtime:",choices:[{name:"Node.js",value:"node"},{name:"C# (.NET)",value:"csharp"}],default:"node"}])).runtime),c.start(`Fetching available templates for ${r}...`);let s=await o.listRuntimeTemplates(r);if(c.stop(),!s.templates||s.templates.length===0)throw new Error(`No templates available for runtime '${r}'`);let a=i;if(!a)if(e.nonInteractive){let S=s.templates.filter(b=>b.name&&b.name.trim());if(S.length>0)a=S[0]?.name||"",n.info(`Using default template: ${a} (non-interactive mode)`);else throw new Error("No templates available")}else{let S=s.templates.filter($=>$.name&&$.name.trim()).map($=>({name:`${$.name} - ${($.description||"No description available").substring(0,100)}`,value:$.name}));a=(await Fe.default.prompt([{type:"list",name:"selectedTemplate",message:"Choose a template:",choices:S,pageSize:10}])).selectedTemplate}let l=e.name;l||(e.nonInteractive?l=a:l=(await Fe.default.prompt([{type:"input",name:"name",message:"Function name:",default:a,validate:b=>!b||b.trim().length===0?"Function name is required":/^[a-z][a-z0-9-]*$/.test(b.trim())?!0:"Function name must be lowercase, start with a letter, and contain only letters, numbers, and hyphens"}])).name.trim());let p=Be.default.join(t,l);if(await X.default.pathExists(p)){let S=!1;if(e.nonInteractive?(S=!0,n.info(`Directory '${l}' already exists. Overwriting (non-interactive mode)...`)):S=(await Fe.default.prompt([{type:"confirm",name:"overwrite",message:`Directory '${l}' already exists. Overwrite?`,default:!1}])).overwrite,!S){n.info("Initialization cancelled");return}await X.default.remove(p)}await X.default.ensureDir(p);let d=s.templates.find(S=>S.name===a);if(!d){let S=s.templates.map(b=>b.name).join(", ");throw new Error(`Template '${a}' not found. Available templates: ${S}`)}let u=["node","csharp"];if(!u.includes(r))throw new Error(`Runtime '${r}' not supported. Supported runtimes: ${u.join(", ")}`);c.start(`\u{1F680} Initializing ${l} with ${a} template (${r})...`);let m=await o.downloadTemplate(r,a);new oo.default(m).extractAllTo(p,!0),c.succeed("\u{1F4E6} Template extracted");let h={},C=[],v=d.category,k=[],re=Be.default.join(p,"template.json");if(await X.default.pathExists(re)){let S=await X.default.readJson(re);S.category&&(v=S.category),!v&&S.requirements?.sinchServices?.includes("voice")&&(v="voice");let b=new Set(["voice","conversation"]);k=(S.requirements?.sinchServices??[]).filter(O=>b.has(O));let $=["AUTO_CONFIGURE_VOICE","AUTO_CONFIGURE_CONVERSATION"],me=S.variables?Object.fromEntries(Object.entries(S.variables).filter(([O])=>!$.includes(O))):{};if(Object.keys(me).length>0)if(e.nonInteractive){n.info("\u{1F4DD} Using default values for template variables (non-interactive mode):");for(let[O,K]of Object.entries(me)){let P;typeof K=="string"?P=K:P=K.default||"",h[O]=P,n.info(` ${O}: ${P}`)}}else{n.newline(),n.info("\u{1F4DD} Configure template variables:");for(let[O,K]of Object.entries(me)){let P;typeof K=="string"?P={type:"input",name:O,message:`${O.replace(/_/g," ").toLowerCase()}:`,default:K}:(P={type:K.type==="number"?"number":"input",name:O,message:`${K.description||O.replace(/_/g," ").toLowerCase()}:`,default:K.default},K.type==="number"&&(P.validate=de=>K.min!==void 0&&de<K.min?`Value must be at least ${K.min}`:K.max!==void 0&&de>K.max?`Value must be at most ${K.max}`:!0));let xt=await Fe.default.prompt([P]);h[O]=xt[O]}}let Dt="sinch-functions-cli";if(S.secrets&&Object.keys(S.secrets).length>0)if(C=Object.keys(S.secrets),e.nonInteractive){n.info("\u{1F4DD} Template secrets detected (non-interactive mode):");for(let O of Object.keys(S.secrets))n.info(` ${O}: [will need to be set manually]`)}else{n.newline(),n.info("\u{1F510} Configure template secrets (stored securely in OS keychain):");for(let[O,K]of Object.entries(S.secrets)){let P=K.description||O.replace(/_/g," ").toLowerCase(),xt=K.required!==!1,de={type:"password",name:O,message:`${P}:`,validate:pe=>xt&&(!pe||pe.trim()==="")?"This secret is required":!0},se=(await Fe.default.prompt([de]))[O];if(se&&se.trim()!=="")try{let pe=`${l}-${O}`;await Hn.default.setPassword(Dt,pe,se),n.info(` \u2705 ${O} stored securely in keychain`)}catch(pe){n.warn(` \u26A0\uFE0F Could not store ${O} in keychain: ${pe.message}`),n.info(` \u{1F4A1} You can add it later with: sinch secrets add ${O} <value>`)}}}await X.default.remove(re)}let j=k.length>0;if(k.length>0&&!e.nonInteractive){let S=k.join(" + "),{autoConfig:b}=await Fe.default.prompt([{type:"confirm",name:"autoConfig",message:`Auto-configure ${S} integration on deploy?`,default:!0}]);j=b}let M=v==="voice";if(M&&!e.nonInteractive&&!await f.getApplicationCredentials()){n.newline(),n.info(ee.default.blue("\u{1F50A} This template uses voice callbacks and needs Voice application credentials.")),n.info(ee.default.gray(` You can find these in the Sinch Dashboard under your Voice app.
|
|
12
|
+
`));let b=await Fe.default.prompt([{type:"input",name:"applicationKey",message:"Voice Application Key:",validate:$=>$.length>0||"Application Key is required for voice templates"},{type:"password",name:"applicationSecret",message:"Voice Application Secret:",validate:$=>$.length>0||"Application Secret is required for voice templates"}]);await f.storeApplicationSecret(b.applicationKey,b.applicationSecret),f.set("defaultApplicationKey",b.applicationKey),await f.save(),n.info(ee.default.green(" \u2705 Voice credentials stored securely"))}c.start("\u{1F527} Finalizing function configuration...");let fe=Be.default.join(p,"sinch.json"),H;if(await X.default.pathExists(fe)){if(H=await X.default.readJson(fe),H.name=l,H.description=`Sinch Functions function: ${l}`,H.functionId=null,delete H.projectId,delete H.voiceAppId,H.variables)for(let[S,b]of Object.entries(H.variables))typeof b=="string"&&(b==="your-project-id"||b==="{{PROJECT_ID}}"?H.variables[S]=f.get("projectId"):(b==="your-application-key"||b==="{{SINCH_APPLICATION_KEY}}")&&(H.variables[S]=f.get("defaultApplicationKey")));H.created=new Date().toISOString(),H.variables={},H.secrets&&delete H.secrets}else H={name:l,functionId:null,runtime:r,description:`Sinch Functions function: ${l}`,created:new Date().toISOString(),variables:{},custom:{}};if(await X.default.writeJson(fe,H,{spaces:2}),r==="node"){let S=Be.default.join(p,"package.json");if(await X.default.pathExists(S)){let P=await X.default.readJson(S);P.name=l,P.description=H.description,await X.default.writeJson(S,P,{spaces:2})}let b=Be.default.join(p,".env"),$=`# Sinch Functions Environment Variables
|
|
13
|
+
`;$+=`# Generated by sinch functions init
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
`,Object.keys(h).forEach(
|
|
17
|
-
`});let
|
|
15
|
+
`,$+=`# Template Variables
|
|
16
|
+
`,Object.keys(h).forEach(P=>{$+=`${P}=${h[P]}
|
|
17
|
+
`});let me=f.get("projectId"),Dt=f.get("functionId"),O=f.get("defaultApplicationKey"),K=f.get("keyId");$+=`
|
|
18
18
|
# Sinch Configuration
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
`,(
|
|
23
|
-
|
|
24
|
-
`)
|
|
19
|
+
`,$+=`PROJECT_ID=${me||""}
|
|
20
|
+
`,$+=`FUNCTION_ID=${Dt||""}
|
|
21
|
+
`,$+=`PROJECT_ID_API_KEY=${K||""}
|
|
22
|
+
`,(M||O)&&($+=`VOICE_APPLICATION_KEY=${O||""}
|
|
23
|
+
`,$+=`PROTECT_VOICE_CALLBACKS=deploy
|
|
24
|
+
`),$+=`
|
|
25
25
|
# Secrets (stored in OS keychain - use "sinch auth login" to configure)
|
|
26
|
-
|
|
27
|
-
`,(
|
|
28
|
-
`),C.length>0&&(
|
|
26
|
+
`,$+=`PROJECT_ID_API_SECRET=
|
|
27
|
+
`,(M||O)&&($+=`VOICE_APPLICATION_SECRET=
|
|
28
|
+
`),C.length>0&&($+=`
|
|
29
29
|
# Template Secrets (stored in OS keychain - use "sinch secrets add <KEY> <VALUE>")
|
|
30
|
-
`,C.forEach(
|
|
31
|
-
`})),
|
|
30
|
+
`,C.forEach(P=>{$+=`${P}=
|
|
31
|
+
`})),k.length>0&&($+=`
|
|
32
|
+
# Sinch Service Auto-Configuration
|
|
33
|
+
`,$+=`AUTO_CONFIGURE=${j}
|
|
34
|
+
`,$+=`SINCH_SERVICES=${k.join(",")}
|
|
35
|
+
`),$+=`
|
|
32
36
|
# Environment
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
`,await
|
|
37
|
-
\u{1F4A1} To download this function, run:`),n.info(` ${
|
|
38
|
-
\u{1F4A1} To view status, run:`),n.info(` ${
|
|
39
|
-
\u{1F4A1} To view logs, run:`),n.info(` ${
|
|
40
|
-
\u{1F4A1} To delete this function, run:`),n.info(` ${
|
|
41
|
-
`).forEach(s=>{if(s.trim()&&!s.trim().startsWith("#")){let[a,...l]=s.split("=");a&&(o[a.trim()]=l.join("=").trim())}}),o.AUTO_CONFIGURE_CONVERSATION!=="true")return{isConversation:!1};let r=o.CONVERSATION_APP_ID;if(r)return{isConversation:!0,appId:r}}catch(t){n.debug("Could not read .env file: "+t.message)}return{isConversation:!1}}async function
|
|
42
|
-
`).forEach(
|
|
37
|
+
`,$+=`NODE_ENV=development
|
|
38
|
+
`,$+=`PORT=3000
|
|
39
|
+
`,$+=`SINCH_TUNNEL=false
|
|
40
|
+
`,await X.default.writeFile(b,$),n.info(""),n.info("\u{1F510} Secrets Management for Node.js:");try{let P=await f.getCredentials();P&&P.keySecret?(n.info(" \u2705 Sinch credentials found in secure storage"),n.info(" \u2705 F5 debugging will automatically load secrets from OS keychain"),n.info(""),n.info(" \u{1F4A1} To add custom secrets, use:"),n.info(` ${ee.default.cyan("sinch functions secrets add <KEY> <VALUE>")}`)):(n.info(" \u26A0\uFE0F No Sinch credentials found in secure storage"),n.info(""),n.info(" To set up authentication:"),n.info(` ${ee.default.cyan("sinch auth login")}`),n.info(""),n.info(" To add custom secrets:"),n.info(` ${ee.default.cyan("sinch functions secrets add <KEY> <VALUE>")}`))}catch{n.info(" \u2139\uFE0F Set up authentication with:"),n.info(` ${ee.default.cyan("sinch auth login")}`)}n.info(""),n.info(" \u{1F4DD} Note: Secrets are stored securely in your OS keychain"),n.info(" \u{1F4DD} Note: F5 debugging requires keytar (npm install keytar)")}if(r==="csharp"){let S=Be.default.join(p,"appsettings.json"),b;await X.default.pathExists(S)?b=await X.default.readJson(S):b={Logging:{LogLevel:{Default:"Information","Microsoft.AspNetCore":"Warning"}},AllowedHosts:"*"},b.Logging||(b.Logging={LogLevel:{Default:"Information","Microsoft.AspNetCore":"Warning"}}),b.AllowedHosts||(b.AllowedHosts="*"),Object.keys(h).forEach(P=>{b[P]=h[P]});let $=f.get("projectId"),me=f.get("defaultApplicationKey"),Dt=f.get("keyId");b.PROJECT_ID=$||"",b.PROJECT_ID_API_KEY=Dt||"",b.PROJECT_ID_API_SECRET="",(M||me)&&(b.VOICE_APPLICATION_KEY=me||"",b.VOICE_APPLICATION_SECRET=""),C.forEach(P=>{b[P]=""}),await X.default.writeJson(S,b,{spaces:2});let O=Be.default.join(p,"appsettings.Development.json"),K={Logging:{LogLevel:{Default:"Debug","Microsoft.AspNetCore":"Information"}},SinchTunnel:!1};await X.default.writeJson(O,K,{spaces:2});try{let P=await f.getCredentials();await new Promise((de,we)=>{let se=(0,wt.spawn)("dotnet",["user-secrets","init"],{cwd:p,shell:!0});se.on("close",pe=>pe===0?de():we(new Error("Failed to init user-secrets"))),se.on("error",we)}),P&&P.keySecret&&await new Promise((de,we)=>{let se=(0,wt.spawn)("dotnet",["user-secrets","set","PROJECT_ID_API_SECRET",P.keySecret],{cwd:p,shell:!0});se.on("close",pe=>pe===0?de():we(new Error("Failed to set API secret"))),se.on("error",we)}),P&&P.applicationSecret&&await new Promise((de,we)=>{let se=(0,wt.spawn)("dotnet",["user-secrets","set","VOICE_APPLICATION_SECRET",P.applicationSecret],{cwd:p,shell:!0});se.on("close",pe=>pe===0?de():we(new Error("Failed to set app secret"))),se.on("error",we)});let xt="sinch-functions-cli";for(let de of C)try{let we=`${l}-${de}`,se=await Hn.default.getPassword(xt,we);se&&await new Promise((pe,Fi)=>{let ji=(0,wt.spawn)("dotnet",["user-secrets","set",de,se],{cwd:p,shell:!0});ji.on("close",Ws=>Ws===0?pe():Fi(new Error(`Failed to set ${de}`))),ji.on("error",Fi)})}catch{}(P&&(P.keySecret||P.applicationSecret)||C.length>0)&&(n.info(""),n.info("\u{1F510} Secrets Management for C#:"),n.info(" \u2705 User secrets have been configured automatically"),n.info(" You can view them with: "+ee.default.cyan("dotnet user-secrets list")),C.length>0&&n.info(" \u{1F4A1} Template secrets have been added to user-secrets"))}catch{n.info(""),n.info("\u{1F510} Secrets Management for C#:"),n.info(" For local development, use dotnet user-secrets:"),n.info(` ${ee.default.cyan("dotnet user-secrets init")}`),n.info(` ${ee.default.cyan('dotnet user-secrets set "PROJECT_ID_API_SECRET" "your-api-secret"')}`),n.info(` ${ee.default.cyan('dotnet user-secrets set "VOICE_APPLICATION_SECRET" "your-app-secret"')}`)}}if(c.succeed("\u{1F680} Function initialized successfully"),n.newline(),n.title(`Function: ${ee.default.cyan(l)}`),n.info(`Template: ${ee.default.yellow(a)}`),n.info(`Runtime: ${ee.default.blue(r)}`),n.info(`Location: ${ee.default.gray(p)}`),r==="node"&&!e.skipInstall){n.newline(),c.start("Installing npm packages...");try{await new Promise((S,b)=>{let $=(0,wt.spawn)("npm",["install"],{cwd:p,stdio:"inherit",shell:!0});$.on("close",me=>{me===0?S():b(new Error(`npm install failed with code ${me}`))}),$.on("error",me=>{b(me)})}),c.succeed("\u{1F4E6} Dependencies installed successfully")}catch(S){c.fail("\u{1F4E6} Failed to install dependencies"),S.code==="ENOENT"?n.warn("npm not found. Please ensure Node.js is installed and in your PATH."):n.debug(`npm install error: ${S.message}`)}}n.newline(),n.info("\u{1F4CB} Next steps:"),n.info(` 1. \u{1F4C1} Navigate to function: ${ee.default.cyan(`cd ${l}`)}`),r==="node"?n.info(" 2. \u{1F3C3} Start development: sinch functions dev"):n.info(" 2. \u{1F3C3} Start development: dotnet run"),n.info(" 3. \u{1F680} Deploy to production: sinch functions deploy"),n.info(" 4. \u{1F4CA} View logs: sinch functions logs --follow"),n.newline(),n.info("\u{1F4A1} Template info:"),n.info(`\u2022 ${d.description}`),d.features&&d.features.length>0&&d.features.forEach(S=>{n.info(`\u2022 ${S}`)})}catch(t){c.stop(),n.error(`Failed to initialize function: ${t.message}`),process.exit(1)}});so.exports=ro});var fo=N((Jl,uo)=>{"use strict";var _=y(require("chalk")),co=require("commander"),lo=y(require("cli-table3")),qt=y(require("inquirer"));Q();E();T();R();var po=new co.Command("list");po.description("List all functions").option("--status <status>","Filter by status (Running, Failed, Pending, Building)").option("--runtime <runtime>","Filter by runtime (node, csharp, python)").option("--limit <limit>","Limit number of results","50").option("-i, --interactive","Interactive mode - select function for actions").action(async i=>{try{await f.load();let e=new J(f.getApiConfig());c.start("\u{1F4CB} Loading functions...");let t={limit:parseInt(i.limit||"50")};i.status&&(t.status=i.status),i.runtime&&(t.runtime=i.runtime);let o=await e.listFunctions();if(c.succeed(`\u{1F4CB} Found ${o.functions.length} functions`),o.functions.length===0){n.newline(),n.info("No functions found"),n.info("\u{1F4A1} Create your first function with:"),n.info(` ${_.default.cyan("sinch functions init")}`);return}n.newline(),n.title("Functions:");let r=o.functions.map(a=>{let l=new Date(a.createdAt).toLocaleDateString(),p=Wn(a.status),d=a.containerAppUrl?a.containerAppUrl.length>40?a.containerAppUrl.substring(0,37)+"...":a.containerAppUrl:_.default.gray("Not deployed");return[_.default.cyan(a.name),_.default.yellow(a.runtime),p,_.default.gray(l),_.default.blue(d)]}),s=new lo.default({head:["Name","Runtime","Status","Created","URL"],style:{head:["cyan"]},colWidths:[20,10,15,12,45]});if(s.push(...r),console.log(s.toString()),o.pagination){let{page:a,totalCount:l,totalPages:p}=o.pagination;n.newline(),n.info(_.default.gray(`Page ${a} of ${p} (${l} total functions)`)),a<p&&n.info(_.default.gray("\u{1F4A1} Use --limit to see more results"))}if(i.interactive&&o.functions.length>0){n.newline();let a=o.functions.map(d=>({name:`${d.name.padEnd(20)} ${d.runtime.padEnd(8)} ${Wn(d.status).padEnd(20)} ${d.id.substring(0,8)}`,value:d.id,short:d.name}));a.push(new qt.default.Separator),a.push({name:_.default.gray("Exit"),value:"exit",short:"Exit"});let{selectedFunction:l}=await qt.default.prompt([{type:"list",name:"selectedFunction",message:"Select a function for actions:",choices:a,pageSize:15}]);if(l==="exit")return;let p=o.functions.find(d=>d.id===l);p&&await Sa(p,e)}else n.newline(),n.info("\u{1F4A1} Function commands:"),n.info(` \u2022 View details: ${_.default.cyan("sinch functions status 01HX3KC5V8G3KCNZ8S5Y9ABC")}`),n.info(` \u2022 View logs: ${_.default.cyan("sinch functions logs 01HX3KC5V8G3KCNZ8S5Y9ABC")}`),n.info(` \u2022 Download: ${_.default.cyan("sinch functions download 01HX3KC5V8G3KCNZ8S5Y9ABC")}`),n.info(` \u2022 Interactive mode: ${_.default.cyan("sinch functions list -i")}`),n.info(` \u2022 Deploy new function: ${_.default.cyan("sinch functions deploy")}`)}catch(e){c.stop(),n.error(`Failed to list functions: ${e.message}`),process.exit(1)}});function Wn(i){return{Running:_.default.green("\u2705 Running"),Failed:_.default.red("\u274C Failed"),Pending:_.default.yellow("\u23F3 Pending"),Building:_.default.blue("\u{1F528} Building")}[i]||_.default.gray(i)}async function Sa(i,e){n.newline(),n.info(`\u{1F4CB} Selected: ${_.default.cyan(i.name)}`),n.info(` ID: ${_.default.gray(i.id)}`),n.info(` Status: ${Wn(i.status)}`),n.newline();let{action:t}=await qt.default.prompt([{type:"list",name:"action",message:"What would you like to do?",choices:[{name:"\u{1F4E5} Download source code",value:"download"},{name:"\u{1F4CA} View status details",value:"status"},{name:"\u{1F4DC} View logs",value:"logs"},{name:"\u{1F517} Copy URL to clipboard",value:"copy-url"},{name:"\u{1F5D1}\uFE0F Delete function",value:"delete"},new qt.default.Separator,{name:_.default.gray("Back"),value:"back"}]}]);switch(t){case"download":n.info(`
|
|
41
|
+
\u{1F4A1} To download this function, run:`),n.info(` ${_.default.cyan(`sinch functions download ${i.id}`)}`);break;case"status":n.info(`
|
|
42
|
+
\u{1F4A1} To view status, run:`),n.info(` ${_.default.cyan(`sinch functions status ${i.id}`)}`);break;case"logs":n.info(`
|
|
43
|
+
\u{1F4A1} To view logs, run:`),n.info(` ${_.default.cyan(`sinch functions logs ${i.id}`)}`);break;case"copy-url":i.containerAppUrl?(await require("clipboardy").write(i.containerAppUrl),n.success(`\u2705 URL copied to clipboard: ${i.containerAppUrl}`)):n.warn("\u26A0\uFE0F Function has no URL (not deployed)");break;case"delete":n.info(`
|
|
44
|
+
\u{1F4A1} To delete this function, run:`),n.info(` ${_.default.cyan(`sinch functions delete ${i.id}`)}`);break;case"back":return}}uo.exports=po});async function Gn(i){if(!await f.hasCredentials())throw new Error('No Sinch credentials found. Run "sinch auth login" first.');let e=await f.getApplicationCredentials();if(!e)throw new Error('No application credentials found. Run "sinch auth login" first.');let o=`https://callingapi.sinch.com/v1/configuration/callbacks/applications/${e.applicationKey}/`,r={url:{primary:i}},s=`${e.applicationKey}:${e.applicationSecret}`,a=Buffer.from(s).toString("base64");await zn.default.post(o,r,{headers:{Authorization:`Basic ${a}`,"Content-Type":"application/json"},timeout:1e4}),await new Promise(u=>setTimeout(u,1e3));let d=(await zn.default.get(o,{headers:{Authorization:`Basic ${a}`},timeout:1e4})).data?.url?.primary;if(d!==i)throw n.debug(`Callback verification mismatch. Expected: ${i}, Got: ${d}`),new Error(`Callback URL update verification failed. Expected: ${i}, Got: ${d}`);n.debug("Voice callback URL successfully updated and verified")}var zn,mo=G(()=>{"use strict";zn=y(require("axios"));E();T()});function ba(){return"https://us.conversation.api.sinch.com"}async function Ia(i,e,t){let o="https://auth.sinch.com/oauth2/token",r=new URLSearchParams;r.append("grant_type","client_credentials");let s=`${e}:${t}`,a=Buffer.from(s).toString("base64");return(await Jt.default.post(o,r,{headers:{Authorization:`Basic ${a}`,"Content-Type":"application/x-www-form-urlencoded"},timeout:1e4})).data.access_token}async function hn(){let i=Vt.default.join(process.cwd(),"appsettings.json");if(await je.default.pathExists(i))try{let t=await je.default.readJson(i);if(t.Webhooks?.AutoConfigureConversation!==!0)return{isConversation:!1};let o=t.CONVERSATION_APP_ID;if(o)return{isConversation:!0,appId:o}}catch(t){n.debug("Could not read appsettings.json: "+t.message)}let e=Vt.default.join(process.cwd(),".env");if(await je.default.pathExists(e))try{let t=await je.default.readFile(e,"utf8"),o={};if(t.split(`
|
|
45
|
+
`).forEach(s=>{if(s.trim()&&!s.trim().startsWith("#")){let[a,...l]=s.split("=");a&&(o[a.trim()]=l.join("=").trim())}}),"AUTO_CONFIGURE"in o){if(o.AUTO_CONFIGURE!=="true")return{isConversation:!1};if(!(o.SINCH_SERVICES??"").split(",").map(l=>l.trim()).includes("conversation"))return{isConversation:!1};let a=o.CONVERSATION_APP_ID;return a?{isConversation:!0,appId:a}:{isConversation:!1}}if(o.AUTO_CONFIGURE_CONVERSATION!=="true")return{isConversation:!1};let r=o.CONVERSATION_APP_ID;if(r)return{isConversation:!0,appId:r}}catch(t){n.debug("Could not read .env file: "+t.message)}return{isConversation:!1}}async function Yn(i){if(!await f.hasCredentials())throw new Error('No Sinch credentials found. Run "sinch auth login" first.');let{isConversation:e,appId:t}=await hn();if(n.debug(`isConversationFunction check: isConversation=${e}, appId=${t}`),!e||!t){n.debug("Not a Conversation function or missing CONVERSATION_APP_ID, skipping webhook config");return}let o=await f.getCredentials();if(!o?.projectId||!o?.keyId||!o?.keySecret)throw new Error('Missing project credentials. Run "sinch auth login" first.');let r=ba(),s=`${i}/webhook`;n.debug(`Conversation webhook URL: ${s}`),n.debug(`Project ID: ${o.projectId}, App ID: ${t}`),n.debug("Getting OAuth access token...");let a=await Ia(o.projectId,o.keyId,o.keySecret);n.debug("Got access token successfully");let l={Authorization:`Bearer ${a}`,"Content-Type":"application/json"},p=`${r}/v1/projects/${o.projectId}/apps/${t}/webhooks`;n.debug(`Listing webhooks: GET ${p}`);let d=await Jt.default.get(p,{headers:l,timeout:1e4});n.debug(`Found ${d.data.webhooks?.length||0} webhooks`);let u=d.data.webhooks?.find(C=>C.target?.includes(".sinch.com")&&(C.target?.includes("fn-dev.")||C.target?.includes("fn-prod.")||C.target?.includes("functions."))),m=["MESSAGE_INBOUND"];if(u){n.debug(`Found existing webhook: id=${u.id}, target=${u.target}`);let C=`${r}/v1/projects/${o.projectId}/webhooks/${u.id}`;n.debug(`Deleting webhook: DELETE ${C}`);try{await Jt.default.delete(C,{headers:l,timeout:1e4}),n.debug(`Deleted existing Conversation webhook ${u.id}`)}catch(v){n.debug(`Failed to delete webhook: ${v.response?.status} ${v.response?.data?JSON.stringify(v.response.data):v.message}`)}}let w=`${r}/v1/projects/${o.projectId}/webhooks`,h={app_id:t,target:s,target_type:"HTTP",triggers:m};n.debug(`Creating webhook: POST ${w}`),n.debug(`Payload: ${JSON.stringify(h)}`);try{let C=await Jt.default.post(w,h,{headers:l,timeout:1e4});n.debug(`Created new Conversation webhook: ${JSON.stringify(C.data)}`)}catch(C){throw n.debug(`Failed to create webhook: ${C.response?.status} ${C.response?.data?JSON.stringify(C.response.data):C.message}`),C}n.debug("Conversation webhook successfully configured")}async function Xn(){let i=Vt.default.join(process.cwd(),"appsettings.json");if(await je.default.pathExists(i))try{let t=await je.default.readJson(i);return t.Webhooks?t.Webhooks.AutoConfigureVoice===!0:!0}catch(t){n.debug("Could not read appsettings.json: "+t.message)}let e=Vt.default.join(process.cwd(),".env");if(await je.default.pathExists(e))try{let t=await je.default.readFile(e,"utf8"),o={};return t.split(`
|
|
46
|
+
`).forEach(r=>{if(r.trim()&&!r.trim().startsWith("#")){let[s,...a]=r.split("=");s&&(o[s.trim()]=a.join("=").trim())}}),"AUTO_CONFIGURE"in o?o.AUTO_CONFIGURE!=="true"?!1:(o.SINCH_SERVICES??"").split(",").map(s=>s.trim()).includes("voice"):o.AUTO_CONFIGURE_VOICE==="true"}catch(t){n.debug("Could not read .env file: "+t.message)}return!1}var Jt,je,Vt,go=G(()=>{"use strict";Jt=y(require("axios")),je=y(require("fs-extra")),Vt=y(require("path"));E();T()});var Co={};xe(Co,{combineDocumentation:()=>yo,detectRuntimeFromFile:()=>wo,findFunctionFile:()=>ho,generateDocsFromLocal:()=>Zn,saveDocumentationToFile:()=>Qn});async function Zn(){let i=process.cwd(),e=await ho(i);if(!e)throw new Error("No function file found. Make sure you're in a function directory with function.js, function.ts, index.js, index.ts, handler.js, or handler.ts");let t=await Ct.readFile(e,"utf8"),o=wo(e),r=Ke.basename(i),a=await new J(f.getApiConfig()).generateDocumentationFromCode(t,o,r);return yo(a)}async function ho(i){let e=["function.js","function.ts","index.js","index.ts","handler.js","handler.ts","function.py","handler.py","Function.cs","Handler.cs"];for(let t of e){let o=Ke.join(i,t);if(await Ct.pathExists(o))return o}return null}function yo(i){let e=i.documentation||"",t=i.diagram||i.callFlowDiagram;return t&&(e&&!e.endsWith(`
|
|
43
47
|
|
|
44
48
|
`)&&(e+=`
|
|
45
49
|
|
|
@@ -49,63 +53,63 @@ ${e}`))}list(e,t={}){let{indent:o=" ",bullet:r="\u2022"}=t;e.forEach(s=>{consol
|
|
|
49
53
|
---
|
|
50
54
|
|
|
51
55
|
`,e+=`*Documentation generated on ${new Date(i.generatedAt).toLocaleString()} using Sinch AI*
|
|
52
|
-
`),e}async function
|
|
53
|
-
`);for(let w of m){let h=w.match(/^([^=]+)\s*=\s*(.+)$/);if(h&&h[1]&&h[2]&&h[1].trim()===a){p=h[2].trim(),d=!0,n.debug(`Found ${a} in dotnet user-secrets`);break}}}catch{}!p&&o&&(a==="PROJECT_ID"&&o.projectId?p=o.projectId:a==="PROJECT_ID_API_KEY"&&o.keyId?p=o.keyId:a==="PROJECT_ID_API_SECRET"&&o.keySecret?(p=o.keySecret,d=!0):a==="VOICE_APPLICATION_KEY"&&o.applicationKey?p=o.applicationKey:a==="VOICE_APPLICATION_SECRET"&&o.applicationSecret&&(p=o.applicationSecret,d=!0)),p&&(t[a]={Value:p,Secret:d})}else t[a]={Value:String(l),Secret:!1}}}catch(s){n.debug("Could not read appsettings.json: "+s.message)}}else{let r=
|
|
54
|
-
`).forEach(p=>{if(p.trim()&&!p.trim().startsWith("#")){let[d,...u]=p.split("=");d&&(a[d.trim()]=u.join("=").trim())}});let l=["PORT","NODE_ENV","SINCH_TUNNEL"];for(let[p,d]of Object.entries(a))if(!l.includes(p))if(d===""||d===null||d===void 0){let u="",m=!1;if(o&&(p==="PROJECT_ID"&&o.projectId?u=o.projectId:p==="PROJECT_ID_API_KEY"&&o.keyId?u=o.keyId:p==="PROJECT_ID_API_SECRET"&&o.keySecret?(u=o.keySecret,m=!0):p==="VOICE_APPLICATION_KEY"&&o.applicationKey?u=o.applicationKey:p==="VOICE_APPLICATION_SECRET"&&o.applicationSecret&&(u=o.applicationSecret,m=!0)),!u)try{let w="sinch-functions-cli",h=`${e}-${p}`;u=await
|
|
55
|
-
${l||p}`)):r()})}),c.succeed("Build successful")}catch(r){throw c.fail("Build failed"),r}c.start("Starting function for validation...");let t=null,o="";try{if(t=(0,
|
|
56
|
+
`),e}async function Qn(i,e){let t=Ke.resolve(e);await Ct.writeFile(t,i,"utf8")}function wo(i){switch(Ke.extname(i).toLowerCase()){case".js":case".ts":return"node";case".py":return"python";case".cs":return"csharp";default:return"node"}}var Ct,Ke,ei=G(()=>{"use strict";Ct=y(require("fs-extra")),Ke=y(require("path"));Q();E()});var Eo=N((rd,Ao)=>{"use strict";var Ie=y(require("fs-extra")),tt=y(require("path")),x=y(require("chalk")),So=require("commander");Q();E();T();R();ut();mo();go();var bo=y(require("adm-zip")),Io=y(require("os")),ti=y(require("inquirer")),Bt=require("child_process"),$o=y(require("keytar")),Po=new So.Command("deploy");Po.description("Deploy function to production").option("-n, --name <name>","Function name (default: current directory)").option("--no-wait","Don't wait for deployment to complete").option("--non-interactive","Use default values without prompting (auto-generates docs)").option("--no-docs","no doc generation").option("--private","Deploy to private namespace (internal access only, not publicly accessible)").action(async i=>{try{if(await f.load(),!f.isInProject())throw new Error('Not in a Sinch Functions project directory. Run "sinch functions init" first.');let e=f.getProjectConfig(),t=i.name||e.name,o=e.runtime;if(await Ea(e,i),o==="csharp"){let u=await Ie.default.readdir(process.cwd()).then(w=>w.filter(h=>h.endsWith(".csproj")));if(u.length===0)throw new Error("No .csproj file found. Make sure you're in a valid C# function directory.");let m=u[0];await Na(process.cwd(),m)}c.start("\u{1F4E6} Packaging function...");let r=await $a(t);c.succeed("\u{1F4E6} Function packaged"),c.start("\u{1F527} Preparing configuration...");let s=await Pa(o,t);c.succeed("\u{1F527} Configuration prepared");let a=await Ta(e,i);c.start("\u{1F680} Submitting deployment...");let l=new J(f.getApiConfig()),p=await Ie.default.readFile(r),d=await l.deployFunction(t,o,p,s,a);if(await Ie.default.remove(r),c.succeed("\u{1F680} Deployment submitted"),f.set("functionId",d.id,!0),await f.saveProjectConfig(),n.newline(),n.info(`Function ID: ${x.default.cyan(d.id)}`),n.info(`Status: ${ni(d.status)}`),i.wait===!1){n.newline(),n.info("\u{1F4A1} Check deployment progress with:"),n.info(` ${x.default.cyan(`sinch functions status ${d.id}`)}`);return}await Aa(l,d.id)}catch(e){c.stop(),n.error(`Failed to deploy function: ${e.message}`);let t=e.exitCode||I.FAILURE;process.exit(t)}});async function $a(i){let e=new bo.default,t=process.cwd(),o=tt.default.join(Io.default.tmpdir(),`${i}-${Date.now()}.zip`),r=["node_modules","bin","obj",".git",".DS_Store","*.zip",".env",".env.local","npm-debug.log*",".sinch-tmp","examples","claude.md","readme.md",".vs",".vscode",".idea",".cursor","*.user","*.suo"];async function s(a,l=""){let p=await Ie.default.readdir(a);for(let d of p){let u=tt.default.join(a,d),m=tt.default.join(l,d).replace(/\\/g,"/");if(r.some(h=>d.match(new RegExp(h.replace("*",".*")))))continue;if((await Ie.default.stat(u)).isDirectory())await s(u,m);else{let h=await Ie.default.readFile(u);e.addFile(m,h)}}}return await s(t),e.writeZip(o),o}async function Pa(i,e){let t={},o=null;try{o=await f.getCredentials()}catch(r){n.debug("Could not load credentials from secure storage: "+r.message)}if(i==="csharp"){let r=tt.default.join(process.cwd(),"appsettings.json");if(await Ie.default.pathExists(r))try{let s=await Ie.default.readJson(r);for(let a of Object.keys(s)){if(a==="Logging"||a==="AllowedHosts")continue;let l=s[a];if(l===""||l===null||l===void 0){let p="",d=!1;try{let m=(0,Bt.execSync)("dotnet user-secrets list",{cwd:process.cwd(),encoding:"utf8",stdio:["pipe","pipe","pipe"]}).trim().split(`
|
|
57
|
+
`);for(let w of m){let h=w.match(/^([^=]+)\s*=\s*(.+)$/);if(h&&h[1]&&h[2]&&h[1].trim()===a){p=h[2].trim(),d=!0,n.debug(`Found ${a} in dotnet user-secrets`);break}}}catch{}!p&&o&&(a==="PROJECT_ID"&&o.projectId?p=o.projectId:a==="PROJECT_ID_API_KEY"&&o.keyId?p=o.keyId:a==="PROJECT_ID_API_SECRET"&&o.keySecret?(p=o.keySecret,d=!0):a==="VOICE_APPLICATION_KEY"&&o.applicationKey?p=o.applicationKey:a==="VOICE_APPLICATION_SECRET"&&o.applicationSecret&&(p=o.applicationSecret,d=!0)),p&&(t[a]={Value:p,Secret:d})}else t[a]={Value:String(l),Secret:!1}}}catch(s){n.debug("Could not read appsettings.json: "+s.message)}}else{let r=tt.default.join(process.cwd(),".env");if(await Ie.default.pathExists(r))try{let s=await Ie.default.readFile(r,"utf8"),a={};s.split(`
|
|
58
|
+
`).forEach(p=>{if(p.trim()&&!p.trim().startsWith("#")){let[d,...u]=p.split("=");d&&(a[d.trim()]=u.join("=").trim())}});let l=["PORT","NODE_ENV","SINCH_TUNNEL"];for(let[p,d]of Object.entries(a))if(!l.includes(p))if(d===""||d===null||d===void 0){let u="",m=!1;if(o&&(p==="PROJECT_ID"&&o.projectId?u=o.projectId:p==="PROJECT_ID_API_KEY"&&o.keyId?u=o.keyId:p==="PROJECT_ID_API_SECRET"&&o.keySecret?(u=o.keySecret,m=!0):p==="VOICE_APPLICATION_KEY"&&o.applicationKey?u=o.applicationKey:p==="VOICE_APPLICATION_SECRET"&&o.applicationSecret&&(u=o.applicationSecret,m=!0)),!u)try{let w="sinch-functions-cli",h=`${e}-${p}`;u=await $o.default.getPassword(w,h)||"",u&&(m=!0,n.debug(`Loaded custom secret ${p} from keychain`))}catch(w){n.debug(`Could not load ${p} from keychain: ${w.message}`)}u&&(t[p]={Value:u,Secret:m})}else t[p]={Value:d,Secret:!1}}catch(s){n.debug("Could not read .env file: "+s.message)}}return t}async function Aa(i,e){let o=Date.now(),r=!1,s;return n.newline(),c.start("\u23F3 Connecting to deployment stream..."),new Promise((a,l)=>{let p,d;i.streamDeployment(e,u=>{let m=Math.floor((Date.now()-o)/1e3);switch(u.type){case"connected":c.text="\u23F3 Deployment stream connected, waiting for updates...";break;case"status":let w=u.data.data.message;c.text=`\u23F3 ${w} (${m}s)`;break;case"progress":let h=u.data.data.message,C=u.data.data.percentComplete;C?c.text=`\u23F3 ${h} (${C}%, ${m}s)`:c.text=`\u23F3 ${h} (${m}s)`;break;case"completed":r=!0,s=u.data.data.url,c.succeed("\u2705 Function deployed successfully"),i.getFunction(e).then(async k=>{if(n.newline(),n.info("\u{1F389} Deployment Complete!"),n.info(` Function: ${x.default.cyan(k.name)}`),n.info(` Status: ${ni("Running")}`),n.info(` URL: ${x.default.blue(s)}`),s){let re=await hn(),j=await Xn();if(re.isConversation){n.newline(),n.info("\u{1F4AC} Conversation Integration:");try{c.start("Updating Sinch Conversation webhook..."),await Yn(s),c.succeed("Conversation webhook updated automatically"),n.info(` Webhook URL set to: ${x.default.cyan(s+"/conversation")}`)}catch(M){c.fail("Failed to update Conversation webhook");let fe=M.response?.data?JSON.stringify(M.response.data):M.message;n.warn(` Error: ${fe}`)}}if(j){n.newline(),n.info("\u{1F4DE} Voice Integration:");try{c.start("Updating Sinch Voice callback URL..."),await Gn(s),c.succeed("Voice callback URL updated automatically"),n.info(` Callback URL set to: ${x.default.cyan(s)}`)}catch(M){c.fail("Failed to update callback URL automatically"),n.warn(` Error: ${M.message}`),n.info(` Manual setup: ${x.default.cyan(`sinch voice callback-url ${s}`)}`)}}n.info(` Test function: ${x.default.cyan(`curl ${s}`)}`)}n.newline(),n.info("\u{1F4A1} Next steps:"),n.info(` \u2022 View logs: ${x.default.cyan(`sinch functions logs ${e} --follow`)}`),n.info(` \u2022 Check status: ${x.default.cyan(`sinch functions status ${e}`)}`),p&&p(),d&&clearTimeout(d),a()}).catch(k=>{n.error(`Failed to get function details: ${k.message}`),p&&p(),d&&clearTimeout(d),a()});break;case"failed":r=!0;let v=u.data.data.errorMessage;c.fail("\u274C Deployment failed"),n.newline(),n.error("Deployment failed:"),v&&n.error(` ${v}`),n.newline(),n.info("\u{1F4A1} Troubleshooting:"),n.info(` \u2022 Check logs: ${x.default.cyan(`sinch functions logs ${e}`)}`),n.info(` \u2022 Check status: ${x.default.cyan(`sinch functions status ${e}`)}`),p&&p(),d&&clearTimeout(d),process.exit(1);break}},u=>{n.debug("SSE stream error, falling back to polling:",u),c.text="\u23F3 Deployment stream unavailable, checking status...",p&&p(),vo(i,e,o,3e5).then(a).catch(l)}).then(u=>{n.debug("SSE stream setup successful, cleanup function received"),p=u,d=setTimeout(()=>{r||(c.fail("\u23F0 Deployment timeout"),n.newline(),n.warn("Deployment is taking longer than expected"),n.info("\u{1F4A1} Check deployment progress with:"),n.info(` ${x.default.cyan(`sinch functions status ${e}`)}`),p&&p(),a())},3e5)}).catch(u=>{n.debug(`Failed to set up SSE stream, falling back to polling: ${u.message}`),vo(i,e,o,3e5).then(a).catch(l)})})}async function vo(i,e,t,o){for(;Date.now()-t<o;){try{let a=(await i.getFunctionStatus(e)).function;if(a.status==="Running"){if(c.succeed("\u2705 Function deployed successfully"),n.newline(),n.info("\u{1F389} Deployment Complete!"),n.info(` Function: ${x.default.cyan(a.name)}`),n.info(` Status: ${ni(a.status)}`),n.info(` URL: ${x.default.blue(a.containerAppUrl)}`),a.containerAppUrl){let p=await hn(),d=await Xn();if(p.isConversation){n.newline(),n.info("\u{1F4AC} Conversation Integration:");try{c.start("Updating Sinch Conversation webhook..."),await Yn(a.containerAppUrl),c.succeed("Conversation webhook updated automatically"),n.info(` Webhook URL set to: ${x.default.cyan(a.containerAppUrl+"/conversation")}`)}catch(u){c.fail("Failed to update Conversation webhook");let m=u.response?.data?JSON.stringify(u.response.data):u.message;n.warn(` Error: ${m}`)}}if(d){n.newline(),n.info("\u{1F4DE} Voice Integration:");try{c.start("Updating Sinch Voice callback URL..."),await Gn(a.containerAppUrl),c.succeed("Voice callback URL updated automatically"),n.info(` Callback URL set to: ${x.default.cyan(a.containerAppUrl)}`)}catch(u){c.fail("Failed to update callback URL automatically"),n.warn(` Error: ${u.message}`),n.info(` Manual setup: ${x.default.cyan(`sinch voice callback-url ${a.containerAppUrl}`)}`)}}n.info(` Test function: ${x.default.cyan(`curl ${a.containerAppUrl}`)}`)}n.newline(),n.info("\u{1F4A1} Next steps:"),n.info(` \u2022 View logs: ${x.default.cyan(`sinch functions logs ${e} --follow`)}`),n.info(` \u2022 Check status: ${x.default.cyan(`sinch functions status ${e}`)}`);return}a.status==="Failed"&&(c.fail("\u274C Deployment failed"),n.newline(),n.error("Deployment failed:"),a.errorMessage&&n.error(` ${a.errorMessage}`),n.newline(),n.info("\u{1F4A1} Troubleshooting:"),n.info(` \u2022 Check logs: ${x.default.cyan(`sinch functions logs ${e}`)}`),n.info(` \u2022 Check status: ${x.default.cyan(`sinch functions status ${e}`)}`),process.exit(1));let l=Math.floor((Date.now()-t)/1e3);c.text=`\u23F3 Deploying function... (${a.status}, ${l}s)`}catch(s){n.debug(`Status check failed: ${s.message}`)}await new Promise(s=>setTimeout(s,3e3))}c.fail("\u23F0 Deployment timeout"),n.newline(),n.warn("Deployment is taking longer than expected"),n.info("\u{1F4A1} Check deployment progress with:"),n.info(` ${x.default.cyan(`sinch functions status ${e}`)}`)}function ni(i){return{Running:x.default.green("\u2705 Running"),Failed:x.default.red("\u274C Failed"),Pending:x.default.yellow("\u23F3 Pending"),Building:x.default.blue("\u{1F528} Building")}[i]||x.default.gray(i)}async function Ea(i,e){let t=!1;if(e.docs===!1){n.info("Skipping documentation generation (--no-docs flag)");return}if(e.nonInteractive)n.info("Generating documentation (non-interactive mode)"),t=!0;else{if(i.docsPreference==="never")return;if(ka(i))t=!0;else{let o=await ti.default.prompt([{type:"list",name:"docsChoice",message:"Generate/update documentation before deployment?",choices:[{name:"Yes - Generate documentation this time",value:"yes"},{name:"No - Skip documentation this time",value:"no"},{name:"Always - Generate documentation and remember preference",value:"always"},{name:"Never - Don't generate documentation and remember preference",value:"never"}],default:"yes"}]);o.docsChoice==="yes"?t=!0:o.docsChoice==="no"?t=!1:o.docsChoice==="always"?(t=!0,f.set("docsPreference","always",!0),await f.saveProjectConfig()):o.docsChoice==="never"&&(t=!1,f.set("docsPreference","never",!0),await f.saveProjectConfig())}}if(t)try{c.start("\u{1F4DD} Generating documentation...");let{generateDocsFromLocal:o,saveDocumentationToFile:r}=(ei(),F(Co)),s=await o(),a=tt.default.basename(process.cwd());await r(s,"README.md",a),c.succeed("\u{1F4DD} Documentation updated in README.md")}catch(o){c.warn(`\u26A0\uFE0F Failed to generate documentation: ${o.message}`),n.warn("Continuing with deployment...")}}function ka(i){return i.docsPreference==="always"}async function Ta(i,e){if(e.private||i.accessPreference==="always-private")return"private";if(i.accessPreference==="always-public"||e.nonInteractive)return"public";let o=(await ti.default.prompt([{type:"list",name:"accessChoice",message:"Deployment access level?",choices:[{name:"Public - Accessible from the internet",value:"public"},{name:"Private - Internal access only (Sinch services)",value:"private"},{name:"Always Public - Remember this choice",value:"always-public"},{name:"Always Private - Remember this choice",value:"always-private"}],default:"public"}])).accessChoice;return o==="always-public"?(f.set("accessPreference","always-public",!0),await f.saveProjectConfig(),"public"):o==="always-private"?(f.set("accessPreference","always-private",!0),await f.saveProjectConfig(),"private"):o}async function Na(i,e){c.start("Building function locally...");try{await new Promise((r,s)=>{let a=(0,Bt.spawn)("dotnet",["build",e,"-c","Release"],{cwd:i,stdio:"pipe",shell:!0}),l="",p="";a.stdout?.on("data",d=>{p+=d}),a.stderr?.on("data",d=>{l+=d}),a.on("close",d=>{d!==0?s(new Error(`Build failed:
|
|
59
|
+
${l||p}`)):r()})}),c.succeed("Build successful")}catch(r){throw c.fail("Build failed"),r}c.start("Starting function for validation...");let t=null,o="";try{if(t=(0,Bt.spawn)("dotnet",["run","--project",e,"--no-build","-c","Release"],{cwd:i,stdio:"pipe",shell:!0}),t.stdout?.on("data",s=>{o+=s.toString()}),t.stderr?.on("data",s=>{o+=s.toString()}),await Ra("http://localhost:3000/health",3e4))c.succeed("Function started and health check passed");else throw c.fail("Function failed to start within timeout"),o&&console.error(`
|
|
56
60
|
Process output:
|
|
57
61
|
`+o),new Error("Function validation failed: could not start function")}catch(r){throw c.fail("Validation failed"),o&&console.error(`
|
|
58
62
|
Process output:
|
|
59
|
-
`+o),r}finally{if(t&&t.pid){try{process.kill(t.pid)}catch{}await new Promise(r=>setTimeout(r,1e3))}}}async function
|
|
63
|
+
`+o),r}finally{if(t&&t.pid){try{process.kill(t.pid)}catch{}await new Promise(r=>setTimeout(r,1e3))}}}async function Ra(i,e){let t=Date.now();for(;Date.now()-t<e;){try{if((await fetch(i)).ok)return!0}catch{}await new Promise(o=>setTimeout(o,500))}return!1}Ao.exports=Po});function xa(i){return Da.some(e=>typeof e=="string"?i===e:e.test(i))}function ko(i){let e={};for(let[t,o]of Object.entries(process.env))xa(t)&&(e[t]=o);return i&&Object.assign(e,i),e}var Da,To=G(()=>{"use strict";Da=["PATH","PATHEXT","SYSTEMROOT","SYSTEMDRIVE","WINDIR","COMSPEC","HOMEDRIVE","HOMEPATH","USERPROFILE","APPDATA","LOCALAPPDATA","PROGRAMFILES","PROGRAMDATA","TEMP","TMP","OS","HOME","USER","SHELL","LANG","LC_ALL","LC_CTYPE","TERM","TZ","TMPDIR","XDG_RUNTIME_DIR","NODE_PATH","NODE_ENV","NODE_OPTIONS","NODE_NO_WARNINGS","NODE_EXTRA_CA_CERTS","DEBUG","EDITOR","TERM_PROGRAM",/^SINCH_/,/^ASPNETCORE_/,/^DOTNET_/,/^npm_/]});var Oo=N((fd,xo)=>{"use strict";var z=y(require("fs-extra")),ke=y(require("path")),Kt=y(require("chalk")),ii=require("child_process"),No=require("commander"),Ro=y(require("inquirer"));E();T();R();ut();To();var Do=new No.Command("dev");Do.description("Start local development server").option("-p, --port <port>","Port to run on","3000").option("-d, --debug","Enable debugging with --inspect").option("--tunnel","Force tunnel creation").option("--no-tunnel",'Disable tunnel and reset "always" preference').action(async i=>{try{if(await f.load(),!f.isInProject())throw new Error('Not in a Sinch Functions project directory. Run "sinch functions init" first.');let e=f.getProjectConfig();if(!e)throw new Error("No project configuration found");let t=e.runtime||"node",o;if(t==="csharp"){let r=await z.default.readdir(process.cwd()).then(s=>s.filter(a=>a.endsWith(".csproj")));if(r.length===0)throw new Error("No .csproj file found. Make sure you're in a valid C# function directory.");o=r[0],n.debug(`Using project file: ${o}`)}else{let r=ke.default.join(process.cwd(),"node_modules",".bin","sinch-runtime");if(!await z.default.pathExists(r))throw new Error("@sinch/functions-runtime not found. Run npm install first.")}n.title(`Starting ${e.name} (${e.runtime})`),n.info(`Port: ${i.port}`),n.newline(),await Fa(i,e,o)}catch(e){c.stop(),n.error(`Failed to start development server: ${e.message}`);let t=e.exitCode||I.FAILURE;process.exit(t)}});async function Oa(i,e){if(e==="node"){let t=ke.default.join(process.cwd(),".env");if(await z.default.pathExists(t)){let o=await z.default.readFile(t,"utf-8"),r=`SINCH_TUNNEL=${i}`;o.includes("SINCH_TUNNEL=")?o=o.replace(/SINCH_TUNNEL=(true|false)/g,r):o+=`
|
|
60
64
|
${r}
|
|
61
|
-
`,await H.default.writeFile(t,o,"utf-8"),n.debug(`Updated .env: SINCH_TUNNEL=${i}`)}}else if(e==="csharp"){let t=Ie.default.join(process.cwd(),"appsettings.Development.json");if(await H.default.pathExists(t)){let o=await H.default.readJson(t);o.SinchTunnel=i,await H.default.writeJson(t,o,{spaces:2}),n.debug(`Updated appsettings.Development.json: SinchTunnel=${i}`)}}}async function Ra(i,e,t){let o=e.runtime||"node",r=!1;if(i.tunnel===!0)r=!0;else if(i.tunnel===!1)r=!1,e.tunnel?.preference==="always"&&(f.set("tunnel",{...e.tunnel,preference:"no"},!0),await f.saveProjectConfig());else if(e.tunnel?.preference==="never")r=!1;else if(ja(e))r=!0;else{let{tunnelChoice:d}=await Ao.default.prompt([{type:"list",name:"tunnelChoice",message:"Enable Sinch tunnel for external access?",choices:[{name:"Yes - Enable tunnel this time",value:"yes"},{name:"No - Local only this time",value:"no"},{name:"Always - Enable tunnel and remember preference",value:"always"},{name:"Never - Don't enable tunnel and remember preference",value:"never"}],default:"no"}]);d==="yes"?r=!0:d==="no"?r=!1:d==="always"?(r=!0,f.set("tunnel",{...e.tunnel,preference:"always"},!0),await f.saveProjectConfig()):d==="never"&&(r=!1,f.set("tunnel",{...e.tunnel,preference:"never"},!0),await f.saveProjectConfig())}await xa(r,o);let s=$o({PORT:i.port,NODE_ENV:"development",SINCH_FUNCTIONS_LOCAL:"true",SINCH_TUNNEL:r?"true":"false"});e.variables&&Object.entries(e.variables).forEach(([d,u])=>{s[d]=u});try{let d=await f.getApplicationCredentials(e.voiceAppKey);d?(s.SINCH_APPLICATION_KEY=d.applicationKey,s.SINCH_APPLICATION_SECRET=d.applicationSecret,n.debug("\u2705 Injected application credentials for voice operations")):n.debug("\u26A0\uFE0F No application credentials found - voice features may not work")}catch(d){n.debug(`\u26A0\uFE0F Could not load application credentials: ${d.message}`)}n.info("\u{1F680} Starting local server...");let a=null,l=!1;function p(){if(a&&a.kill(),o==="csharp"){let d=["watch","run","--no-launch-profile"];t&&d.push("--project",t),i.port&&d.push("--urls",`http://localhost:${i.port}`),s.ASPNETCORE_ENVIRONMENT="Development",s.ASPNETCORE_URLS=`http://localhost:${i.port}`,a=(0,ei.spawn)("dotnet",d,{env:s,stdio:"inherit",cwd:process.cwd()})}else a=(0,ei.spawn)("npm",["run","dev"],{env:s,stdio:"inherit",cwd:process.cwd(),shell:!0});a.on("spawn",async()=>{if(!l){l=!0,n.newline(),n.success(`\u2705 Server running on http://localhost:${i.port}`),i.debug&&(n.newline(),o==="csharp"?Fa():Da()),n.newline(),n.info("\u{1F4A1} Development commands:"),n.info(` \u2022 Test function: ${Jt.default.cyan(`curl http://localhost:${i.port}`)}`),n.info(` \u2022 View in browser: ${Jt.default.cyan(`http://localhost:${i.port}`)}`),n.info(` \u2022 Stop server: ${Jt.default.gray("Ctrl+C")}`);let d=o==="csharp"?"dotnet watch":"nodemon";n.info(` \u2022 File watching: ${Jt.default.green(`enabled (via ${d})`)}`)}}),a.on("error",d=>{n.error(`Server error: ${d.message}`)}),a.on("exit",(d,u)=>{u!=="SIGTERM"&&u!=="SIGKILL"&&n.error(`Server exited with code ${d}`)})}p(),process.on("SIGINT",()=>{n.newline(),n.info("\u{1F534} Stopping development server..."),a&&a.kill("SIGTERM"),process.exit(0)}),await new Promise(()=>{})}async function Da(){try{let i=await Ct("code",".vscode"),e=await Ct("cursor",".cursor"),t=await Ct("webstorm",".idea");if(i||e){let o=i?"VS Code":"Cursor",r=".vscode";if(n.info(`\u{1F41B} ${o} detected! Debug setup:`),await Oa(r))n.info(" 1. \u2705 Created .vscode/launch.json for you");else{let a=Ie.default.join(process.cwd(),r,"launch.json");await H.default.pathExists(a)?n.info(" 1. \u2705 Found existing .vscode/launch.json"):n.info(" 1. \u26A0\uFE0F Could not create .vscode/launch.json")}n.info(" 2. \u{1F50D} Press F5 to attach debugger"),n.info(" 3. \u{1F534} Set breakpoints in your function.js"),n.info(" 4. \u{1F4DE} Test your function to hit breakpoints")}else t?(n.info("\u{1F41B} WebStorm detected! Debug setup:"),n.info(" 1. \u{1F50D} Run \u2192 Attach to Node.js/Chrome \u2192 localhost:9229"),n.info(" 2. \u{1F534} Set breakpoints in your function.js")):(n.info("\u{1F41B} Manual debug setup:"),n.info(' \u2022 VS Code/Cursor: Open "Run and Debug" \u2192 "Attach to Node.js Process"'),n.info(' \u2022 Chrome DevTools: Visit chrome://inspect \u2192 Click "inspect"'),n.info(" \u2022 Manual: Connect debugger to ws://localhost:9229"))}catch{n.info("\u{1F41B} Debug instructions:"),n.info(" \u2022 Connect your debugger to ws://localhost:9229"),n.info(" \u2022 Set breakpoints and test your function")}}async function Ct(i,e){try{if(i==="code"&&Na())return!0;let{spawn:t}=require("child_process"),o=await new Promise(s=>{let a=t(i,["--version"],{stdio:"pipe"});a.on("close",l=>s(l===0)),a.on("error",()=>s(!1))}),r=e?await H.default.pathExists(e):!1;return o||r}catch{return!1}}function Na(){return process.env.TERM_PROGRAM==="vscode"||!!process.env.VSCODE_IPC_HOOK||!!process.env.VSCODE_PID}async function Oa(i=".vscode"){try{let e=Ie.default.join(process.cwd(),i),t=Ie.default.join(e,"launch.json");if(await H.default.pathExists(t))return!1;await H.default.ensureDir(e);let o={version:"0.2.0",configurations:[{name:"Attach to Sinch Function",type:"node",request:"attach",port:9229,localRoot:"${workspaceFolder}",remoteRoot:"${workspaceFolder}",skipFiles:["<node_internals>/**","node_modules/**"]}]};return await H.default.writeJson(t,o,{spaces:2}),!!await H.default.pathExists(t)}catch{return!1}}function ja(i){return i.tunnel?i.tunnel.preference==="always":!1}async function Fa(){try{let i=await Ct("code",".vscode"),e=await Ct("devenv"),t=await Ct("rider",".idea");i?(n.info("\u{1F41B} VS Code detected! Debug setup:"),await La(".vscode")?n.info(" 1. \u2705 Created .vscode/launch.json for C#"):n.info(" 1. \u2705 Found existing .vscode/launch.json"),n.info(" 2. \u{1F50D} Press F5 to attach debugger"),n.info(" 3. \u{1F534} Set breakpoints in your Function.cs"),n.info(" 4. \u{1F4DE} Test your function to hit breakpoints")):e?(n.info("\u{1F41B} Visual Studio detected! Debug setup:"),n.info(" 1. \u{1F50D} Debug \u2192 Attach to Process \u2192 dotnet.exe"),n.info(" 2. \u{1F534} Set breakpoints in your Function.cs"),n.info(" 3. \u{1F4DE} Test your function to hit breakpoints")):t?(n.info("\u{1F41B} JetBrains Rider detected! Debug setup:"),n.info(" 1. \u{1F50D} Run \u2192 Attach to Process \u2192 dotnet"),n.info(" 2. \u{1F534} Set breakpoints in your Function.cs")):(n.info("\u{1F41B} C# Debug setup:"),n.info(" \u2022 Visual Studio: Debug \u2192 Attach to Process \u2192 dotnet.exe"),n.info(" \u2022 VS Code: Install C# extension, then F5 to debug"),n.info(" \u2022 Rider: Run \u2192 Attach to Process"))}catch{n.info("\u{1F41B} C# Debug instructions:"),n.info(" \u2022 Attach your debugger to the dotnet process"),n.info(" \u2022 Set breakpoints in Function.cs")}}async function La(i=".vscode"){try{let e=Ie.default.join(process.cwd(),i),t=Ie.default.join(e,"launch.json");if(await H.default.pathExists(t))return!1;await H.default.ensureDir(e);let o={version:"0.2.0",configurations:[{name:".NET Core Launch (web)",type:"coreclr",request:"launch",preLaunchTask:"build",program:"${workspaceFolder}/bin/Debug/net8.0/Function.dll",args:[],cwd:"${workspaceFolder}",stopAtEntry:!1,serverReadyAction:{action:"openExternally",pattern:"\\bNow listening on:\\s+(https?://\\S+)"},env:{ASPNETCORE_ENVIRONMENT:"Development"},sourceFileMap:{"/Views":"${workspaceFolder}/Views"}},{name:".NET Core Attach",type:"coreclr",request:"attach"}]};await H.default.writeJson(t,o,{spaces:2});let r=Ie.default.join(e,"tasks.json");if(!await H.default.pathExists(r)){let s={version:"2.0.0",tasks:[{label:"build",command:"dotnet",type:"process",args:["build","${workspaceFolder}/Function.csproj","/property:GenerateFullPaths=true","/consoleloggerparameters:NoSummary"],problemMatcher:"$msCompile"}]};await H.default.writeJson(r,s,{spaces:2})}return await H.default.pathExists(t)}catch{return!1}}To.exports=Eo});var jo=T((ud,Oo)=>{"use strict";var le=y(require("chalk")),Ro=require("commander");X();A();E();x();var Do=new Ro.Command("status");Do.description("Show function status and details").argument("[function-id]","Function ID to check (optional if sinch.json exists)").option("-f, --follow","Watch status changes in real-time").option("--json","Output raw JSON").action(async(i,e)=>{try{await f.load();let t=new V(f.getApiConfig()),o=i;if(!o){if(!f.isInProject())throw new Error("Function ID required. Provide as argument or run from function directory with sinch.json");if(o=f.getProjectConfig()?.functionId,!o)throw new Error("No function ID found in sinch.json. Deploy the function first or provide function ID as argument.")}e.follow?await Ua(t,o):await _a(t,o,e)}catch(t){c.stop(),n.error(`Failed to get function status: ${t.message}`),process.exit(1)}});async function _a(i,e,t){c.start("\u{1F4E1} Loading function status...");try{let o=await i.getFunction(e),r=await i.getFunctionStatus(e);if(c.stop(),t.json){console.log(JSON.stringify({function:o,deployment:r},null,2));return}let s=o,a=r.status,l=r.error;n.newline(),n.title(`Function Status: ${s.name}`),n.newline(),n.info("\u{1F4CB} Function Details:"),n.info(` ID: ${le.default.gray(s.id)}`),n.info(` Name: ${le.default.cyan(s.name)}`),n.info(` Runtime: ${le.default.yellow(s.runtime)}`),n.info(` Deployment Status: ${No(a)}`),s.created&&n.info(` Created: ${new Date(s.created).toLocaleString()}`),s.updated&&n.info(` Updated: ${new Date(s.updated).toLocaleString()}`),s.url&&n.info(` URL: ${le.default.blue(s.url)}`),a==="Failed"&&l&&(n.newline(),n.error("Deployment Error:"),n.error(` ${l}`)),n.newline(),n.info("\u{1F4A1} Commands:"),n.info(` \u2022 View logs: ${le.default.cyan(`sinch functions logs ${e}`)}`),n.info(` \u2022 Redeploy: ${le.default.cyan("sinch functions deploy")}`),n.info(` \u2022 Delete: ${le.default.cyan(`sinch functions delete ${e}`)}`)}catch(o){throw c.stop(),o}}async function Ua(i,e){n.info("\u{1F440} Watching deployment status (press Ctrl+C to stop)..."),n.newline();let t=null,o=setInterval(async()=>{try{let r=await i.getFunctionStatus(e),s=r.status;if(s!==t){let a=new Date().toLocaleTimeString();if(n.info(`[${a}] Status: ${No(s)}`),t=s,s==="Running"){n.success("Function deployment is now running!");try{let l=await i.getFunction(e);l.url&&n.info(`URL: ${le.default.blue(l.url)}`)}catch{}}else s==="Failed"&&(n.error("Function deployment failed!"),r.error&&n.error(`Error: ${r.error}`),clearInterval(o))}}catch(r){n.error(`Error checking status: ${r.message}`)}},3e3);process.on("SIGINT",()=>{clearInterval(o),n.newline(),n.info("Stopped watching function status"),process.exit(0)})}function No(i){return{Running:le.default.green("\u2705 Running"),Failed:le.default.red("\u274C Failed"),Pending:le.default.yellow("\u23F3 Pending"),Building:le.default.blue("\u{1F528} Building")}[i]||le.default.gray(i)}Oo.exports=Do});var Bo=T((yd,Jo)=>{"use strict";var tt=y(require("chalk")),_o=require("commander");X();A();E();x();var ti=require("child_process"),Bt=y(require("fs")),Kt=y(require("os")),Ht=y(require("path")),ni=new _o.Command("logs");ni.description("View function logs").argument("[function-id]","Function ID to get logs for (optional if sinch.json exists)").option("-f, --follow","Follow log output in real-time").option("-n, --lines <number>","Number of historical lines to show","50").option("--level <level>","Filter by log level (debug, info, warning, error)").option("--search <text>","Search for text in log messages").option("--since <duration>","Show logs since duration (e.g., 1h, 30m, 5s)").action(async(i,e)=>{try{await f.load();let t=new V(f.getApiConfig()),o=i;if(!o){if(!f.isInProject())throw new Error("Function ID required. Provide as argument or run from function directory with sinch.json");let s=f.getProjectConfig();if(!s)throw new Error("No project configuration found");if(o=s.functionId,!o)throw new Error("No function ID found in sinch.json. Deploy the function first or provide function ID as argument.")}c.start("Loading function details...");let r=await t.getFunction(o);c.stop(),n.info(`\u{1F4CB} Logs for function: ${tt.default.cyan(r.name)} (${qa(r.status)})`),n.newline(),e.follow?await Uo(t,o,r.name,e):await Xa(t,o,e)}catch(t){c.stop(),n.error(`Failed to get logs: ${t.message}`),process.exit(1)}});ni.command("stream").description("Stream function logs in real-time").argument("[function-id]","Function ID to stream logs for (optional if sinch.json exists)").option("--level <level>","Filter by log level (debug, info, warning, error)").option("--search <text>","Search for text in log messages").action(async(i,e)=>{try{await f.load();let t=new V(f.getApiConfig()),o=i;if(!o){if(!f.isInProject())throw new Error("Function ID required. Provide as argument or run from function directory with sinch.json");let s=f.getProjectConfig();if(!s)throw new Error("No project configuration found");if(o=s.functionId,!o)throw new Error("No function ID found in sinch.json. Deploy the function first or provide function ID as argument.")}c.start("Connecting to log stream...");let r=await Ma(t,o);c.stop(),await Uo(t,o,r.name,{...e,follow:!0})}catch(t){c.stop(),n.error(`Failed to stream logs: ${t.message}`),process.exit(1)}});async function Ma(i,e){return await i.getFunction(e)}async function Uo(i,e,t,o){let r=i.baseUrl.replace(/\/+$/,""),s=i.projectId,a=`${r}/v1/projects/${s}/functions/${e}/logs/stream`,l=i.credentials,p=[],d=qo(p,"STREAMING",t),u={Accept:"text/event-stream","Cache-Control":"no-cache"};if(l)try{let w=await l.retrieve();if(w&&w.keyId&&w.keySecret){let h=Buffer.from(`${w.keyId}:${w.keySecret}`).toString("base64");u.Authorization=`Basic ${h}`}}catch(w){n.debug("Failed to add authentication:",w)}let m=new AbortController;try{let w=await fetch(a,{method:"GET",headers:u,signal:m.signal});if(!w.ok)throw new Error(`SSE connection failed: ${w.status} ${w.statusText}`);if(!w.body)throw new Error("Response body is null");Fo(d.statusBar,"CONNECTED",t),d.screen.render();let h=w.body.getReader(),C=new TextDecoder,v="";(async()=>{try{for(;;){let{done:ee,value:O}=await h.read();if(ee)break;v+=C.decode(O,{stream:!0});let P=v.split(`
|
|
62
|
-
`);v=
|
|
63
|
-
`,e+=
|
|
64
|
-
`,e+=
|
|
65
|
-
`,e+=
|
|
66
|
-
`;let o=
|
|
65
|
+
`,await z.default.writeFile(t,o,"utf-8"),n.debug(`Updated .env: SINCH_TUNNEL=${i}`)}}else if(e==="csharp"){let t=ke.default.join(process.cwd(),"appsettings.Development.json");if(await z.default.pathExists(t)){let o=await z.default.readJson(t);o.SinchTunnel=i,await z.default.writeJson(t,o,{spaces:2}),n.debug(`Updated appsettings.Development.json: SinchTunnel=${i}`)}}}async function Fa(i,e,t){let o=e.runtime||"node",r=!1;if(i.tunnel===!0)r=!0;else if(i.tunnel===!1)r=!1,e.tunnel?.preference==="always"&&(f.set("tunnel",{...e.tunnel,preference:"no"},!0),await f.saveProjectConfig());else if(e.tunnel?.preference==="never")r=!1;else if(Ua(e))r=!0;else{let{tunnelChoice:d}=await Ro.default.prompt([{type:"list",name:"tunnelChoice",message:"Enable Sinch tunnel for external access?",choices:[{name:"Yes - Enable tunnel this time",value:"yes"},{name:"No - Local only this time",value:"no"},{name:"Always - Enable tunnel and remember preference",value:"always"},{name:"Never - Don't enable tunnel and remember preference",value:"never"}],default:"no"}]);d==="yes"?r=!0:d==="no"?r=!1:d==="always"?(r=!0,f.set("tunnel",{...e.tunnel,preference:"always"},!0),await f.saveProjectConfig()):d==="never"&&(r=!1,f.set("tunnel",{...e.tunnel,preference:"never"},!0),await f.saveProjectConfig())}await Oa(r,o);let s=ko({PORT:i.port,NODE_ENV:"development",SINCH_FUNCTIONS_LOCAL:"true",SINCH_TUNNEL:r?"true":"false"});e.variables&&Object.entries(e.variables).forEach(([d,u])=>{s[d]=u});try{let d=await f.getApplicationCredentials(e.voiceAppKey);d?(s.SINCH_APPLICATION_KEY=d.applicationKey,s.SINCH_APPLICATION_SECRET=d.applicationSecret,n.debug("\u2705 Injected application credentials for voice operations")):n.debug("\u26A0\uFE0F No application credentials found - voice features may not work")}catch(d){n.debug(`\u26A0\uFE0F Could not load application credentials: ${d.message}`)}n.info("\u{1F680} Starting local server...");let a=null,l=!1;function p(){if(a&&a.kill(),o==="csharp"){let d=["watch","run","--no-launch-profile"];t&&d.push("--project",t),i.port&&d.push("--urls",`http://localhost:${i.port}`),s.ASPNETCORE_ENVIRONMENT="Development",s.ASPNETCORE_URLS=`http://localhost:${i.port}`,a=(0,ii.spawn)("dotnet",d,{env:s,stdio:"inherit",cwd:process.cwd()})}else a=(0,ii.spawn)("npm",["run","dev"],{env:s,stdio:"inherit",cwd:process.cwd(),shell:!0});a.on("spawn",async()=>{if(!l){l=!0,n.newline(),n.success(`\u2705 Server running on http://localhost:${i.port}`),i.debug&&(n.newline(),o==="csharp"?Ma():ja()),n.newline(),n.info("\u{1F4A1} Development commands:"),n.info(` \u2022 Test function: ${Kt.default.cyan(`curl http://localhost:${i.port}`)}`),n.info(` \u2022 View in browser: ${Kt.default.cyan(`http://localhost:${i.port}`)}`),n.info(` \u2022 Stop server: ${Kt.default.gray("Ctrl+C")}`);let d=o==="csharp"?"dotnet watch":"nodemon";n.info(` \u2022 File watching: ${Kt.default.green(`enabled (via ${d})`)}`)}}),a.on("error",d=>{n.error(`Server error: ${d.message}`)}),a.on("exit",(d,u)=>{u!=="SIGTERM"&&u!=="SIGKILL"&&n.error(`Server exited with code ${d}`)})}p(),process.on("SIGINT",()=>{n.newline(),n.info("\u{1F534} Stopping development server..."),a&&a.kill("SIGTERM"),process.exit(0)}),await new Promise(()=>{})}async function ja(){try{let i=await vt("code",".vscode"),e=await vt("cursor",".cursor"),t=await vt("webstorm",".idea");if(i||e){let o=i?"VS Code":"Cursor",r=".vscode";if(n.info(`\u{1F41B} ${o} detected! Debug setup:`),await _a(r))n.info(" 1. \u2705 Created .vscode/launch.json for you");else{let a=ke.default.join(process.cwd(),r,"launch.json");await z.default.pathExists(a)?n.info(" 1. \u2705 Found existing .vscode/launch.json"):n.info(" 1. \u26A0\uFE0F Could not create .vscode/launch.json")}n.info(" 2. \u{1F50D} Press F5 to attach debugger"),n.info(" 3. \u{1F534} Set breakpoints in your function.js"),n.info(" 4. \u{1F4DE} Test your function to hit breakpoints")}else t?(n.info("\u{1F41B} WebStorm detected! Debug setup:"),n.info(" 1. \u{1F50D} Run \u2192 Attach to Node.js/Chrome \u2192 localhost:9229"),n.info(" 2. \u{1F534} Set breakpoints in your function.js")):(n.info("\u{1F41B} Manual debug setup:"),n.info(' \u2022 VS Code/Cursor: Open "Run and Debug" \u2192 "Attach to Node.js Process"'),n.info(' \u2022 Chrome DevTools: Visit chrome://inspect \u2192 Click "inspect"'),n.info(" \u2022 Manual: Connect debugger to ws://localhost:9229"))}catch{n.info("\u{1F41B} Debug instructions:"),n.info(" \u2022 Connect your debugger to ws://localhost:9229"),n.info(" \u2022 Set breakpoints and test your function")}}async function vt(i,e){try{if(i==="code"&&La())return!0;let{spawn:t}=require("child_process"),o=await new Promise(s=>{let a=t(i,["--version"],{stdio:"pipe"});a.on("close",l=>s(l===0)),a.on("error",()=>s(!1))}),r=e?await z.default.pathExists(e):!1;return o||r}catch{return!1}}function La(){return process.env.TERM_PROGRAM==="vscode"||!!process.env.VSCODE_IPC_HOOK||!!process.env.VSCODE_PID}async function _a(i=".vscode"){try{let e=ke.default.join(process.cwd(),i),t=ke.default.join(e,"launch.json");if(await z.default.pathExists(t))return!1;await z.default.ensureDir(e);let o={version:"0.2.0",configurations:[{name:"Attach to Sinch Function",type:"node",request:"attach",port:9229,localRoot:"${workspaceFolder}",remoteRoot:"${workspaceFolder}",skipFiles:["<node_internals>/**","node_modules/**"]}]};return await z.default.writeJson(t,o,{spaces:2}),!!await z.default.pathExists(t)}catch{return!1}}function Ua(i){return i.tunnel?i.tunnel.preference==="always":!1}async function Ma(){try{let i=await vt("code",".vscode"),e=await vt("devenv"),t=await vt("rider",".idea");i?(n.info("\u{1F41B} VS Code detected! Debug setup:"),await qa(".vscode")?n.info(" 1. \u2705 Created .vscode/launch.json for C#"):n.info(" 1. \u2705 Found existing .vscode/launch.json"),n.info(" 2. \u{1F50D} Press F5 to attach debugger"),n.info(" 3. \u{1F534} Set breakpoints in your Function.cs"),n.info(" 4. \u{1F4DE} Test your function to hit breakpoints")):e?(n.info("\u{1F41B} Visual Studio detected! Debug setup:"),n.info(" 1. \u{1F50D} Debug \u2192 Attach to Process \u2192 dotnet.exe"),n.info(" 2. \u{1F534} Set breakpoints in your Function.cs"),n.info(" 3. \u{1F4DE} Test your function to hit breakpoints")):t?(n.info("\u{1F41B} JetBrains Rider detected! Debug setup:"),n.info(" 1. \u{1F50D} Run \u2192 Attach to Process \u2192 dotnet"),n.info(" 2. \u{1F534} Set breakpoints in your Function.cs")):(n.info("\u{1F41B} C# Debug setup:"),n.info(" \u2022 Visual Studio: Debug \u2192 Attach to Process \u2192 dotnet.exe"),n.info(" \u2022 VS Code: Install C# extension, then F5 to debug"),n.info(" \u2022 Rider: Run \u2192 Attach to Process"))}catch{n.info("\u{1F41B} C# Debug instructions:"),n.info(" \u2022 Attach your debugger to the dotnet process"),n.info(" \u2022 Set breakpoints in Function.cs")}}async function qa(i=".vscode"){try{let e=ke.default.join(process.cwd(),i),t=ke.default.join(e,"launch.json");if(await z.default.pathExists(t))return!1;await z.default.ensureDir(e);let o={version:"0.2.0",configurations:[{name:".NET Core Launch (web)",type:"coreclr",request:"launch",preLaunchTask:"build",program:"${workspaceFolder}/bin/Debug/net8.0/Function.dll",args:[],cwd:"${workspaceFolder}",stopAtEntry:!1,serverReadyAction:{action:"openExternally",pattern:"\\bNow listening on:\\s+(https?://\\S+)"},env:{ASPNETCORE_ENVIRONMENT:"Development"},sourceFileMap:{"/Views":"${workspaceFolder}/Views"}},{name:".NET Core Attach",type:"coreclr",request:"attach"}]};await z.default.writeJson(t,o,{spaces:2});let r=ke.default.join(e,"tasks.json");if(!await z.default.pathExists(r)){let s={version:"2.0.0",tasks:[{label:"build",command:"dotnet",type:"process",args:["build","${workspaceFolder}/Function.csproj","/property:GenerateFullPaths=true","/consoleloggerparameters:NoSummary"],problemMatcher:"$msCompile"}]};await z.default.writeJson(r,s,{spaces:2})}return await z.default.pathExists(t)}catch{return!1}}xo.exports=Do});var Uo=N((wd,_o)=>{"use strict";var ue=y(require("chalk")),Fo=require("commander");Q();E();T();R();var jo=new Fo.Command("status");jo.description("Show function status and details").argument("[function-id]","Function ID to check (optional if sinch.json exists)").option("-f, --follow","Watch status changes in real-time").option("--json","Output raw JSON").action(async(i,e)=>{try{await f.load();let t=new J(f.getApiConfig()),o=i;if(!o){if(!f.isInProject())throw new Error("Function ID required. Provide as argument or run from function directory with sinch.json");if(o=f.getProjectConfig()?.functionId,!o)throw new Error("No function ID found in sinch.json. Deploy the function first or provide function ID as argument.")}e.follow?await Va(t,o):await Ja(t,o,e)}catch(t){c.stop(),n.error(`Failed to get function status: ${t.message}`),process.exit(1)}});async function Ja(i,e,t){c.start("\u{1F4E1} Loading function status...");try{let o=await i.getFunction(e),r=await i.getFunctionStatus(e);if(c.stop(),t.json){console.log(JSON.stringify({function:o,deployment:r},null,2));return}let s=o,a=r.status,l=r.error;n.newline(),n.title(`Function Status: ${s.name}`),n.newline(),n.info("\u{1F4CB} Function Details:"),n.info(` ID: ${ue.default.gray(s.id)}`),n.info(` Name: ${ue.default.cyan(s.name)}`),n.info(` Runtime: ${ue.default.yellow(s.runtime)}`),n.info(` Deployment Status: ${Lo(a)}`),s.created&&n.info(` Created: ${new Date(s.created).toLocaleString()}`),s.updated&&n.info(` Updated: ${new Date(s.updated).toLocaleString()}`),s.url&&n.info(` URL: ${ue.default.blue(s.url)}`),a==="Failed"&&l&&(n.newline(),n.error("Deployment Error:"),n.error(` ${l}`)),n.newline(),n.info("\u{1F4A1} Commands:"),n.info(` \u2022 View logs: ${ue.default.cyan(`sinch functions logs ${e}`)}`),n.info(` \u2022 Redeploy: ${ue.default.cyan("sinch functions deploy")}`),n.info(` \u2022 Delete: ${ue.default.cyan(`sinch functions delete ${e}`)}`)}catch(o){throw c.stop(),o}}async function Va(i,e){n.info("\u{1F440} Watching deployment status (press Ctrl+C to stop)..."),n.newline();let t=null,o=setInterval(async()=>{try{let r=await i.getFunctionStatus(e),s=r.status;if(s!==t){let a=new Date().toLocaleTimeString();if(n.info(`[${a}] Status: ${Lo(s)}`),t=s,s==="Running"){n.success("Function deployment is now running!");try{let l=await i.getFunction(e);l.url&&n.info(`URL: ${ue.default.blue(l.url)}`)}catch{}}else s==="Failed"&&(n.error("Function deployment failed!"),r.error&&n.error(`Error: ${r.error}`),clearInterval(o))}}catch(r){n.error(`Error checking status: ${r.message}`)}},3e3);process.on("SIGINT",()=>{clearInterval(o),n.newline(),n.info("Stopped watching function status"),process.exit(0)})}function Lo(i){return{Running:ue.default.green("\u2705 Running"),Failed:ue.default.red("\u274C Failed"),Pending:ue.default.yellow("\u23F3 Pending"),Building:ue.default.blue("\u{1F528} Building")}[i]||ue.default.gray(i)}_o.exports=jo});var zo=N((Id,Wo)=>{"use strict";var nt=y(require("chalk")),Jo=require("commander");Q();E();T();R();var oi=require("child_process"),Ht=y(require("fs")),Wt=y(require("os")),zt=y(require("path")),ri=new Jo.Command("logs");ri.description("View function logs").argument("[function-id]","Function ID to get logs for (optional if sinch.json exists)").option("-f, --follow","Follow log output in real-time").option("-n, --lines <number>","Number of historical lines to show","50").option("--level <level>","Filter by log level (debug, info, warning, error)").option("--search <text>","Search for text in log messages").option("--since <duration>","Show logs since duration (e.g., 1h, 30m, 5s)").action(async(i,e)=>{try{await f.load();let t=new J(f.getApiConfig()),o=i;if(!o){if(!f.isInProject())throw new Error("Function ID required. Provide as argument or run from function directory with sinch.json");let s=f.getProjectConfig();if(!s)throw new Error("No project configuration found");if(o=s.functionId,!o)throw new Error("No function ID found in sinch.json. Deploy the function first or provide function ID as argument.")}c.start("Loading function details...");let r=await t.getFunction(o);c.stop(),n.info(`\u{1F4CB} Logs for function: ${nt.default.cyan(r.name)} (${Ka(r.status)})`),n.newline(),e.follow?await Vo(t,o,r.name,e):await tc(t,o,e)}catch(t){c.stop(),n.error(`Failed to get logs: ${t.message}`),process.exit(1)}});ri.command("stream").description("Stream function logs in real-time").argument("[function-id]","Function ID to stream logs for (optional if sinch.json exists)").option("--level <level>","Filter by log level (debug, info, warning, error)").option("--search <text>","Search for text in log messages").action(async(i,e)=>{try{await f.load();let t=new J(f.getApiConfig()),o=i;if(!o){if(!f.isInProject())throw new Error("Function ID required. Provide as argument or run from function directory with sinch.json");let s=f.getProjectConfig();if(!s)throw new Error("No project configuration found");if(o=s.functionId,!o)throw new Error("No function ID found in sinch.json. Deploy the function first or provide function ID as argument.")}c.start("Connecting to log stream...");let r=await Ba(t,o);c.stop(),await Vo(t,o,r.name,{...e,follow:!0})}catch(t){c.stop(),n.error(`Failed to stream logs: ${t.message}`),process.exit(1)}});async function Ba(i,e){return await i.getFunction(e)}async function Vo(i,e,t,o){let r=i.baseUrl.replace(/\/+$/,""),s=i.projectId,a=`${r}/v1/projects/${s}/functions/${e}/logs/stream`,l=i.credentials,p=[],d=Ko(p,"STREAMING",t),u={Accept:"text/event-stream","Cache-Control":"no-cache"};if(l)try{let w=await l.retrieve();if(w&&w.keyId&&w.keySecret){let h=Buffer.from(`${w.keyId}:${w.keySecret}`).toString("base64");u.Authorization=`Basic ${h}`}}catch(w){n.debug("Failed to add authentication:",w)}let m=new AbortController;try{let w=await fetch(a,{method:"GET",headers:u,signal:m.signal});if(!w.ok)throw new Error(`SSE connection failed: ${w.status} ${w.statusText}`);if(!w.body)throw new Error("Response body is null");Mo(d.statusBar,"CONNECTED",t),d.screen.render();let h=w.body.getReader(),C=new TextDecoder,v="";(async()=>{try{for(;;){let{done:re,value:j}=await h.read();if(re)break;v+=C.decode(j,{stream:!0});let M=v.split(`
|
|
66
|
+
`);v=M.pop()||"";for(let fe of M)if(!fe.startsWith("event:")&&fe.startsWith("data:")){let H=fe.substring(5).trim();if(H)try{let S=JSON.parse(H);S.type==="request"&&S.request&&(p.push(S.request),Bo(d.table,S.request,p),d.table.focus(),d.screen.render())}catch{}}}}catch(re){re.name!=="AbortError"&&(Mo(d.statusBar,"RECONNECTING",t),d.screen.render())}})(),d.screen.key(["q","C-c"],()=>{m.abort(),process.exit(0)}),await new Promise(()=>{})}catch(w){m.abort(),n.error(`\u274C Streaming failed: ${w.message}`),process.exit(1)}}function Ka(i){return{Running:nt.default.green("\u2705 Running"),Failed:nt.default.red("\u274C Failed"),Pending:nt.default.yellow("\u23F3 Pending"),Building:nt.default.blue("\u{1F528} Building")}[i]||nt.default.gray(i)}var it=[];function Bo(i,e,t){let o=new Date(e.startTime),r=o.getFullYear()+"-"+String(o.getMonth()+1).padStart(2,"0")+"-"+String(o.getDate()).padStart(2,"0")+" "+String(o.getHours()).padStart(2,"0")+":"+String(o.getMinutes()).padStart(2,"0")+":"+String(o.getSeconds()).padStart(2,"0"),s=ec(e),a=`${e.executionTimeMs}ms`,l=e.statusCode.toString(),p=process.stdout.columns||120,u=Math.max(30,p-35),m=e.url.length>u?e.url.substring(0,u-2)+"..":e.url;it.push([r,s,a,l,m]),it.length>100&&(it=it.slice(-100),t&&t.length>100&&t.splice(0,t.length-100));let w=[["Time","Callback","Duration","Status","Path"],...it];i.setData(w)}function Ha(i,e,t,o,r){try{let s=require("blessed");n.debug(`Showing request details for ${i.httpMethod} ${i.url}`);let a=s.box({parent:e,top:0,left:0,width:"100%",height:"100%",border:{type:"line"},style:{border:{fg:"cyan"},bg:"black",fg:"white"},scrollable:!0,alwaysScroll:!0,keys:!0,vi:!0,tags:!0,label:" Request Details "}),l=s.box({parent:a,top:1,left:2,width:"100%-4",height:1,content:"{gray-fg}[Esc/Q] Close [\u2191\u2193] Scroll [J/1] JSON [C/2] cURL{/}",tags:!0,style:{bg:"blue",fg:"white"}});s.box({parent:a,top:2,left:2,width:"100%-4",height:1,content:`{bold}{cyan-fg}${i.httpMethod}{/} {blue-fg}${i.url}{/} - {${Za(i.statusCode)}}${i.statusCode}{/} - {yellow-fg}${i.executionTimeMs}ms{/} - {magenta-fg}${i.memoryUsedMB||0}MB{/}`,tags:!0,style:{bg:"black"}});let p=s.box({parent:a,top:4,left:2,width:"100%-4",height:"100%-5",scrollable:!0,alwaysScroll:!0,keys:!0,vi:!0,tags:!0,content:Wa(i)});p.focus(),e.render();let d=!0,u=()=>{d&&(d=!1,a.destroy(),t.focus(),e.render())};e.key(["escape","q"],()=>{d&&u()}),e.key(["up","k"],()=>{d&&(p.scroll(-1),e.render())}),e.key(["down","j"],()=>{d&&(p.scroll(1),e.render())}),e.on("keypress",(m,w)=>{d&&n.debug(`Key pressed: ch="${m}" key=${JSON.stringify(w)}`)}),e.key(["J","j"],()=>{d&&(n.debug("J/j key pressed - attempting JSON copy"),l.setContent("{black-bg}{yellow-fg} J KEY PRESSED - COPYING JSON... {/}"),e.render(),setTimeout(()=>{try{let m=JSON.stringify(i,null,2);n.debug(`JSON content length: ${m.length}`),n.debug("Attempting native clipboard copy"),yn(m).then(()=>{l.setContent("{green-fg}\u2713 Request JSON copied to clipboard!{/}"),n.debug("Native clipboard copy succeeded"),e.render(),setTimeout(()=>{d&&(l.setContent("{gray-fg}[Esc/Q] Close [\u2191\u2193] Scroll [J] JSON [C] cURL{/}"),e.render())},3e3)}).catch(w=>{n.debug(`Native clipboard failed: ${w.message}`);let h=zt.default.join(Wt.default.tmpdir(),`sinch-request-${Date.now()}.json`);Ht.default.writeFileSync(h,m),l.setContent(`{yellow-fg}\u2713 JSON saved to: ${h}{/}`),n.debug(`Saved to temp file: ${h}`),e.render(),setTimeout(()=>{d&&(l.setContent("{gray-fg}[Esc/Q] Close [\u2191\u2193] Scroll [J] JSON [C] cURL{/}"),e.render())},3e3)})}catch(m){n.debug(`JSON copy error: ${m.message}`),l.setContent(`{red-fg}\u2717 Copy failed: ${m.message}{/}`),e.render(),setTimeout(()=>{d&&(l.setContent("{gray-fg}[Esc/Q] Close [\u2191\u2193] Scroll [J] JSON [C] cURL{/}"),e.render())},3e3)}},100))}),e.key(["C","c"],()=>{d&&(n.debug("C/c key pressed - attempting cURL copy"),l.setContent("{black-bg}{yellow-fg} C KEY PRESSED - COPYING CURL... {/}"),e.render(),setTimeout(()=>{try{let m=qo(i);n.debug("Attempting native clipboard copy for cURL"),yn(m).then(()=>{l.setContent("{green-fg}\u2713 cURL command copied to clipboard!{/}"),n.debug("Native clipboard copy succeeded for cURL"),e.render(),setTimeout(()=>{d&&(l.setContent("{gray-fg}[Esc/Q] Close [\u2191\u2193] Scroll [J] JSON [C] cURL{/}"),e.render())},3e3)}).catch(w=>{n.debug(`Native clipboard failed for cURL: ${w.message}`);let h=zt.default.join(Wt.default.tmpdir(),`sinch-curl-${Date.now()}.sh`);Ht.default.writeFileSync(h,m),l.setContent(`{yellow-fg}\u2713 cURL saved to: ${h}{/}`),e.render(),setTimeout(()=>{d&&(l.setContent("{gray-fg}[Esc/Q] Close [\u2191\u2193] Scroll [J] JSON [C] cURL{/}"),e.render())},3e3)})}catch(m){n.debug(`cURL copy error: ${m.message}`),l.setContent(`{red-fg}\u2717 Copy failed: ${m.message}{/}`),e.render(),setTimeout(()=>{d&&(l.setContent("{gray-fg}[Esc/Q] Close [\u2191\u2193] Scroll [J] JSON [C] cURL{/}"),e.render())},3e3)}},100))}),e.key(["1"],()=>{d&&(n.debug("1 key pressed - copying JSON (alternative binding)"),l.setContent("{black-bg}{yellow-fg} 1 KEY - COPYING JSON... {/}"),e.render(),setTimeout(()=>{try{let m=JSON.stringify(i,null,2);yn(m).then(()=>{l.setContent("{green-fg}\u2713 Request JSON copied to clipboard!{/}"),e.render(),setTimeout(()=>{d&&(l.setContent("{gray-fg}[Esc/Q] Close [\u2191\u2193] Scroll [J] JSON [C] cURL{/}"),e.render())},3e3)}).catch(w=>{let h=zt.default.join(Wt.default.tmpdir(),`sinch-request-${Date.now()}.json`);Ht.default.writeFileSync(h,m),l.setContent(`{yellow-fg}\u2713 JSON saved to: ${h}{/}`),e.render(),setTimeout(()=>{d&&(l.setContent("{gray-fg}[Esc/Q] Close [\u2191\u2193] Scroll [J] JSON [C] cURL{/}"),e.render())},3e3)})}catch(m){l.setContent(`{red-fg}\u2717 Copy failed: ${m.message}{/}`),e.render(),setTimeout(()=>{d&&(l.setContent("{gray-fg}[Esc/Q] Close [\u2191\u2193] Scroll [J] JSON [C] cURL{/}"),e.render())},3e3)}},100))}),e.key(["2"],()=>{d&&(n.debug("2 key pressed - copying cURL (alternative binding)"),l.setContent("{black-bg}{yellow-fg} 2 KEY - COPYING CURL... {/}"),e.render(),setTimeout(()=>{try{let m=qo(i);yn(m).then(()=>{l.setContent("{green-fg}\u2713 cURL command copied to clipboard!{/}"),e.render(),setTimeout(()=>{d&&(l.setContent("{gray-fg}[Esc/Q] Close [\u2191\u2193] Scroll [J] JSON [C] cURL{/}"),e.render())},3e3)}).catch(w=>{let h=zt.default.join(Wt.default.tmpdir(),`sinch-curl-${Date.now()}.sh`);Ht.default.writeFileSync(h,m),l.setContent(`{yellow-fg}\u2713 cURL saved to: ${h}{/}`),e.render(),setTimeout(()=>{d&&(l.setContent("{gray-fg}[Esc/Q] Close [\u2191\u2193] Scroll [J] JSON [C] cURL{/}"),e.render())},3e3)})}catch(m){l.setContent(`{red-fg}\u2717 Copy failed: ${m.message}{/}`),e.render(),setTimeout(()=>{d&&(l.setContent("{gray-fg}[Esc/Q] Close [\u2191\u2193] Scroll [J] JSON [C] cURL{/}"),e.render())},3e3)}},100))})}catch(s){n.debug(`Error in showBlessedZoomedRequest: ${s.message}`)}}function Wa(i){let e="";return e+=`
|
|
67
|
+
`,e+=za(i),e+=`
|
|
68
|
+
`,e+=Ga(i),e+=`
|
|
69
|
+
`,e+=Ya(i),e}function za(i){let e="",t=process.stdout.columns-6;e+="{bold}{green-fg}\u250C\u2500 REQUEST "+"\u2500".repeat(Math.max(0,t-10))+`\u2510{/}
|
|
70
|
+
`;let o=Qa(i);if(o&&(e+=`{green-fg}\u2502{/} {bold}Call ID:{/} {cyan-fg}${o}{/}
|
|
67
71
|
`),i.headers){e+=`{green-fg}\u2502{/} {bold}Headers:{/}
|
|
68
|
-
`;try{let r=typeof i.headers=="string"?JSON.parse(i.headers):i.headers;Object.entries(r).forEach(([s,a])=>{let l=` ${s}: ${a}`;e
|
|
72
|
+
`;try{let r=typeof i.headers=="string"?JSON.parse(i.headers):i.headers;Object.entries(r).forEach(([s,a])=>{let l=` ${s}: ${a}`;e+=Te(l,t-2,"{green-fg}\u2502{/} ")})}catch{e+=Te(` ${i.headers}`,t-2,"{green-fg}\u2502{/} ")}}if(i.requestBody){e+=`{green-fg}\u2502{/} {bold}Body:{/}
|
|
69
73
|
`;try{let r=JSON.parse(i.requestBody);JSON.stringify(r,null,2).split(`
|
|
70
|
-
`).forEach(a=>{e
|
|
71
|
-
`,e}function
|
|
74
|
+
`).forEach(a=>{e+=Te(a,t-2,"{green-fg}\u2502{/} ")})}catch{e+=Te(i.requestBody,t-2,"{green-fg}\u2502{/} ")}}return e+="{green-fg}\u2514"+"\u2500".repeat(Math.max(0,t))+`\u2518{/}
|
|
75
|
+
`,e}function Ga(i){let e="",t=process.stdout.columns-6;if(e+="{bold}{blue-fg}\u250C\u2500 RESPONSE "+"\u2500".repeat(Math.max(0,t-11))+`\u2510{/}
|
|
72
76
|
`,i.responseHeaders){e+=`{blue-fg}\u2502{/} {bold}Headers:{/}
|
|
73
|
-
`;try{let o=typeof i.responseHeaders=="string"?JSON.parse(i.responseHeaders):i.responseHeaders;Object.entries(o).forEach(([r,s])=>{let a=` ${r}: ${s}`;e
|
|
77
|
+
`;try{let o=typeof i.responseHeaders=="string"?JSON.parse(i.responseHeaders):i.responseHeaders;Object.entries(o).forEach(([r,s])=>{let a=` ${r}: ${s}`;e+=Te(a,t-2,"{blue-fg}\u2502{/} ")})}catch{e+=Te(` ${i.responseHeaders}`,t-2,"{blue-fg}\u2502{/} ")}}if(i.responseBody){e+=`{blue-fg}\u2502{/} {bold}Body:{/}
|
|
74
78
|
`;try{let o=JSON.parse(i.responseBody);JSON.stringify(o,null,2).split(`
|
|
75
|
-
`).forEach(s=>{e
|
|
76
|
-
`,e
|
|
77
|
-
`,e}function
|
|
78
|
-
`,i.logs&&i.logs.length>0?i.logs.forEach((o,r)=>{let s=new Date(o.timestamp).toLocaleTimeString(),a=o.level.toUpperCase().padEnd(5),l=
|
|
79
|
+
`).forEach(s=>{e+=Te(s,t-2,"{blue-fg}\u2502{/} ")})}catch{e+=Te(i.responseBody,t-2,"{blue-fg}\u2502{/} ")}}return i.errorMessage&&(e+=`{blue-fg}\u2502{/} {bold}{red-fg}Error:{/}
|
|
80
|
+
`,e+=Te(i.errorMessage,t-2,"{blue-fg}\u2502{/} ")),e+="{blue-fg}\u2514"+"\u2500".repeat(Math.max(0,t))+`\u2518{/}
|
|
81
|
+
`,e}function Ya(i){let e="",t=process.stdout.columns-6;return e+="{bold}{magenta-fg}\u250C\u2500 CONSOLE LOGS "+"\u2500".repeat(Math.max(0,t-15))+`\u2510{/}
|
|
82
|
+
`,i.logs&&i.logs.length>0?i.logs.forEach((o,r)=>{let s=new Date(o.timestamp).toLocaleTimeString(),a=o.level.toUpperCase().padEnd(5),l=Xa(o.level),p=`${s} [${a}] ${o.message}`;e+=Te(p,t-2,"{magenta-fg}\u2502{/} ",l)}):e+=`{magenta-fg}\u2502{/} {gray-fg}No console logs for this request{/}
|
|
79
83
|
`,e+="{magenta-fg}\u2514"+"\u2500".repeat(Math.max(0,t))+`\u2518{/}
|
|
80
|
-
`,e}function
|
|
84
|
+
`,e}function Te(i,e,t,o=""){if(!i)return"";let r="";return i.split(`
|
|
81
85
|
`).forEach(a=>{if(a.length<=e)r+=`${t}${o}${a}{/}
|
|
82
86
|
`;else{let l=a,p=!0;for(;l.length>e;){let d=e-(p?0:4),u=l.substring(0,d);r+=`${t}${p?"":" "}${o}${u}{/}
|
|
83
87
|
`,l=l.substring(d),p=!1}l.length>0&&(r+=`${t}${p?"":" "}${o}${l}{/}
|
|
84
|
-
`)}}),r}function
|
|
88
|
+
`)}}),r}function Xa(i){switch(i.toLowerCase()){case"debug":return"gray-fg";case"info":return"blue-fg";case"warning":return"yellow-fg";case"error":return"red-fg";default:return"white-fg"}}function Za(i){return i>=200&&i<300?"green-fg":i>=300&&i<400?"yellow-fg":i>=400&&i<500?"red-fg":i>=500?"red-fg}{bold":"white-fg"}function Qa(i){try{if(i.requestBody){let e=JSON.parse(i.requestBody);return e.callId||e.callid||e.call_id||null}}catch{}return null}function ec(i){try{let e="";if(i.requestBody){let t=JSON.parse(i.requestBody);if(t.event)e=t.event.toLowerCase();else{let o=i.url.split("/").filter(r=>r);e=o[o.length-1]||""}return e||""}}catch{}return""}async function tc(i,e,t){try{c.start(`Loading ${t.lines} recent log entries...`);let o={limit:parseInt(t.lines||"50"),level:t.level,search:t.search};if(t.since){let a=nc(t.since);a&&(o.startTime=a.toISOString())}let r=await i.getFunctionLogs(e,o);if(c.stop(),n.debug("Historical API response:",{totalRequests:r.requests?.length||0,firstRequest:r.requests?.[0]||"No requests",responseKeys:Object.keys(r)}),!r.requests||r.requests.length===0){n.info("\u{1F4DD} No logs found"),n.info("\u{1F4A1} Logs will appear here after function receives requests");return}let s=r.requests;n.debug("Historical requests:",{totalRequests:s.length,firstRequest:s[0]||"No requests",requestTimestamps:s.slice(0,3).map(a=>a.startTime)}),await ic(s,"HISTORICAL","Function")}catch(o){throw c.stop(),o}}function nc(i){if(!i)return null;let e=i.match(/^(\d+)([smhd])$/);if(!e)return null;let t=parseInt(e[1]),o=e[2],r=new Date;switch(o){case"s":return new Date(r.getTime()-t*1e3);case"m":return new Date(r.getTime()-t*60*1e3);case"h":return new Date(r.getTime()-t*60*60*1e3);case"d":return new Date(r.getTime()-t*24*60*60*1e3);default:return null}}async function ic(i,e,t){let o=Ko(i,e,t);i.forEach(r=>{Bo(o.table,r,i)}),o.screen.render(),await new Promise(()=>{})}function Ko(i,e,t){let o=require("blessed");process.stdout.write("\x1Bc"),it=[];let r=o.screen({smartCSR:!0,title:`Sinch Functions - ${t} Logs`,fullUnicode:!0}),s=o.box({parent:r,top:0,left:0,width:"100%",height:1,content:Ho(e,t),tags:!0,style:{bg:"black"}}),a=o.listtable({parent:r,top:1,left:0,width:"100%",height:"100%-1",border:{type:"line",fg:"blue"},style:{header:{fg:"white",bg:"blue",bold:!0},cell:{fg:"white"},selected:{bg:"blue",fg:"white",bold:!0}},keys:!0,vi:!0,mouse:!0,interactive:!0,label:`${t} Logs (q to quit)`,align:"left",pad:1}),l=["Time","Callback","Duration","Status","Path"];a.setData([l]),a.focus(),r.key(["q","C-c"],()=>{process.exit(0)});let p=()=>{try{let d=a.selected||0,u=d-1;if(u>=0&&u<i.length&&i[u])n.debug(`Opening request details for index ${u}`),Ha(i[u],r,a,s,t);else{let m=`Selected: ${d}, DataIndex: ${u}, Requests: ${i.length}, TableData: ${it.length}`;n.debug(`Selection out of bounds: ${m}`)}}catch(d){n.debug(`Error in request selection: ${d.message}`)}};return r.key(["enter"],p),a.on("select",(d,u)=>{p()}),r.on("wheelup",()=>{a.focused&&(a.scroll(-1),r.render())}),r.on("wheeldown",()=>{a.focused&&(a.scroll(1),r.render())}),{screen:r,table:a,statusBar:s}}function Ho(i,e){switch(i){case"STREAMING":return"{blue-fg}\u{1F534} STREAMING: "+e+"{/} {gray-fg}| \u2191\u2193/Wheel=scroll | Enter/Click=details | Q=quit{/}";case"CONNECTED":return"{green-fg}\u2705 CONNECTED: "+e+"{/} {gray-fg}| \u2191\u2193/Wheel=scroll | Enter/Click=details | Q=quit{/}";case"RECONNECTING":return"{yellow-fg}\u26A0\uFE0F RECONNECTING: "+e+"{/} {gray-fg}| \u2191\u2193/Wheel=scroll | Enter/Click=details | Q=quit{/}";case"HISTORICAL":return"{cyan-fg}\u{1F4DC} HISTORICAL: "+e+"{/} {gray-fg}| \u2191\u2193/Wheel=scroll | Enter/Click=details | Q=quit{/}";default:return"{gray-fg}"+e+" | \u2191\u2193/Wheel=scroll | Enter/Click=details | Q=quit{/}"}}function Mo(i,e,t){i.setContent(Ho(e,t))}function yn(i){return new Promise((e,t)=>{let o,r;process.platform==="win32"?(o="clip",r=[]):process.platform==="darwin"?(o="pbcopy",r=[]):(o="xclip",r=["-selection","clipboard"]),n.debug(`Using clipboard command: ${o} with args:`,r);let s=(0,oi.spawn)(o,r,{stdio:["pipe","ignore","pipe"]}),a="";s.stderr.on("data",l=>{a+=l.toString()}),s.on("error",l=>{if(n.debug(`Clipboard process error: ${l.message}`),process.platform==="linux"&&o==="xclip"){n.debug("Trying xsel as fallback");let p=(0,oi.spawn)("xsel",["--clipboard","--input"],{stdio:["pipe","ignore","pipe"]});p.on("error",d=>{t(new Error(`No clipboard utility found: ${l.message} / ${d.message}`))}),p.on("close",d=>{d===0?e():t(new Error(`xsel failed with code ${d}`))}),p.stdin&&(p.stdin.write(i),p.stdin.end());return}t(l)}),s.on("close",l=>{l===0?(n.debug("Clipboard copy successful"),e()):(n.debug(`Clipboard process failed with code ${l}, error: ${a}`),t(new Error(`Clipboard command failed with code ${l}: ${a}`)))}),s.stdin&&(s.stdin.write(i),s.stdin.end())})}function qo(i){let e=process.platform==="win32",t=`curl -X ${i.httpMethod}`,o={};if(i.headers)try{o=typeof i.headers=="string"?JSON.parse(i.headers):i.headers}catch{}let r=i.url;if(r&&!r.startsWith("http")){let s=o.host||o.Host;s&&(r=`${s.includes("localhost")||s.includes("127.0.0.1")?"http":"https"}://${s}${r.startsWith("/")?r:"/"+r}`)}if(t+=` "${r}"`,Object.entries(o).forEach(([s,a])=>{let l=["content-length","connection","user-agent"];i.url.startsWith("http")||l.push("host"),l.includes(s.toLowerCase())||(e?t+=` -H "${s}: ${a}"`:t+=` \\
|
|
85
89
|
-H "${s}: ${a}"`)}),i.requestBody&&["POST","PUT","PATCH"].includes(i.httpMethod)){try{let s=JSON.parse(i.requestBody),a=JSON.stringify(s);e?t+=` -d '${a.replace(/'/g,"\\'")}'`:t+=` \\
|
|
86
90
|
-d '${JSON.stringify(s,null,2)}'`}catch{e?t+=` -d '${i.requestBody.replace(/'/g,"\\'")}'`:t+=` \\
|
|
87
91
|
-d '${i.requestBody}'`}t.toLowerCase().includes("content-type")||(e?t+=' -H "Content-Type: application/json"':t+=` \\
|
|
88
92
|
-H "Content-Type: application/json"`)}return e?t+=" -v":t+=` \\
|
|
89
|
-
-v`,t}Jo.exports=ni});var Go=T((Sd,zo)=>{"use strict";var de=y(require("chalk")),Ko=y(require("inquirer")),Ho=require("commander");X();A();E();x();var Wo=new Ho.Command("delete");Wo.alias("del").description("Delete a function").argument("<function-id>","Function ID to delete").option("-f, --force","Skip confirmation").action(async(i,e)=>{try{await f.load();let t=new V(f.getApiConfig());c.start("Loading function details...");let o=await t.getFunction(i);if(c.stop(),n.newline(),n.info("\u{1F5D1}\uFE0F Function to delete:"),n.info(` Name: ${de.default.cyan(o.name)}`),n.info(` ID: ${de.default.gray(o.id)}`),n.info(` Runtime: ${de.default.yellow(o.runtime)}`),n.info(` Status: ${ec(o.status)}`),n.info(` Created: ${new Date(o.createdAt).toLocaleString()}`),o.containerAppUrl&&n.info(` URL: ${de.default.blue(o.containerAppUrl)}`),!e.force){n.newline(),n.warn("\u26A0\uFE0F This action cannot be undone!");let{confirm:r}=await Ko.default.prompt([{type:"confirm",name:"confirm",message:`Are you sure you want to delete function '${o.name}'?`,default:!1}]);if(!r){n.info("Deletion cancelled");return}}c.start("Deleting function..."),await t.deleteFunction(i),c.succeed(`Function '${o.name}' deleted successfully`),f.isInProject()&&f.getProjectConfig()?.functionId===i&&(f.set("functionId",void 0,!0),await f.saveProjectConfig(),n.newline(),n.info("\u{1F4A1} Removed function ID from sinch.json"),n.info(" Deploy again with: sinch functions deploy")),n.newline(),n.info("\u{1F4A1} Next steps:"),n.info(` \u2022 List remaining functions: ${de.default.cyan("sinch functions list")}`),n.info(` \u2022 Deploy new function: ${de.default.cyan("sinch functions deploy")}`)}catch(t){c.stop(),t.message.includes("404")||t.message.includes("not found")?(n.error(`Function '${i}' not found`),n.info("\u{1F4A1} List available functions with:"),n.info(` ${de.default.cyan("sinch functions list")}`)):n.error(`Failed to delete function: ${t.message}`),process.exit(1)}});function ec(i){return{Running:de.default.green("\u2705 Running"),Failed:de.default.red("\u274C Failed"),Pending:de.default.yellow("\u23F3 Pending"),Building:de.default.blue("\u{1F528} Building")}[i]||de.default.gray(i)}zo.exports=Wo});var Zo=T((Ed,Xo)=>{"use strict";var Yo=require("commander"),ii=y(require("fs-extra")),oi=y(require("path")),it=y(require("chalk"));A();E();x();Xn();X();var ri=new Yo.Command("docs");ri.description("Generate documentation for voice functions (saves to README.md)");ri.option("-f, --fresh","Force regeneration (skip cache)").option("-u, --update","Update documentation for deployed function via API").action(async i=>{try{await f.load(),i.update?await nc():await tc(i)}catch(e){c.fail("\u274C Failed to generate documentation"),e.message.includes("No function file found")?n.error("No function file found. Make sure you're in a function directory with function.js, index.js, or handler.js"):e.message.includes("unauthorized")||e.message.includes("401")?n.error("Authentication failed. Run `sinch auth login` first."):e.message.includes("AI service")?n.error("AI documentation service unavailable. Please try again later."):e.message.includes("Function not found")||e.message.includes("404")?n.error("Function not found. Make sure the function is deployed first."):n.error(`Error: ${e.message}`),n.debug("Full error:",e),process.exit(1)}});async function tc(i){c.start("\u{1F916} Generating documentation...");let e=await Gn();c.succeed("\u2705 Documentation generated!"),await Yn(e,"README.md"),await ic()}async function nc(){let i=oi.default.basename(process.cwd());c.start("\u{1F4D6} Reading local README.md...");let e=oi.default.join(process.cwd(),"README.md");if(!await ii.default.pathExists(e))throw new Error("README.md not found. Run `sinch functions docs` first to generate documentation locally.");if(!(await ii.default.readFile(e,"utf8")).trim())throw new Error("README.md is empty. Run `sinch functions docs` first to generate documentation.");c.text="\u{1F50D} Finding deployed function...";let s=(await new V(f.getApiConfig()).listFunctions()).find(a=>a.name===i);if(!s)throw new Error(`Function '${i}' not found in project. Make sure it's deployed first.`);c.text="\u{1F4E4} Uploading documentation content...",n.info("Documentation content ready for update"),c.succeed("\u2705 Documentation updated!"),n.newline(),n.success(`\u{1F4C4} Documentation updated for deployed function: ${it.default.cyan(i)}`),n.info(""),n.info("\u2728 Your function documentation has been updated:"),n.info(` \u2022 Function ID: ${it.default.gray(s.id)}`),n.info(` \u2022 Source: ${it.default.gray("Local README.md")}`),n.info(` \u2022 Updated: ${it.default.gray(new Date().toLocaleString())}`),n.info(` \u2022 View in dashboard: ${it.default.cyan("Dashboard \u2192 Functions \u2192 "+i)}`),n.newline(),n.info("\u{1F4A1} The updated documentation is now available in the dashboard!")}async function ic(){n.newline(),n.success(`\u{1F4C4} Documentation updated in: ${it.default.cyan("README.md")}`),n.info(""),n.info("\u2728 Your function documentation is ready:"),n.info(" \u2022 Review and edit the AI-generated content as needed"),n.info(" \u2022 Sinch-themed diagrams will render in markdown viewers"),n.info(" \u2022 File is ready for version control and deployment"),n.newline(),n.info("\u{1F4A1} Popular markdown viewers:"),n.info(" \u2022 VS Code (built-in)"),n.info(" \u2022 GitHub (drag & drop file)"),n.info(" \u2022 Typora, Mark Text, or any markdown app")}Xo.exports=ri});var ir=T((Nd,nr)=>{"use strict";var Q=y(require("chalk")),si=y(require("inquirer")),Qo=require("commander"),ve=y(require("fs-extra")),Je=y(require("path")),er=y(require("adm-zip"));X();A();E();x();var tr=new Qo.Command("download");tr.description("Download function source code").argument("[function-id]","Function ID to download (ULID format)").option("-o, --output <dir>","Output directory (default: ./functions/<function-name>)").option("--no-extract","Keep as ZIP file without extracting").option("--non-interactive","Skip interactive selection").option("-f, --force","Overwrite existing directory without prompting").action(async(i,e)=>{try{await f.load();let t=new V(f.getApiConfig()),o=i;if(!o&&!e.nonInteractive){let d=await oc(t);if(!d){n.info("Download cancelled");return}o=d}o||(n.error("Function ID required. Provide as argument or select interactively"),n.info(`Usage: ${Q.default.cyan("sinch functions download 01HX3KC5V8G3KCNZ8S5Y9ABCDE")}`),n.info(` or: ${Q.default.cyan("sinch functions download")} (interactive selection)`),process.exit(1)),c.start("\u{1F4E1} Fetching function metadata...");let r=await t.getFunction(o);c.succeed("Function metadata loaded");let s=Je.join("functions",r.name),a=e.output||s,l=Je.resolve(a);if(await ve.pathExists(l)){if(!e.force){let{overwrite:d}=await si.default.prompt([{type:"confirm",name:"overwrite",message:`Directory '${a}' already exists. Overwrite?`,default:!1}]);if(!d){n.info("Download cancelled");return}}c.start("\u{1F5D1}\uFE0F Removing existing directory..."),await ve.remove(l),c.succeed("Existing directory removed")}c.start("\u{1F4E5} Downloading function source code...");let p=await t.downloadFunction(o);if(c.succeed("Source code downloaded"),e.extract!==!1){c.start("\u{1F4E6} Extracting files..."),await ve.ensureDir(l);let d=new er.default(p),u=d.getEntries();d.extractAllTo(l,!0),c.succeed(`\u{1F4E6} Extracted ${u.length} files`);let m=Je.join(l,"sinch-metadata.json"),w={functionId:r.id,name:r.name,runtime:r.runtime,status:r.status,downloadedAt:new Date().toISOString(),url:r.containerAppUrl,configuration:r.configuration};await ve.writeJson(m,w,{spaces:2}),n.newline(),n.success("\u2705 Function downloaded successfully!"),n.newline(),n.info(`\u{1F4C1} Location: ${Q.default.cyan(a)}`),n.info(`\u{1F4CB} Files: ${u.length} files extracted`);let h=Je.join(l,"sinch.json");await ve.pathExists(h)&&n.info("\u{1F527} Config: sinch.json found"),n.newline(),n.info("\u{1F4A1} Next steps:"),n.info(` \u2022 Navigate: ${Q.default.cyan(`cd ${a}`)}`),n.info(` \u2022 Run locally: ${Q.default.cyan("sinch functions dev")}`),n.info(` \u2022 Deploy changes: ${Q.default.cyan("sinch functions deploy")}`)}else{let d=`${r.name}.zip`,u=e.output?Je.resolve(e.output):Je.resolve(d);c.start(`\u{1F4BE} Saving as ${d}...`),await ve.writeFile(u,p),c.succeed("ZIP file saved"),n.newline(),n.success("\u2705 Function downloaded as ZIP!"),n.info(`\u{1F4C1} File: ${Q.default.cyan(u)}`),n.info(`\u{1F4E6} Size: ${(p.length/1024).toFixed(2)} KB`)}}catch(t){c.stop(),t.message.includes("404")||t.message.includes("not found")?(n.error(`Function not found with ID: ${i}`),n.info("\u{1F4A1} List available functions with:"),n.info(` ${Q.default.cyan("sinch functions list")}`),n.info("\u{1F4A1} Or use interactive selection:"),n.info(` ${Q.default.cyan("sinch functions download")}`)):n.error(`Failed to download function: ${t.message}`),process.exit(1)}});async function oc(i){try{c.start("\u{1F4CB} Loading functions...");let e=await i.listFunctions();if(c.stop(),!e.functions||e.functions.length===0)return n.warn("No functions found to download"),null;let t=e.functions.map(r=>({name:`${Q.default.cyan(r.name.padEnd(20))} ${Q.default.yellow(r.runtime.padEnd(8))} ${rc(r.status)}`,value:r.id,short:r.name}));n.newline();let{selectedFunction:o}=await si.default.prompt([{type:"list",name:"selectedFunction",message:"Select a function to download:",choices:t,pageSize:15}]);return o}catch(e){throw c.stop(),e}}function rc(i){return{Running:Q.default.green("\u2705 Running"),Failed:Q.default.red("\u274C Failed"),Pending:Q.default.yellow("\u23F3 Pending"),Building:Q.default.blue("\u{1F528} Building")}[i]||Q.default.gray(i)}nr.exports=tr});var sr=T((Od,rr)=>{"use strict";var or=require("commander"),sc=io(),ac=co(),cc=Io(),lc=xo(),dc=jo(),pc=Bo(),uc=Go(),fc=Zo(),mc=ir(),be=new or.Command("functions");be.description("Manage Sinch Functions");be.addCommand(sc);be.addCommand(ac);be.addCommand(cc);be.addCommand(mc);be.addCommand(lc);be.addCommand(dc);be.addCommand(pc);be.addCommand(uc);be.addCommand(fc);rr.exports=be});var lr=T((Ud,cr)=>{"use strict";var ar=require("commander"),pe=y(require("chalk"));X();A();E();x();var Pe=new ar.Command("templates");Pe.description("Browse and manage function templates");Pe.command("list").alias("ls").description("List available templates").argument("[runtime]","Filter by runtime (node, csharp, python)").option("-c, --category <category>","Filter by category (voice, sms, verification)").option("-d, --detailed","Show detailed information").action(async(i,e)=>{try{await f.load();let t=new V(f.getApiConfig());c.start("Loading templates...");let o;if(i?o=await t.listRuntimeTemplates(i,e.category):o=await t.listAllTemplates(e.category),c.stop(),o.templates.length===0){n.info(`No templates found${i?` for ${i}`:""}${e.category?` in category ${e.category}`:""}`);return}let r=`Available Templates${i?` (${i})`:""}${e.category?` - ${e.category}`:""}`;if(n.title(r),e.detailed)o.templates.forEach((s,a)=>{a>0&&n.newline(),n.log(pe.default.bold.blue(`${s.name}`)),n.log(` Runtime: ${s.runtime}`),n.log(` Category: ${s.category}`),n.log(` Description: ${s.description}`),s.tags&&s.tags.length>0&&n.log(` Tags: ${s.tags.map(l=>pe.default.gray(l)).join(", ")}`),n.log(` Path: ${pe.default.gray(s.path)}`)});else{let s=o.templates.map(a=>[a.name,a.runtime,a.category,a.description.substring(0,50)+(a.description.length>50?"...":""),a.tags?a.tags.slice(0,2).join(", ")+(a.tags.length>2?"...":""):""]);n.table(["Name","Runtime","Category","Description","Tags"],s)}n.newline(),n.info(`Found ${o.templates.length} template${o.templates.length===1?"":"s"}`),n.info('Use "sinch templates show <runtime>/<template>" for details')}catch(t){c.stop(),n.error(`Failed to list templates: ${t.message}`),process.exit(1)}});Pe.command("show").description("Show detailed template information").argument("<template>",'Template name in format "runtime/template-name"').action(async i=>{try{await f.load();let e=new V(f.getApiConfig());if(!i.includes("/"))throw new Error('Template must be in format "runtime/template-name" (e.g., "node/simple-voice-ivr")');let t=i.split("/"),o=t[0],r=t[1];if(!o||!r)throw new Error('Template must be in format "runtime/template-name" (e.g., "node/simple-voice-ivr")');c.start(`Loading template details for ${i}...`);let s=await e.getTemplateDetails(o,r);c.stop(),n.title(`Template: ${s.name}`),n.newline(),n.log(pe.default.bold("Basic Information:")),n.log(` Runtime: ${s.runtime}`),n.log(` Category: ${s.category}`),n.log(` Description: ${s.description}`),s.tags&&s.tags.length>0&&n.log(` Tags: ${s.tags.map(a=>pe.default.blue(a)).join(", ")}`),s.variables&&Object.keys(s.variables).length>0&&(n.newline(),n.log(pe.default.bold("Template Variables:")),Object.entries(s.variables).forEach(([a,l])=>{n.log(` ${a}: ${pe.default.gray(l)}`)})),s.files&&s.files.length>0&&(n.newline(),n.log(pe.default.bold("Files:")),s.files.forEach(a=>{n.log(` ${pe.default.gray("\u2022")} ${a}`)})),s.readmeContent&&(n.newline(),n.log(pe.default.bold("README:")),s.readmeContent.split(`
|
|
90
|
-
`).slice(0,10).forEach(l=>{n.log(` ${
|
|
91
|
-
`).length>10&&n.log(` ${
|
|
93
|
+
-v`,t}Wo.exports=ri});var Qo=N((kd,Zo)=>{"use strict";var ge=y(require("chalk")),Go=y(require("inquirer")),Yo=require("commander");Q();E();T();R();var Xo=new Yo.Command("delete");Xo.alias("del").description("Delete a function").argument("<function-id>","Function ID to delete").option("-f, --force","Skip confirmation").action(async(i,e)=>{try{await f.load();let t=new J(f.getApiConfig());c.start("Loading function details...");let o=await t.getFunction(i);if(c.stop(),n.newline(),n.info("\u{1F5D1}\uFE0F Function to delete:"),n.info(` Name: ${ge.default.cyan(o.name)}`),n.info(` ID: ${ge.default.gray(o.id)}`),n.info(` Runtime: ${ge.default.yellow(o.runtime)}`),n.info(` Status: ${oc(o.status)}`),n.info(` Created: ${new Date(o.createdAt).toLocaleString()}`),o.containerAppUrl&&n.info(` URL: ${ge.default.blue(o.containerAppUrl)}`),!e.force){n.newline(),n.warn("\u26A0\uFE0F This action cannot be undone!");let{confirm:r}=await Go.default.prompt([{type:"confirm",name:"confirm",message:`Are you sure you want to delete function '${o.name}'?`,default:!1}]);if(!r){n.info("Deletion cancelled");return}}c.start("Deleting function..."),await t.deleteFunction(i),c.succeed(`Function '${o.name}' deleted successfully`),f.isInProject()&&f.getProjectConfig()?.functionId===i&&(f.set("functionId",void 0,!0),await f.saveProjectConfig(),n.newline(),n.info("\u{1F4A1} Removed function ID from sinch.json"),n.info(" Deploy again with: sinch functions deploy")),n.newline(),n.info("\u{1F4A1} Next steps:"),n.info(` \u2022 List remaining functions: ${ge.default.cyan("sinch functions list")}`),n.info(` \u2022 Deploy new function: ${ge.default.cyan("sinch functions deploy")}`)}catch(t){c.stop(),t.message.includes("404")||t.message.includes("not found")?(n.error(`Function '${i}' not found`),n.info("\u{1F4A1} List available functions with:"),n.info(` ${ge.default.cyan("sinch functions list")}`)):n.error(`Failed to delete function: ${t.message}`),process.exit(1)}});function oc(i){return{Running:ge.default.green("\u2705 Running"),Failed:ge.default.red("\u274C Failed"),Pending:ge.default.yellow("\u23F3 Pending"),Building:ge.default.blue("\u{1F528} Building")}[i]||ge.default.gray(i)}Zo.exports=Xo});var nr=N((Od,tr)=>{"use strict";var er=require("commander"),si=y(require("fs-extra")),ai=y(require("path")),ot=y(require("chalk"));E();T();R();ei();Q();var ci=new er.Command("docs");ci.description("Generate documentation for voice functions (saves to README.md)");ci.option("-f, --fresh","Force regeneration (skip cache)").option("-u, --update","Update documentation for deployed function via API").action(async i=>{try{await f.load(),i.update?await sc():await rc(i)}catch(e){c.fail("\u274C Failed to generate documentation"),e.message.includes("No function file found")?n.error("No function file found. Make sure you're in a function directory with function.js, index.js, or handler.js"):e.message.includes("unauthorized")||e.message.includes("401")?n.error("Authentication failed. Run `sinch auth login` first."):e.message.includes("AI service")?n.error("AI documentation service unavailable. Please try again later."):e.message.includes("Function not found")||e.message.includes("404")?n.error("Function not found. Make sure the function is deployed first."):n.error(`Error: ${e.message}`),n.debug("Full error:",e),process.exit(1)}});async function rc(i){c.start("\u{1F916} Generating documentation...");let e=await Zn();c.succeed("\u2705 Documentation generated!"),await Qn(e,"README.md"),await ac()}async function sc(){let i=ai.default.basename(process.cwd());c.start("\u{1F4D6} Reading local README.md...");let e=ai.default.join(process.cwd(),"README.md");if(!await si.default.pathExists(e))throw new Error("README.md not found. Run `sinch functions docs` first to generate documentation locally.");if(!(await si.default.readFile(e,"utf8")).trim())throw new Error("README.md is empty. Run `sinch functions docs` first to generate documentation.");c.text="\u{1F50D} Finding deployed function...";let s=(await new J(f.getApiConfig()).listFunctions()).find(a=>a.name===i);if(!s)throw new Error(`Function '${i}' not found in project. Make sure it's deployed first.`);c.text="\u{1F4E4} Uploading documentation content...",n.info("Documentation content ready for update"),c.succeed("\u2705 Documentation updated!"),n.newline(),n.success(`\u{1F4C4} Documentation updated for deployed function: ${ot.default.cyan(i)}`),n.info(""),n.info("\u2728 Your function documentation has been updated:"),n.info(` \u2022 Function ID: ${ot.default.gray(s.id)}`),n.info(` \u2022 Source: ${ot.default.gray("Local README.md")}`),n.info(` \u2022 Updated: ${ot.default.gray(new Date().toLocaleString())}`),n.info(` \u2022 View in dashboard: ${ot.default.cyan("Dashboard \u2192 Functions \u2192 "+i)}`),n.newline(),n.info("\u{1F4A1} The updated documentation is now available in the dashboard!")}async function ac(){n.newline(),n.success(`\u{1F4C4} Documentation updated in: ${ot.default.cyan("README.md")}`),n.info(""),n.info("\u2728 Your function documentation is ready:"),n.info(" \u2022 Review and edit the AI-generated content as needed"),n.info(" \u2022 Sinch-themed diagrams will render in markdown viewers"),n.info(" \u2022 File is ready for version control and deployment"),n.newline(),n.info("\u{1F4A1} Popular markdown viewers:"),n.info(" \u2022 VS Code (built-in)"),n.info(" \u2022 GitHub (drag & drop file)"),n.info(" \u2022 Typora, Mark Text, or any markdown app")}tr.exports=ci});var ar=N((Ud,sr)=>{"use strict";var te=y(require("chalk")),li=y(require("inquirer")),ir=require("commander"),$e=y(require("fs-extra")),He=y(require("path")),or=y(require("adm-zip"));Q();E();T();R();var rr=new ir.Command("download");rr.description("Download function source code").argument("[function-id]","Function ID to download (ULID format)").option("-o, --output <dir>","Output directory (default: ./functions/<function-name>)").option("--no-extract","Keep as ZIP file without extracting").option("--non-interactive","Skip interactive selection").option("-f, --force","Overwrite existing directory without prompting").action(async(i,e)=>{try{await f.load();let t=new J(f.getApiConfig()),o=i;if(!o&&!e.nonInteractive){let d=await cc(t);if(!d){n.info("Download cancelled");return}o=d}o||(n.error("Function ID required. Provide as argument or select interactively"),n.info(`Usage: ${te.default.cyan("sinch functions download 01HX3KC5V8G3KCNZ8S5Y9ABCDE")}`),n.info(` or: ${te.default.cyan("sinch functions download")} (interactive selection)`),process.exit(1)),c.start("\u{1F4E1} Fetching function metadata...");let r=await t.getFunction(o);c.succeed("Function metadata loaded");let s=He.join("functions",r.name),a=e.output||s,l=He.resolve(a);if(await $e.pathExists(l)){if(!e.force){let{overwrite:d}=await li.default.prompt([{type:"confirm",name:"overwrite",message:`Directory '${a}' already exists. Overwrite?`,default:!1}]);if(!d){n.info("Download cancelled");return}}c.start("\u{1F5D1}\uFE0F Removing existing directory..."),await $e.remove(l),c.succeed("Existing directory removed")}c.start("\u{1F4E5} Downloading function source code...");let p=await t.downloadFunction(o);if(c.succeed("Source code downloaded"),e.extract!==!1){c.start("\u{1F4E6} Extracting files..."),await $e.ensureDir(l);let d=new or.default(p),u=d.getEntries();d.extractAllTo(l,!0),c.succeed(`\u{1F4E6} Extracted ${u.length} files`);let m=He.join(l,"sinch-metadata.json"),w={functionId:r.id,name:r.name,runtime:r.runtime,status:r.status,downloadedAt:new Date().toISOString(),url:r.containerAppUrl,configuration:r.configuration};await $e.writeJson(m,w,{spaces:2}),n.newline(),n.success("\u2705 Function downloaded successfully!"),n.newline(),n.info(`\u{1F4C1} Location: ${te.default.cyan(a)}`),n.info(`\u{1F4CB} Files: ${u.length} files extracted`);let h=He.join(l,"sinch.json");await $e.pathExists(h)&&n.info("\u{1F527} Config: sinch.json found"),n.newline(),n.info("\u{1F4A1} Next steps:"),n.info(` \u2022 Navigate: ${te.default.cyan(`cd ${a}`)}`),n.info(` \u2022 Run locally: ${te.default.cyan("sinch functions dev")}`),n.info(` \u2022 Deploy changes: ${te.default.cyan("sinch functions deploy")}`)}else{let d=`${r.name}.zip`,u=e.output?He.resolve(e.output):He.resolve(d);c.start(`\u{1F4BE} Saving as ${d}...`),await $e.writeFile(u,p),c.succeed("ZIP file saved"),n.newline(),n.success("\u2705 Function downloaded as ZIP!"),n.info(`\u{1F4C1} File: ${te.default.cyan(u)}`),n.info(`\u{1F4E6} Size: ${(p.length/1024).toFixed(2)} KB`)}}catch(t){c.stop(),t.message.includes("404")||t.message.includes("not found")?(n.error(`Function not found with ID: ${i}`),n.info("\u{1F4A1} List available functions with:"),n.info(` ${te.default.cyan("sinch functions list")}`),n.info("\u{1F4A1} Or use interactive selection:"),n.info(` ${te.default.cyan("sinch functions download")}`)):n.error(`Failed to download function: ${t.message}`),process.exit(1)}});async function cc(i){try{c.start("\u{1F4CB} Loading functions...");let e=await i.listFunctions();if(c.stop(),!e.functions||e.functions.length===0)return n.warn("No functions found to download"),null;let t=e.functions.map(r=>({name:`${te.default.cyan(r.name.padEnd(20))} ${te.default.yellow(r.runtime.padEnd(8))} ${lc(r.status)}`,value:r.id,short:r.name}));n.newline();let{selectedFunction:o}=await li.default.prompt([{type:"list",name:"selectedFunction",message:"Select a function to download:",choices:t,pageSize:15}]);return o}catch(e){throw c.stop(),e}}function lc(i){return{Running:te.default.green("\u2705 Running"),Failed:te.default.red("\u274C Failed"),Pending:te.default.yellow("\u23F3 Pending"),Building:te.default.blue("\u{1F528} Building")}[i]||te.default.gray(i)}sr.exports=rr});var dr=N((Md,lr)=>{"use strict";var cr=require("commander"),dc=ao(),pc=fo(),uc=Eo(),fc=Oo(),mc=Uo(),gc=zo(),hc=Qo(),yc=nr(),wc=ar(),Pe=new cr.Command("functions");Pe.description("Manage Sinch Functions");Pe.addCommand(dc);Pe.addCommand(pc);Pe.addCommand(uc);Pe.addCommand(wc);Pe.addCommand(fc);Pe.addCommand(mc);Pe.addCommand(gc);Pe.addCommand(hc);Pe.addCommand(yc);lr.exports=Pe});var fr=N((Kd,ur)=>{"use strict";var pr=require("commander"),he=y(require("chalk"));Q();E();T();R();var Ne=new pr.Command("templates");Ne.description("Browse and manage function templates");Ne.command("list").alias("ls").description("List available templates").argument("[runtime]","Filter by runtime (node, csharp, python)").option("-c, --category <category>","Filter by category (voice, sms, verification)").option("-d, --detailed","Show detailed information").action(async(i,e)=>{try{await f.load();let t=new J(f.getApiConfig());c.start("Loading templates...");let o;if(i?o=await t.listRuntimeTemplates(i,e.category):o=await t.listAllTemplates(e.category),c.stop(),o.templates.length===0){n.info(`No templates found${i?` for ${i}`:""}${e.category?` in category ${e.category}`:""}`);return}let r=`Available Templates${i?` (${i})`:""}${e.category?` - ${e.category}`:""}`;if(n.title(r),e.detailed)o.templates.forEach((s,a)=>{a>0&&n.newline(),n.log(he.default.bold.blue(`${s.name}`)),n.log(` Runtime: ${s.runtime}`),n.log(` Category: ${s.category}`),n.log(` Description: ${s.description}`),s.tags&&s.tags.length>0&&n.log(` Tags: ${s.tags.map(l=>he.default.gray(l)).join(", ")}`),n.log(` Path: ${he.default.gray(s.path)}`)});else{let s=o.templates.map(a=>[a.name,a.runtime,a.category,a.description.substring(0,50)+(a.description.length>50?"...":""),a.tags?a.tags.slice(0,2).join(", ")+(a.tags.length>2?"...":""):""]);n.table(["Name","Runtime","Category","Description","Tags"],s)}n.newline(),n.info(`Found ${o.templates.length} template${o.templates.length===1?"":"s"}`),n.info('Use "sinch templates show <runtime>/<template>" for details')}catch(t){c.stop(),n.error(`Failed to list templates: ${t.message}`),process.exit(1)}});Ne.command("show").description("Show detailed template information").argument("<template>",'Template name in format "runtime/template-name"').action(async i=>{try{await f.load();let e=new J(f.getApiConfig());if(!i.includes("/"))throw new Error('Template must be in format "runtime/template-name" (e.g., "node/simple-voice-ivr")');let t=i.split("/"),o=t[0],r=t[1];if(!o||!r)throw new Error('Template must be in format "runtime/template-name" (e.g., "node/simple-voice-ivr")');c.start(`Loading template details for ${i}...`);let s=await e.getTemplateDetails(o,r);c.stop(),n.title(`Template: ${s.name}`),n.newline(),n.log(he.default.bold("Basic Information:")),n.log(` Runtime: ${s.runtime}`),n.log(` Category: ${s.category}`),n.log(` Description: ${s.description}`),s.tags&&s.tags.length>0&&n.log(` Tags: ${s.tags.map(a=>he.default.blue(a)).join(", ")}`),s.variables&&Object.keys(s.variables).length>0&&(n.newline(),n.log(he.default.bold("Template Variables:")),Object.entries(s.variables).forEach(([a,l])=>{n.log(` ${a}: ${he.default.gray(l)}`)})),s.files&&s.files.length>0&&(n.newline(),n.log(he.default.bold("Files:")),s.files.forEach(a=>{n.log(` ${he.default.gray("\u2022")} ${a}`)})),s.readmeContent&&(n.newline(),n.log(he.default.bold("README:")),s.readmeContent.split(`
|
|
94
|
+
`).slice(0,10).forEach(l=>{n.log(` ${he.default.gray(l)}`)}),s.readmeContent.split(`
|
|
95
|
+
`).length>10&&n.log(` ${he.default.gray("... (truncated)")}`)),n.newline(),n.info(`Use "sinch functions init --template ${i}" to create a function from this template`)}catch(e){c.stop(),n.error(`Failed to show template details: ${e.message}`),process.exit(1)}});Ne.command("node").description("List Node.js templates").option("-c, --category <category>","Filter by category").action(async i=>{let e=Ne.commands.find(t=>t.name()==="list");e&&await e.action("node",i)});Ne.command("csharp").description("List C# templates").option("-c, --category <category>","Filter by category").action(async i=>{let e=Ne.commands.find(t=>t.name()==="list");e&&await e.action("csharp",i)});Ne.command("python").description("List Python templates").option("-c, --category <category>","Filter by category").action(async i=>{let e=Ne.commands.find(t=>t.name()==="list");e&&await e.action("python",i)});ur.exports=Ne});var yr=N((Gd,hr)=>{"use strict";var mr=require("commander"),rt=y(require("chalk")),gr=y(require("inquirer"));E();T();R();var Gt=new mr.Command("voice");Gt.description("Manage Sinch Voice applications and settings");Gt.command("callback-url").alias("webhook").description("Update webhook callback URL for your Voice application").argument("[url]","New callback URL (if not provided, will prompt)").option("-a, --app-key <key>","Application key (if not provided, will show selection)").action(async(i,e)=>{try{await f.load(),await di()||(n.error('Not authenticated. Run "sinch auth login" first.'),process.exit(1));let t=await Cc(),o=e.appKey;if(!o){let r=f.getPublicCredentialInfo()?.applicationKey;r||(n.error('No default application key found. Run "sinch auth login" first.'),process.exit(1)),o=r,n.info(`Using default application: ${o}`)}if(!i){let{newUrl:r}=await gr.default.prompt([{type:"input",name:"newUrl",message:"Enter new callback URL:",validate:s=>{if(!s)return"URL is required";try{return new URL(s),!0}catch{return"Please enter a valid URL"}}}]);i=r}c.start("Updating callback URL...");try{let r=await t.voice.applications.get(o),s={...r,capability:{...r.capability,voice:{...r.capability?.voice,webhooks:{...r.capability?.voice?.webhooks,url:i,method:"POST"}}}};await t.voice.applications.update(o,s),c.succeed("Callback URL updated successfully!"),n.newline(),n.info(`Application: ${r.displayName||o}`),n.info(`New callback URL: ${i}`),n.newline(),n.info("\u{1F389} Your Voice functions will now receive webhooks at this URL"),n.info("\u{1F4A1} Test with: sinch functions dev --tunnel")}catch(r){throw c.fail("Failed to update callback URL"),r}}catch(t){c.stop(),n.error(`Failed to update callback URL: ${t.message}`),process.exit(1)}});Gt.command("get-callbacks").description("Get current callback URLs with full debug output").option("-a, --app-key <key>","Application key (defaults to stored app key)").option("--curl","Show equivalent curl command").action(async i=>{try{await f.load(),await di()||(n.error('Not authenticated. Run "sinch auth login" first.'),process.exit(1));let e=await f.getApplicationCredentials();e||(n.error('No application credentials found. Run "sinch auth login" first.'),process.exit(1));let t=i.appKey||e.applicationKey;if(n.info("\u{1F50D} Getting callback URLs..."),n.newline(),i.curl){let o=`${e.applicationKey}:${e.applicationSecret}`,r=Buffer.from(o).toString("base64");n.info("\u{1F4CB} CURL Command:"),n.info(rt.default.gray("```bash"));let s=`curl -X GET \\
|
|
92
96
|
https://calling.api.sinch.com/calling/v1/applications/${t}/callbacks/urls \\
|
|
93
|
-
-H "Authorization: Basic ${r}"`;n.info(
|
|
97
|
+
-H "Authorization: Basic ${r}"`;n.info(rt.default.cyan(s)),n.info(rt.default.gray("```")),n.newline()}try{let{SinchClient:o}=require("@sinch/sdk-core"),r=new o({applicationKey:e.applicationKey,applicationSecret:e.applicationSecret});c.start("Fetching callback URLs...");let s=await r.voice.applications.getCallbackURLs({applicationkey:t});c.succeed("Callback URLs retrieved"),n.newline(),n.info("\u{1F4E5} Current Callback Configuration:"),n.info(` currentCallbacks.primary: ${s?.primary||"undefined"}`),n.info(` currentCallbacks.fallback: ${s?.fallback||"undefined"}`)}catch(o){c.fail("Failed to get callback URLs"),n.error(`Error: ${o.message}`),n.newline(),n.info("Full error details:"),n.info(JSON.stringify(o,null,2))}}catch(e){n.error(`Command failed: ${e.message}`),process.exit(1)}});Gt.command("set-callback").description("Update callback URL with debug output showing exact API call").argument("<url>","Callback URL to set").option("-a, --app-key <key>","Application key (defaults to stored app key)").option("--primary-only","Only set primary URL (no fallback)").option("--debug","Show full curl command and response").action(async(i,e)=>{try{await f.load(),await di()||(n.error('Not authenticated. Run "sinch auth login" first.'),process.exit(1));let t=await f.getApplicationCredentials();t||(n.error('No application credentials found. Run "sinch auth login" first.'),process.exit(1));let o=e.appKey||t.applicationKey;n.info("\u{1F527} Updating callback URL with debug output..."),n.newline();let r=e.primaryOnly?{url:{primary:i}}:{url:{primary:i,fallback:i}},s=`${t.applicationKey}:${t.applicationSecret}`,a=Buffer.from(s).toString("base64");n.info("\u{1F4CB} CURL Command:"),n.info(rt.default.gray("```bash"));let l=`curl -X POST \\
|
|
94
98
|
https://calling.api.sinch.com/calling/v1/applications/${o}/callbacks/urls \\
|
|
95
99
|
-H "Authorization: Basic ${a}" \\
|
|
96
100
|
-H "Content-Type: application/json" \\
|
|
97
|
-
-d '${JSON.stringify(r,null,2)}'`;n.info(
|
|
101
|
+
-d '${JSON.stringify(r,null,2)}'`;n.info(rt.default.cyan(l)),n.info(rt.default.gray("```")),n.newline();try{let{SinchClient:p}=require("@sinch/sdk-core"),d=new p({applicationKey:t.applicationKey,applicationSecret:t.applicationSecret});n.info("\u{1F4E4} Request Body:"),n.info(JSON.stringify(r,null,2)),n.newline(),c.start("Sending update request..."),await d.voice.applications.updateCallbackURLs({applicationkey:o,updateCallbacksRequestBody:r}),c.succeed("Update request sent"),c.start("Waiting for changes to propagate..."),await new Promise(w=>setTimeout(w,5e3)),c.start("Verifying update...");let u=await d.voice.applications.getCallbackURLs({applicationkey:o});c.succeed("Verification complete"),n.newline(),n.info("\u{1F4E5} Current Callback URLs:"),n.info(JSON.stringify(u,null,2));let m=u?.url||u?.primary||u?.urls?.primary;m===i?(n.newline(),n.success("\u2705 Callback URL successfully updated!")):(n.newline(),n.warn("\u26A0\uFE0F Callback URL may not have been updated correctly"),n.info("Expected: "+i),n.info("Actual: "+(typeof m=="object"?JSON.stringify(m):m||"not found")),n.newline(),n.info("\u{1F50D} Debug - Response structure:"),n.info(" typeof currentCallbacks: "+typeof u),n.info(" currentCallbacks.url: "+(u?.url||"undefined")),n.info(" currentCallbacks.primary: "+(u?.primary||"undefined")),n.info(" currentCallbacks.urls?.primary: "+(u?.urls?.primary||"undefined")))}catch(p){c.fail("Update failed"),n.error(`Error: ${p.message}`),e.debug&&(n.newline(),n.info("Full error details:"),n.info(JSON.stringify(p,null,2)))}}catch(t){n.error(`Command failed: ${t.message}`),process.exit(1)}});async function di(){return await f.hasCredentials()}async function Cc(){return await f.createSinchClient()}hr.exports=Gt});var vr=N((Xd,Cr)=>{"use strict";var wr=require("commander"),Le=y(require("keytar")),Y=y(require("chalk"));T();var pi=y(require("inquirer")),We="sinch-functions-cli",st=new wr.Command("secrets");st.description("Manage secure secrets in OS keychain").addHelpText("after",`
|
|
98
102
|
Examples:
|
|
99
|
-
${
|
|
100
|
-
${
|
|
101
|
-
${
|
|
102
|
-
${
|
|
103
|
+
${Y.default.cyan("sinch secrets list")} List all custom secrets
|
|
104
|
+
${Y.default.cyan("sinch secrets add API_KEY abc123")} Add or update a secret
|
|
105
|
+
${Y.default.cyan("sinch secrets get API_KEY")} Get a specific secret value
|
|
106
|
+
${Y.default.cyan("sinch secrets delete API_KEY")} Remove a secret
|
|
103
107
|
|
|
104
108
|
Note: Secrets are stored securely in your OS keychain:
|
|
105
109
|
- Windows: Credential Manager
|
|
106
110
|
- macOS: Keychain
|
|
107
111
|
- Linux: Secret Service API
|
|
108
|
-
`);
|
|
112
|
+
`);st.command("list").description("List all custom secrets (keys only)").action(async()=>{try{let e=(await Le.default.findCredentials(We)).filter(t=>t.account&&t.account.startsWith("custom-")).map(t=>t.account.replace("custom-",""));if(e.length===0){n.info("No custom secrets found"),n.info(""),n.info("\u{1F4A1} Add a secret with:"),n.info(` ${Y.default.cyan("sinch secrets add <KEY> <VALUE>")}`);return}n.info(Y.default.bold("Custom Secrets:")),n.info(""),e.forEach(t=>{n.info(` \u{1F510} ${Y.default.cyan(t)}`)}),n.info(""),n.info(`Total: ${e.length} secret(s)`)}catch(i){n.error("Failed to list secrets:",i.message),process.exit(1)}});st.command("add <key> <value>").description("Add or update a secret in OS keychain").action(async(i,e)=>{try{i.match(/^[A-Z0-9_]+$/)||(n.error("Secret key must be uppercase letters, numbers, and underscores only"),n.info(`Example: ${Y.default.cyan("API_KEY")}, ${Y.default.cyan("DATABASE_PASSWORD")}`),process.exit(1));let t=`custom-${i}`,r=await Le.default.getPassword(We,t)!==null;await Le.default.setPassword(We,t,e),r?n.success(`\u2705 Updated secret: ${Y.default.cyan(i)}`):n.success(`\u2705 Added secret: ${Y.default.cyan(i)}`),n.info(""),n.info("\u{1F4DD} To use in your function:"),n.info(` 1. Add ${Y.default.cyan(i+"=")} to your .env file (leave value empty)`),n.info(` 2. Access via ${Y.default.cyan("process.env."+i)} in your code`),n.info(" 3. The secret will be loaded automatically from OS keychain")}catch(t){n.error("Failed to add secret:",t.message),process.exit(1)}});st.command("get <key>").description("Get a specific secret value").option("--show","Show the actual value (be careful!)").action(async(i,e)=>{try{let t=`custom-${i}`,o=await Le.default.getPassword(We,t);o||(n.error(`Secret not found: ${Y.default.cyan(i)}`),n.info(""),n.info("\u{1F4A1} Available secrets:"),n.info(` Run ${Y.default.cyan("sinch secrets list")} to see all secrets`),process.exit(1)),n.info(`Secret: ${Y.default.cyan(i)}`),e.show?(n.warn("\u26A0\uFE0F Showing secret value - be careful not to expose it!"),n.info(`Value: ${o}`)):(n.info(`Value: ${Y.default.gray("[HIDDEN - use --show to reveal]")}`),n.info(`Length: ${o.length} characters`))}catch(t){n.error("Failed to get secret:",t.message),process.exit(1)}});st.command("delete <key>").alias("remove").alias("rm").description("Remove a secret from OS keychain").option("-f, --force","Skip confirmation").action(async(i,e)=>{try{let t=`custom-${i}`;if(await Le.default.getPassword(We,t)||(n.error(`Secret not found: ${Y.default.cyan(i)}`),process.exit(1)),!e.force&&!(await pi.default.prompt([{type:"confirm",name:"confirm",message:`Are you sure you want to delete secret '${i}'?`,default:!1}])).confirm){n.info("Cancelled");return}await Le.default.deletePassword(We,t)?n.success(`\u2705 Deleted secret: ${Y.default.cyan(i)}`):(n.error("Failed to delete secret"),process.exit(1))}catch(t){n.error("Failed to delete secret:",t.message),process.exit(1)}});st.command("clear").description("Remove ALL custom secrets (use with caution!)").option("-f, --force","Skip confirmation").action(async i=>{try{let t=(await Le.default.findCredentials(We)).filter(r=>r.account&&r.account.startsWith("custom-"));if(t.length===0){n.info("No custom secrets to clear");return}if(!i.force&&(n.warn(`\u26A0\uFE0F This will delete ${t.length} custom secret(s)`),!(await pi.default.prompt([{type:"confirm",name:"confirm",message:"Are you sure you want to delete ALL custom secrets?",default:!1}])).confirm)){n.info("Cancelled");return}let o=0;for(let r of t)await Le.default.deletePassword(We,r.account)&&o++;n.success(`\u2705 Deleted ${o} custom secret(s)`)}catch(e){n.error("Failed to clear secrets:",e.message),process.exit(1)}});Cr.exports=st});var Ar=N((Qd,Pr)=>{"use strict";var Sr=require("commander"),B=y(require("chalk")),V=y(require("fs-extra")),ie=y(require("path")),br=y(require("os"));T();function Ir(){return ie.default.join(__dirname,"..","skills")}function ui(){return ie.default.join(br.default.homedir(),".claude","skills","sinch-functions")}function fi(){return ie.default.join(process.cwd(),".claude","skills","sinch-functions")}function mi(){return ie.default.join(process.cwd(),".github","skills","sinch-functions")}function $r(i={}){let e=[],t=ui();if(e.push({tool:"Claude Code",path:t,type:"global",installed:V.default.existsSync(ie.default.join(t,"SKILL.md"))}),i.project){let o=fi();e.push({tool:"Claude Code",path:o,type:"project",installed:V.default.existsSync(ie.default.join(o,"SKILL.md"))})}if(i.project){let o=mi();e.push({tool:"GitHub Copilot",path:o,type:"project",installed:V.default.existsSync(ie.default.join(o,"SKILL.md"))})}return e}var St=new Sr.Command("skills");St.description("Manage AI coding assistant skills for Sinch development").addHelpText("after",`
|
|
109
113
|
Examples:
|
|
110
114
|
${B.default.cyan("sinch skills install")} Install skills globally (Claude Code)
|
|
111
115
|
${B.default.cyan("sinch skills install --project")} Install to current project (Claude + Copilot)
|
|
@@ -115,14 +119,14 @@ Examples:
|
|
|
115
119
|
${B.default.cyan("sinch skills uninstall")} Remove installed skills
|
|
116
120
|
|
|
117
121
|
Skills provide AI coding assistants with accurate Sinch development patterns.
|
|
118
|
-
`);
|
|
119
|
-
`)),n.info(B.default.underline("Global (personal machine):"));let o=!1;for(let a of e)a.installed?(n.info(` ${B.default.green("\u2713")} ${a.tool}: ${B.default.gray(a.path)}`),o=!0):n.info(` ${B.default.gray("\u25CB")} ${a.tool}: ${B.default.gray("not installed")}`);o||n.info(` ${B.default.gray("No global skills installed")}`),n.info(""),n.info(B.default.underline("Project (current directory):"));let r=!1;for(let a of t)a.installed?(n.info(` ${B.default.green("\u2713")} ${a.tool}: ${B.default.gray(a.path)}`),r=!0):n.info(` ${B.default.gray("\u25CB")} ${a.tool}: ${B.default.gray("not installed")}`);r||n.info(` ${B.default.gray("No project skills installed")}`),n.info(""),i.some(a=>a.installed)||(n.info("Run `sinch skills install` to install skills globally"),n.info("Run `sinch skills install --project` to install for this project"))}catch(i){n.error("Failed to list skills:",i.message),process.exit(1)}});
|
|
120
|
-
`);let t=vr({project:i.project}).filter(a=>a.installed);if(t.length===0){n.info("No skills installed. Run `sinch skills install` first.");return}let o=Cr(),r=ie.default.join(o,"sinch-functions"),s=0;for(let a of t)await J.default.copy(r,a.path,{overwrite:!0}),n.success(`Updated ${a.tool} (${a.type})`),s++;n.info(""),n.success(`Updated ${s} skill(s)`)}catch(e){n.error("Failed to update skills:",e.message),process.exit(1)}});br.exports=vt});async function hc(){await f.load(),await f.hasCredentials()||(n.error('Not authenticated. Run "sinch auth login" first.'),process.exit(1))}async function q(){return await hc(),await f.createSinchClient()}function bt(i){let e=i||f.get("conversation-app-id");return e||(n.error("No Conversation App ID configured."),n.info("Set default: sinch config set conversation-app-id <id>"),n.info("Or specify: --app <app-id>"),process.exit(1)),e}var st=W(()=>{"use strict";A();E()});var Ar=T((ep,kr)=>{"use strict";var Ir=require("commander"),$r=y(require("inquirer"));E();x();st();var Pr=new Ir.Command("send");Pr.description("Send a message via Conversation API").argument("[recipient]","Recipient phone number (e.g., +15551234567)").argument("[message]","Message text to send").option("-c, --channel <channel>","Channel (SMS, WHATSAPP, MESSENGER, etc.)","SMS").option("-a, --app <app-id>","Conversation App ID (uses default if configured)").option("-m, --media <url>","Media URL for media messages").option("--caption <text>","Caption for media messages").option("-t, --template <name>","Template name for template messages").option("-p, --params <json>","Template parameters as JSON string").option("--location","Send location message").option("--lat <latitude>","Latitude for location messages",parseFloat).option("--lng <longitude>","Longitude for location messages",parseFloat).option("-n, --name <name>","Location name").option("--json","Output result as JSON").action(async(i,e,t)=>{try{let o=await q();if(!i||!e&&!t?.media&&!t?.template&&!t?.location){let s=await $r.default.prompt([{type:"input",name:"recipient",message:"Enter recipient phone number:",when:!i,validate:a=>a?a.startsWith("+")?!0:"Phone number must start with +":"Recipient is required"},{type:"input",name:"message",message:"Enter message:",when:!e&&!t?.media&&!t?.template&&!t?.location,validate:a=>a?!0:"Message is required"},{type:"list",name:"channel",message:"Select channel:",choices:["SMS","WHATSAPP","MESSENGER","INSTAGRAM","VIBER","TELEGRAM","RCS","LINE"],default:t?.channel||"SMS",when:!t?.channel}]);i=i||s.recipient,e=e||s.message,s.channel&&(t={...t,channel:s.channel})}let r=bt(t?.app);c.start("Sending message...");try{let s;if(t?.location)(!t.lat||!t.lng)&&(c.fail("Location messages require --lat and --lng"),process.exit(1)),s=await o.conversation.messages.send({sendMessageRequestBody:{app_id:r,recipient:{identified_by:{channel_identities:[{channel:t.channel||"SMS",identity:i}]}},message:{location_message:{coordinates:{latitude:t.lat,longitude:t.lng},title:t.name}}}});else if(t?.template){let a=t.params?JSON.parse(t.params):{};s=await o.conversation.messages.send({sendMessageRequestBody:{app_id:r,recipient:{identified_by:{channel_identities:[{channel:t.channel||"WHATSAPP",identity:i}]}},message:{template_message:{template_reference:{template_id:t.template,version:a.version||"1"},parameters:a}}}})}else t?.media?s=await o.conversation.messages.send({sendMessageRequestBody:{app_id:r,recipient:{identified_by:{channel_identities:[{channel:t.channel||"WHATSAPP",identity:i}]}},message:{media_message:{url:t.media,caption:t.caption}}}}):s=await o.conversation.messages.send({sendMessageRequestBody:{app_id:r,recipient:{identified_by:{channel_identities:[{channel:t?.channel||"SMS",identity:i}]}},message:{text_message:{text:e}}}});c.succeed("Message sent successfully!"),t?.json?console.log(JSON.stringify(s,null,2)):(n.newline(),n.info(`Message ID: ${s.message_id}`),n.info(`Recipient: ${i}`),n.info(`Channel: ${t?.channel||"SMS"}`))}catch(s){c.fail("Failed to send message"),n.error(`Error: ${s.message}`),(s.message?.includes("WHATSAPP")||s.message?.includes("channel not configured"))&&(n.newline(),n.info("To use WhatsApp, configure WhatsApp credentials in your Conversation app:"),n.info(" 1. Visit https://dashboard.sinch.com/convapi/apps"),n.info(" 2. Add WhatsApp channel credentials"),n.info(" 3. Verify your WhatsApp Business Account"),n.newline(),n.info("Or use SMS (no additional setup required):"),n.info(` sinch conversation send ${i} "${e}"`)),process.exit(1)}}catch(o){c.stop(),n.error(`Failed to send message: ${o.message}`),process.exit(1)}});kr.exports=Pr});var xr=T((op,Tr)=>{"use strict";var Er=require("commander");E();x();st();var zt=new Er.Command("messages");zt.description("Manage conversation messages");zt.command("get").description("Get a specific message by ID").argument("<message-id>","Message ID to retrieve").option("--json","Output result as JSON").action(async(i,e)=>{try{let t=await q();c.start("Fetching message...");let o=await t.conversation.messages.get({message_id:i});c.succeed("Message retrieved"),e.json?console.log(JSON.stringify(o,null,2)):(n.newline(),n.info(`Message ID: ${o.id}`),n.info(`Direction: ${o.direction}`),n.info(`Channel: ${o.channel_identity?.channel||"N/A"}`),n.info(`Contact ID: ${o.contact_id||"N/A"}`),n.info(`Conversation ID: ${o.conversation_id||"N/A"}`),n.info(`Status: ${o.accept_time?"Accepted":"Pending"}`),o.text_message&&n.info(`Text: ${o.text_message.text}`),o.media_message&&n.info(`Media URL: ${o.media_message.url}`))}catch(t){c.stop(),n.error(`Failed to get message: ${t.message}`),process.exit(1)}});zt.command("list").description("List messages").option("-c, --channel <channel>","Filter by channel").option("-l, --limit <number>","Limit number of results",parseInt,20).option("--json","Output result as JSON").action(async i=>{try{let e=await q();c.start("Fetching messages...");let t=await e.conversation.messages.list({page_size:i.limit||20,...i.channel&&{channel:i.channel}});c.succeed(`Retrieved ${t.messages?.length||0} messages`),i.json?console.log(JSON.stringify(t,null,2)):(n.newline(),t.messages&&t.messages.length>0?t.messages.forEach(o=>{n.info(`[${o.id}] ${o.direction} via ${o.channel_identity?.channel||"N/A"}`),o.text_message&&n.info(` "${o.text_message.text}"`),n.newline()}):n.info("No messages found"))}catch(e){c.stop(),n.error(`Failed to list messages: ${e.message}`),process.exit(1)}});zt.command("delete").description("Delete a message").argument("<message-id>","Message ID to delete").action(async i=>{try{let e=await q();c.start("Deleting message..."),await e.conversation.messages.delete({message_id:i}),c.succeed("Message deleted successfully")}catch(e){c.stop(),n.error(`Failed to delete message: ${e.message}`),process.exit(1)}});Tr.exports=zt});function _(i){try{let e=Rr.parse(i);return Rr.format(e,gn.PhoneNumberFormat.INTERNATIONAL)}catch{return i}}var gn,Rr,St=W(()=>{"use strict";gn=require("google-libphonenumber"),Rr=gn.PhoneNumberUtil.getInstance()});var Or=T((dp,Nr)=>{"use strict";var Dr=require("commander"),ce=y(require("inquirer"));E();x();st();St();var hn=class{sinchClient;constructor(e){this.sinchClient=e}hasChannel(e,t){return e.channel_identities?.some(o=>{let r=o.channel;return r==="CHANNEL_UNSPECIFIED"&&o.identity.includes("@")&&(r="EMAIL"),t.includes(r)})}getChannelIdentities(e,t){return e.channel_identities.filter(o=>{let r=o.channel;return r==="CHANNEL_UNSPECIFIED"&&o.identity.includes("@")&&(r="EMAIL"),t.includes(r)})}buildContactMenu(e){let t=this.hasChannel(e,["SMS","WHATSAPP"]),o=this.hasChannel(e,["SMS","WHATSAPP"]),r=this.hasChannel(e,["EMAIL"]),s=[];return t&&s.push({name:"\u{1F4AC} Send Message",value:"send-message"}),s.push({name:"Edit Name",value:"edit-name"}),o&&s.push({name:"Edit Phone",value:"edit-phone"}),r&&s.push({name:"Edit Email",value:"edit-email"}),s.push({name:"Delete Contact",value:"delete"},{name:"See More Details",value:"details"},{name:"\u2190 Back",value:"back"}),s}async sendMessage(e){let t=e.channel_identities.map(s=>{let a=s.channel;return a==="CHANNEL_UNSPECIFIED"&&s.identity.includes("@")&&(a="EMAIL"),{name:`${a}: ${_(s.identity)}`,value:{channel:a,identity:s.identity}}});t.push({name:"\u2190 Back",value:"back"});let{selectedChannel:o}=await ce.default.prompt([{type:"list",name:"selectedChannel",message:"Select channel to send to:",choices:t}]);if(o==="back")return!1;let{messageText:r}=await ce.default.prompt([{type:"input",name:"messageText",message:"Enter your message:",validate:s=>s?!0:"Message is required"}]);try{let s=bt();c.start("Sending message...");let a=await this.sinchClient.conversation.messages.send({sendMessageRequestBody:{app_id:s,recipient:{identified_by:{channel_identities:[{channel:o.channel,identity:o.identity,app_id:""}]}},message:{text_message:{text:r}}}});c.succeed("Message sent successfully!"),n.newline(),n.info(`Message ID: ${a.message_id}`),n.info(`Recipient: ${_(o.identity)}`),n.info(`Channel: ${o.channel}`),n.newline()}catch(s){c.fail("Failed to send message"),n.error(`Error: ${s.message}`),n.newline()}return!1}showDetails(e){n.newline(),n.info("Contact Details:"),n.info(`ID: ${e.id}`),n.info(`Display Name: ${e.display_name||"N/A"}`),n.info(`Email: ${e.email||"N/A"}`),n.info(`External ID: ${e.external_id||"N/A"}`),n.info(`Language: ${e.language||"N/A"}`),n.info(`Metadata: ${e.metadata||"N/A"}`),e.channel_identities&&e.channel_identities.length>0&&(n.newline(),n.info("Channel Identities:"),e.channel_identities.forEach(t=>{let o=t.channel;o==="CHANNEL_UNSPECIFIED"&&t.identity.includes("@")&&(o="EMAIL"),n.info(` ${o}: ${_(t.identity)}`)})),n.newline()}async editName(e,t){let{newDisplayName:o}=await ce.default.prompt([{type:"input",name:"newDisplayName",message:"Enter new display name:",default:e.display_name}]);c.start("Updating contact..."),await this.sinchClient.conversation.contact.update({contact_id:t,display_name:o}),c.succeed("Contact updated successfully!"),e.display_name=o,n.newline()}async editChannelIdentities(e,t,o){let s={phone:{channels:["SMS","WHATSAPP"],addPrompt:"+ Add new phone number",selectPrompt:"Select phone number to edit or add new:",typePrompt:"Select type:",valuePrompt:"Enter phone number:",editPrompt:"Enter new phone number:",typeChoices:["SMS","WHATSAPP"],successAdd:"Phone number added successfully!",successEdit:"Phone number updated successfully!",successDelete:"Phone number deleted successfully!",validator:d=>d?d.startsWith("+")?!0:"Phone number must start with +":"Phone number is required"},email:{channels:["EMAIL"],addPrompt:"+ Add new email address",selectPrompt:"Select email address to edit or add new:",typePrompt:null,valuePrompt:"Enter email address:",editPrompt:"Enter new email address:",typeChoices:null,successAdd:"Email address added successfully!",successEdit:"Email address updated successfully!",successDelete:"Email address deleted successfully!",validator:d=>d?d.includes("@")?!0:"Invalid email address":"Email is required"}}[o],l=this.getChannelIdentities(e,s.channels).map(d=>{let u=e.channel_identities.indexOf(d),m=d.channel;return m==="CHANNEL_UNSPECIFIED"&&d.identity.includes("@")&&(m="EMAIL"),{name:`${m}: ${_(d.identity)}`,value:u}});l.push({name:s.addPrompt,value:"add"}),l.push({name:"\u2190 Back",value:"cancel"});let{identityAction:p}=await ce.default.prompt([{type:"list",name:"identityAction",message:s.selectPrompt,choices:l}]);if(p!=="cancel")if(p==="add"){let d=[];s.typePrompt&&s.typeChoices&&d.push({type:"list",name:"newIdentityType",message:s.typePrompt,choices:s.typeChoices}),d.push({type:"input",name:"newIdentityValue",message:s.valuePrompt,validate:s.validator});let u=await ce.default.prompt(d);e.channel_identities.push({channel:u.newIdentityType||s.channels[0],identity:u.newIdentityValue,app_id:""}),c.start("Updating contact..."),await this.sinchClient.conversation.contact.update({contact_id:t,channel_identities:e.channel_identities,display_name:e.display_name}),c.succeed(s.successAdd),n.newline()}else{let d=e.channel_identities[p],{editOrDelete:u}=await ce.default.prompt([{type:"list",name:"editOrDelete",message:"What would you like to do?",choices:["Edit","Delete","\u2190 Back"]}]);if(u==="Edit"){let{newValue:m}=await ce.default.prompt([{type:"input",name:"newValue",message:s.editPrompt,default:d.identity,validate:s.validator}]);d.identity=m,c.start("Updating contact..."),await this.sinchClient.conversation.contact.update({contact_id:t,channel_identities:e.channel_identities,display_name:e.display_name}),c.succeed(s.successEdit),n.newline()}else u==="Delete"&&(e.channel_identities.splice(p,1),c.start("Updating contact..."),await this.sinchClient.conversation.contact.update({contact_id:t,channel_identities:e.channel_identities,display_name:e.display_name}),c.succeed(s.successDelete),n.newline())}}async deleteContact(e,t,o){let{confirmDelete:r}=await ce.default.prompt([{type:"confirm",name:"confirmDelete",message:`Are you sure you want to delete "${e.display_name||"this contact"}"?`,default:!1}]);if(r){c.start("Deleting contact..."),await this.sinchClient.conversation.contact.delete({contact_id:t}),c.succeed("Contact deleted successfully");let s=o.findIndex(a=>a.id===t);if(s>-1&&o.splice(s,1),o.length===0)return n.info("No more contacts."),!0;n.newline()}return!1}async handleAction(e,t,o,r){switch(e){case"send-message":return await this.sendMessage(t);case"details":return this.showDetails(t),!1;case"edit-name":return await this.editName(t,o),!1;case"edit-phone":return await this.editChannelIdentities(t,o,"phone"),!1;case"edit-email":return await this.editChannelIdentities(t,o,"email"),!1;case"delete":return await this.deleteContact(t,o,r);default:return!1}}async runInteractiveList(e){let t=!0;for(;t;){let o=[];e.forEach(p=>{o.push(new ce.default.Separator(`
|
|
121
|
-
${p.display_name||"No name"}`)),p.channel_identities&&p.channel_identities.length>0&&p.channel_identities.forEach(d=>{let u=d.channel;u==="CHANNEL_UNSPECIFIED"&&d.identity.includes("@")&&(u="EMAIL"),o.push(new ce.default.Separator(`${u}: ${d.identity}`))}),o.push({name:"Edit Delete More",value:`menu:${p.id}`})}),o.push(new ce.default.Separator("")),o.push({name:"\u2190 Exit",value:"exit"});let{action:r}=await ce.default.prompt([{type:"list",name:"action",message:"Contacts",choices:o,pageSize:20}]);if(r==="exit")break;if(!r||!r.includes(":"))continue;let[s,a]=r.split(":"),l=e.find(p=>p.id===a);if(s==="menu"){let p=this.buildContactMenu(l),{subAction:d}=await ce.default.prompt([{type:"list",name:"subAction",message:`Actions for ${l.display_name||"contact"}:`,choices:p}]);if(d==="back")continue;await this.handleAction(d,l,a,e)&&(t=!1)}}}},Ke=new Dr.Command("contacts");Ke.description("Manage conversation contacts");Ke.command("create").description("Create a new contact").option("-p, --phone <number>","Phone number").option("-e, --email <email>","Email address").option("-n, --name <name>","Contact name").option("-d, --display-name <name>","Display name").option("--json","Output result as JSON").action(async i=>{try{if(!i.phone&&!i.email){let s=await ce.default.prompt([{type:"input",name:"phone",message:"Enter phone number (optional):",validate:a=>a&&!a.startsWith("+")?"Phone number must start with +":!0},{type:"input",name:"email",message:"Enter email address (optional):"},{type:"input",name:"name",message:"Enter contact name (optional):"}]);i={...i,...s}}!i.phone&&!i.email&&(n.error("At least one of phone or email is required"),process.exit(1));let e=await q();c.start("Creating contact...");let t=[];i.phone&&t.push({channel:"SMS",identity:i.phone}),i.email&&t.push({channel:"EMAIL",identity:i.email});let o={contactCreateRequestBody:{channel_identities:t,display_name:i.displayName||i.name,language:"EN_US"}},r=await e.conversation.contact.create(o);c.succeed("Contact created successfully!"),i.json||(n.newline(),n.info(`Contact ID: ${r.id}`),n.info(`Display Name: ${r.display_name||"N/A"}`),i.phone&&n.info(`Phone: ${_(i.phone)}`),i.email&&n.info(`Email: ${i.email}`))}catch(e){c.stop(),n.error(`Failed to create contact: ${e.message}`),e.response?.data&&n.error("API Response:",JSON.stringify(e.response.data,null,2)),e.data&&n.error("Error data:",JSON.stringify(e.data,null,2)),process.exit(1)}});Ke.command("get").description("Get a specific contact by ID").argument("<contact-id>","Contact ID to retrieve").option("--json","Output result as JSON").action(async(i,e)=>{try{let t=await q();c.start("Fetching contact...");let o=await t.conversation.contact.get({contact_id:i});c.succeed("Contact retrieved"),e.json?console.log(JSON.stringify(o,null,2)):new hn(t).showDetails(o)}catch(t){c.stop(),n.error(`Failed to get contact: ${t.message}`),process.exit(1)}});Ke.command("list").description("List contacts").option("-l, --limit <number>","Limit number of results",parseInt,50).option("--json","Output result as JSON").option("--no-interactive","Disable interactive mode").action(async i=>{try{let e=await q();c.start("Fetching contacts...");let t=await e.conversation.contact.list({page_size:i.limit||50}),o=t.data||t.contacts||[];if(c.succeed(`Retrieved ${o.length} contacts`),i.json){console.log(JSON.stringify(t,null,2));return}o&&o.length>0?(n.newline(),n.newline(),i.interactive!==!1?await new hn(e).runInteractiveList(o):o.forEach(r=>{n.info(r.display_name||"No name"),r.channel_identities&&r.channel_identities.length>0&&r.channel_identities.forEach(s=>{let a=s.channel;a==="CHANNEL_UNSPECIFIED"&&s.identity.includes("@")&&(a="EMAIL"),n.info(`${a}: ${s.identity}`)}),n.newline()})):(n.newline(),n.info("No contacts found"))}catch(e){c.stop(),n.error(`Failed to list contacts: ${e.message}`),process.exit(1)}});Ke.command("update").description("Update a contact").argument("<contact-id>","Contact ID to update").option("-n, --name <name>","New contact name").option("-d, --display-name <name>","New display name").option("--json","Output result as JSON").action(async(i,e)=>{try{!e.displayName&&!e.name&&(n.error("At least one update field is required (--name or --display-name)"),process.exit(1));let t=await q();c.start("Updating contact...");let o=await t.conversation.contact.update({contact_id:i,display_name:e.displayName||e.name,...e.name&&{metadata:JSON.stringify({name:e.name})}});c.succeed("Contact updated successfully!"),e.json?console.log(JSON.stringify(o,null,2)):(n.newline(),n.info(`Contact ID: ${o.id}`),n.info(`Display Name: ${o.display_name||"N/A"}`))}catch(t){c.stop(),n.error(`Failed to update contact: ${t.message}`),process.exit(1)}});Ke.command("delete").description("Delete a contact").argument("<contact-id>","Contact ID to delete").action(async i=>{try{let e=await q();c.start("Deleting contact..."),await e.conversation.contact.delete({contact_id:i}),c.succeed("Contact deleted successfully")}catch(e){c.stop(),n.error(`Failed to delete contact: ${e.message}`),process.exit(1)}});Ke.command("merge").description("Merge two contacts").argument("<source-id>","Source contact ID (will be merged into destination)").argument("<dest-id>","Destination contact ID").option("--json","Output result as JSON").action(async(i,e,t)=>{try{let o=await q();c.start("Merging contacts...");let r=await o.conversation.contact.mergeContact({destination_id:e,source_id:i});c.succeed("Contacts merged successfully!"),t.json?console.log(JSON.stringify(r,null,2)):(n.newline(),n.info(`Source contact ${i} merged into ${e}`),n.info(`Result Contact ID: ${r.id}`))}catch(o){c.stop(),n.error(`Failed to merge contacts: ${o.message}`),process.exit(1)}});Nr.exports=Ke});var Lr=T((mp,Fr)=>{"use strict";var jr=require("commander");E();x();st();var Gt=new jr.Command("conversations");Gt.description("Manage conversations");Gt.command("list").description("List conversations").option("-a, --app <app-id>","Filter by Conversation App ID").option("-l, --limit <number>","Limit number of results",parseInt,50).option("--json","Output result as JSON").action(async i=>{try{let e=await q();c.start("Fetching conversations...");let t=await e.conversation.conversation.list({page_size:i.limit||50,...i.app&&{app_id:i.app}});c.succeed(`Retrieved ${t.conversations?.length||0} conversations`),i.json?console.log(JSON.stringify(t,null,2)):(n.newline(),t.conversations&&t.conversations.length>0?t.conversations.forEach(o=>{n.info(`[${o.id}]`),n.info(` App ID: ${o.app_id}`),n.info(` Active: ${o.active_channel||"N/A"}`),n.info(` Last Updated: ${o.last_received?new Date(o.last_received).toLocaleString():"N/A"}`),n.newline()}):n.info("No conversations found"))}catch(e){c.stop(),n.error(`Failed to list conversations: ${e.message}`),process.exit(1)}});Gt.command("get").description("Get a specific conversation by ID").argument("<conversation-id>","Conversation ID to retrieve").option("--json","Output result as JSON").action(async(i,e)=>{try{let t=await q();c.start("Fetching conversation...");let o=await t.conversation.conversation.get({conversation_id:i});c.succeed("Conversation retrieved"),e.json?console.log(JSON.stringify(o,null,2)):(n.newline(),n.info(`Conversation ID: ${o.id}`),n.info(`App ID: ${o.app_id}`),n.info(`Active Channel: ${o.active_channel||"N/A"}`),n.info(`Contact ID: ${o.contact_id||"N/A"}`),o.metadata&&(n.newline(),n.info("Metadata:"),n.info(JSON.stringify(o.metadata,null,2))))}catch(t){c.stop(),n.error(`Failed to get conversation: ${t.message}`),process.exit(1)}});Gt.command("stop").description("Stop an active conversation").argument("<conversation-id>","Conversation ID to stop").action(async i=>{try{let e=await q();c.start("Stopping conversation..."),await e.conversation.conversation.delete({conversation_id:i}),c.succeed("Conversation stopped successfully")}catch(e){c.stop(),n.error(`Failed to stop conversation: ${e.message}`),process.exit(1)}});Fr.exports=Gt});var Mr=T((wp,Ur)=>{"use strict";var _r=require("commander"),ui=y(require("inquirer"));E();x();st();var It=new _r.Command("apps");It.description("Manage Conversation apps");It.command("list").description("List Conversation apps").option("-l, --limit <number>","Limit number of results",parseInt,50).option("--json","Output result as JSON").action(async i=>{try{let e=await q();c.start("Fetching apps...");let t=await e.conversation.app.list({page_size:i.limit||50});c.succeed(`Retrieved ${t.apps?.length||0} apps`),i.json?console.log(JSON.stringify(t,null,2)):(n.newline(),t.apps&&t.apps.length>0?t.apps.forEach(o=>{n.info(`[${o.id}] ${o.display_name||"No name"}`),n.info(` Channels: ${o.channel_credentials?.length||0} configured`),n.newline()}):n.info("No apps found"))}catch(e){c.stop(),n.error(`Failed to list apps: ${e.message}`),process.exit(1)}});It.command("get").description("Get a specific Conversation app by ID").argument("<app-id>","App ID to retrieve").option("--json","Output result as JSON").action(async(i,e)=>{try{let t=await q();c.start("Fetching app...");let o=await t.conversation.app.get({app_id:i});c.succeed("App retrieved"),e.json?console.log(JSON.stringify(o,null,2)):(n.newline(),n.info(`App ID: ${o.id}`),n.info(`Display Name: ${o.display_name||"N/A"}`),n.info("Rate Limits:",o.rate_limits||"N/A"),o.channel_credentials&&o.channel_credentials.length>0&&(n.newline(),n.info("Configured Channels:"),o.channel_credentials.forEach(r=>{n.info(` - ${r.channel}`)})),o.conversation_metadata_report_view&&(n.newline(),n.info(`Metadata Report: ${o.conversation_metadata_report_view}`)))}catch(t){c.stop(),n.error(`Failed to get app: ${t.message}`),process.exit(1)}});It.command("create").description("Create a new Conversation app").argument("[name]","App display name").option("--json","Output result as JSON").action(async(i,e)=>{try{i||(i=(await ui.default.prompt([{type:"input",name:"name",message:"Enter app display name:",validate:s=>s?!0:"App name is required"}])).name);let t=await q();c.start("Creating app...");let o=await t.conversation.app.create({display_name:i});c.succeed("App created successfully!"),e?.json?console.log(JSON.stringify(o,null,2)):(n.newline(),n.info(`App ID: ${o.id}`),n.info(`Display Name: ${o.display_name}`),n.newline(),n.info("\u{1F4A1} Set as default: sinch config set conversation-app-id "+o.id))}catch(t){c.stop(),n.error(`Failed to create app: ${t.message}`),process.exit(1)}});It.command("delete").description("Delete a Conversation app").argument("<app-id>","App ID to delete").action(async i=>{try{let{confirm:e}=await ui.default.prompt([{type:"confirm",name:"confirm",message:`Are you sure you want to delete app ${i}?`,default:!1}]);if(!e){n.info("Deletion cancelled");return}let t=await q();c.start("Deleting app..."),await t.conversation.app.delete({app_id:i}),c.succeed("App deleted successfully")}catch(e){c.stop(),n.error(`Failed to delete app: ${e.message}`),process.exit(1)}});Ur.exports=It});var Jr=T((Ip,Vr)=>{"use strict";var qr=require("commander"),fi=y(require("inquirer"));A();E();x();st();var $t=new qr.Command("webhooks");$t.description("Manage webhooks for Conversation apps");$t.command("list").description("List webhooks for a Conversation app").option("-a, --app <app-id>","Conversation App ID").option("--json","Output result as JSON").action(async i=>{try{let e=bt(i.app),t=await q();c.start("Fetching webhooks...");let o=await t.conversation.webhooks.list({app_id:e});c.succeed(`Retrieved ${o.webhooks?.length||0} webhooks`),i.json?console.log(JSON.stringify(o,null,2)):(n.newline(),o.webhooks&&o.webhooks.length>0?o.webhooks.forEach(r=>{n.info(`[${r.id}]`),n.info(` URL: ${r.target}`),n.info(` Triggers: ${r.triggers?.join(", ")||"N/A"}`),n.info(` Secret: ${r.secret?"********":"Not set"}`),n.newline()}):n.info("No webhooks found for this app"))}catch(e){c.stop(),n.error(`Failed to list webhooks: ${e.message}`),process.exit(1)}});$t.command("create").description("Create a new webhook for a Conversation app").option("-a, --app <app-id>","Conversation App ID").option("-u, --url <url>","Webhook URL").option("-t, --triggers <triggers>","Comma-separated list of triggers (e.g., MESSAGE_INBOUND,MESSAGE_DELIVERY)").option("-s, --secret <secret>","Webhook secret for signature validation").option("--json","Output result as JSON").action(async i=>{try{await f.load(),await f.hasCredentials()||(n.error('Not authenticated. Run "sinch auth login" first.'),process.exit(1));let t=i.app;if(!t){let a=f.get("conversation-app-id");a&&(t=a,n.info(`Using default app: ${t}`))}if(!t||!i.url||!i.triggers){let a=await fi.default.prompt([{type:"input",name:"appId",message:"Enter Conversation App ID:",when:!t,validate:l=>l?!0:"App ID is required"},{type:"input",name:"url",message:"Enter webhook URL:",when:!i.url,validate:l=>{if(!l)return"URL is required";try{return new URL(l),!0}catch{return"Please enter a valid URL"}}},{type:"checkbox",name:"triggers",message:"Select webhook triggers:",when:!i.triggers,choices:["MESSAGE_INBOUND","MESSAGE_DELIVERY","MESSAGE_SUBMIT","EVENT_INBOUND","CONVERSATION_START","CONVERSATION_STOP","CONTACT_CREATE","CONTACT_DELETE","CONTACT_MERGE","CONTACT_UPDATE"],validate:l=>l.length>0?!0:"Select at least one trigger"},{type:"input",name:"secret",message:"Enter webhook secret (optional, press enter to skip):"}]);t=t||a.appId,i.url=i.url||a.url,i.triggers=i.triggers||a.triggers.join(","),i.secret=i.secret||a.secret}let o=await q(),r=i.triggers.split(",").map(a=>a.trim());c.start("Creating webhook...");let s=await o.conversation.webhooks.create({app_id:t,target:i.url,triggers:r,...i.secret&&{secret:i.secret}});c.succeed("Webhook created successfully!"),i.json?console.log(JSON.stringify(s,null,2)):(n.newline(),n.info(`Webhook ID: ${s.id}`),n.info(`URL: ${s.target}`),n.info(`Triggers: ${s.triggers?.join(", ")}`),i.secret&&n.info("Secret: ********"))}catch(e){c.stop(),n.error(`Failed to create webhook: ${e.message}`),process.exit(1)}});$t.command("update").description("Update a webhook").argument("<webhook-id>","Webhook ID to update").option("-u, --url <url>","New webhook URL").option("-t, --triggers <triggers>","New comma-separated list of triggers").option("-s, --secret <secret>","New webhook secret").option("--json","Output result as JSON").action(async(i,e)=>{try{!e.url&&!e.triggers&&!e.secret&&(n.error("At least one update field is required (--url, --triggers, or --secret)"),process.exit(1));let t=await q(),o={};e.url&&(o.target=e.url),e.triggers&&(o.triggers=e.triggers.split(",").map(s=>s.trim())),e.secret&&(o.secret=e.secret),c.start("Updating webhook...");let r=await t.conversation.webhooks.update({webhook_id:i,...o});c.succeed("Webhook updated successfully!"),e.json?console.log(JSON.stringify(r,null,2)):(n.newline(),n.info(`Webhook ID: ${r.id}`),n.info(`URL: ${r.target}`),n.info(`Triggers: ${r.triggers?.join(", ")}`))}catch(t){c.stop(),n.error(`Failed to update webhook: ${t.message}`),process.exit(1)}});$t.command("delete").description("Delete a webhook").argument("<webhook-id>","Webhook ID to delete").action(async i=>{try{let{confirm:e}=await fi.default.prompt([{type:"confirm",name:"confirm",message:`Are you sure you want to delete webhook ${i}?`,default:!1}]);if(!e){n.info("Deletion cancelled");return}let t=await q();c.start("Deleting webhook..."),await t.conversation.webhooks.delete({webhook_id:i}),c.succeed("Webhook deleted successfully")}catch(e){c.stop(),n.error(`Failed to delete webhook: ${e.message}`),process.exit(1)}});Vr.exports=$t});var Hr=T(($p,Kr)=>{"use strict";var Br=require("commander"),yc=Ar(),wc=xr(),Cc=Or(),vc=Lr(),bc=Mr(),Sc=Jr(),He=new Br.Command("conversation");He.description("Manage Sinch Conversations API");He.addCommand(yc);He.addCommand(wc);He.addCommand(Cc);He.addCommand(vc);He.addCommand(bc);He.addCommand(Sc);Kr.exports=He});var mi,yn,Wr,oe,We=W(()=>{"use strict";mi=y(require("axios")),yn=y(require("axios-retry")),Wr=y(require("chalk"));pt();jt();oe=class{baseUrl="https://elastic-trunking.api.sinch.com";projectId;credentials;client;timeout=6e4;constructor(e){this.projectId=e.projectId,this.credentials=e.credentials,this.client=mi.default.create({baseURL:this.baseUrl,timeout:this.timeout,headers:{"Content-Type":"application/json","User-Agent":"sinch-functions-cli/1.0.0"}}),(0,yn.default)(this.client,{retries:3,retryDelay:(t,o)=>{let r=o.response?.headers?.["retry-after"];return r?parseInt(r,10)*1e3:yn.default.exponentialDelay(t)},retryCondition:t=>{if(yn.default.isNetworkError(t))return!0;let o=t.response?.status;return!!(o&&o>=500||o===429)},onRetry:(t,o)=>{ue(1,`Retry ${t}/3: ${o.message}`)}}),this.client.interceptors.request.use(async t=>{let o=await this.getAuthHeader();return o&&(t.headers.Authorization=o),se()>=2&&ue(2,`\u2192 ${t.method?.toUpperCase()} ${t.url}`),t},t=>Promise.reject(t)),this.client.interceptors.response.use(t=>(se()>=2&&ue(2,`\u2190 ${t.status} ${t.config.url}`),t),t=>(se()>=2&&ue(2,`\u2190 ${t.response?.status||"ERROR"} ${t.config?.url}`),Promise.reject(t)))}async getAuthHeader(){try{let e=await this.credentials.retrieve();return e&&e.keyId&&e.keySecret?`Basic ${Buffer.from(`${e.keyId}:${e.keySecret}`).toString("base64")}`:null}catch{return console.error(Wr.default.yellow("Failed to get authentication credentials")),null}}async listTrunks(e={}){try{let t={};return e.page&&(t.pageToken=e.page),e.pageSize&&(t.pageSize=e.pageSize),(await this.client.get(`/v1/projects/${this.projectId}/trunks`,{params:t})).data}catch(t){throw this.handleError(t,"Failed to list SIP trunks")}}async getTrunk(e){try{return(await this.client.get(`/v1/projects/${this.projectId}/trunks/${e}`)).data}catch(t){throw this.handleError(t,`Failed to get SIP trunk ${e}`)}}async createTrunk(e){try{return(await this.client.post(`/v1/projects/${this.projectId}/trunks`,e)).data}catch(t){throw this.handleError(t,"Failed to create SIP trunk")}}async updateTrunk(e,t){try{return(await this.client.put(`/v1/projects/${this.projectId}/trunks/${e}`,t)).data}catch(o){throw this.handleError(o,`Failed to update SIP trunk ${e}`)}}async deleteTrunk(e){try{await this.client.delete(`/v1/projects/${this.projectId}/trunks/${e}`)}catch(t){throw this.handleError(t,`Failed to delete SIP trunk ${e}`)}}async listEndpoints(e,t={}){try{let o={};return t.page&&(o.pageToken=t.page),t.pageSize&&(o.pageSize=t.pageSize),(await this.client.get(`/v1/projects/${this.projectId}/trunks/${e}/endpoints`,{params:o})).data}catch(o){throw this.handleError(o,`Failed to list endpoints for trunk ${e}`)}}async getEndpoint(e,t){try{return(await this.client.get(`/v1/projects/${this.projectId}/trunks/${e}/endpoints/${t}`)).data}catch(o){throw this.handleError(o,`Failed to get endpoint ${t}`)}}async createEndpoint(e,t){try{return(await this.client.post(`/v1/projects/${this.projectId}/trunks/${e}/endpoints`,t)).data}catch(o){throw this.handleError(o,"Failed to create SIP endpoint")}}async updateEndpoint(e,t,o){try{return(await this.client.put(`/v1/projects/${this.projectId}/trunks/${e}/endpoints/${t}`,o)).data}catch(r){throw this.handleError(r,`Failed to update endpoint ${t}`)}}async deleteEndpoint(e,t){try{await this.client.delete(`/v1/projects/${this.projectId}/trunks/${e}/endpoints/${t}`)}catch(o){throw this.handleError(o,`Failed to delete endpoint ${t}`)}}async listAcls(e={}){try{let t={};return e.page&&(t.pageToken=e.page),e.pageSize&&(t.pageSize=e.pageSize),(await this.client.get(`/v1/projects/${this.projectId}/accessControlLists`,{params:t})).data}catch(t){throw this.handleError(t,"Failed to list ACLs")}}async getAcl(e){try{return(await this.client.get(`/v1/projects/${this.projectId}/accessControlLists/${e}`)).data}catch(t){throw this.handleError(t,`Failed to get ACL ${e}`)}}async createAcl(e){try{return(await this.client.post(`/v1/projects/${this.projectId}/accessControlLists`,e)).data}catch(t){throw this.handleError(t,"Failed to create ACL")}}async updateAcl(e,t){try{return(await this.client.put(`/v1/projects/${this.projectId}/accessControlLists/${e}`,t)).data}catch(o){throw this.handleError(o,`Failed to update ACL ${e}`)}}async deleteAcl(e){try{await this.client.delete(`/v1/projects/${this.projectId}/accessControlLists/${e}`)}catch(t){throw this.handleError(t,`Failed to delete ACL ${e}`)}}async getAclTrunks(e,t={}){try{let o={};return t.page&&(o.pageToken=t.page),t.pageSize&&(o.pageSize=t.pageSize),(await this.client.get(`/v1/projects/${this.projectId}/accessControlLists/${e}/trunks`,{params:o})).data}catch(o){throw this.handleError(o,`Failed to get trunks for ACL ${e}`)}}async listIpRanges(e,t={}){try{let o={};return t.page&&(o.pageToken=t.page),t.pageSize&&(o.pageSize=t.pageSize),(await this.client.get(`/v1/projects/${this.projectId}/accessControlLists/${e}/ipRanges`,{params:o})).data}catch(o){throw this.handleError(o,`Failed to list IP ranges for ACL ${e}`)}}async getIpRange(e,t){try{return(await this.client.get(`/v1/projects/${this.projectId}/accessControlLists/${e}/ipRanges/${t}`)).data}catch(o){throw this.handleError(o,`Failed to get IP range ${t}`)}}async addIpRange(e,t){try{return(await this.client.post(`/v1/projects/${this.projectId}/accessControlLists/${e}/ipRanges`,t)).data}catch(o){throw this.handleError(o,`Failed to add IP range to ACL ${e}`)}}async updateIpRange(e,t,o){try{return(await this.client.put(`/v1/projects/${this.projectId}/accessControlLists/${e}/ipRanges/${t}`,o)).data}catch(r){throw this.handleError(r,`Failed to update IP range ${t}`)}}async deleteIpRange(e,t){try{await this.client.delete(`/v1/projects/${this.projectId}/accessControlLists/${e}/ipRanges/${t}`)}catch(o){throw this.handleError(o,`Failed to delete IP range ${t}`)}}async listCountryPermissions(e={}){try{let t={};return e.page&&(t.pageToken=e.page),e.pageSize&&(t.pageSize=e.pageSize),(await this.client.get(`/v1/projects/${this.projectId}/countryPermissions`,{params:t})).data}catch(t){throw this.handleError(t,"Failed to list country permissions")}}async getCountryPermission(e){try{return(await this.client.get(`/v1/projects/${this.projectId}/countryPermissions/${e}`)).data}catch(t){throw this.handleError(t,`Failed to get country permission for ${e}`)}}async updateCountryPermission(e,t){try{return(await this.client.put(`/v1/projects/${this.projectId}/countryPermissions/${e}`,{enabled:t})).data}catch(o){throw this.handleError(o,`Failed to update country permission for ${e}`)}}async listTrunkAcls(e,t={}){try{let o={};return t.page&&(o.pageToken=t.page),t.pageSize&&(o.pageSize=t.pageSize),(await this.client.get(`/v1/projects/${this.projectId}/trunks/${e}/accessControlLists`,{params:o})).data}catch(o){throw this.handleError(o,`Failed to list ACLs for trunk ${e}`)}}async addTrunkAcl(e,t){try{await this.client.post(`/v1/projects/${this.projectId}/trunks/${e}/accessControlLists`,{accessControlListId:t})}catch(o){throw this.handleError(o,`Failed to add ACL ${t} to trunk ${e}`)}}async removeTrunkAcl(e,t){try{await this.client.delete(`/v1/projects/${this.projectId}/trunks/${e}/accessControlLists/${t}`)}catch(o){throw this.handleError(o,`Failed to remove ACL ${t} from trunk ${e}`)}}async getCredentialListTrunks(e,t={}){try{let o={};return t.page&&(o.pageNumber=t.page),t.pageSize&&(o.pageSize=t.pageSize),(await this.client.get(`/v1/projects/${this.projectId}/credentialLists/${e}/trunks`,{params:o})).data}catch(o){throw this.handleError(o,`Failed to get trunks for credential list ${e}`)}}async updateTrunkCredentialLists(e,t){try{return(await this.client.put(`/v1/projects/${this.projectId}/trunks/${e}/credentialLists`,{credentialListIds:t})).data}catch(o){throw this.handleError(o,`Failed to update credential lists for trunk ${e}`)}}async findCalls(e={}){try{let t={};return e.from&&(t.from=e.from),e.to&&(t.to=e.to),e.trunkId&&(t.trunkId=e.trunkId),e.createTime&&(t.createTime=e.createTime),e.callResult&&(t.callResult=e.callResult),e.direction&&(t.direction=e.direction),e.page&&(t.pageNumber=e.page),e.pageSize&&(t.pageSize=e.pageSize),(await this.client.get(`/v1/projects/${this.projectId}/calls`,{params:t})).data}catch(t){throw this.handleError(t,"Failed to find calls")}}async getCall(e){try{return(await this.client.get(`/v1/projects/${this.projectId}/calls/${e}`)).data}catch(t){throw this.handleError(t,`Failed to get call ${e}`)}}handleError(e,t){if(mi.default.isAxiosError(e)){let o=e;if(o.response){let r=o.response.status,s=o.response.data,a=s?.message||s?.error||o.message;throw r===401?new D('Authentication required. Please run "sinch auth login" first.',$.AUTH_REQUIRED):r===403?new D(`Permission denied: ${a}`,$.NO_PERMISSION):r===404?new D(`Resource not found: ${a}`,$.NOT_FOUND):r===429?new D(`Rate limited: ${a}`,$.UNAVAILABLE):r>=500?new D(`Server error: ${a}`,$.UNAVAILABLE):new D(`${t}: ${a}`,$.FAILURE)}else throw o.request?o.code==="ECONNREFUSED"?new D(`Cannot connect to EST API at ${this.baseUrl}`,$.UNAVAILABLE):o.code==="ETIMEDOUT"?new D(`Request timeout after ${this.timeout}ms`,$.TIMEOUT):new D(`${t}: No response from server (${o.code||"unknown error"})`,$.IO_ERROR):new D(`${t}: ${o.message}`,$.FAILURE)}else throw new D(`${t}: ${e.message||e}`,$.FAILURE)}}});var Gr=T((jp,zr)=>{"use strict";var wn=require("commander"),Ne=y(require("inquirer"));E();x();A();We();async function Oe(){await f.load(),await f.hasCredentials()||(n.error('Not authenticated. Run "sinch auth login" first.'),process.exit(1));let e=f.getApiConfig();return new oe({projectId:e.projectId,credentials:e.credentials})}function gi(i){n.info(`ID: ${i.id}`),n.info(`Name: ${i.name}`),i.hostName&&n.info(`Host: ${i.hostName}`),n.info(`Caller ID: ${i.enableCallerId?"enabled":"disabled"}`),i.createTime&&n.info(`Created: ${new Date(i.createTime).toLocaleString()}`),i.updateTime&&n.info(`Updated: ${new Date(i.updateTime).toLocaleString()}`)}var je=new wn.Command("trunks");je.description("Manage SIP trunks");je.command("list").description("List all SIP trunks").option("-l, --limit <number>","Limit number of results",parseInt,50).option("--json","Output result as JSON").action(async i=>{try{let e=await Oe();c.start("Fetching SIP trunks...");let t=await e.listTrunks({pageSize:i.limit});c.succeed(`Retrieved ${t.trunks?.length||0} trunk(s)`),i.json?console.log(JSON.stringify(t,null,2)):(n.newline(),t.trunks&&t.trunks.length>0?t.trunks.forEach(o=>{n.info(`[${o.id}] ${o.name}`),o.hostName&&n.info(` Host: ${o.hostName}`),n.info(` Caller ID: ${o.enableCallerId?"enabled":"disabled"}`),n.newline()}):(n.info("No SIP trunks found"),n.newline(),n.info("Create one with: sinch sip trunks create")))}catch(e){c.stop(),n.error(`Failed to list trunks: ${e.message}`),process.exit(1)}});je.command("get").description("Get a SIP trunk by ID").argument("<trunk-id>","Trunk ID to retrieve").option("--json","Output result as JSON").action(async(i,e)=>{try{let t=await Oe();c.start("Fetching trunk...");let o=await t.getTrunk(i);c.succeed("Trunk retrieved"),e.json?console.log(JSON.stringify(o,null,2)):(n.newline(),gi(o))}catch(t){c.stop(),n.error(`Failed to get trunk: ${t.message}`),process.exit(1)}});je.command("create").description("Create a new SIP trunk").option("-n, --name <name>","Trunk name (required)").option("-h, --host-name <hostname>","Host name for the trunk (required)").option("--caller-id","Enable caller ID").option("--non-interactive","Skip prompts, use defaults for missing options").option("--json","Output result as JSON").action(async i=>{try{let e=i.name,t=i.hostName,o=i.callerId??!1,r=!i.nonInteractive;e||(r?e=(await Ne.default.prompt([{type:"input",name:"name",message:"Enter trunk name:",validate:p=>p?!0:"Trunk name is required"}])).name:(n.error("Name is required. Use --name <name>"),process.exit(1))),t||(r?t=(await Ne.default.prompt([{type:"input",name:"hostName",message:"Enter host name:",validate:p=>p?!0:"Host name is required"}])).hostName:(n.error("Host name is required. Use --host-name <hostname>"),process.exit(1))),i.callerId===void 0&&r&&(o=(await Ne.default.prompt([{type:"confirm",name:"enableCallerId",message:"Enable caller ID?",default:!1}])).enableCallerId);let s=await Oe();c.start("Creating SIP trunk...");let a=await s.createTrunk({name:e,hostName:t,enableCallerId:o});c.succeed("SIP trunk created successfully!"),i.json?console.log(JSON.stringify(a,null,2)):(n.newline(),gi(a),n.newline(),n.info(`Add an endpoint: sinch sip endpoints create ${a.id}`))}catch(e){c.stop(),n.error(`Failed to create trunk: ${e.message}`),process.exit(1)}});je.command("update").description("Update a SIP trunk").argument("<trunk-id>","Trunk ID to update").option("-n, --name <name>","New trunk name").option("-h, --host-name <hostname>","New host name").option("--caller-id","Enable caller ID").option("--no-caller-id","Disable caller ID").option("--non-interactive","Skip prompts, use current values for missing options").option("--json","Output result as JSON").action(async(i,e)=>{try{let t=await Oe();c.start("Fetching current trunk details...");let o=await t.getTrunk(i);c.stop();let r=e.name,s=e.hostName,a=e.callerId,l=!e.nonInteractive;r||(l?r=(await Ne.default.prompt([{type:"input",name:"name",message:"Enter trunk name:",default:o.name,validate:u=>u?!0:"Trunk name is required"}])).name:r=o.name),s===void 0&&(l?s=(await Ne.default.prompt([{type:"input",name:"hostName",message:"Enter host name:",default:o.hostName||""}])).hostName||void 0:s=o.hostName),a===void 0&&(l?a=(await Ne.default.prompt([{type:"confirm",name:"enableCallerId",message:"Enable caller ID?",default:o.enableCallerId??!1}])).enableCallerId:a=o.enableCallerId),c.start("Updating SIP trunk...");let p=await t.updateTrunk(i,{name:r,hostName:s,enableCallerId:a});c.succeed("SIP trunk updated successfully!"),e.json?console.log(JSON.stringify(p,null,2)):(n.newline(),gi(p))}catch(t){c.stop(),n.error(`Failed to update trunk: ${t.message}`),process.exit(1)}});je.command("delete").description("Delete a SIP trunk").argument("<trunk-id>","Trunk ID to delete").option("-f, --force","Skip confirmation prompt").action(async(i,e)=>{try{if(!e.force){let{confirm:o}=await Ne.default.prompt([{type:"confirm",name:"confirm",message:`Are you sure you want to delete trunk ${i}?`,default:!1}]);if(!o){n.info("Deletion cancelled");return}}let t=await Oe();c.start("Deleting SIP trunk..."),await t.deleteTrunk(i),c.succeed("SIP trunk deleted successfully")}catch(t){c.stop(),n.error(`Failed to delete trunk: ${t.message}`),process.exit(1)}});var Yt=new wn.Command("acls");Yt.description("Manage ACLs for a trunk");Yt.command("list").description("List ACLs associated with a trunk").argument("<trunk-id>","Trunk ID").option("-l, --limit <number>","Limit number of results",parseInt,50).option("--json","Output result as JSON").action(async(i,e)=>{try{let t=await Oe();c.start("Fetching trunk ACLs...");let o=await t.listTrunkAcls(i,{pageSize:e.limit});c.succeed(`Retrieved ${o.accessControlLists?.length||0} ACL(s)`),e.json?console.log(JSON.stringify(o,null,2)):(n.newline(),o.accessControlLists&&o.accessControlLists.length>0?o.accessControlLists.forEach(r=>{let s=r.enabled!==!1?"":" (disabled)";n.info(`[${r.id}] ${r.name}${s}`),n.newline()}):(n.info("No ACLs associated with this trunk"),n.newline(),n.info(`Add an ACL: sinch sip trunks acls add ${i} <acl-id>`)))}catch(t){c.stop(),n.error(`Failed to list trunk ACLs: ${t.message}`),process.exit(1)}});Yt.command("add").description("Add an ACL to a trunk").argument("<trunk-id>","Trunk ID").argument("<acl-id>","ACL ID to add").option("--json","Output result as JSON").action(async(i,e,t)=>{try{let o=await Oe();c.start(`Adding ACL ${e} to trunk ${i}...`),await o.addTrunkAcl(i,e),c.succeed("ACL added to trunk successfully"),t.json||(n.newline(),n.info(`ACL ${e} is now associated with trunk ${i}`))}catch(o){c.stop(),n.error(`Failed to add ACL to trunk: ${o.message}`),process.exit(1)}});Yt.command("remove").description("Remove an ACL from a trunk").argument("<trunk-id>","Trunk ID").argument("<acl-id>","ACL ID to remove").option("-f, --force","Skip confirmation prompt").action(async(i,e,t)=>{try{if(!t.force){let{confirm:r}=await Ne.default.prompt([{type:"confirm",name:"confirm",message:`Remove ACL ${e} from trunk ${i}?`,default:!1}]);if(!r){n.info("Operation cancelled");return}}let o=await Oe();c.start("Removing ACL from trunk..."),await o.removeTrunkAcl(i,e),c.succeed("ACL removed from trunk successfully")}catch(o){c.stop(),n.error(`Failed to remove ACL from trunk: ${o.message}`),process.exit(1)}});je.addCommand(Yt);var hi=new wn.Command("credential-lists");hi.description("Manage credential lists for a trunk");hi.command("update").description("Bulk update credential lists for a trunk").argument("<trunk-id>","Trunk ID").argument("<credential-list-ids...>","Credential list IDs to assign (space-separated)").option("--json","Output result as JSON").action(async(i,e,t)=>{try{let o=await Oe();c.start(`Updating credential lists for trunk ${i}...`);let r=await o.updateTrunkCredentialLists(i,e);if(c.succeed("Credential lists updated successfully"),t.json)console.log(JSON.stringify(r,null,2));else{n.newline();let s=r?.credentialListIds??[];n.info(`Trunk ${i} now uses ${s.length} credential list(s):`),s.forEach(a=>{n.info(` - ${a}`)})}}catch(o){c.stop(),n.error(`Failed to update credential lists: ${o.message}`),process.exit(1)}});je.addCommand(hi);zr.exports=je});var Zr=T((qp,Xr)=>{"use strict";var Yr=require("commander"),ke=y(require("inquirer"));E();x();A();We();async function Xt(){await f.load(),await f.hasCredentials()||(n.error('Not authenticated. Run "sinch auth login" first.'),process.exit(1));let e=f.getApiConfig();return new oe({projectId:e.projectId,credentials:e.credentials})}async function yi(i,e){c.start("Looking up endpoint...");let o=(await i.listTrunks()).trunks||[];for(let r of o)if(((await i.listEndpoints(r.id)).endpoints||[]).find(p=>p.id===e))return c.stop(),r.id;throw c.stop(),new Error(`Endpoint ${e} not found`)}function wi(i){if(n.info(`ID: ${i.id}`),n.info(`Name: ${i.name}`),i.address){let e=i.port?`${i.address}:${i.port}`:i.address;n.info(`Address: ${e}`)}i.transport&&n.info(`Transport: ${i.transport}`),n.info(`Priority: ${i.priority}`),n.info(`Enabled: ${i.enabled!==!1?"yes":"no"}`),i.createTime&&n.info(`Created: ${new Date(i.createTime).toLocaleString()}`),i.updateTime&&n.info(`Updated: ${new Date(i.updateTime).toLocaleString()}`)}var at=new Yr.Command("endpoints");at.description("Manage SIP endpoints");at.command("list").description("List all SIP endpoints for a trunk").argument("<trunk-id>","Trunk ID").option("-l, --limit <number>","Limit number of results",parseInt,50).option("--json","Output result as JSON").action(async(i,e)=>{try{let t=await Xt();c.start("Fetching SIP endpoints...");let o=await t.listEndpoints(i,{pageSize:e.limit});c.succeed(`Retrieved ${o.endpoints?.length||0} endpoint(s)`),e.json?console.log(JSON.stringify(o,null,2)):(n.newline(),o.endpoints&&o.endpoints.length>0?o.endpoints.forEach(r=>{let s=r.enabled!==!1?"":" (disabled)",a=r.port?`${r.address}:${r.port}`:r.address;n.info(`[${r.id}] ${r.name}${s}`),n.info(` Address: ${a||"N/A"}`),n.info(` Priority: ${r.priority}, Transport: ${r.transport||"UDP"}`),n.newline()}):(n.info("No endpoints found for this trunk"),n.newline(),n.info(`Create one with: sinch sip endpoints create ${i}`)))}catch(t){c.stop(),n.error(`Failed to list endpoints: ${t.message}`),process.exit(1)}});at.command("get").description("Get a SIP endpoint by ID").argument("<endpoint-id>","Endpoint ID to retrieve").option("--json","Output result as JSON").action(async(i,e)=>{try{let t=await Xt(),o=await yi(t,i);c.start("Fetching endpoint...");let r=await t.getEndpoint(o,i);c.succeed("Endpoint retrieved"),e.json?console.log(JSON.stringify(r,null,2)):(n.newline(),wi(r))}catch(t){c.stop(),n.error(`Failed to get endpoint: ${t.message}`),process.exit(1)}});at.command("create").description("Create a new SIP endpoint").argument("<trunk-id>","Trunk ID to add endpoint to").option("-n, --name <name>","Endpoint name (required)").option("-a, --address <address>","SIP address (IP or hostname, without port)").option("--port <number>","SIP port (default: 5060)",parseInt).option("-t, --transport <transport>","Transport protocol: UDP, TCP, or TLS (default: UDP)").option("-p, --priority <number>","Priority (required, lower = higher priority)",parseInt).option("--non-interactive","Skip prompts, use defaults for missing options").option("--json","Output result as JSON").action(async(i,e)=>{try{let t=e.name,o=e.address,r=e.port,s=e.transport,a=e.priority,l=!e.nonInteractive;t||(l?t=(await ke.default.prompt([{type:"input",name:"name",message:"Enter endpoint name:",validate:m=>m?!0:"Endpoint name is required"}])).name:(n.error("Name is required. Use --name <name>"),process.exit(1))),o||(l?o=(await ke.default.prompt([{type:"input",name:"address",message:"Enter SIP address (IP or hostname):",validate:m=>m?!0:"SIP address is required"}])).address:(n.error("Address is required. Use --address <address>"),process.exit(1))),r===void 0&&l&&(r=(await ke.default.prompt([{type:"input",name:"port",message:"Enter SIP port (default 5060):",default:"5060",filter:m=>m?parseInt(m,10):5060}])).port),a===void 0&&(l?a=(await ke.default.prompt([{type:"input",name:"priority",message:"Enter priority (lower = higher priority):",default:"1",filter:m=>parseInt(m,10),validate:m=>{let w=parseInt(m,10);return isNaN(w)?"Please enter a valid number":!0}}])).priority:(n.error("Priority is required. Use --priority <number>"),process.exit(1)));let p=await Xt();c.start("Creating SIP endpoint...");let d=await p.createEndpoint(i,{name:t,address:o,port:r,transport:s,priority:a});c.succeed("SIP endpoint created successfully!"),e.json?console.log(JSON.stringify(d,null,2)):(n.newline(),wi(d))}catch(t){c.stop(),n.error(`Failed to create endpoint: ${t.message}`),process.exit(1)}});at.command("update").description("Update a SIP endpoint").argument("<endpoint-id>","Endpoint ID to update").option("-n, --name <name>","New endpoint name").option("-a, --address <address>","New SIP address").option("--port <number>","New SIP port",parseInt).option("-t, --transport <transport>","Transport protocol: UDP, TCP, or TLS").option("-p, --priority <number>","New priority",parseInt).option("--non-interactive","Skip prompts, use current values for missing options").option("--json","Output result as JSON").action(async(i,e)=>{try{let t=await Xt(),o=await yi(t,i);c.start("Fetching current endpoint details...");let r=await t.getEndpoint(o,i);c.stop();let s=e.name,a=e.address,l=e.port,p=e.transport,d=e.priority,u=!e.nonInteractive;s||(u?s=(await ke.default.prompt([{type:"input",name:"name",message:"Enter endpoint name:",default:r.name,validate:h=>h?!0:"Name is required"}])).name:s=r.name),a||(u?a=(await ke.default.prompt([{type:"input",name:"address",message:"Enter SIP address:",default:r.address,validate:h=>h?!0:"SIP address is required"}])).address:a=r.address||""),l===void 0&&(u?l=(await ke.default.prompt([{type:"input",name:"port",message:"Enter SIP port:",default:(r.port||5060).toString(),filter:h=>parseInt(h,10)}])).port:l=r.port),d===void 0&&(u?d=(await ke.default.prompt([{type:"input",name:"priority",message:"Enter priority:",default:r.priority.toString(),filter:h=>parseInt(h,10)}])).priority:d=r.priority),c.start("Updating SIP endpoint...");let m=await t.updateEndpoint(o,i,{name:s,address:a,port:l,transport:p,priority:d});c.succeed("SIP endpoint updated successfully!"),e.json?console.log(JSON.stringify(m,null,2)):(n.newline(),wi(m))}catch(t){c.stop(),n.error(`Failed to update endpoint: ${t.message}`),process.exit(1)}});at.command("delete").description("Delete a SIP endpoint").argument("<endpoint-id>","Endpoint ID to delete").option("-f, --force","Skip confirmation prompt").action(async(i,e)=>{try{let t=await Xt(),o=await yi(t,i);if(!e.force){let{confirm:r}=await ke.default.prompt([{type:"confirm",name:"confirm",message:`Are you sure you want to delete endpoint ${i}?`,default:!1}]);if(!r){n.info("Deletion cancelled");return}}c.start("Deleting SIP endpoint..."),await t.deleteEndpoint(o,i),c.succeed("SIP endpoint deleted successfully")}catch(t){c.stop(),n.error(`Failed to delete endpoint: ${t.message}`),process.exit(1)}});Xr.exports=at});var ts=T((zp,es)=>{"use strict";var Ci=require("commander"),Y=y(require("inquirer"));E();x();A();We();async function Ae(){await f.load(),await f.hasCredentials()||(n.error('Not authenticated. Run "sinch auth login" first.'),process.exit(1));let e=f.getApiConfig();return new oe({projectId:e.projectId,credentials:e.credentials})}function vi(i){n.info(`ID: ${i.id}`),n.info(`Name: ${i.name}`),n.info(`Enabled: ${i.enabled!==!1?"yes":"no"}`),i.createTime&&n.info(`Created: ${new Date(i.createTime).toLocaleString()}`),i.updateTime&&n.info(`Updated: ${new Date(i.updateTime).toLocaleString()}`)}function Qr(i){n.info(`ID: ${i.id}`),i.description&&n.info(`Description: ${i.description}`),i.ipAddress&&n.info(`IP Address: ${i.ipAddress}`),i.range&&n.info(`CIDR Range: ${i.range}`),i.createTime&&n.info(`Created: ${new Date(i.createTime).toLocaleString()}`)}function ct(i){return/^(\d{1,3}\.){3}\d{1,3}$/.test(i)?i.split(".").every(o=>{let r=parseInt(o,10);return r>=0&&r<=255}):!1}function Cn(i){if(!/^(\d{1,3}\.){3}\d{1,3}\/\d{1,2}$/.test(i))return!1;let t=i.split("/");if(t.length!==2)return!1;let o=t[0],r=t[1];if(!o||!r)return!1;let s=parseInt(r,10);return ct(o)&&s>=0&&s<=32}var Fe=new Ci.Command("acls");Fe.description("Manage Access Control Lists (ACLs)");Fe.command("list").description("List all Access Control Lists").option("-l, --limit <number>","Limit number of results",parseInt,50).option("--json","Output result as JSON").action(async i=>{try{let e=await Ae();c.start("Fetching ACLs...");let t=await e.listAcls({pageSize:i.limit});c.succeed(`Retrieved ${t.accessControlLists?.length||0} ACL(s)`),i.json?console.log(JSON.stringify(t,null,2)):(n.newline(),t.accessControlLists&&t.accessControlLists.length>0?t.accessControlLists.forEach(o=>{let r=o.enabled!==!1?"":" (disabled)";n.info(`[${o.id}] ${o.name}${r}`),n.newline()}):(n.info("No ACLs found"),n.newline(),n.info("Create one with: sinch sip acls create")))}catch(e){c.stop(),n.error(`Failed to list ACLs: ${e.message}`),process.exit(1)}});Fe.command("get").description("Get an ACL by ID").argument("<acl-id>","ACL ID to retrieve").option("--json","Output result as JSON").action(async(i,e)=>{try{let t=await Ae();c.start("Fetching ACL...");let o=await t.getAcl(i);c.succeed("ACL retrieved"),e.json?console.log(JSON.stringify(o,null,2)):(n.newline(),vi(o))}catch(t){c.stop(),n.error(`Failed to get ACL: ${t.message}`),process.exit(1)}});Fe.command("create").description("Create a new Access Control List").option("-n, --name <name>","ACL name (required)").option("--enabled","Enable the ACL (default: true)").option("--disabled","Create ACL in disabled state").option("-i, --ip <address>","IP address for initial IP range (required)").option("-r, --range <cidr>","CIDR mask for IP range (default: 32)",parseInt).option("--ip-description <text>","Description for the IP range").option("--non-interactive","Skip prompts, use defaults for missing options").option("--json","Output result as JSON").action(async i=>{try{let e=i.name,t=i.enabled??!i.disabled,o=i.ip,r=i.range,s=i.ipDescription,a=!i.nonInteractive;e||(a?e=(await Y.default.prompt([{type:"input",name:"name",message:"Enter ACL name:",validate:m=>m?!0:"ACL name is required"}])).name:(n.error("Name is required. Use --name <name>"),process.exit(1))),i.enabled===void 0&&!i.disabled&&a&&(t=(await Y.default.prompt([{type:"confirm",name:"enabled",message:"Enable ACL?",default:!0}])).enabled),o?ct(o)||(n.error(`Invalid IP address format: ${o}`),process.exit(1)):a?o=(await Y.default.prompt([{type:"input",name:"ipAddress",message:"Enter IP address for initial IP range (required):",validate:m=>m?ct(m)?!0:"Invalid IP address format":"At least one IP range is required to create an ACL"}])).ipAddress:(n.error("IP address is required. Use --ip <address>"),process.exit(1)),r===void 0&&a&&(r=(await Y.default.prompt([{type:"input",name:"range",message:"Enter CIDR mask (default 32):",default:"32",filter:m=>parseInt(m,10),validate:m=>{let w=parseInt(m,10);return!isNaN(w)&&w>=0&&w<=32?!0:"Please enter a number between 0 and 32"}}])).range),s===void 0&&a&&(s=(await Y.default.prompt([{type:"input",name:"description",message:"Enter IP range description (optional):"}])).description||void 0);let l=await Ae(),p={ipAddress:o};r!==void 0&&(p.range=r),s&&(p.description=s),c.start("Creating ACL...");let d=await l.createAcl({name:e,enabled:t,ipRanges:[p]});c.succeed("ACL created successfully!"),i.json?console.log(JSON.stringify(d,null,2)):(n.newline(),vi(d),n.newline(),n.info(`Add an IP range: sinch sip acls ip-ranges add ${d.id}`))}catch(e){c.stop(),n.error(`Failed to create ACL: ${e.message}`),process.exit(1)}});Fe.command("update").description("Update an ACL").argument("<acl-id>","ACL ID to update").option("-n, --name <name>","New ACL name").option("--enabled","Enable the ACL").option("--disabled","Disable the ACL").option("--non-interactive","Skip prompts, use current values for missing options").option("--json","Output result as JSON").action(async(i,e)=>{try{let t=await Ae();c.start("Fetching current ACL details...");let o=await t.getAcl(i);c.stop();let r=e.name,s;e.enabled?s=!0:e.disabled&&(s=!1);let a=!e.nonInteractive;r||(a?r=(await Y.default.prompt([{type:"input",name:"name",message:"Enter ACL name:",default:o.name,validate:d=>d?!0:"ACL name is required"}])).name:r=o.name),s===void 0&&(a?s=(await Y.default.prompt([{type:"confirm",name:"enabled",message:"Enable ACL?",default:o.enabled??!0}])).enabled:s=o.enabled),c.start("Updating ACL...");let l=await t.updateAcl(i,{name:r,enabled:s});c.succeed("ACL updated successfully!"),e.json?console.log(JSON.stringify(l,null,2)):(n.newline(),vi(l))}catch(t){c.stop(),n.error(`Failed to update ACL: ${t.message}`),process.exit(1)}});Fe.command("delete").description("Delete an ACL").argument("<acl-id>","ACL ID to delete").option("-f, --force","Skip confirmation prompt").action(async(i,e)=>{try{if(!e.force){let{confirm:o}=await Y.default.prompt([{type:"confirm",name:"confirm",message:`Are you sure you want to delete ACL ${i}?`,default:!1}]);if(!o){n.info("Deletion cancelled");return}}let t=await Ae();c.start("Deleting ACL..."),await t.deleteAcl(i),c.succeed("ACL deleted successfully")}catch(t){c.stop(),n.error(`Failed to delete ACL: ${t.message}`),process.exit(1)}});Fe.command("trunks").description("List trunks using an ACL").argument("<acl-id>","ACL ID").option("-l, --limit <number>","Limit number of results",parseInt,50).option("--json","Output result as JSON").action(async(i,e)=>{try{let t=await Ae();c.start("Fetching trunks...");let o=await t.getAclTrunks(i,{pageSize:e.limit});c.succeed(`Retrieved ${o.trunks?.length||0} trunk(s)`),e.json?console.log(JSON.stringify(o,null,2)):(n.newline(),o.trunks&&o.trunks.length>0?o.trunks.forEach(r=>{n.info(`[${r.id}] ${r.name}`),r.hostName&&n.info(` Host: ${r.hostName}`),n.newline()}):n.info("No trunks are using this ACL"))}catch(t){c.stop(),n.error(`Failed to list trunks: ${t.message}`),process.exit(1)}});var Pt=new Ci.Command("ip-ranges");Pt.description("Manage IP ranges for ACLs");Pt.command("list").description("List IP ranges for an ACL").argument("<acl-id>","ACL ID").option("-l, --limit <number>","Limit number of results",parseInt,50).option("--json","Output result as JSON").action(async(i,e)=>{try{let t=await Ae();c.start("Fetching IP ranges...");let o=await t.listIpRanges(i,{pageSize:e.limit});c.succeed(`Retrieved ${o.ipRanges?.length||0} IP range(s)`),e.json?console.log(JSON.stringify(o,null,2)):(n.newline(),o.ipRanges&&o.ipRanges.length>0?o.ipRanges.forEach(r=>{let s=r.range||r.ipAddress||"N/A";n.info(`[${r.id}] ${s}`),r.description&&n.info(` ${r.description}`),n.newline()}):(n.info("No IP ranges found for this ACL"),n.newline(),n.info(`Add one with: sinch sip acls ip-ranges add ${i}`)))}catch(t){c.stop(),n.error(`Failed to list IP ranges: ${t.message}`),process.exit(1)}});Pt.command("add").description("Add an IP range to an ACL").argument("<acl-id>","ACL ID").option("-d, --description <description>","Description for the IP range").option("-i, --ip <ip>","Single IP address (e.g., 192.168.1.1)").option("-r, --range <cidr>","CIDR range (e.g., 192.168.1.0/24)").option("--non-interactive","Skip prompts, use defaults for missing options").option("--json","Output result as JSON").action(async(i,e)=>{try{let t=e.description,o=e.ip,r=e.range,s=!e.nonInteractive;o&&r&&(n.error("Cannot specify both --ip and --range. Please provide only one."),process.exit(1)),!o&&!r&&(s?(await Y.default.prompt([{type:"list",name:"type",message:"What would you like to add?",choices:[{name:"Single IP address",value:"ip"},{name:"CIDR range",value:"range"}]}])).type==="ip"?o=(await Y.default.prompt([{type:"input",name:"ipAddress",message:"Enter IP address (e.g., 192.168.1.1):",validate:m=>m?ct(m)?!0:"Invalid IP address format":"IP address is required"}])).ipAddress:r=(await Y.default.prompt([{type:"input",name:"range",message:"Enter CIDR range (e.g., 192.168.1.0/24):",validate:m=>m?Cn(m)?!0:"Invalid CIDR format (e.g., 192.168.1.0/24)":"CIDR range is required"}])).range:(n.error("Either --ip or --range is required"),process.exit(1))),o&&!ct(o)&&(n.error(`Invalid IP address format: ${o}`),process.exit(1)),r&&!Cn(r)&&(n.error(`Invalid CIDR range format: ${r}. Expected format: 192.168.1.0/24`),process.exit(1)),!t&&s&&(t=(await Y.default.prompt([{type:"input",name:"description",message:"Enter description (optional):"}])).description||void 0);let a=await Ae();c.start("Adding IP range...");let l={description:t};o?l.ipAddress=o:r&&(l.range=r);let p=await a.addIpRange(i,l);c.succeed("IP range added successfully!"),e.json?console.log(JSON.stringify(p,null,2)):(n.newline(),Qr(p))}catch(t){c.stop(),n.error(`Failed to add IP range: ${t.message}`),process.exit(1)}});Pt.command("update").description("Update an IP range").argument("<acl-id>","ACL ID").argument("<ip-range-id>","IP range ID to update").option("-d, --description <description>","New description").option("-i, --ip <ip>","New single IP address").option("-r, --range <cidr>","New CIDR range").option("--non-interactive","Skip prompts, use current values for missing options").option("--json","Output result as JSON").action(async(i,e,t)=>{try{let o=await Ae();c.start("Fetching current IP range details...");let r;try{r=await o.getIpRange(i,e)}catch(m){c.stop(),n.error(`IP range ${e} not found in ACL ${i}: ${m.message}`),process.exit(1)}c.stop();let s=t.description,a=t.ip,l=t.range,p=!t.nonInteractive;if(a&&l&&(n.error("Cannot specify both --ip and --range. Please provide only one."),process.exit(1)),s===void 0&&p?s=(await Y.default.prompt([{type:"input",name:"description",message:"Enter description:",default:r.description||""}])).description||void 0:s===void 0&&(s=r.description),!a&&!l&&p){let m=r.range||r.ipAddress||"",w=r.range?"range":"ip";(await Y.default.prompt([{type:"list",name:"type",message:"Update as:",choices:[{name:"Single IP address",value:"ip"},{name:"CIDR range",value:"range"}],default:w}])).type==="ip"?(a=(await Y.default.prompt([{type:"input",name:"ipAddress",message:"Enter IP address:",default:w==="ip"?m:"",validate:v=>v?ct(v)?!0:"Invalid IP address format":"IP address is required"}])).ipAddress,l=void 0):(l=(await Y.default.prompt([{type:"input",name:"range",message:"Enter CIDR range:",default:w==="range"?m:"",validate:v=>v?Cn(v)?!0:"Invalid CIDR format":"CIDR range is required"}])).range,a=void 0)}else!a&&!l?(a=r.ipAddress,l=r.range):a?l=void 0:l&&(a=void 0);a&&!ct(a)&&(n.error(`Invalid IP address format: ${a}`),process.exit(1)),l&&!Cn(l)&&(n.error(`Invalid CIDR range format: ${l}`),process.exit(1)),c.start("Updating IP range...");let d={description:s};a?d.ipAddress=a:l&&(d.range=l);let u=await o.updateIpRange(i,e,d);c.succeed("IP range updated successfully!"),t.json?console.log(JSON.stringify(u,null,2)):(n.newline(),Qr(u))}catch(o){c.stop(),n.error(`Failed to update IP range: ${o.message}`),process.exit(1)}});Pt.command("delete").description("Delete an IP range").argument("<acl-id>","ACL ID").argument("<ip-range-id>","IP range ID to delete").option("-f, --force","Skip confirmation prompt").action(async(i,e,t)=>{try{if(!t.force){let{confirm:r}=await Y.default.prompt([{type:"confirm",name:"confirm",message:`Are you sure you want to delete IP range ${e}?`,default:!1}]);if(!r){n.info("Deletion cancelled");return}}let o=await Ae();c.start("Deleting IP range..."),await o.deleteIpRange(i,e),c.succeed("IP range deleted successfully")}catch(o){c.stop(),n.error(`Failed to delete IP range: ${o.message}`),process.exit(1)}});Fe.addCommand(Pt);es.exports=Fe});var os=T((eu,is)=>{"use strict";var ns=require("commander");E();x();A();We();async function vn(){await f.load(),await f.hasCredentials()||(n.error('Not authenticated. Run "sinch auth login" first.'),process.exit(1));let e=f.getApiConfig();return new oe({projectId:e.projectId,credentials:e.credentials})}function bi(i){n.info(`ISO Code: ${i.isoCode}`),n.info(`Country: ${i.name}`),n.info(`Continent: ${i.continent}`),n.info(`Dialing Codes: ${i.countryDialingCodes.join(", ")}`),n.info(`Status: ${i.enabled?"enabled":"disabled"}`)}var kt=new ns.Command("countries");kt.description("Manage country permissions for dialing");kt.command("list").description("List all country permissions").option("-l, --limit <number>","Limit number of results",parseInt,50).option("--json","Output result as JSON").action(async i=>{try{let e=await vn();c.start("Fetching country permissions...");let t=await e.listCountryPermissions({pageSize:i.limit});c.succeed(`Retrieved ${t.countryPermissions?.length||0} country permission(s)`),i.json?console.log(JSON.stringify(t,null,2)):(n.newline(),t.countryPermissions&&t.countryPermissions.length>0?([...t.countryPermissions].sort((r,s)=>r.isoCode.localeCompare(s.isoCode)).forEach(r=>{let s=r.enabled?"\u2713 enabled":"\u2717 disabled",a=r.name.padEnd(30);n.info(`${r.isoCode.padEnd(4)} ${a} ${s}`)}),n.newline(),n.info("Enable a country: sinch sip countries enable <iso-code>"),n.info("Disable a country: sinch sip countries disable <iso-code>")):n.info("No country permissions found"))}catch(e){c.stop(),n.error(`Failed to list country permissions: ${e.message}`),process.exit(1)}});kt.command("get").description("Get a specific country permission by ISO code").argument("<iso-code>","ISO country code (e.g., US, CA, *)").option("--json","Output result as JSON").action(async(i,e)=>{try{let t=await vn();c.start("Fetching country permission...");let o=await t.getCountryPermission(i.toUpperCase());c.succeed("Country permission retrieved"),e.json?console.log(JSON.stringify(o,null,2)):(n.newline(),bi(o))}catch(t){c.stop(),n.error(`Failed to get country permission: ${t.message}`),process.exit(1)}});kt.command("enable").description("Enable a country for dialing").argument("<iso-code>","ISO country code (e.g., US, CA, *)").option("--json","Output result as JSON").action(async(i,e)=>{try{let t=await vn();c.start(`Enabling country ${i.toUpperCase()}...`);let o=await t.updateCountryPermission(i.toUpperCase(),!0);c.succeed(`Country ${i.toUpperCase()} enabled for dialing`),e.json?console.log(JSON.stringify(o,null,2)):(n.newline(),bi(o),n.newline(),n.info(`Country ${i.toUpperCase()} is now enabled for dialing`))}catch(t){c.stop(),n.error(`Failed to enable country: ${t.message}`),process.exit(1)}});kt.command("disable").description("Disable a country for dialing").argument("<iso-code>","ISO country code (e.g., US, CA, *)").option("--json","Output result as JSON").action(async(i,e)=>{try{let t=await vn();c.start(`Disabling country ${i.toUpperCase()}...`);let o=await t.updateCountryPermission(i.toUpperCase(),!1);c.succeed(`Country ${i.toUpperCase()} disabled for dialing`),e.json?console.log(JSON.stringify(o,null,2)):(n.newline(),bi(o),n.newline(),n.info(`Country ${i.toUpperCase()} is now disabled for dialing`))}catch(t){c.stop(),n.error(`Failed to disable country: ${t.message}`),process.exit(1)}});is.exports=kt});var as=T((su,ss)=>{"use strict";var rs=require("commander");E();x();A();We();async function Ic(){await f.load(),await f.hasCredentials()||(n.error('Not authenticated. Run "sinch auth login" first.'),process.exit(1));let e=f.getApiConfig();return new oe({projectId:e.projectId,credentials:e.credentials})}var Si=new rs.Command("credential-lists");Si.description("Manage credential list relationships");Si.command("trunks").description("Get trunks using a credential list").argument("<credential-list-id>","Credential list ID").option("-l, --limit <number>","Limit number of results",parseInt,50).option("--json","Output result as JSON").action(async(i,e)=>{try{let t=await Ic();c.start("Fetching trunks using credential list...");let o=await t.getCredentialListTrunks(i,{pageSize:e.limit});c.succeed(`Retrieved ${o.trunks?.length||0} trunk(s)`),e.json?console.log(JSON.stringify(o,null,2)):(n.newline(),o.trunks&&o.trunks.length>0?(n.info(`Trunks using credential list ${i}:`),n.newline(),o.trunks.forEach(r=>{n.info(`[${r.id}] ${r.name}`),r.hostName&&n.info(` Host: ${r.hostName}`),n.info(` Caller ID: ${r.enableCallerId?"enabled":"disabled"}`),n.newline()}),o.totalItems&&n.info(`Total: ${o.totalItems} trunk(s)`)):n.info("No trunks found using this credential list"))}catch(t){c.stop(),n.error(`Failed to get trunks for credential list: ${t.message}`),process.exit(1)}});ss.exports=Si});var ps=T((gu,Zt)=>{"use strict";var cs=require("commander");E();x();A();We();St();async function ls(){await f.load(),await f.hasCredentials()||(n.error('Not authenticated. Run "sinch auth login" first.'),process.exit(1));let e=f.getApiConfig();return new oe({projectId:e.projectId,credentials:e.credentials})}function ds(i){if(!i){let t=new Date;return`>=${new Date(t.getTime()-1440*60*1e3).toISOString()}`}if(i.startsWith(">=")||i.startsWith("<=")||i.startsWith(">")||i.startsWith("<"))return i;let e=i.split("-");if(e.length===1&&e[0]){let t=e[0];return`>=${t}-01-01T00:00:00Z,<=${t}-12-31T23:59:59Z`}else if(e.length===2&&e[0]&&e[1]){let t=e[0],o=e[1],r=new Date(parseInt(t),parseInt(o),0).getDate();return`>=${t}-${o}-01T00:00:00Z,<=${t}-${o}-${r.toString().padStart(2,"0")}T23:59:59Z`}else return`>=${i}T00:00:00Z,<=${i}T23:59:59Z`}function bn(i){if(i===void 0||i===0)return"-";let e=Math.floor(i/3600),t=Math.floor(i%3600/60),o=i%60;return e>0?`${e}h ${t}m ${o}s`:t>0?`${t}m ${o}s`:`${o}s`}function Ii(i){return!i||!i.amount?"-":`${parseFloat(i.amount).toFixed(4)} ${i.currencyCode}`}function $c(i,e=!1){n.info(`Call ID: ${i.callId}`),n.info(`From: ${_(i.from)}`),n.info(`To: ${_(i.to)}`),n.info(`Direction: ${i.direction}`),n.info(`Status: ${i.callResult||"In Progress"}`),(e||i.durationSeconds)&&n.info(`Duration: ${bn(i.durationSeconds)}`),(e||i.billingDurationSeconds)&&n.info(`Billing Duration: ${bn(i.billingDurationSeconds)}`),i.price&&n.info(`Cost: ${Ii(i.price)}`),n.info(`Trunk ID: ${i.trunkId}`),n.info(`Created: ${new Date(i.createTime).toLocaleString()}`),i.answerTime&&n.info(`Answered: ${new Date(i.answerTime).toLocaleString()}`),i.endTime&&n.info(`Ended: ${new Date(i.endTime).toLocaleString()}`)}var Sn=new cs.Command("calls");Sn.description("View call history and details");Sn.command("list").description("List calls with filtering options").option("--from <number>","Filter by originating phone number (supports partial matching)").option("--to <number>","Filter by destination phone number (supports partial matching)").option("--trunk-id <id>","Filter by trunk ID").option("--direction <direction>","Filter by direction (INBOUND or OUTBOUND)").option("--result <result>","Filter by call result (COMPLETED, NO_ANSWER, CANCEL, BUSY, FAILED)").option("--date <date>","Filter by date (YYYY-MM-DD, YYYY-MM, or YYYY). Defaults to last 24 hours.").option("--page <number>","Page number",parseInt).option("--page-size <number>","Number of results per page (max 1000)",parseInt,100).option("--json","Output result as JSON").action(async i=>{try{let e=await ls(),t={pageSize:i.pageSize};if(i.from&&(t.from=i.from),i.to&&(t.to=i.to),i.trunkId&&(t.trunkId=i.trunkId),i.direction&&(["INBOUND","OUTBOUND"].includes(i.direction.toUpperCase())||(n.error("Invalid direction. Must be INBOUND or OUTBOUND."),process.exit(1)),t.direction=i.direction.toUpperCase()),i.result){let r=["COMPLETED","NO_ANSWER","CANCEL","BUSY","FAILED"];r.includes(i.result.toUpperCase())||(n.error(`Invalid result. Must be one of: ${r.join(", ")}`),process.exit(1)),t.callResult=i.result.toUpperCase()}i.page&&(t.page=i.page),t.createTime=ds(i.date),c.start("Fetching calls...");let o=await e.findCalls(t);c.succeed(`Retrieved ${o.calls?.length||0} call(s)`),i.json?console.log(JSON.stringify(o,null,2)):(n.newline(),o.calls&&o.calls.length>0?(o.calls.forEach(r=>{let s=bn(r.durationSeconds),a=r.callResult||"In Progress",l=Ii(r.price);n.info(`${r.callId}`),n.info(` ${_(r.from)} \u2192 ${_(r.to)}`),n.info(` ${r.direction} | ${a} | ${s} | ${l}`),n.info(` ${new Date(r.createTime).toLocaleString()}`),n.newline()}),o.totalItems&&(n.info(`Total: ${o.totalItems} call(s)`),o.pageNumber&&n.info(`Page: ${o.pageNumber}`))):(n.info("No calls found matching the filters"),n.newline(),n.info("Try adjusting your filters or date range.")))}catch(e){c.fail("Failed to fetch calls"),n.error(e.message),process.exit(1)}});Sn.command("get").description("Get details of a specific call").argument("<call-id>","Call ID").option("--json","Output result as JSON").action(async(i,e)=>{try{let t=await ls();c.start(`Fetching call ${i}...`);let o=await t.getCall(i);c.succeed("Call retrieved"),e.json?console.log(JSON.stringify(o,null,2)):(n.newline(),$c(o,!0))}catch(t){c.fail("Failed to get call"),n.error(t.message),process.exit(1)}});Zt.exports=Sn;Zt.exports.parseDateFilter=ds;Zt.exports.formatDuration=bn;Zt.exports.formatPrice=Ii});var ms=T((hu,fs)=>{"use strict";var us=require("commander"),Pc=Gr(),kc=Zr(),Ac=ts(),Ec=os(),Tc=as(),xc=ps(),ze=new us.Command("sip");ze.description("Manage Elastic SIP Trunking resources");ze.addCommand(Pc);ze.addCommand(kc);ze.addCommand(Ac);ze.addCommand(Ec);ze.addCommand(Tc);ze.addCommand(xc);fs.exports=ze});var ys=T((bu,hs)=>{"use strict";var gs=require("commander"),fe=y(require("inquirer"));E();x();A();St();async function In(){return await f.load(),await f.hasCredentials()||(n.error('Not authenticated. Run "sinch auth login" first.'),process.exit(1)),(await f.createSinchClient()).numbers}function $i(i){n.info(`Phone Number: ${_(i.phoneNumber)}`),i.displayName&&n.info(`Display Name: ${i.displayName}`),n.info(`Region: ${i.regionCode}`),n.info(`Type: ${i.type}`),n.info(`Capabilities: ${i.capability?.join(", ")||"none"}`),i.money&&n.info(`Cost: ${i.money.amount} ${i.money.currencyCode}/month`),i.nextChargeDate&&n.info(`Next Charge: ${new Date(i.nextChargeDate).toLocaleDateString()}`),i.expireAt&&n.info(`Expires: ${new Date(i.expireAt).toLocaleDateString()}`),i.smsConfiguration&&(n.info(`SMS Service Plan: ${i.smsConfiguration.servicePlanId||"n/a"}`),i.smsConfiguration.campaignId&&n.info(`SMS Campaign: ${i.smsConfiguration.campaignId}`)),i.voiceConfiguration&&(n.info(`Voice Type: ${i.voiceConfiguration.type||"n/a"}`),i.voiceConfiguration.appId&&n.info(`Voice App: ${i.voiceConfiguration.appId}`),i.voiceConfiguration.trunkId&&n.info(`EST Trunk: ${i.voiceConfiguration.trunkId}`)),i.callbackUrl&&n.info(`Callback: ${i.callbackUrl}`)}var At=new gs.Command("active");At.description("Manage your active phone numbers");At.command("list").description("List all active numbers for this project").option("-r, --region <code>","Filter by region code (e.g. US, GB, SE)").option("-t, --type <type>","Filter by type: MOBILE, LOCAL, or TOLL_FREE").option("-c, --capability <cap...>","Filter by capability: SMS, VOICE").option("-p, --pattern <digits>","Filter by digit pattern").option("--search-pattern <mode>","Pattern match mode: START, CONTAINS, or END").option("-l, --limit <number>","Max results",parseInt).option("--order-by <field>","Sort by: phoneNumber or displayName").option("--non-interactive","Skip prompts, require all options as flags").option("--json","Output result as JSON").action(async i=>{try{let e=!i.nonInteractive,t=i.region,o=i.type;!t&&e&&(t=(await fe.default.prompt([{type:"input",name:"regionCode",message:"Region code to filter by (e.g. US, GB, SE) \u2014 leave blank for all:"}])).regionCode||void 0),!o&&e&&(o=(await fe.default.prompt([{type:"list",name:"type",message:"Filter by number type?",choices:[{name:"All types",value:""},{name:"MOBILE",value:"MOBILE"},{name:"LOCAL",value:"LOCAL"},{name:"TOLL_FREE",value:"TOLL_FREE"}]}])).type||void 0);let r=await In();c.start("Fetching active numbers...");let s=i.limit||100,a=[],l={};t&&(l.regionCode=t),o&&(l.type=o),i.capability&&(l.capability=i.capability),i.pattern&&(l["numberPattern.pattern"]=i.pattern),i.searchPattern&&(l["numberPattern.searchPattern"]=i.searchPattern),i.limit&&(l.pageSize=i.limit),i.orderBy&&(l.orderBy=i.orderBy);for await(let d of r.list(l))if(a.push(d),a.length>=s)break;let p=a.length;c.succeed(`Found ${p} active number(s)`),i.json?console.log(JSON.stringify(a,null,2)):(n.newline(),p>0?a.forEach(d=>{let u=d.capability?.join(", ")||"",m=d.displayName?` "${d.displayName}"`:"";console.log(`${_(d.phoneNumber)}${m} [${d.regionCode}] ${d.type} ${u}`)}):(n.info("No active numbers found for this project."),n.newline(),n.info("Search for available numbers: sinch numbers available search")))}catch(e){c.stop(),n.error(`Failed to list active numbers: ${e.message}`),process.exit(1)}});At.command("get").description("Get details for a specific active number").argument("[phone-number]","Phone number in E.164 format (e.g. +12025550134)").option("--non-interactive","Skip prompts").option("--json","Output result as JSON").action(async(i,e)=>{try{let t=!e.nonInteractive;i||(t?i=(await fe.default.prompt([{type:"input",name:"phoneNumber",message:"Enter the phone number (E.164 format, e.g. +12025550134):",validate:a=>a?a.startsWith("+")?!0:"Phone number must start with + (E.164 format)":"Phone number is required"}])).phoneNumber:(n.error("Phone number is required. Usage: sinch numbers active get <phone-number>"),process.exit(1)));let o=await In();c.start(`Fetching number ${i}...`);let r=await o.get({phoneNumber:i});c.succeed("Number retrieved"),e.json?console.log(JSON.stringify(r,null,2)):(n.newline(),$i(r))}catch(t){c.stop(),n.error(`Failed to get number: ${t.message}`),process.exit(1)}});At.command("update").description("Update an active phone number (display name, SMS/Voice config)").argument("[phone-number]","Phone number in E.164 format").option("-d, --display-name <name>","New display name").option("--sms-service-plan <id>","SMS service plan ID (empty string to unlink)").option("--sms-campaign <id>","SMS campaign ID").option("--voice-app <id>","Voice app ID").option("--callback-url <url>","Callback URL for provisioning events").option("--non-interactive","Skip prompts").option("--json","Output result as JSON").action(async(i,e)=>{try{let t=!e.nonInteractive;i||(t?i=(await fe.default.prompt([{type:"input",name:"phoneNumber",message:"Which number do you want to update? (E.164 format):",validate:h=>h?h.startsWith("+")?!0:"Phone number must start with + (E.164 format)":"Phone number is required"}])).phoneNumber:(n.error("Phone number is required. Usage: sinch numbers active update <phone-number>"),process.exit(1)));let o=await In();c.start(`Fetching current details for ${i}...`);let r=await o.get({phoneNumber:i});c.stop();let s=e.displayName,a=e.smsServicePlan,l=e.smsCampaign,p=e.voiceApp,d=e.callbackUrl;if(t){n.newline(),n.info(`Current configuration for ${i}:`),$i(r),n.newline(),s===void 0&&(s=(await fe.default.prompt([{type:"input",name:"displayName",message:"Display name:",default:r.displayName||""}])).displayName||void 0),d===void 0&&(d=(await fe.default.prompt([{type:"input",name:"callbackUrl",message:"Callback URL (leave blank to keep current):",default:r.callbackUrl||""}])).callbackUrl||void 0);let w=await fe.default.prompt([{type:"checkbox",name:"configure",message:"Which configurations do you want to update?",choices:[{name:"SMS Configuration",value:"sms"},{name:"Voice Configuration",value:"voice"}]}]);if(w.configure.includes("sms")&&a===void 0){let h=await fe.default.prompt([{type:"input",name:"servicePlanId",message:"SMS service plan ID (empty to unlink):",default:r.smsConfiguration?.servicePlanId||""},{type:"input",name:"campaignId",message:"SMS campaign ID (for US numbers):",default:r.smsConfiguration?.campaignId||""}]);a=h.servicePlanId,l=h.campaignId||void 0}w.configure.includes("voice")&&p===void 0&&(p=(await fe.default.prompt([{type:"input",name:"appId",message:"Voice app ID:",default:r.voiceConfiguration?.appId||""}])).appId||void 0)}let u={};if(s!==void 0&&(u.displayName=s),d!==void 0&&(u.callbackUrl=d),a!==void 0&&(u.smsConfiguration={servicePlanId:a},l&&(u.smsConfiguration.campaignId=l)),p!==void 0&&(u.voiceConfiguration={type:"RTC",appId:p}),Object.keys(u).length===0){n.info("No changes specified. Nothing to update.");return}c.start(`Updating ${i}...`);let m=await o.update({phoneNumber:i,updateActiveNumberRequestBody:u});c.succeed("Number updated successfully!"),e.json?console.log(JSON.stringify(m,null,2)):(n.newline(),$i(m))}catch(t){c.stop(),n.error(`Failed to update number: ${t.message}`),process.exit(1)}});At.command("release").description("Release (cancel subscription for) an active number").argument("[phone-number]","Phone number in E.164 format").option("-f, --force","Skip confirmation prompt").option("--non-interactive","Skip prompts").option("--json","Output result as JSON").action(async(i,e)=>{try{let t=!e.nonInteractive;if(i||(t?i=(await fe.default.prompt([{type:"input",name:"phoneNumber",message:"Which number do you want to release? (E.164 format):",validate:a=>a?a.startsWith("+")?!0:"Phone number must start with + (E.164 format)":"Phone number is required"}])).phoneNumber:(n.error("Phone number is required. Usage: sinch numbers active release <phone-number>"),process.exit(1))),!e.force){let{confirm:s}=await fe.default.prompt([{type:"confirm",name:"confirm",message:`Are you sure you want to release ${i}? This will cancel your subscription.`,default:!1}]);if(!s){n.info("Release cancelled");return}}let o=await In();c.start(`Releasing ${i}...`);let r=await o.release({phoneNumber:i});c.succeed(`Number ${i} released`),e.json?console.log(JSON.stringify(r,null,2)):(n.newline(),n.info(`${i} has been released from your project.`))}catch(t){c.stop(),n.error(`Failed to release number: ${t.message}`),process.exit(1)}});hs.exports=At});var Ss=T((Au,bs)=>{"use strict";var ws=require("commander"),k=y(require("inquirer"));E();x();A();We();St();async function Rc(){let i=f.getApiConfig();return new oe({projectId:i.projectId,credentials:i.credentials})}async function Cs(){try{c.start("Fetching EST trunks...");let e=await(await Rc()).listTrunks({pageSize:50});c.stop();let t=e.trunks||[];if(t.length===0){console.log("No trunks found. You can create one with: sinch sip trunks create");let{trunkId:s}=await k.default.prompt([{type:"input",name:"trunkId",message:"Enter trunk ID manually:",validate:a=>a?!0:"Trunk ID is required for EST"}]);return s}let o=t.map(s=>({name:`${s.name||s.id}${s.hostName?` (${s.hostName})`:""}`,value:s.id}));o.push(new k.default.Separator),o.push({name:"Enter trunk ID manually",value:"__manual__"});let{selected:r}=await k.default.prompt([{type:"list",name:"selected",message:"Select a trunk:",choices:o}]);if(r==="__manual__"){let{trunkId:s}=await k.default.prompt([{type:"input",name:"trunkId",message:"Enter trunk ID:",validate:a=>a?!0:"Trunk ID is required"}]);return s}return r}catch{c.stop();let{trunkId:i}=await k.default.prompt([{type:"input",name:"trunkId",message:"EST trunk ID (could not fetch trunk list):",validate:e=>e?!0:"Trunk ID is required for EST"}]);return i}}async function vs(){try{c.start("Fetching fax services...");let i=await f.createSinchClient(),e=[];for await(let r of i.fax.services.list({projectId:f.getApiConfig().projectId}))e.push(r);if(c.stop(),e.length===0){console.log("No fax services found.");let{serviceId:r}=await k.default.prompt([{type:"input",name:"serviceId",message:"Enter fax service ID manually:",validate:s=>s?!0:"Service ID is required for FAX"}]);return r}let t=e.map(r=>({name:`${r.name||r.id}${r.defaultForProject?" (default)":""}`,value:r.id}));t.push(new k.default.Separator),t.push({name:"Enter service ID manually",value:"__manual__"});let{selected:o}=await k.default.prompt([{type:"list",name:"selected",message:"Select a fax service:",choices:t}]);if(o==="__manual__"){let{serviceId:r}=await k.default.prompt([{type:"input",name:"serviceId",message:"Enter fax service ID:",validate:s=>s?!0:"Service ID is required"}]);return r}return o}catch{c.stop();let{serviceId:i}=await k.default.prompt([{type:"input",name:"serviceId",message:"Fax service ID (could not fetch service list):",validate:e=>e?!0:"Service ID is required for FAX"}]);return i}}async function Pn(){return await f.load(),await f.hasCredentials()||(n.error('Not authenticated. Run "sinch auth login" first.'),process.exit(1)),(await f.createSinchClient()).numbers}function $n(i){let e=i.capability?.join(", ")||"",t=i.setupPrice?`${i.setupPrice.amount} ${i.setupPrice.currencyCode} setup`:"",o=i.monthlyPrice?`${i.monthlyPrice.amount} ${i.monthlyPrice.currencyCode}/mo`:"",r=[t,o].filter(Boolean).join(" + "),s=i.supportingDocumentationRequired?" [docs required]":"";return`${_(i.phoneNumber)} ${e} ${r}${s}`}async function Dc(i,e){let t,o,r,{configureSms:s}=await k.default.prompt([{type:"confirm",name:"configureSms",message:"Configure SMS for this number?",default:!1}]);if(s){let m=await k.default.prompt([{type:"input",name:"servicePlanId",message:"SMS service plan ID:",validate:w=>w?!0:"Service plan ID is required for SMS"},{type:"input",name:"campaignId",message:"SMS campaign ID (required for US, optional otherwise):"}]);t={servicePlanId:m.servicePlanId},m.campaignId&&(t.campaignId=m.campaignId)}let{voiceType:a}=await k.default.prompt([{type:"list",name:"voiceType",message:"Voice configuration:",choices:[{name:"None (configure later)",value:"none"},{name:"RTC \u2014 Real-time Communication",value:"RTC"},{name:"EST \u2014 Elastic SIP Trunking",value:"EST"},{name:"FAX",value:"FAX"}]}]);if(a==="RTC"){let{appId:m}=await k.default.prompt([{type:"input",name:"appId",message:"Voice app ID:",validate:w=>w?!0:"Voice app ID is required"}]);o={type:"RTC",appId:m}}else a==="EST"?o={type:"EST",trunkId:await Cs()}:a==="FAX"&&(o={type:"FAX",serviceId:await vs()});r=(await k.default.prompt([{type:"input",name:"callbackUrl",message:"Callback URL for provisioning events (optional):"}])).callbackUrl||void 0;let{confirm:p}=await k.default.prompt([{type:"confirm",name:"confirm",message:`Rent ${_(e)}? This will activate it on your project.`,default:!0}]);if(!p){console.log("Rental cancelled.");return}let d={};t&&(d.smsConfiguration=t),o&&(d.voiceConfiguration=o),r&&(d.callbackUrl=r),c.start(`Renting ${e}...`);let u=await i.rent({phoneNumber:e,rentNumberRequestBody:d});c.succeed(`${_(u.phoneNumber)} rented successfully!`),console.log(),console.log(` Phone Number: ${_(u.phoneNumber)}`),console.log(` Region: ${u.regionCode}`),console.log(` Type: ${u.type}`),console.log(` Capabilities: ${u.capability?.join(", ")}`),u.money&&console.log(` Cost: ${u.money.amount} ${u.money.currencyCode}/month`),console.log(),console.log(`Manage this number: sinch numbers active get ${e}`)}var Et=new ws.Command("available");Et.description("Search and rent available phone numbers");Et.command("search").description("Search for available phone numbers to rent").option("-r, --region <code>","Region code (required, e.g. US, GB, SE)").option("-t, --type <type>","Number type (required): MOBILE, LOCAL, or TOLL_FREE").option("-c, --capabilities <cap...>","Capabilities: SMS, VOICE").option("-p, --pattern <digits>","Digit pattern to match").option("--search-pattern <mode>","Pattern match: START, CONTAINS, or END").option("-s, --size <number>","Max results",parseInt).option("--non-interactive","Skip prompts, require all options as flags").option("--json","Output result as JSON").action(async i=>{try{let e=!i.nonInteractive,t=i.region,o=i.type,r=i.capabilities;if(t||(e?t=(await k.default.prompt([{type:"input",name:"regionCode",message:"Region code (e.g. US, GB, SE):",default:"US"}])).regionCode.toUpperCase():(n.error("Region code is required. Use --region <code>"),process.exit(1))),o||(e?o=(await k.default.prompt([{type:"list",name:"type",message:"What type of number?",choices:[{name:"LOCAL \u2014 assigned to a geographic region",value:"LOCAL"},{name:"MOBILE \u2014 belongs to a mobile range",value:"MOBILE"},{name:"TOLL_FREE \u2014 free for the caller",value:"TOLL_FREE"}]}])).type:(n.error("Number type is required. Use --type <MOBILE|LOCAL|TOLL_FREE>"),process.exit(1))),!r&&e){let u=await k.default.prompt([{type:"checkbox",name:"capabilities",message:"Required capabilities:",choices:[{name:"SMS",value:"SMS",checked:!0},{name:"VOICE",value:"VOICE"}]}]);r=u.capabilities.length>0?u.capabilities:void 0}let s=i.pattern,a=i.searchPattern;!s&&e&&(s=(await k.default.prompt([{type:"input",name:"pattern",message:"Digit pattern to search for (leave blank for any):"}])).pattern||void 0,s&&!a&&(a=(await k.default.prompt([{type:"list",name:"searchPattern",message:"Where should the pattern appear?",choices:[{name:"Starts with these digits",value:"START"},{name:"Contains these digits",value:"CONTAINS"},{name:"Ends with these digits",value:"END"}]}])).searchPattern));let l=await Pn();c.start(`Searching for ${o} numbers in ${t}...`);let p=await l.searchForAvailableNumbers({regionCode:t,type:o,capabilities:r,"numberPattern.pattern":s,"numberPattern.searchPattern":a,size:i.size}),d=p.availableNumbers?.length||0;if(c.succeed(`Found ${d} available number(s)`),i.json)console.log(JSON.stringify(p,null,2));else if(d===0)console.log(),console.log("No numbers found matching your criteria."),console.log("Try a different region, type, or relax your pattern filter.");else if(e){let u=p.availableNumbers.map(w=>({name:$n(w),value:w.phoneNumber}));u.push(new k.default.Separator),u.push({name:"Exit without renting",value:""});let{selected:m}=await k.default.prompt([{type:"list",name:"selected",message:`Select a number to rent (${d} available):`,choices:u,pageSize:Math.min(d+2,20)}]);m&&await Dc(l,m)}else console.log(),p.availableNumbers.forEach(u=>console.log($n(u)))}catch(e){c.stop(),n.error(`Failed to search numbers: ${e.message}`),process.exit(1)}});Et.command("check").description("Check if a specific phone number is available").argument("[phone-number]","Phone number in E.164 format").option("--non-interactive","Skip prompts").option("--json","Output result as JSON").action(async(i,e)=>{try{let t=!e.nonInteractive;i||(t?i=(await k.default.prompt([{type:"input",name:"phoneNumber",message:"Enter the phone number to check (E.164, e.g. +12025550134):",validate:a=>a?a.startsWith("+")?!0:"Must be in E.164 format (starts with +)":"Phone number is required"}])).phoneNumber:(n.error("Phone number is required. Usage: sinch numbers available check <phone-number>"),process.exit(1)));let o=await Pn();c.start(`Checking availability for ${i}...`);let r=await o.checkAvailability({phoneNumber:i});c.succeed("Number is available!"),e.json?console.log(JSON.stringify(r,null,2)):(console.log(),console.log($n(r)),console.log(),console.log(`Rent this number: sinch numbers available rent ${i}`))}catch(t){c.stop(),n.error(`${t.message}`),process.exit(1)}});Et.command("rent").description("Rent (activate) a specific phone number").argument("[phone-number]","Phone number in E.164 format").option("--sms-service-plan <id>","SMS service plan ID").option("--sms-campaign <id>","SMS campaign ID (for US numbers)").option("--voice-app <id>","Voice app ID (for RTC)").option("--voice-type <type>","Voice config type: RTC, EST, or FAX").option("--trunk-id <id>","EST trunk ID (when voice-type is EST)").option("--callback-url <url>","Callback URL for provisioning events").option("-f, --force","Skip confirmation").option("--non-interactive","Skip all prompts").option("--json","Output result as JSON").action(async(i,e)=>{try{let t=!e.nonInteractive;i||(t?i=(await k.default.prompt([{type:"input",name:"phoneNumber",message:"Which number do you want to rent? (E.164 format):",validate:u=>u?u.startsWith("+")?!0:"Must be in E.164 format (starts with +)":"Phone number is required"}])).phoneNumber:(n.error("Phone number is required. Usage: sinch numbers available rent <phone-number>"),process.exit(1)));let o=await Pn();if(t){c.start(`Checking availability for ${i}...`);try{let d=await o.checkAvailability({phoneNumber:i});c.succeed("Number is available"),console.log(),console.log($n(d)),console.log()}catch{c.fail("Number may not be available"),n.warn("Could not verify availability. Proceeding anyway..."),n.newline()}}let r,s,a=e.callbackUrl;if(e.smsServicePlan&&(r={servicePlanId:e.smsServicePlan},e.smsCampaign&&(r.campaignId=e.smsCampaign)),(e.voiceApp||e.trunkId)&&(s={type:e.voiceType||"RTC"},e.voiceApp&&(s.appId=e.voiceApp),e.trunkId&&(s.trunkId=e.trunkId)),t&&!r&&!s){let{configureSms:d}=await k.default.prompt([{type:"confirm",name:"configureSms",message:"Configure SMS for this number?",default:!1}]);if(d){let m=await k.default.prompt([{type:"input",name:"servicePlanId",message:"SMS service plan ID:",validate:w=>w?!0:"Service plan ID is required for SMS"},{type:"input",name:"campaignId",message:"SMS campaign ID (required for US, optional otherwise):"}]);r={servicePlanId:m.servicePlanId},m.campaignId&&(r.campaignId=m.campaignId)}let{voiceType:u}=await k.default.prompt([{type:"list",name:"voiceType",message:"Voice configuration:",choices:[{name:"None (configure later)",value:"none"},{name:"RTC \u2014 Real-time Communication",value:"RTC"},{name:"EST \u2014 Elastic SIP Trunking",value:"EST"},{name:"FAX",value:"FAX"}]}]);if(u==="RTC"){let{appId:m}=await k.default.prompt([{type:"input",name:"appId",message:"Voice app ID:",validate:w=>w?!0:"Voice app ID is required"}]);s={type:"RTC",appId:m}}else u==="EST"?s={type:"EST",trunkId:await Cs()}:u==="FAX"&&(s={type:"FAX",serviceId:await vs()});a||(a=(await k.default.prompt([{type:"input",name:"callbackUrl",message:"Callback URL for provisioning events (optional):"}])).callbackUrl||void 0)}if(!e.force){let{confirm:d}=await k.default.prompt([{type:"confirm",name:"confirm",message:`Rent ${i}? This will activate it on your project.`,default:!0}]);if(!d){n.info("Rental cancelled");return}}let l={};r&&(l.smsConfiguration=r),s&&(l.voiceConfiguration=s),a&&(l.callbackUrl=a),c.start(`Renting ${i}...`);let p=await o.rent({phoneNumber:i,rentNumberRequestBody:l});c.succeed(`Number ${i} rented successfully!`),e.json?console.log(JSON.stringify(p,null,2)):(console.log(),console.log(` Phone Number: ${_(p.phoneNumber)}`),console.log(` Region: ${p.regionCode}`),console.log(` Type: ${p.type}`),console.log(` Capabilities: ${p.capability?.join(", ")}`),p.money&&console.log(` Cost: ${p.money.amount} ${p.money.currencyCode}/month`),console.log(),console.log(`Manage this number: sinch numbers active get ${i}`))}catch(t){c.stop(),n.error(`Failed to rent number: ${t.message}`),process.exit(1)}});Et.command("rent-any").description("Rent any number matching your criteria (US LOCAL only)").option("-r, --region <code>","Region code (required)").option("-t, --type <type>","Number type (required): MOBILE, LOCAL, or TOLL_FREE").option("-c, --capabilities <cap...>","Capabilities: SMS, VOICE").option("-p, --pattern <digits>","Digit pattern to match").option("--search-pattern <mode>","Pattern match: START, CONTAINS, or END").option("--sms-service-plan <id>","SMS service plan ID").option("--sms-campaign <id>","SMS campaign ID").option("--voice-app <id>","Voice app ID").option("--callback-url <url>","Callback URL").option("-f, --force","Skip confirmation").option("--non-interactive","Skip all prompts").option("--json","Output result as JSON").action(async i=>{try{let e=!i.nonInteractive,t=i.region,o=i.type,r=i.capabilities;if(t||(e?t=(await k.default.prompt([{type:"input",name:"regionCode",message:"Region code (e.g. US, GB, SE):",default:"US"}])).regionCode.toUpperCase():(n.error("Region code is required. Use --region <code>"),process.exit(1))),o||(e?o=(await k.default.prompt([{type:"list",name:"type",message:"Number type:",choices:[{name:"LOCAL",value:"LOCAL"},{name:"MOBILE",value:"MOBILE"},{name:"TOLL_FREE",value:"TOLL_FREE"}]}])).type:(n.error("Number type is required. Use --type <MOBILE|LOCAL|TOLL_FREE>"),process.exit(1))),!r&&e){let m=await k.default.prompt([{type:"checkbox",name:"capabilities",message:"Required capabilities:",choices:[{name:"SMS",value:"SMS",checked:!0},{name:"VOICE",value:"VOICE"}]}]);r=m.capabilities.length>0?m.capabilities:void 0}let s,a;if(i.smsServicePlan)s={servicePlanId:i.smsServicePlan},i.smsCampaign&&(s.campaignId=i.smsCampaign);else if(e&&(await k.default.prompt([{type:"confirm",name:"configureSms",message:"Configure SMS for this number?",default:!1}])).configureSms){let w=await k.default.prompt([{type:"input",name:"servicePlanId",message:"SMS service plan ID:",validate:h=>h?!0:"Required"},{type:"input",name:"campaignId",message:"SMS campaign ID (optional):"}]);s={servicePlanId:w.servicePlanId},w.campaignId&&(s.campaignId=w.campaignId)}i.voiceApp&&(a={type:"RTC",appId:i.voiceApp});let l=i.callbackUrl;if(!l&&e&&(l=(await k.default.prompt([{type:"input",name:"callbackUrl",message:"Callback URL (optional):"}])).callbackUrl||void 0),!i.force){let{confirm:m}=await k.default.prompt([{type:"confirm",name:"confirm",message:`Rent any available ${o} number in ${t}?`,default:!0}]);if(!m){n.info("Rental cancelled");return}}let p=await Pn(),d={regionCode:t,type:o};r&&(d.capabilities=r),i.pattern&&(d.numberPattern={pattern:i.pattern,searchPattern:i.searchPattern||"CONTAINS"}),s&&(d.smsConfiguration=s),a&&(d.voiceConfiguration=a),l&&(d.callbackUrl=l),c.start(`Finding and renting a ${o} number in ${t}...`);let u=await p.rentAny({rentAnyNumberRequestBody:d});c.succeed(`Rented ${u.phoneNumber}!`),i.json?console.log(JSON.stringify(u,null,2)):(console.log(),console.log(` Phone Number: ${_(u.phoneNumber)}`),console.log(` Region: ${u.regionCode}`),console.log(` Type: ${u.type}`),console.log(` Capabilities: ${u.capability?.join(", ")}`),u.money&&console.log(` Cost: ${u.money.amount} ${u.money.currencyCode}/month`),console.log(),console.log(`Manage this number: sinch numbers active get ${u.phoneNumber}`))}catch(e){c.stop(),n.error(`Failed to rent number: ${e.message}`),process.exit(1)}});bs.exports=Et});var Ps=T((Ru,$s)=>{"use strict";var Is=require("commander");E();x();A();async function Nc(){return await f.load(),await f.hasCredentials()||(n.error('Not authenticated. Run "sinch auth login" first.'),process.exit(1)),(await f.createSinchClient()).numbers}var Pi=new Is.Command("regions");Pi.description("List regions where numbers are available");Pi.command("list").description("List all available regions for phone numbers").option("-t, --types <type...>","Filter by number type: MOBILE, LOCAL, TOLL_FREE").option("--json","Output result as JSON").action(async i=>{try{let e=await Nc();c.start("Fetching available regions...");let t=await e.availableRegions.list({types:i.types}),o=t.availableRegions?.length||0;c.succeed(`Found ${o} region(s)`),i.json?console.log(JSON.stringify(t,null,2)):(n.newline(),o>0?t.availableRegions.forEach(r=>{console.log(`${r.regionCode} ${r.regionName} [${r.types?.join(", ")}]`)}):n.info("No regions found."))}catch(e){c.stop(),n.error(`Failed to list regions: ${e.message}`),process.exit(1)}});$s.exports=Pi});var Es=T((Du,As)=>{"use strict";var ks=require("commander"),Oc=ys(),jc=Ss(),Fc=Ps(),Qt=new ks.Command("numbers");Qt.description("Manage Sinch phone numbers \u2014 search, rent, update, and release");Qt.addCommand(Oc);Qt.addCommand(jc);Qt.addCommand(Fc);As.exports=Qt});async function me(i){let e={};for(let t of i){if(t.when!==void 0&&!(typeof t.when=="function"?await t.when(e):t.when))continue;let o;switch(t.type){case"input":{let r=await(0,Se.input)({message:t.message,default:t.default,validate:t.validate});t.filter&&(r=t.filter(r)),o=r;break}case"password":o=await(0,Se.password)({message:t.message,validate:t.validate});break;case"confirm":o=await(0,Se.confirm)({message:t.message,default:t.default});break;case"list":o=await(0,Se.select)({message:t.message,choices:(t.choices||[]).map(r=>typeof r=="string"?{name:r,value:r}:r),default:t.default,pageSize:t.pageSize});break;case"checkbox":o=await(0,Se.checkbox)({message:t.message,choices:(t.choices||[]).map(r=>typeof r=="string"?{name:r,value:r}:r),pageSize:t.pageSize});break;default:throw new Error(`Unsupported prompt type: ${t.type}`)}e[t.name]=o}return e}var Se,Ts=W(()=>{"use strict";Se=require("@inquirer/prompts")});var xs,ki,Ai,Rs=W(()=>{"use strict";xs=require("@sinch/sdk-core");A();ki=class{client=null;initialized=!1;async initialize(){if(!(this.initialized&&this.client))try{await f.load();let e=await f.getCredentials();if(!e)throw new Error("Not authenticated. Please run: sinch auth login");this.client=new xs.SinchClient({projectId:e.projectId,keyId:e.keyId,keySecret:e.keySecret}),this.initialized=!0}catch(e){throw new Error(`Failed to initialize fax client: ${e.message}`)}}async getClient(){return this.initialized||await this.initialize(),this.client}isInitialized(){return this.initialized}async getServiceConfig(){return await f.load(),{serviceId:f.getFaxServiceId(),senderNumber:f.getFaxSenderNumber()}}async validateConfig(){let e=await this.getServiceConfig(),t=[];return e.serviceId||t.push("fax service ID (set with: sinch config set fax service-id <id>)"),{valid:t.length===0,missing:t}}},Ai=new ki});var _s={};Te(_s,{FaxManager:()=>kn,default:()=>_c,getFaxClient:()=>Fs,getFaxManager:()=>Le});async function Fs(){try{return await f.load(),await f.hasCredentials()||(n.error("Not authenticated. Please run: sinch auth login"),process.exit(1)),await Ai.initialize(),await Ai.getClient()}catch(i){n.error(`Failed to initialize fax client: ${i.message}`),process.exit(1)}}async function Le(){let i=await Fs(),e=await f.getFaxCredentials();return new kn(i,e)}async function Lc(){let i=Ns.platform();try{if(i==="darwin")return(0,en.execSync)(`osascript -e '${`
|
|
122
|
+
`);St.command("install").description("Install Sinch skills for AI coding assistants").option("--claude","Install for Claude Code only").option("--copilot","Install for GitHub Copilot only (requires --project)").option("--project","Install to current project (for team sharing via git)").option("--link","Symlink instead of copy (for development)").option("--force","Overwrite existing skills without prompting").action(async i=>{try{let e=Ir();V.default.existsSync(e)||(n.error("Skills source not found. This may indicate a corrupted CLI installation."),n.info(`Expected path: ${e}`),process.exit(1));let t=ie.default.join(e,"sinch-functions");V.default.existsSync(t)||(n.error("Skill source not found."),process.exit(1));let o=0,r=0,s=i.claude||!i.claude&&!i.copilot,a=i.copilot||!i.claude&&!i.copilot&&i.project;if(s){if(!i.project||i.claude){let l=ui();V.default.existsSync(ie.default.join(l,"SKILL.md"))&&!i.force?(n.warn(`Claude Code skill already installed at ${l}`),n.info("Use --force to overwrite"),r++):(await V.default.ensureDir(ie.default.dirname(l)),i.link&&process.platform!=="win32"?(V.default.existsSync(l)&&await V.default.remove(l),await V.default.symlink(t,l,"junction"),n.success(`Linked Claude Code skill to ${l}`)):(await V.default.copy(t,l,{overwrite:!0}),n.success(`Installed Claude Code skill to ${l}`)),o++)}if(i.project){let l=fi();V.default.existsSync(ie.default.join(l,"SKILL.md"))&&!i.force?(n.warn(`Claude Code project skill already installed at ${l}`),n.info("Use --force to overwrite"),r++):(await V.default.ensureDir(ie.default.dirname(l)),await V.default.copy(t,l,{overwrite:!0}),n.success(`Installed Claude Code skill to ${l}`),o++)}}if(a&&i.project){let l=mi();V.default.existsSync(ie.default.join(l,"SKILL.md"))&&!i.force?(n.warn(`Copilot skill already installed at ${l}`),n.info("Use --force to overwrite"),r++):(await V.default.ensureDir(ie.default.dirname(l)),await V.default.copy(t,l,{overwrite:!0}),n.success(`Installed Copilot skill to ${l}`),o++)}else i.copilot&&!i.project&&(n.warn("Copilot requires --project flag (no global installation supported)"),n.info("Use: sinch skills install --copilot --project"));n.info(""),o>0&&n.success(`Installed ${o} skill(s)`),r>0&&n.info(`Skipped ${r} existing skill(s)`),o>0&&(n.info(""),n.info(B.default.bold("Next steps:")),s&&(n.info(` ${B.default.cyan("\u2022")} Claude Code will now have Sinch expertise`),n.info(` ${B.default.cyan("\u2022")} Ask about voice IVRs, SVAML, or CLI commands`)),a&&i.project&&(n.info(` ${B.default.cyan("\u2022")} Copilot will use Sinch patterns for code suggestions`),n.info(` ${B.default.cyan("\u2022")} Commit .github/skills/ to share with team`)))}catch(e){n.error("Failed to install skills:",e.message),process.exit(1)}});St.command("list").description("Show installed skill locations").action(async()=>{try{let i=$r({project:!0}),e=i.filter(a=>a.type==="global"),t=i.filter(a=>a.type==="project");n.info(B.default.bold(`Sinch Skills Installation Status
|
|
123
|
+
`)),n.info(B.default.underline("Global (personal machine):"));let o=!1;for(let a of e)a.installed?(n.info(` ${B.default.green("\u2713")} ${a.tool}: ${B.default.gray(a.path)}`),o=!0):n.info(` ${B.default.gray("\u25CB")} ${a.tool}: ${B.default.gray("not installed")}`);o||n.info(` ${B.default.gray("No global skills installed")}`),n.info(""),n.info(B.default.underline("Project (current directory):"));let r=!1;for(let a of t)a.installed?(n.info(` ${B.default.green("\u2713")} ${a.tool}: ${B.default.gray(a.path)}`),r=!0):n.info(` ${B.default.gray("\u25CB")} ${a.tool}: ${B.default.gray("not installed")}`);r||n.info(` ${B.default.gray("No project skills installed")}`),n.info(""),i.some(a=>a.installed)||(n.info("Run `sinch skills install` to install skills globally"),n.info("Run `sinch skills install --project` to install for this project"))}catch(i){n.error("Failed to list skills:",i.message),process.exit(1)}});St.command("uninstall").description("Remove installed Sinch skills").option("--claude","Uninstall from Claude Code only").option("--copilot","Uninstall from GitHub Copilot only").option("--project","Uninstall from current project only").option("--all","Uninstall from all locations").action(async i=>{try{let e=0,t=!i.claude&&!i.copilot&&!i.project&&!i.all,o=i.all||t,r=i.project&&!i.all&&!t,s=i.claude||o||r,a=i.copilot||o||r;if(s){if(!r){let l=ui();V.default.existsSync(l)&&(await V.default.remove(l),n.success(`Removed Claude Code skill from ${l}`),e++)}if(r||o){let l=fi();V.default.existsSync(l)&&(await V.default.remove(l),n.success(`Removed Claude Code skill from ${l}`),e++)}}if(a&&(r||o)){let l=mi();V.default.existsSync(l)&&(await V.default.remove(l),n.success(`Removed Copilot skill from ${l}`),e++)}n.info(""),e>0?n.success(`Removed ${e} skill(s)`):n.info("No skills found to remove")}catch(e){n.error("Failed to uninstall skills:",e.message),process.exit(1)}});St.command("update").description("Update skills to latest version").option("--project","Update project skills as well").action(async i=>{try{n.info(`Updating Sinch skills...
|
|
124
|
+
`);let t=$r({project:i.project}).filter(a=>a.installed);if(t.length===0){n.info("No skills installed. Run `sinch skills install` first.");return}let o=Ir(),r=ie.default.join(o,"sinch-functions"),s=0;for(let a of t)await V.default.copy(r,a.path,{overwrite:!0}),n.success(`Updated ${a.tool} (${a.type})`),s++;n.info(""),n.success(`Updated ${s} skill(s)`)}catch(e){n.error("Failed to update skills:",e.message),process.exit(1)}});Pr.exports=St});async function vc(){await f.load(),await f.hasCredentials()||(n.error('Not authenticated. Run "sinch auth login" first.'),process.exit(1))}async function U(){return await vc(),await f.createSinchClient()}function bt(i){let e=i||f.get("conversation-app-id");return e||(n.error("No Conversation App ID configured."),n.info("Set default: sinch config set conversation-app-id <id>"),n.info("Or specify: --app <app-id>"),process.exit(1)),e}var at=G(()=>{"use strict";E();T()});var Rr=N((sp,Nr)=>{"use strict";var Er=require("commander"),kr=y(require("inquirer"));T();R();at();var Tr=new Er.Command("send");Tr.description("Send a message via Conversation API").argument("[recipient]","Recipient phone number (e.g., +15551234567)").argument("[message]","Message text to send").option("-c, --channel <channel>","Channel (SMS, WHATSAPP, MESSENGER, etc.)","SMS").option("-a, --app <app-id>","Conversation App ID (uses default if configured)").option("-m, --media <url>","Media URL for media messages").option("--caption <text>","Caption for media messages").option("-t, --template <name>","Template name for template messages").option("-p, --params <json>","Template parameters as JSON string").option("--location","Send location message").option("--lat <latitude>","Latitude for location messages",parseFloat).option("--lng <longitude>","Longitude for location messages",parseFloat).option("-n, --name <name>","Location name").option("--json","Output result as JSON").action(async(i,e,t)=>{try{let o=await U();if(!i||!e&&!t?.media&&!t?.template&&!t?.location){let s=await kr.default.prompt([{type:"input",name:"recipient",message:"Enter recipient phone number:",when:!i,validate:a=>a?a.startsWith("+")?!0:"Phone number must start with +":"Recipient is required"},{type:"input",name:"message",message:"Enter message:",when:!e&&!t?.media&&!t?.template&&!t?.location,validate:a=>a?!0:"Message is required"},{type:"list",name:"channel",message:"Select channel:",choices:["SMS","WHATSAPP","MESSENGER","INSTAGRAM","VIBER","TELEGRAM","RCS","LINE"],default:t?.channel||"SMS",when:!t?.channel}]);i=i||s.recipient,e=e||s.message,s.channel&&(t={...t,channel:s.channel})}let r=bt(t?.app);c.start("Sending message...");try{let s;if(t?.location)(!t.lat||!t.lng)&&(c.fail("Location messages require --lat and --lng"),process.exit(1)),s=await o.conversation.messages.send({sendMessageRequestBody:{app_id:r,recipient:{identified_by:{channel_identities:[{channel:t.channel||"SMS",identity:i}]}},message:{location_message:{coordinates:{latitude:t.lat,longitude:t.lng},title:t.name}}}});else if(t?.template){let a=t.params?JSON.parse(t.params):{};s=await o.conversation.messages.send({sendMessageRequestBody:{app_id:r,recipient:{identified_by:{channel_identities:[{channel:t.channel||"WHATSAPP",identity:i}]}},message:{template_message:{template_reference:{template_id:t.template,version:a.version||"1"},parameters:a}}}})}else t?.media?s=await o.conversation.messages.send({sendMessageRequestBody:{app_id:r,recipient:{identified_by:{channel_identities:[{channel:t.channel||"WHATSAPP",identity:i}]}},message:{media_message:{url:t.media,caption:t.caption}}}}):s=await o.conversation.messages.send({sendMessageRequestBody:{app_id:r,recipient:{identified_by:{channel_identities:[{channel:t?.channel||"SMS",identity:i}]}},message:{text_message:{text:e}}}});c.succeed("Message sent successfully!"),t?.json?console.log(JSON.stringify(s,null,2)):(n.newline(),n.info(`Message ID: ${s.message_id}`),n.info(`Recipient: ${i}`),n.info(`Channel: ${t?.channel||"SMS"}`))}catch(s){c.fail("Failed to send message"),n.error(`Error: ${s.message}`),(s.message?.includes("WHATSAPP")||s.message?.includes("channel not configured"))&&(n.newline(),n.info("To use WhatsApp, configure WhatsApp credentials in your Conversation app:"),n.info(" 1. Visit https://dashboard.sinch.com/convapi/apps"),n.info(" 2. Add WhatsApp channel credentials"),n.info(" 3. Verify your WhatsApp Business Account"),n.newline(),n.info("Or use SMS (no additional setup required):"),n.info(` sinch conversation send ${i} "${e}"`)),process.exit(1)}}catch(o){c.stop(),n.error(`Failed to send message: ${o.message}`),process.exit(1)}});Nr.exports=Tr});var Or=N((dp,xr)=>{"use strict";var Dr=require("commander");T();R();at();var Yt=new Dr.Command("messages");Yt.description("Manage conversation messages");Yt.command("get").description("Get a specific message by ID").argument("<message-id>","Message ID to retrieve").option("--json","Output result as JSON").action(async(i,e)=>{try{let t=await U();c.start("Fetching message...");let o=await t.conversation.messages.get({message_id:i});c.succeed("Message retrieved"),e.json?console.log(JSON.stringify(o,null,2)):(n.newline(),n.info(`Message ID: ${o.id}`),n.info(`Direction: ${o.direction}`),n.info(`Channel: ${o.channel_identity?.channel||"N/A"}`),n.info(`Contact ID: ${o.contact_id||"N/A"}`),n.info(`Conversation ID: ${o.conversation_id||"N/A"}`),n.info(`Status: ${o.accept_time?"Accepted":"Pending"}`),o.text_message&&n.info(`Text: ${o.text_message.text}`),o.media_message&&n.info(`Media URL: ${o.media_message.url}`))}catch(t){c.stop(),n.error(`Failed to get message: ${t.message}`),process.exit(1)}});Yt.command("list").description("List messages").option("-c, --channel <channel>","Filter by channel").option("-l, --limit <number>","Limit number of results",parseInt,20).option("--json","Output result as JSON").action(async i=>{try{let e=await U();c.start("Fetching messages...");let t=await e.conversation.messages.list({page_size:i.limit||20,...i.channel&&{channel:i.channel}});c.succeed(`Retrieved ${t.messages?.length||0} messages`),i.json?console.log(JSON.stringify(t,null,2)):(n.newline(),t.messages&&t.messages.length>0?t.messages.forEach(o=>{n.info(`[${o.id}] ${o.direction} via ${o.channel_identity?.channel||"N/A"}`),o.text_message&&n.info(` "${o.text_message.text}"`),n.newline()}):n.info("No messages found"))}catch(e){c.stop(),n.error(`Failed to list messages: ${e.message}`),process.exit(1)}});Yt.command("delete").description("Delete a message").argument("<message-id>","Message ID to delete").action(async i=>{try{let e=await U();c.start("Deleting message..."),await e.conversation.messages.delete({message_id:i}),c.succeed("Message deleted successfully")}catch(e){c.stop(),n.error(`Failed to delete message: ${e.message}`),process.exit(1)}});xr.exports=Yt});function q(i){try{let e=Fr.parse(i);return Fr.format(e,wn.PhoneNumberFormat.INTERNATIONAL)}catch{return i}}var wn,Fr,It=G(()=>{"use strict";wn=require("google-libphonenumber"),Fr=wn.PhoneNumberUtil.getInstance()});var _r=N((hp,Lr)=>{"use strict";var jr=require("commander"),le=y(require("inquirer"));T();R();at();It();var Cn=class{sinchClient;constructor(e){this.sinchClient=e}hasChannel(e,t){return e.channel_identities?.some(o=>{let r=o.channel;return r==="CHANNEL_UNSPECIFIED"&&o.identity.includes("@")&&(r="EMAIL"),t.includes(r)})}getChannelIdentities(e,t){return e.channel_identities.filter(o=>{let r=o.channel;return r==="CHANNEL_UNSPECIFIED"&&o.identity.includes("@")&&(r="EMAIL"),t.includes(r)})}buildContactMenu(e){let t=this.hasChannel(e,["SMS","WHATSAPP"]),o=this.hasChannel(e,["SMS","WHATSAPP"]),r=this.hasChannel(e,["EMAIL"]),s=[];return t&&s.push({name:"\u{1F4AC} Send Message",value:"send-message"}),s.push({name:"Edit Name",value:"edit-name"}),o&&s.push({name:"Edit Phone",value:"edit-phone"}),r&&s.push({name:"Edit Email",value:"edit-email"}),s.push({name:"Delete Contact",value:"delete"},{name:"See More Details",value:"details"},{name:"\u2190 Back",value:"back"}),s}async sendMessage(e){let t=e.channel_identities.map(s=>{let a=s.channel;return a==="CHANNEL_UNSPECIFIED"&&s.identity.includes("@")&&(a="EMAIL"),{name:`${a}: ${q(s.identity)}`,value:{channel:a,identity:s.identity}}});t.push({name:"\u2190 Back",value:"back"});let{selectedChannel:o}=await le.default.prompt([{type:"list",name:"selectedChannel",message:"Select channel to send to:",choices:t}]);if(o==="back")return!1;let{messageText:r}=await le.default.prompt([{type:"input",name:"messageText",message:"Enter your message:",validate:s=>s?!0:"Message is required"}]);try{let s=bt();c.start("Sending message...");let a=await this.sinchClient.conversation.messages.send({sendMessageRequestBody:{app_id:s,recipient:{identified_by:{channel_identities:[{channel:o.channel,identity:o.identity,app_id:""}]}},message:{text_message:{text:r}}}});c.succeed("Message sent successfully!"),n.newline(),n.info(`Message ID: ${a.message_id}`),n.info(`Recipient: ${q(o.identity)}`),n.info(`Channel: ${o.channel}`),n.newline()}catch(s){c.fail("Failed to send message"),n.error(`Error: ${s.message}`),n.newline()}return!1}showDetails(e){n.newline(),n.info("Contact Details:"),n.info(`ID: ${e.id}`),n.info(`Display Name: ${e.display_name||"N/A"}`),n.info(`Email: ${e.email||"N/A"}`),n.info(`External ID: ${e.external_id||"N/A"}`),n.info(`Language: ${e.language||"N/A"}`),n.info(`Metadata: ${e.metadata||"N/A"}`),e.channel_identities&&e.channel_identities.length>0&&(n.newline(),n.info("Channel Identities:"),e.channel_identities.forEach(t=>{let o=t.channel;o==="CHANNEL_UNSPECIFIED"&&t.identity.includes("@")&&(o="EMAIL"),n.info(` ${o}: ${q(t.identity)}`)})),n.newline()}async editName(e,t){let{newDisplayName:o}=await le.default.prompt([{type:"input",name:"newDisplayName",message:"Enter new display name:",default:e.display_name}]);c.start("Updating contact..."),await this.sinchClient.conversation.contact.update({contact_id:t,display_name:o}),c.succeed("Contact updated successfully!"),e.display_name=o,n.newline()}async editChannelIdentities(e,t,o){let s={phone:{channels:["SMS","WHATSAPP"],addPrompt:"+ Add new phone number",selectPrompt:"Select phone number to edit or add new:",typePrompt:"Select type:",valuePrompt:"Enter phone number:",editPrompt:"Enter new phone number:",typeChoices:["SMS","WHATSAPP"],successAdd:"Phone number added successfully!",successEdit:"Phone number updated successfully!",successDelete:"Phone number deleted successfully!",validator:d=>d?d.startsWith("+")?!0:"Phone number must start with +":"Phone number is required"},email:{channels:["EMAIL"],addPrompt:"+ Add new email address",selectPrompt:"Select email address to edit or add new:",typePrompt:null,valuePrompt:"Enter email address:",editPrompt:"Enter new email address:",typeChoices:null,successAdd:"Email address added successfully!",successEdit:"Email address updated successfully!",successDelete:"Email address deleted successfully!",validator:d=>d?d.includes("@")?!0:"Invalid email address":"Email is required"}}[o],l=this.getChannelIdentities(e,s.channels).map(d=>{let u=e.channel_identities.indexOf(d),m=d.channel;return m==="CHANNEL_UNSPECIFIED"&&d.identity.includes("@")&&(m="EMAIL"),{name:`${m}: ${q(d.identity)}`,value:u}});l.push({name:s.addPrompt,value:"add"}),l.push({name:"\u2190 Back",value:"cancel"});let{identityAction:p}=await le.default.prompt([{type:"list",name:"identityAction",message:s.selectPrompt,choices:l}]);if(p!=="cancel")if(p==="add"){let d=[];s.typePrompt&&s.typeChoices&&d.push({type:"list",name:"newIdentityType",message:s.typePrompt,choices:s.typeChoices}),d.push({type:"input",name:"newIdentityValue",message:s.valuePrompt,validate:s.validator});let u=await le.default.prompt(d);e.channel_identities.push({channel:u.newIdentityType||s.channels[0],identity:u.newIdentityValue,app_id:""}),c.start("Updating contact..."),await this.sinchClient.conversation.contact.update({contact_id:t,channel_identities:e.channel_identities,display_name:e.display_name}),c.succeed(s.successAdd),n.newline()}else{let d=e.channel_identities[p],{editOrDelete:u}=await le.default.prompt([{type:"list",name:"editOrDelete",message:"What would you like to do?",choices:["Edit","Delete","\u2190 Back"]}]);if(u==="Edit"){let{newValue:m}=await le.default.prompt([{type:"input",name:"newValue",message:s.editPrompt,default:d.identity,validate:s.validator}]);d.identity=m,c.start("Updating contact..."),await this.sinchClient.conversation.contact.update({contact_id:t,channel_identities:e.channel_identities,display_name:e.display_name}),c.succeed(s.successEdit),n.newline()}else u==="Delete"&&(e.channel_identities.splice(p,1),c.start("Updating contact..."),await this.sinchClient.conversation.contact.update({contact_id:t,channel_identities:e.channel_identities,display_name:e.display_name}),c.succeed(s.successDelete),n.newline())}}async deleteContact(e,t,o){let{confirmDelete:r}=await le.default.prompt([{type:"confirm",name:"confirmDelete",message:`Are you sure you want to delete "${e.display_name||"this contact"}"?`,default:!1}]);if(r){c.start("Deleting contact..."),await this.sinchClient.conversation.contact.delete({contact_id:t}),c.succeed("Contact deleted successfully");let s=o.findIndex(a=>a.id===t);if(s>-1&&o.splice(s,1),o.length===0)return n.info("No more contacts."),!0;n.newline()}return!1}async handleAction(e,t,o,r){switch(e){case"send-message":return await this.sendMessage(t);case"details":return this.showDetails(t),!1;case"edit-name":return await this.editName(t,o),!1;case"edit-phone":return await this.editChannelIdentities(t,o,"phone"),!1;case"edit-email":return await this.editChannelIdentities(t,o,"email"),!1;case"delete":return await this.deleteContact(t,o,r);default:return!1}}async runInteractiveList(e){let t=!0;for(;t;){let o=[];e.forEach(p=>{o.push(new le.default.Separator(`
|
|
125
|
+
${p.display_name||"No name"}`)),p.channel_identities&&p.channel_identities.length>0&&p.channel_identities.forEach(d=>{let u=d.channel;u==="CHANNEL_UNSPECIFIED"&&d.identity.includes("@")&&(u="EMAIL"),o.push(new le.default.Separator(`${u}: ${d.identity}`))}),o.push({name:"Edit Delete More",value:`menu:${p.id}`})}),o.push(new le.default.Separator("")),o.push({name:"\u2190 Exit",value:"exit"});let{action:r}=await le.default.prompt([{type:"list",name:"action",message:"Contacts",choices:o,pageSize:20}]);if(r==="exit")break;if(!r||!r.includes(":"))continue;let[s,a]=r.split(":"),l=e.find(p=>p.id===a);if(s==="menu"){let p=this.buildContactMenu(l),{subAction:d}=await le.default.prompt([{type:"list",name:"subAction",message:`Actions for ${l.display_name||"contact"}:`,choices:p}]);if(d==="back")continue;await this.handleAction(d,l,a,e)&&(t=!1)}}}},ze=new jr.Command("contacts");ze.description("Manage conversation contacts");ze.command("create").description("Create a new contact").option("-p, --phone <number>","Phone number").option("-e, --email <email>","Email address").option("-n, --name <name>","Contact name").option("-d, --display-name <name>","Display name").option("--json","Output result as JSON").action(async i=>{try{if(!i.phone&&!i.email){let s=await le.default.prompt([{type:"input",name:"phone",message:"Enter phone number (optional):",validate:a=>a&&!a.startsWith("+")?"Phone number must start with +":!0},{type:"input",name:"email",message:"Enter email address (optional):"},{type:"input",name:"name",message:"Enter contact name (optional):"}]);i={...i,...s}}!i.phone&&!i.email&&(n.error("At least one of phone or email is required"),process.exit(1));let e=await U();c.start("Creating contact...");let t=[];i.phone&&t.push({channel:"SMS",identity:i.phone}),i.email&&t.push({channel:"EMAIL",identity:i.email});let o={contactCreateRequestBody:{channel_identities:t,display_name:i.displayName||i.name,language:"EN_US"}},r=await e.conversation.contact.create(o);c.succeed("Contact created successfully!"),i.json||(n.newline(),n.info(`Contact ID: ${r.id}`),n.info(`Display Name: ${r.display_name||"N/A"}`),i.phone&&n.info(`Phone: ${q(i.phone)}`),i.email&&n.info(`Email: ${i.email}`))}catch(e){c.stop(),n.error(`Failed to create contact: ${e.message}`),e.response?.data&&n.error("API Response:",JSON.stringify(e.response.data,null,2)),e.data&&n.error("Error data:",JSON.stringify(e.data,null,2)),process.exit(1)}});ze.command("get").description("Get a specific contact by ID").argument("<contact-id>","Contact ID to retrieve").option("--json","Output result as JSON").action(async(i,e)=>{try{let t=await U();c.start("Fetching contact...");let o=await t.conversation.contact.get({contact_id:i});c.succeed("Contact retrieved"),e.json?console.log(JSON.stringify(o,null,2)):new Cn(t).showDetails(o)}catch(t){c.stop(),n.error(`Failed to get contact: ${t.message}`),process.exit(1)}});ze.command("list").description("List contacts").option("-l, --limit <number>","Limit number of results",parseInt,50).option("--json","Output result as JSON").option("--no-interactive","Disable interactive mode").action(async i=>{try{let e=await U();c.start("Fetching contacts...");let t=await e.conversation.contact.list({page_size:i.limit||50}),o=t.data||t.contacts||[];if(c.succeed(`Retrieved ${o.length} contacts`),i.json){console.log(JSON.stringify(t,null,2));return}o&&o.length>0?(n.newline(),n.newline(),i.interactive!==!1?await new Cn(e).runInteractiveList(o):o.forEach(r=>{n.info(r.display_name||"No name"),r.channel_identities&&r.channel_identities.length>0&&r.channel_identities.forEach(s=>{let a=s.channel;a==="CHANNEL_UNSPECIFIED"&&s.identity.includes("@")&&(a="EMAIL"),n.info(`${a}: ${s.identity}`)}),n.newline()})):(n.newline(),n.info("No contacts found"))}catch(e){c.stop(),n.error(`Failed to list contacts: ${e.message}`),process.exit(1)}});ze.command("update").description("Update a contact").argument("<contact-id>","Contact ID to update").option("-n, --name <name>","New contact name").option("-d, --display-name <name>","New display name").option("--json","Output result as JSON").action(async(i,e)=>{try{!e.displayName&&!e.name&&(n.error("At least one update field is required (--name or --display-name)"),process.exit(1));let t=await U();c.start("Updating contact...");let o=await t.conversation.contact.update({contact_id:i,display_name:e.displayName||e.name,...e.name&&{metadata:JSON.stringify({name:e.name})}});c.succeed("Contact updated successfully!"),e.json?console.log(JSON.stringify(o,null,2)):(n.newline(),n.info(`Contact ID: ${o.id}`),n.info(`Display Name: ${o.display_name||"N/A"}`))}catch(t){c.stop(),n.error(`Failed to update contact: ${t.message}`),process.exit(1)}});ze.command("delete").description("Delete a contact").argument("<contact-id>","Contact ID to delete").action(async i=>{try{let e=await U();c.start("Deleting contact..."),await e.conversation.contact.delete({contact_id:i}),c.succeed("Contact deleted successfully")}catch(e){c.stop(),n.error(`Failed to delete contact: ${e.message}`),process.exit(1)}});ze.command("merge").description("Merge two contacts").argument("<source-id>","Source contact ID (will be merged into destination)").argument("<dest-id>","Destination contact ID").option("--json","Output result as JSON").action(async(i,e,t)=>{try{let o=await U();c.start("Merging contacts...");let r=await o.conversation.contact.mergeContact({destination_id:e,source_id:i});c.succeed("Contacts merged successfully!"),t.json?console.log(JSON.stringify(r,null,2)):(n.newline(),n.info(`Source contact ${i} merged into ${e}`),n.info(`Result Contact ID: ${r.id}`))}catch(o){c.stop(),n.error(`Failed to merge contacts: ${o.message}`),process.exit(1)}});Lr.exports=ze});var qr=N((vp,Mr)=>{"use strict";var Ur=require("commander");T();R();at();var Xt=new Ur.Command("conversations");Xt.description("Manage conversations");Xt.command("list").description("List conversations").option("-a, --app <app-id>","Filter by Conversation App ID").option("-l, --limit <number>","Limit number of results",parseInt,50).option("--json","Output result as JSON").action(async i=>{try{let e=await U();c.start("Fetching conversations...");let t=await e.conversation.conversation.list({page_size:i.limit||50,...i.app&&{app_id:i.app}});c.succeed(`Retrieved ${t.conversations?.length||0} conversations`),i.json?console.log(JSON.stringify(t,null,2)):(n.newline(),t.conversations&&t.conversations.length>0?t.conversations.forEach(o=>{n.info(`[${o.id}]`),n.info(` App ID: ${o.app_id}`),n.info(` Active: ${o.active_channel||"N/A"}`),n.info(` Last Updated: ${o.last_received?new Date(o.last_received).toLocaleString():"N/A"}`),n.newline()}):n.info("No conversations found"))}catch(e){c.stop(),n.error(`Failed to list conversations: ${e.message}`),process.exit(1)}});Xt.command("get").description("Get a specific conversation by ID").argument("<conversation-id>","Conversation ID to retrieve").option("--json","Output result as JSON").action(async(i,e)=>{try{let t=await U();c.start("Fetching conversation...");let o=await t.conversation.conversation.get({conversation_id:i});c.succeed("Conversation retrieved"),e.json?console.log(JSON.stringify(o,null,2)):(n.newline(),n.info(`Conversation ID: ${o.id}`),n.info(`App ID: ${o.app_id}`),n.info(`Active Channel: ${o.active_channel||"N/A"}`),n.info(`Contact ID: ${o.contact_id||"N/A"}`),o.metadata&&(n.newline(),n.info("Metadata:"),n.info(JSON.stringify(o.metadata,null,2))))}catch(t){c.stop(),n.error(`Failed to get conversation: ${t.message}`),process.exit(1)}});Xt.command("stop").description("Stop an active conversation").argument("<conversation-id>","Conversation ID to stop").action(async i=>{try{let e=await U();c.start("Stopping conversation..."),await e.conversation.conversation.delete({conversation_id:i}),c.succeed("Conversation stopped successfully")}catch(e){c.stop(),n.error(`Failed to stop conversation: ${e.message}`),process.exit(1)}});Mr.exports=Xt});var Br=N(($p,Vr)=>{"use strict";var Jr=require("commander"),gi=y(require("inquirer"));T();R();at();var $t=new Jr.Command("apps");$t.description("Manage Conversation apps");$t.command("list").description("List Conversation apps").option("-l, --limit <number>","Limit number of results",parseInt,50).option("--json","Output result as JSON").action(async i=>{try{let e=await U();c.start("Fetching apps...");let t=await e.conversation.app.list({page_size:i.limit||50});c.succeed(`Retrieved ${t.apps?.length||0} apps`),i.json?console.log(JSON.stringify(t,null,2)):(n.newline(),t.apps&&t.apps.length>0?t.apps.forEach(o=>{n.info(`[${o.id}] ${o.display_name||"No name"}`),n.info(` Channels: ${o.channel_credentials?.length||0} configured`),n.newline()}):n.info("No apps found"))}catch(e){c.stop(),n.error(`Failed to list apps: ${e.message}`),process.exit(1)}});$t.command("get").description("Get a specific Conversation app by ID").argument("<app-id>","App ID to retrieve").option("--json","Output result as JSON").action(async(i,e)=>{try{let t=await U();c.start("Fetching app...");let o=await t.conversation.app.get({app_id:i});c.succeed("App retrieved"),e.json?console.log(JSON.stringify(o,null,2)):(n.newline(),n.info(`App ID: ${o.id}`),n.info(`Display Name: ${o.display_name||"N/A"}`),n.info("Rate Limits:",o.rate_limits||"N/A"),o.channel_credentials&&o.channel_credentials.length>0&&(n.newline(),n.info("Configured Channels:"),o.channel_credentials.forEach(r=>{n.info(` - ${r.channel}`)})),o.conversation_metadata_report_view&&(n.newline(),n.info(`Metadata Report: ${o.conversation_metadata_report_view}`)))}catch(t){c.stop(),n.error(`Failed to get app: ${t.message}`),process.exit(1)}});$t.command("create").description("Create a new Conversation app").argument("[name]","App display name").option("--json","Output result as JSON").action(async(i,e)=>{try{i||(i=(await gi.default.prompt([{type:"input",name:"name",message:"Enter app display name:",validate:s=>s?!0:"App name is required"}])).name);let t=await U();c.start("Creating app...");let o=await t.conversation.app.create({display_name:i});c.succeed("App created successfully!"),e?.json?console.log(JSON.stringify(o,null,2)):(n.newline(),n.info(`App ID: ${o.id}`),n.info(`Display Name: ${o.display_name}`),n.newline(),n.info("\u{1F4A1} Set as default: sinch config set conversation-app-id "+o.id))}catch(t){c.stop(),n.error(`Failed to create app: ${t.message}`),process.exit(1)}});$t.command("delete").description("Delete a Conversation app").argument("<app-id>","App ID to delete").action(async i=>{try{let{confirm:e}=await gi.default.prompt([{type:"confirm",name:"confirm",message:`Are you sure you want to delete app ${i}?`,default:!1}]);if(!e){n.info("Deletion cancelled");return}let t=await U();c.start("Deleting app..."),await t.conversation.app.delete({app_id:i}),c.succeed("App deleted successfully")}catch(e){c.stop(),n.error(`Failed to delete app: ${e.message}`),process.exit(1)}});Vr.exports=$t});var Wr=N((Tp,Hr)=>{"use strict";var Kr=require("commander"),hi=y(require("inquirer"));E();T();R();at();var Pt=new Kr.Command("webhooks");Pt.description("Manage webhooks for Conversation apps");Pt.command("list").description("List webhooks for a Conversation app").option("-a, --app <app-id>","Conversation App ID").option("--json","Output result as JSON").action(async i=>{try{let e=bt(i.app),t=await U();c.start("Fetching webhooks...");let o=await t.conversation.webhooks.list({app_id:e});c.succeed(`Retrieved ${o.webhooks?.length||0} webhooks`),i.json?console.log(JSON.stringify(o,null,2)):(n.newline(),o.webhooks&&o.webhooks.length>0?o.webhooks.forEach(r=>{n.info(`[${r.id}]`),n.info(` URL: ${r.target}`),n.info(` Triggers: ${r.triggers?.join(", ")||"N/A"}`),n.info(` Secret: ${r.secret?"********":"Not set"}`),n.newline()}):n.info("No webhooks found for this app"))}catch(e){c.stop(),n.error(`Failed to list webhooks: ${e.message}`),process.exit(1)}});Pt.command("create").description("Create a new webhook for a Conversation app").option("-a, --app <app-id>","Conversation App ID").option("-u, --url <url>","Webhook URL").option("-t, --triggers <triggers>","Comma-separated list of triggers (e.g., MESSAGE_INBOUND,MESSAGE_DELIVERY)").option("-s, --secret <secret>","Webhook secret for signature validation").option("--json","Output result as JSON").action(async i=>{try{await f.load(),await f.hasCredentials()||(n.error('Not authenticated. Run "sinch auth login" first.'),process.exit(1));let t=i.app;if(!t){let a=f.get("conversation-app-id");a&&(t=a,n.info(`Using default app: ${t}`))}if(!t||!i.url||!i.triggers){let a=await hi.default.prompt([{type:"input",name:"appId",message:"Enter Conversation App ID:",when:!t,validate:l=>l?!0:"App ID is required"},{type:"input",name:"url",message:"Enter webhook URL:",when:!i.url,validate:l=>{if(!l)return"URL is required";try{return new URL(l),!0}catch{return"Please enter a valid URL"}}},{type:"checkbox",name:"triggers",message:"Select webhook triggers:",when:!i.triggers,choices:["MESSAGE_INBOUND","MESSAGE_DELIVERY","MESSAGE_SUBMIT","EVENT_INBOUND","CONVERSATION_START","CONVERSATION_STOP","CONTACT_CREATE","CONTACT_DELETE","CONTACT_MERGE","CONTACT_UPDATE"],validate:l=>l.length>0?!0:"Select at least one trigger"},{type:"input",name:"secret",message:"Enter webhook secret (optional, press enter to skip):"}]);t=t||a.appId,i.url=i.url||a.url,i.triggers=i.triggers||a.triggers.join(","),i.secret=i.secret||a.secret}let o=await U(),r=i.triggers.split(",").map(a=>a.trim());c.start("Creating webhook...");let s=await o.conversation.webhooks.create({app_id:t,target:i.url,triggers:r,...i.secret&&{secret:i.secret}});c.succeed("Webhook created successfully!"),i.json?console.log(JSON.stringify(s,null,2)):(n.newline(),n.info(`Webhook ID: ${s.id}`),n.info(`URL: ${s.target}`),n.info(`Triggers: ${s.triggers?.join(", ")}`),i.secret&&n.info("Secret: ********"))}catch(e){c.stop(),n.error(`Failed to create webhook: ${e.message}`),process.exit(1)}});Pt.command("update").description("Update a webhook").argument("<webhook-id>","Webhook ID to update").option("-u, --url <url>","New webhook URL").option("-t, --triggers <triggers>","New comma-separated list of triggers").option("-s, --secret <secret>","New webhook secret").option("--json","Output result as JSON").action(async(i,e)=>{try{!e.url&&!e.triggers&&!e.secret&&(n.error("At least one update field is required (--url, --triggers, or --secret)"),process.exit(1));let t=await U(),o={};e.url&&(o.target=e.url),e.triggers&&(o.triggers=e.triggers.split(",").map(s=>s.trim())),e.secret&&(o.secret=e.secret),c.start("Updating webhook...");let r=await t.conversation.webhooks.update({webhook_id:i,...o});c.succeed("Webhook updated successfully!"),e.json?console.log(JSON.stringify(r,null,2)):(n.newline(),n.info(`Webhook ID: ${r.id}`),n.info(`URL: ${r.target}`),n.info(`Triggers: ${r.triggers?.join(", ")}`))}catch(t){c.stop(),n.error(`Failed to update webhook: ${t.message}`),process.exit(1)}});Pt.command("delete").description("Delete a webhook").argument("<webhook-id>","Webhook ID to delete").action(async i=>{try{let{confirm:e}=await hi.default.prompt([{type:"confirm",name:"confirm",message:`Are you sure you want to delete webhook ${i}?`,default:!1}]);if(!e){n.info("Deletion cancelled");return}let t=await U();c.start("Deleting webhook..."),await t.conversation.webhooks.delete({webhook_id:i}),c.succeed("Webhook deleted successfully")}catch(e){c.stop(),n.error(`Failed to delete webhook: ${e.message}`),process.exit(1)}});Hr.exports=Pt});var Yr=N((Np,Gr)=>{"use strict";var zr=require("commander"),Sc=Rr(),bc=Or(),Ic=_r(),$c=qr(),Pc=Br(),Ac=Wr(),Ge=new zr.Command("conversation");Ge.description("Manage Sinch Conversations API");Ge.addCommand(Sc);Ge.addCommand(bc);Ge.addCommand(Ic);Ge.addCommand($c);Ge.addCommand(Pc);Ge.addCommand(Ac);Gr.exports=Ge});var yi,vn,Xr,oe,Ye=G(()=>{"use strict";yi=y(require("axios")),vn=y(require("axios-retry")),Xr=y(require("chalk"));ut();Lt();oe=class{baseUrl="https://elastic-trunking.api.sinch.com";projectId;credentials;client;timeout=6e4;constructor(e){this.projectId=e.projectId,this.credentials=e.credentials,this.client=yi.default.create({baseURL:this.baseUrl,timeout:this.timeout,headers:{"Content-Type":"application/json","User-Agent":"sinch-functions-cli/1.0.0"}}),(0,vn.default)(this.client,{retries:3,retryDelay:(t,o)=>{let r=o.response?.headers?.["retry-after"];return r?parseInt(r,10)*1e3:vn.default.exponentialDelay(t)},retryCondition:t=>{if(vn.default.isNetworkError(t))return!0;let o=t.response?.status;return!!(o&&o>=500||o===429)},onRetry:(t,o)=>{Ce(1,`Retry ${t}/3: ${o.message}`)}}),this.client.interceptors.request.use(async t=>{let o=await this.getAuthHeader();return o&&(t.headers.Authorization=o),ae()>=2&&Ce(2,`\u2192 ${t.method?.toUpperCase()} ${t.url}`),t},t=>Promise.reject(t)),this.client.interceptors.response.use(t=>(ae()>=2&&Ce(2,`\u2190 ${t.status} ${t.config.url}`),t),t=>(ae()>=2&&Ce(2,`\u2190 ${t.response?.status||"ERROR"} ${t.config?.url}`),Promise.reject(t)))}async getAuthHeader(){try{let e=await this.credentials.retrieve();return e&&e.keyId&&e.keySecret?`Basic ${Buffer.from(`${e.keyId}:${e.keySecret}`).toString("base64")}`:null}catch{return console.error(Xr.default.yellow("Failed to get authentication credentials")),null}}async listTrunks(e={}){try{let t={};return e.page&&(t.pageToken=e.page),e.pageSize&&(t.pageSize=e.pageSize),(await this.client.get(`/v1/projects/${this.projectId}/trunks`,{params:t})).data}catch(t){throw this.handleError(t,"Failed to list SIP trunks")}}async getTrunk(e){try{return(await this.client.get(`/v1/projects/${this.projectId}/trunks/${e}`)).data}catch(t){throw this.handleError(t,`Failed to get SIP trunk ${e}`)}}async createTrunk(e){try{return(await this.client.post(`/v1/projects/${this.projectId}/trunks`,e)).data}catch(t){throw this.handleError(t,"Failed to create SIP trunk")}}async updateTrunk(e,t){try{return(await this.client.put(`/v1/projects/${this.projectId}/trunks/${e}`,t)).data}catch(o){throw this.handleError(o,`Failed to update SIP trunk ${e}`)}}async deleteTrunk(e){try{await this.client.delete(`/v1/projects/${this.projectId}/trunks/${e}`)}catch(t){throw this.handleError(t,`Failed to delete SIP trunk ${e}`)}}async listEndpoints(e,t={}){try{let o={};return t.page&&(o.pageToken=t.page),t.pageSize&&(o.pageSize=t.pageSize),(await this.client.get(`/v1/projects/${this.projectId}/trunks/${e}/endpoints`,{params:o})).data}catch(o){throw this.handleError(o,`Failed to list endpoints for trunk ${e}`)}}async getEndpoint(e,t){try{return(await this.client.get(`/v1/projects/${this.projectId}/trunks/${e}/endpoints/${t}`)).data}catch(o){throw this.handleError(o,`Failed to get endpoint ${t}`)}}async createEndpoint(e,t){try{return(await this.client.post(`/v1/projects/${this.projectId}/trunks/${e}/endpoints`,t)).data}catch(o){throw this.handleError(o,"Failed to create SIP endpoint")}}async updateEndpoint(e,t,o){try{return(await this.client.put(`/v1/projects/${this.projectId}/trunks/${e}/endpoints/${t}`,o)).data}catch(r){throw this.handleError(r,`Failed to update endpoint ${t}`)}}async deleteEndpoint(e,t){try{await this.client.delete(`/v1/projects/${this.projectId}/trunks/${e}/endpoints/${t}`)}catch(o){throw this.handleError(o,`Failed to delete endpoint ${t}`)}}async listAcls(e={}){try{let t={};return e.page&&(t.pageToken=e.page),e.pageSize&&(t.pageSize=e.pageSize),(await this.client.get(`/v1/projects/${this.projectId}/accessControlLists`,{params:t})).data}catch(t){throw this.handleError(t,"Failed to list ACLs")}}async getAcl(e){try{return(await this.client.get(`/v1/projects/${this.projectId}/accessControlLists/${e}`)).data}catch(t){throw this.handleError(t,`Failed to get ACL ${e}`)}}async createAcl(e){try{return(await this.client.post(`/v1/projects/${this.projectId}/accessControlLists`,e)).data}catch(t){throw this.handleError(t,"Failed to create ACL")}}async updateAcl(e,t){try{return(await this.client.put(`/v1/projects/${this.projectId}/accessControlLists/${e}`,t)).data}catch(o){throw this.handleError(o,`Failed to update ACL ${e}`)}}async deleteAcl(e){try{await this.client.delete(`/v1/projects/${this.projectId}/accessControlLists/${e}`)}catch(t){throw this.handleError(t,`Failed to delete ACL ${e}`)}}async getAclTrunks(e,t={}){try{let o={};return t.page&&(o.pageToken=t.page),t.pageSize&&(o.pageSize=t.pageSize),(await this.client.get(`/v1/projects/${this.projectId}/accessControlLists/${e}/trunks`,{params:o})).data}catch(o){throw this.handleError(o,`Failed to get trunks for ACL ${e}`)}}async listIpRanges(e,t={}){try{let o={};return t.page&&(o.pageToken=t.page),t.pageSize&&(o.pageSize=t.pageSize),(await this.client.get(`/v1/projects/${this.projectId}/accessControlLists/${e}/ipRanges`,{params:o})).data}catch(o){throw this.handleError(o,`Failed to list IP ranges for ACL ${e}`)}}async getIpRange(e,t){try{return(await this.client.get(`/v1/projects/${this.projectId}/accessControlLists/${e}/ipRanges/${t}`)).data}catch(o){throw this.handleError(o,`Failed to get IP range ${t}`)}}async addIpRange(e,t){try{return(await this.client.post(`/v1/projects/${this.projectId}/accessControlLists/${e}/ipRanges`,t)).data}catch(o){throw this.handleError(o,`Failed to add IP range to ACL ${e}`)}}async updateIpRange(e,t,o){try{return(await this.client.put(`/v1/projects/${this.projectId}/accessControlLists/${e}/ipRanges/${t}`,o)).data}catch(r){throw this.handleError(r,`Failed to update IP range ${t}`)}}async deleteIpRange(e,t){try{await this.client.delete(`/v1/projects/${this.projectId}/accessControlLists/${e}/ipRanges/${t}`)}catch(o){throw this.handleError(o,`Failed to delete IP range ${t}`)}}async listCountryPermissions(e={}){try{let t={};return e.page&&(t.pageToken=e.page),e.pageSize&&(t.pageSize=e.pageSize),(await this.client.get(`/v1/projects/${this.projectId}/countryPermissions`,{params:t})).data}catch(t){throw this.handleError(t,"Failed to list country permissions")}}async getCountryPermission(e){try{return(await this.client.get(`/v1/projects/${this.projectId}/countryPermissions/${e}`)).data}catch(t){throw this.handleError(t,`Failed to get country permission for ${e}`)}}async updateCountryPermission(e,t){try{return(await this.client.put(`/v1/projects/${this.projectId}/countryPermissions/${e}`,{enabled:t})).data}catch(o){throw this.handleError(o,`Failed to update country permission for ${e}`)}}async listTrunkAcls(e,t={}){try{let o={};return t.page&&(o.pageToken=t.page),t.pageSize&&(o.pageSize=t.pageSize),(await this.client.get(`/v1/projects/${this.projectId}/trunks/${e}/accessControlLists`,{params:o})).data}catch(o){throw this.handleError(o,`Failed to list ACLs for trunk ${e}`)}}async addTrunkAcl(e,t){try{await this.client.post(`/v1/projects/${this.projectId}/trunks/${e}/accessControlLists`,{accessControlListId:t})}catch(o){throw this.handleError(o,`Failed to add ACL ${t} to trunk ${e}`)}}async removeTrunkAcl(e,t){try{await this.client.delete(`/v1/projects/${this.projectId}/trunks/${e}/accessControlLists/${t}`)}catch(o){throw this.handleError(o,`Failed to remove ACL ${t} from trunk ${e}`)}}async getCredentialListTrunks(e,t={}){try{let o={};return t.page&&(o.pageNumber=t.page),t.pageSize&&(o.pageSize=t.pageSize),(await this.client.get(`/v1/projects/${this.projectId}/credentialLists/${e}/trunks`,{params:o})).data}catch(o){throw this.handleError(o,`Failed to get trunks for credential list ${e}`)}}async updateTrunkCredentialLists(e,t){try{return(await this.client.put(`/v1/projects/${this.projectId}/trunks/${e}/credentialLists`,{credentialListIds:t})).data}catch(o){throw this.handleError(o,`Failed to update credential lists for trunk ${e}`)}}async findCalls(e={}){try{let t={};return e.from&&(t.from=e.from),e.to&&(t.to=e.to),e.trunkId&&(t.trunkId=e.trunkId),e.createTime&&(t.createTime=e.createTime),e.callResult&&(t.callResult=e.callResult),e.direction&&(t.direction=e.direction),e.page&&(t.pageNumber=e.page),e.pageSize&&(t.pageSize=e.pageSize),(await this.client.get(`/v1/projects/${this.projectId}/calls`,{params:t})).data}catch(t){throw this.handleError(t,"Failed to find calls")}}async getCall(e){try{return(await this.client.get(`/v1/projects/${this.projectId}/calls/${e}`)).data}catch(t){throw this.handleError(t,`Failed to get call ${e}`)}}handleError(e,t){if(yi.default.isAxiosError(e)){let o=e;if(o.response){let r=o.response.status,s=o.response.data,a=s?.message||s?.error||o.message;throw r===401?new D('Authentication required. Please run "sinch auth login" first.',I.AUTH_REQUIRED):r===403?new D(`Permission denied: ${a}`,I.NO_PERMISSION):r===404?new D(`Resource not found: ${a}`,I.NOT_FOUND):r===429?new D(`Rate limited: ${a}`,I.UNAVAILABLE):r>=500?new D(`Server error: ${a}`,I.UNAVAILABLE):new D(`${t}: ${a}`,I.FAILURE)}else throw o.request?o.code==="ECONNREFUSED"?new D(`Cannot connect to EST API at ${this.baseUrl}`,I.UNAVAILABLE):o.code==="ETIMEDOUT"?new D(`Request timeout after ${this.timeout}ms`,I.TIMEOUT):new D(`${t}: No response from server (${o.code||"unknown error"})`,I.IO_ERROR):new D(`${t}: ${o.message}`,I.FAILURE)}else throw new D(`${t}: ${e.message||e}`,I.FAILURE)}}});var Qr=N((qp,Zr)=>{"use strict";var Sn=require("commander"),_e=y(require("inquirer"));T();R();E();Ye();async function Ue(){await f.load(),await f.hasCredentials()||(n.error('Not authenticated. Run "sinch auth login" first.'),process.exit(1));let e=f.getApiConfig();return new oe({projectId:e.projectId,credentials:e.credentials})}function wi(i){n.info(`ID: ${i.id}`),n.info(`Name: ${i.name}`),i.hostName&&n.info(`Host: ${i.hostName}`),n.info(`Caller ID: ${i.enableCallerId?"enabled":"disabled"}`),i.createTime&&n.info(`Created: ${new Date(i.createTime).toLocaleString()}`),i.updateTime&&n.info(`Updated: ${new Date(i.updateTime).toLocaleString()}`)}var Me=new Sn.Command("trunks");Me.description("Manage SIP trunks");Me.command("list").description("List all SIP trunks").option("-l, --limit <number>","Limit number of results",parseInt,50).option("--json","Output result as JSON").action(async i=>{try{let e=await Ue();c.start("Fetching SIP trunks...");let t=await e.listTrunks({pageSize:i.limit});c.succeed(`Retrieved ${t.trunks?.length||0} trunk(s)`),i.json?console.log(JSON.stringify(t,null,2)):(n.newline(),t.trunks&&t.trunks.length>0?t.trunks.forEach(o=>{n.info(`[${o.id}] ${o.name}`),o.hostName&&n.info(` Host: ${o.hostName}`),n.info(` Caller ID: ${o.enableCallerId?"enabled":"disabled"}`),n.newline()}):(n.info("No SIP trunks found"),n.newline(),n.info("Create one with: sinch sip trunks create")))}catch(e){c.stop(),n.error(`Failed to list trunks: ${e.message}`),process.exit(1)}});Me.command("get").description("Get a SIP trunk by ID").argument("<trunk-id>","Trunk ID to retrieve").option("--json","Output result as JSON").action(async(i,e)=>{try{let t=await Ue();c.start("Fetching trunk...");let o=await t.getTrunk(i);c.succeed("Trunk retrieved"),e.json?console.log(JSON.stringify(o,null,2)):(n.newline(),wi(o))}catch(t){c.stop(),n.error(`Failed to get trunk: ${t.message}`),process.exit(1)}});Me.command("create").description("Create a new SIP trunk").option("-n, --name <name>","Trunk name (required)").option("-h, --host-name <hostname>","Host name for the trunk (required)").option("--caller-id","Enable caller ID").option("--non-interactive","Skip prompts, use defaults for missing options").option("--json","Output result as JSON").action(async i=>{try{let e=i.name,t=i.hostName,o=i.callerId??!1,r=!i.nonInteractive;e||(r?e=(await _e.default.prompt([{type:"input",name:"name",message:"Enter trunk name:",validate:p=>p?!0:"Trunk name is required"}])).name:(n.error("Name is required. Use --name <name>"),process.exit(1))),t||(r?t=(await _e.default.prompt([{type:"input",name:"hostName",message:"Enter host name:",validate:p=>p?!0:"Host name is required"}])).hostName:(n.error("Host name is required. Use --host-name <hostname>"),process.exit(1))),i.callerId===void 0&&r&&(o=(await _e.default.prompt([{type:"confirm",name:"enableCallerId",message:"Enable caller ID?",default:!1}])).enableCallerId);let s=await Ue();c.start("Creating SIP trunk...");let a=await s.createTrunk({name:e,hostName:t,enableCallerId:o});c.succeed("SIP trunk created successfully!"),i.json?console.log(JSON.stringify(a,null,2)):(n.newline(),wi(a),n.newline(),n.info(`Add an endpoint: sinch sip endpoints create ${a.id}`))}catch(e){c.stop(),n.error(`Failed to create trunk: ${e.message}`),process.exit(1)}});Me.command("update").description("Update a SIP trunk").argument("<trunk-id>","Trunk ID to update").option("-n, --name <name>","New trunk name").option("-h, --host-name <hostname>","New host name").option("--caller-id","Enable caller ID").option("--no-caller-id","Disable caller ID").option("--non-interactive","Skip prompts, use current values for missing options").option("--json","Output result as JSON").action(async(i,e)=>{try{let t=await Ue();c.start("Fetching current trunk details...");let o=await t.getTrunk(i);c.stop();let r=e.name,s=e.hostName,a=e.callerId,l=!e.nonInteractive;r||(l?r=(await _e.default.prompt([{type:"input",name:"name",message:"Enter trunk name:",default:o.name,validate:u=>u?!0:"Trunk name is required"}])).name:r=o.name),s===void 0&&(l?s=(await _e.default.prompt([{type:"input",name:"hostName",message:"Enter host name:",default:o.hostName||""}])).hostName||void 0:s=o.hostName),a===void 0&&(l?a=(await _e.default.prompt([{type:"confirm",name:"enableCallerId",message:"Enable caller ID?",default:o.enableCallerId??!1}])).enableCallerId:a=o.enableCallerId),c.start("Updating SIP trunk...");let p=await t.updateTrunk(i,{name:r,hostName:s,enableCallerId:a});c.succeed("SIP trunk updated successfully!"),e.json?console.log(JSON.stringify(p,null,2)):(n.newline(),wi(p))}catch(t){c.stop(),n.error(`Failed to update trunk: ${t.message}`),process.exit(1)}});Me.command("delete").description("Delete a SIP trunk").argument("<trunk-id>","Trunk ID to delete").option("-f, --force","Skip confirmation prompt").action(async(i,e)=>{try{if(!e.force){let{confirm:o}=await _e.default.prompt([{type:"confirm",name:"confirm",message:`Are you sure you want to delete trunk ${i}?`,default:!1}]);if(!o){n.info("Deletion cancelled");return}}let t=await Ue();c.start("Deleting SIP trunk..."),await t.deleteTrunk(i),c.succeed("SIP trunk deleted successfully")}catch(t){c.stop(),n.error(`Failed to delete trunk: ${t.message}`),process.exit(1)}});var Zt=new Sn.Command("acls");Zt.description("Manage ACLs for a trunk");Zt.command("list").description("List ACLs associated with a trunk").argument("<trunk-id>","Trunk ID").option("-l, --limit <number>","Limit number of results",parseInt,50).option("--json","Output result as JSON").action(async(i,e)=>{try{let t=await Ue();c.start("Fetching trunk ACLs...");let o=await t.listTrunkAcls(i,{pageSize:e.limit});c.succeed(`Retrieved ${o.accessControlLists?.length||0} ACL(s)`),e.json?console.log(JSON.stringify(o,null,2)):(n.newline(),o.accessControlLists&&o.accessControlLists.length>0?o.accessControlLists.forEach(r=>{let s=r.enabled!==!1?"":" (disabled)";n.info(`[${r.id}] ${r.name}${s}`),n.newline()}):(n.info("No ACLs associated with this trunk"),n.newline(),n.info(`Add an ACL: sinch sip trunks acls add ${i} <acl-id>`)))}catch(t){c.stop(),n.error(`Failed to list trunk ACLs: ${t.message}`),process.exit(1)}});Zt.command("add").description("Add an ACL to a trunk").argument("<trunk-id>","Trunk ID").argument("<acl-id>","ACL ID to add").option("--json","Output result as JSON").action(async(i,e,t)=>{try{let o=await Ue();c.start(`Adding ACL ${e} to trunk ${i}...`),await o.addTrunkAcl(i,e),c.succeed("ACL added to trunk successfully"),t.json||(n.newline(),n.info(`ACL ${e} is now associated with trunk ${i}`))}catch(o){c.stop(),n.error(`Failed to add ACL to trunk: ${o.message}`),process.exit(1)}});Zt.command("remove").description("Remove an ACL from a trunk").argument("<trunk-id>","Trunk ID").argument("<acl-id>","ACL ID to remove").option("-f, --force","Skip confirmation prompt").action(async(i,e,t)=>{try{if(!t.force){let{confirm:r}=await _e.default.prompt([{type:"confirm",name:"confirm",message:`Remove ACL ${e} from trunk ${i}?`,default:!1}]);if(!r){n.info("Operation cancelled");return}}let o=await Ue();c.start("Removing ACL from trunk..."),await o.removeTrunkAcl(i,e),c.succeed("ACL removed from trunk successfully")}catch(o){c.stop(),n.error(`Failed to remove ACL from trunk: ${o.message}`),process.exit(1)}});Me.addCommand(Zt);var Ci=new Sn.Command("credential-lists");Ci.description("Manage credential lists for a trunk");Ci.command("update").description("Bulk update credential lists for a trunk").argument("<trunk-id>","Trunk ID").argument("<credential-list-ids...>","Credential list IDs to assign (space-separated)").option("--json","Output result as JSON").action(async(i,e,t)=>{try{let o=await Ue();c.start(`Updating credential lists for trunk ${i}...`);let r=await o.updateTrunkCredentialLists(i,e);if(c.succeed("Credential lists updated successfully"),t.json)console.log(JSON.stringify(r,null,2));else{n.newline();let s=r?.credentialListIds??[];n.info(`Trunk ${i} now uses ${s.length} credential list(s):`),s.forEach(a=>{n.info(` - ${a}`)})}}catch(o){c.stop(),n.error(`Failed to update credential lists: ${o.message}`),process.exit(1)}});Me.addCommand(Ci);Zr.exports=Me});var ns=N((Wp,ts)=>{"use strict";var es=require("commander"),Re=y(require("inquirer"));T();R();E();Ye();async function Qt(){await f.load(),await f.hasCredentials()||(n.error('Not authenticated. Run "sinch auth login" first.'),process.exit(1));let e=f.getApiConfig();return new oe({projectId:e.projectId,credentials:e.credentials})}async function vi(i,e){c.start("Looking up endpoint...");let o=(await i.listTrunks()).trunks||[];for(let r of o)if(((await i.listEndpoints(r.id)).endpoints||[]).find(p=>p.id===e))return c.stop(),r.id;throw c.stop(),new Error(`Endpoint ${e} not found`)}function Si(i){if(n.info(`ID: ${i.id}`),n.info(`Name: ${i.name}`),i.address){let e=i.port?`${i.address}:${i.port}`:i.address;n.info(`Address: ${e}`)}i.transport&&n.info(`Transport: ${i.transport}`),n.info(`Priority: ${i.priority}`),n.info(`Enabled: ${i.enabled!==!1?"yes":"no"}`),i.createTime&&n.info(`Created: ${new Date(i.createTime).toLocaleString()}`),i.updateTime&&n.info(`Updated: ${new Date(i.updateTime).toLocaleString()}`)}var ct=new es.Command("endpoints");ct.description("Manage SIP endpoints");ct.command("list").description("List all SIP endpoints for a trunk").argument("<trunk-id>","Trunk ID").option("-l, --limit <number>","Limit number of results",parseInt,50).option("--json","Output result as JSON").action(async(i,e)=>{try{let t=await Qt();c.start("Fetching SIP endpoints...");let o=await t.listEndpoints(i,{pageSize:e.limit});c.succeed(`Retrieved ${o.endpoints?.length||0} endpoint(s)`),e.json?console.log(JSON.stringify(o,null,2)):(n.newline(),o.endpoints&&o.endpoints.length>0?o.endpoints.forEach(r=>{let s=r.enabled!==!1?"":" (disabled)",a=r.port?`${r.address}:${r.port}`:r.address;n.info(`[${r.id}] ${r.name}${s}`),n.info(` Address: ${a||"N/A"}`),n.info(` Priority: ${r.priority}, Transport: ${r.transport||"UDP"}`),n.newline()}):(n.info("No endpoints found for this trunk"),n.newline(),n.info(`Create one with: sinch sip endpoints create ${i}`)))}catch(t){c.stop(),n.error(`Failed to list endpoints: ${t.message}`),process.exit(1)}});ct.command("get").description("Get a SIP endpoint by ID").argument("<endpoint-id>","Endpoint ID to retrieve").option("--json","Output result as JSON").action(async(i,e)=>{try{let t=await Qt(),o=await vi(t,i);c.start("Fetching endpoint...");let r=await t.getEndpoint(o,i);c.succeed("Endpoint retrieved"),e.json?console.log(JSON.stringify(r,null,2)):(n.newline(),Si(r))}catch(t){c.stop(),n.error(`Failed to get endpoint: ${t.message}`),process.exit(1)}});ct.command("create").description("Create a new SIP endpoint").argument("<trunk-id>","Trunk ID to add endpoint to").option("-n, --name <name>","Endpoint name (required)").option("-a, --address <address>","SIP address (IP or hostname, without port)").option("--port <number>","SIP port (default: 5060)",parseInt).option("-t, --transport <transport>","Transport protocol: UDP, TCP, or TLS (default: UDP)").option("-p, --priority <number>","Priority (required, lower = higher priority)",parseInt).option("--non-interactive","Skip prompts, use defaults for missing options").option("--json","Output result as JSON").action(async(i,e)=>{try{let t=e.name,o=e.address,r=e.port,s=e.transport,a=e.priority,l=!e.nonInteractive;t||(l?t=(await Re.default.prompt([{type:"input",name:"name",message:"Enter endpoint name:",validate:m=>m?!0:"Endpoint name is required"}])).name:(n.error("Name is required. Use --name <name>"),process.exit(1))),o||(l?o=(await Re.default.prompt([{type:"input",name:"address",message:"Enter SIP address (IP or hostname):",validate:m=>m?!0:"SIP address is required"}])).address:(n.error("Address is required. Use --address <address>"),process.exit(1))),r===void 0&&l&&(r=(await Re.default.prompt([{type:"input",name:"port",message:"Enter SIP port (default 5060):",default:"5060",filter:m=>m?parseInt(m,10):5060}])).port),a===void 0&&(l?a=(await Re.default.prompt([{type:"input",name:"priority",message:"Enter priority (lower = higher priority):",default:"1",filter:m=>parseInt(m,10),validate:m=>{let w=parseInt(m,10);return isNaN(w)?"Please enter a valid number":!0}}])).priority:(n.error("Priority is required. Use --priority <number>"),process.exit(1)));let p=await Qt();c.start("Creating SIP endpoint...");let d=await p.createEndpoint(i,{name:t,address:o,port:r,transport:s,priority:a});c.succeed("SIP endpoint created successfully!"),e.json?console.log(JSON.stringify(d,null,2)):(n.newline(),Si(d))}catch(t){c.stop(),n.error(`Failed to create endpoint: ${t.message}`),process.exit(1)}});ct.command("update").description("Update a SIP endpoint").argument("<endpoint-id>","Endpoint ID to update").option("-n, --name <name>","New endpoint name").option("-a, --address <address>","New SIP address").option("--port <number>","New SIP port",parseInt).option("-t, --transport <transport>","Transport protocol: UDP, TCP, or TLS").option("-p, --priority <number>","New priority",parseInt).option("--non-interactive","Skip prompts, use current values for missing options").option("--json","Output result as JSON").action(async(i,e)=>{try{let t=await Qt(),o=await vi(t,i);c.start("Fetching current endpoint details...");let r=await t.getEndpoint(o,i);c.stop();let s=e.name,a=e.address,l=e.port,p=e.transport,d=e.priority,u=!e.nonInteractive;s||(u?s=(await Re.default.prompt([{type:"input",name:"name",message:"Enter endpoint name:",default:r.name,validate:h=>h?!0:"Name is required"}])).name:s=r.name),a||(u?a=(await Re.default.prompt([{type:"input",name:"address",message:"Enter SIP address:",default:r.address,validate:h=>h?!0:"SIP address is required"}])).address:a=r.address||""),l===void 0&&(u?l=(await Re.default.prompt([{type:"input",name:"port",message:"Enter SIP port:",default:(r.port||5060).toString(),filter:h=>parseInt(h,10)}])).port:l=r.port),d===void 0&&(u?d=(await Re.default.prompt([{type:"input",name:"priority",message:"Enter priority:",default:r.priority.toString(),filter:h=>parseInt(h,10)}])).priority:d=r.priority),c.start("Updating SIP endpoint...");let m=await t.updateEndpoint(o,i,{name:s,address:a,port:l,transport:p,priority:d});c.succeed("SIP endpoint updated successfully!"),e.json?console.log(JSON.stringify(m,null,2)):(n.newline(),Si(m))}catch(t){c.stop(),n.error(`Failed to update endpoint: ${t.message}`),process.exit(1)}});ct.command("delete").description("Delete a SIP endpoint").argument("<endpoint-id>","Endpoint ID to delete").option("-f, --force","Skip confirmation prompt").action(async(i,e)=>{try{let t=await Qt(),o=await vi(t,i);if(!e.force){let{confirm:r}=await Re.default.prompt([{type:"confirm",name:"confirm",message:`Are you sure you want to delete endpoint ${i}?`,default:!1}]);if(!r){n.info("Deletion cancelled");return}}c.start("Deleting SIP endpoint..."),await t.deleteEndpoint(o,i),c.succeed("SIP endpoint deleted successfully")}catch(t){c.stop(),n.error(`Failed to delete endpoint: ${t.message}`),process.exit(1)}});ts.exports=ct});var rs=N((eu,os)=>{"use strict";var bi=require("commander"),Z=y(require("inquirer"));T();R();E();Ye();async function De(){await f.load(),await f.hasCredentials()||(n.error('Not authenticated. Run "sinch auth login" first.'),process.exit(1));let e=f.getApiConfig();return new oe({projectId:e.projectId,credentials:e.credentials})}function Ii(i){n.info(`ID: ${i.id}`),n.info(`Name: ${i.name}`),n.info(`Enabled: ${i.enabled!==!1?"yes":"no"}`),i.createTime&&n.info(`Created: ${new Date(i.createTime).toLocaleString()}`),i.updateTime&&n.info(`Updated: ${new Date(i.updateTime).toLocaleString()}`)}function is(i){n.info(`ID: ${i.id}`),i.description&&n.info(`Description: ${i.description}`),i.ipAddress&&n.info(`IP Address: ${i.ipAddress}`),i.range&&n.info(`CIDR Range: ${i.range}`),i.createTime&&n.info(`Created: ${new Date(i.createTime).toLocaleString()}`)}function lt(i){return/^(\d{1,3}\.){3}\d{1,3}$/.test(i)?i.split(".").every(o=>{let r=parseInt(o,10);return r>=0&&r<=255}):!1}function bn(i){if(!/^(\d{1,3}\.){3}\d{1,3}\/\d{1,2}$/.test(i))return!1;let t=i.split("/");if(t.length!==2)return!1;let o=t[0],r=t[1];if(!o||!r)return!1;let s=parseInt(r,10);return lt(o)&&s>=0&&s<=32}var qe=new bi.Command("acls");qe.description("Manage Access Control Lists (ACLs)");qe.command("list").description("List all Access Control Lists").option("-l, --limit <number>","Limit number of results",parseInt,50).option("--json","Output result as JSON").action(async i=>{try{let e=await De();c.start("Fetching ACLs...");let t=await e.listAcls({pageSize:i.limit});c.succeed(`Retrieved ${t.accessControlLists?.length||0} ACL(s)`),i.json?console.log(JSON.stringify(t,null,2)):(n.newline(),t.accessControlLists&&t.accessControlLists.length>0?t.accessControlLists.forEach(o=>{let r=o.enabled!==!1?"":" (disabled)";n.info(`[${o.id}] ${o.name}${r}`),n.newline()}):(n.info("No ACLs found"),n.newline(),n.info("Create one with: sinch sip acls create")))}catch(e){c.stop(),n.error(`Failed to list ACLs: ${e.message}`),process.exit(1)}});qe.command("get").description("Get an ACL by ID").argument("<acl-id>","ACL ID to retrieve").option("--json","Output result as JSON").action(async(i,e)=>{try{let t=await De();c.start("Fetching ACL...");let o=await t.getAcl(i);c.succeed("ACL retrieved"),e.json?console.log(JSON.stringify(o,null,2)):(n.newline(),Ii(o))}catch(t){c.stop(),n.error(`Failed to get ACL: ${t.message}`),process.exit(1)}});qe.command("create").description("Create a new Access Control List").option("-n, --name <name>","ACL name (required)").option("--enabled","Enable the ACL (default: true)").option("--disabled","Create ACL in disabled state").option("-i, --ip <address>","IP address for initial IP range (required)").option("-r, --range <cidr>","CIDR mask for IP range (default: 32)",parseInt).option("--ip-description <text>","Description for the IP range").option("--non-interactive","Skip prompts, use defaults for missing options").option("--json","Output result as JSON").action(async i=>{try{let e=i.name,t=i.enabled??!i.disabled,o=i.ip,r=i.range,s=i.ipDescription,a=!i.nonInteractive;e||(a?e=(await Z.default.prompt([{type:"input",name:"name",message:"Enter ACL name:",validate:m=>m?!0:"ACL name is required"}])).name:(n.error("Name is required. Use --name <name>"),process.exit(1))),i.enabled===void 0&&!i.disabled&&a&&(t=(await Z.default.prompt([{type:"confirm",name:"enabled",message:"Enable ACL?",default:!0}])).enabled),o?lt(o)||(n.error(`Invalid IP address format: ${o}`),process.exit(1)):a?o=(await Z.default.prompt([{type:"input",name:"ipAddress",message:"Enter IP address for initial IP range (required):",validate:m=>m?lt(m)?!0:"Invalid IP address format":"At least one IP range is required to create an ACL"}])).ipAddress:(n.error("IP address is required. Use --ip <address>"),process.exit(1)),r===void 0&&a&&(r=(await Z.default.prompt([{type:"input",name:"range",message:"Enter CIDR mask (default 32):",default:"32",filter:m=>parseInt(m,10),validate:m=>{let w=parseInt(m,10);return!isNaN(w)&&w>=0&&w<=32?!0:"Please enter a number between 0 and 32"}}])).range),s===void 0&&a&&(s=(await Z.default.prompt([{type:"input",name:"description",message:"Enter IP range description (optional):"}])).description||void 0);let l=await De(),p={ipAddress:o};r!==void 0&&(p.range=r),s&&(p.description=s),c.start("Creating ACL...");let d=await l.createAcl({name:e,enabled:t,ipRanges:[p]});c.succeed("ACL created successfully!"),i.json?console.log(JSON.stringify(d,null,2)):(n.newline(),Ii(d),n.newline(),n.info(`Add an IP range: sinch sip acls ip-ranges add ${d.id}`))}catch(e){c.stop(),n.error(`Failed to create ACL: ${e.message}`),process.exit(1)}});qe.command("update").description("Update an ACL").argument("<acl-id>","ACL ID to update").option("-n, --name <name>","New ACL name").option("--enabled","Enable the ACL").option("--disabled","Disable the ACL").option("--non-interactive","Skip prompts, use current values for missing options").option("--json","Output result as JSON").action(async(i,e)=>{try{let t=await De();c.start("Fetching current ACL details...");let o=await t.getAcl(i);c.stop();let r=e.name,s;e.enabled?s=!0:e.disabled&&(s=!1);let a=!e.nonInteractive;r||(a?r=(await Z.default.prompt([{type:"input",name:"name",message:"Enter ACL name:",default:o.name,validate:d=>d?!0:"ACL name is required"}])).name:r=o.name),s===void 0&&(a?s=(await Z.default.prompt([{type:"confirm",name:"enabled",message:"Enable ACL?",default:o.enabled??!0}])).enabled:s=o.enabled),c.start("Updating ACL...");let l=await t.updateAcl(i,{name:r,enabled:s});c.succeed("ACL updated successfully!"),e.json?console.log(JSON.stringify(l,null,2)):(n.newline(),Ii(l))}catch(t){c.stop(),n.error(`Failed to update ACL: ${t.message}`),process.exit(1)}});qe.command("delete").description("Delete an ACL").argument("<acl-id>","ACL ID to delete").option("-f, --force","Skip confirmation prompt").action(async(i,e)=>{try{if(!e.force){let{confirm:o}=await Z.default.prompt([{type:"confirm",name:"confirm",message:`Are you sure you want to delete ACL ${i}?`,default:!1}]);if(!o){n.info("Deletion cancelled");return}}let t=await De();c.start("Deleting ACL..."),await t.deleteAcl(i),c.succeed("ACL deleted successfully")}catch(t){c.stop(),n.error(`Failed to delete ACL: ${t.message}`),process.exit(1)}});qe.command("trunks").description("List trunks using an ACL").argument("<acl-id>","ACL ID").option("-l, --limit <number>","Limit number of results",parseInt,50).option("--json","Output result as JSON").action(async(i,e)=>{try{let t=await De();c.start("Fetching trunks...");let o=await t.getAclTrunks(i,{pageSize:e.limit});c.succeed(`Retrieved ${o.trunks?.length||0} trunk(s)`),e.json?console.log(JSON.stringify(o,null,2)):(n.newline(),o.trunks&&o.trunks.length>0?o.trunks.forEach(r=>{n.info(`[${r.id}] ${r.name}`),r.hostName&&n.info(` Host: ${r.hostName}`),n.newline()}):n.info("No trunks are using this ACL"))}catch(t){c.stop(),n.error(`Failed to list trunks: ${t.message}`),process.exit(1)}});var At=new bi.Command("ip-ranges");At.description("Manage IP ranges for ACLs");At.command("list").description("List IP ranges for an ACL").argument("<acl-id>","ACL ID").option("-l, --limit <number>","Limit number of results",parseInt,50).option("--json","Output result as JSON").action(async(i,e)=>{try{let t=await De();c.start("Fetching IP ranges...");let o=await t.listIpRanges(i,{pageSize:e.limit});c.succeed(`Retrieved ${o.ipRanges?.length||0} IP range(s)`),e.json?console.log(JSON.stringify(o,null,2)):(n.newline(),o.ipRanges&&o.ipRanges.length>0?o.ipRanges.forEach(r=>{let s=r.range||r.ipAddress||"N/A";n.info(`[${r.id}] ${s}`),r.description&&n.info(` ${r.description}`),n.newline()}):(n.info("No IP ranges found for this ACL"),n.newline(),n.info(`Add one with: sinch sip acls ip-ranges add ${i}`)))}catch(t){c.stop(),n.error(`Failed to list IP ranges: ${t.message}`),process.exit(1)}});At.command("add").description("Add an IP range to an ACL").argument("<acl-id>","ACL ID").option("-d, --description <description>","Description for the IP range").option("-i, --ip <ip>","Single IP address (e.g., 192.168.1.1)").option("-r, --range <cidr>","CIDR range (e.g., 192.168.1.0/24)").option("--non-interactive","Skip prompts, use defaults for missing options").option("--json","Output result as JSON").action(async(i,e)=>{try{let t=e.description,o=e.ip,r=e.range,s=!e.nonInteractive;o&&r&&(n.error("Cannot specify both --ip and --range. Please provide only one."),process.exit(1)),!o&&!r&&(s?(await Z.default.prompt([{type:"list",name:"type",message:"What would you like to add?",choices:[{name:"Single IP address",value:"ip"},{name:"CIDR range",value:"range"}]}])).type==="ip"?o=(await Z.default.prompt([{type:"input",name:"ipAddress",message:"Enter IP address (e.g., 192.168.1.1):",validate:m=>m?lt(m)?!0:"Invalid IP address format":"IP address is required"}])).ipAddress:r=(await Z.default.prompt([{type:"input",name:"range",message:"Enter CIDR range (e.g., 192.168.1.0/24):",validate:m=>m?bn(m)?!0:"Invalid CIDR format (e.g., 192.168.1.0/24)":"CIDR range is required"}])).range:(n.error("Either --ip or --range is required"),process.exit(1))),o&&!lt(o)&&(n.error(`Invalid IP address format: ${o}`),process.exit(1)),r&&!bn(r)&&(n.error(`Invalid CIDR range format: ${r}. Expected format: 192.168.1.0/24`),process.exit(1)),!t&&s&&(t=(await Z.default.prompt([{type:"input",name:"description",message:"Enter description (optional):"}])).description||void 0);let a=await De();c.start("Adding IP range...");let l={description:t};o?l.ipAddress=o:r&&(l.range=r);let p=await a.addIpRange(i,l);c.succeed("IP range added successfully!"),e.json?console.log(JSON.stringify(p,null,2)):(n.newline(),is(p))}catch(t){c.stop(),n.error(`Failed to add IP range: ${t.message}`),process.exit(1)}});At.command("update").description("Update an IP range").argument("<acl-id>","ACL ID").argument("<ip-range-id>","IP range ID to update").option("-d, --description <description>","New description").option("-i, --ip <ip>","New single IP address").option("-r, --range <cidr>","New CIDR range").option("--non-interactive","Skip prompts, use current values for missing options").option("--json","Output result as JSON").action(async(i,e,t)=>{try{let o=await De();c.start("Fetching current IP range details...");let r;try{r=await o.getIpRange(i,e)}catch(m){c.stop(),n.error(`IP range ${e} not found in ACL ${i}: ${m.message}`),process.exit(1)}c.stop();let s=t.description,a=t.ip,l=t.range,p=!t.nonInteractive;if(a&&l&&(n.error("Cannot specify both --ip and --range. Please provide only one."),process.exit(1)),s===void 0&&p?s=(await Z.default.prompt([{type:"input",name:"description",message:"Enter description:",default:r.description||""}])).description||void 0:s===void 0&&(s=r.description),!a&&!l&&p){let m=r.range||r.ipAddress||"",w=r.range?"range":"ip";(await Z.default.prompt([{type:"list",name:"type",message:"Update as:",choices:[{name:"Single IP address",value:"ip"},{name:"CIDR range",value:"range"}],default:w}])).type==="ip"?(a=(await Z.default.prompt([{type:"input",name:"ipAddress",message:"Enter IP address:",default:w==="ip"?m:"",validate:v=>v?lt(v)?!0:"Invalid IP address format":"IP address is required"}])).ipAddress,l=void 0):(l=(await Z.default.prompt([{type:"input",name:"range",message:"Enter CIDR range:",default:w==="range"?m:"",validate:v=>v?bn(v)?!0:"Invalid CIDR format":"CIDR range is required"}])).range,a=void 0)}else!a&&!l?(a=r.ipAddress,l=r.range):a?l=void 0:l&&(a=void 0);a&&!lt(a)&&(n.error(`Invalid IP address format: ${a}`),process.exit(1)),l&&!bn(l)&&(n.error(`Invalid CIDR range format: ${l}`),process.exit(1)),c.start("Updating IP range...");let d={description:s};a?d.ipAddress=a:l&&(d.range=l);let u=await o.updateIpRange(i,e,d);c.succeed("IP range updated successfully!"),t.json?console.log(JSON.stringify(u,null,2)):(n.newline(),is(u))}catch(o){c.stop(),n.error(`Failed to update IP range: ${o.message}`),process.exit(1)}});At.command("delete").description("Delete an IP range").argument("<acl-id>","ACL ID").argument("<ip-range-id>","IP range ID to delete").option("-f, --force","Skip confirmation prompt").action(async(i,e,t)=>{try{if(!t.force){let{confirm:r}=await Z.default.prompt([{type:"confirm",name:"confirm",message:`Are you sure you want to delete IP range ${e}?`,default:!1}]);if(!r){n.info("Deletion cancelled");return}}let o=await De();c.start("Deleting IP range..."),await o.deleteIpRange(i,e),c.succeed("IP range deleted successfully")}catch(o){c.stop(),n.error(`Failed to delete IP range: ${o.message}`),process.exit(1)}});qe.addCommand(At);os.exports=qe});var cs=N((su,as)=>{"use strict";var ss=require("commander");T();R();E();Ye();async function In(){await f.load(),await f.hasCredentials()||(n.error('Not authenticated. Run "sinch auth login" first.'),process.exit(1));let e=f.getApiConfig();return new oe({projectId:e.projectId,credentials:e.credentials})}function $i(i){n.info(`ISO Code: ${i.isoCode}`),n.info(`Country: ${i.name}`),n.info(`Continent: ${i.continent}`),n.info(`Dialing Codes: ${i.countryDialingCodes.join(", ")}`),n.info(`Status: ${i.enabled?"enabled":"disabled"}`)}var Et=new ss.Command("countries");Et.description("Manage country permissions for dialing");Et.command("list").description("List all country permissions").option("-l, --limit <number>","Limit number of results",parseInt,50).option("--json","Output result as JSON").action(async i=>{try{let e=await In();c.start("Fetching country permissions...");let t=await e.listCountryPermissions({pageSize:i.limit});c.succeed(`Retrieved ${t.countryPermissions?.length||0} country permission(s)`),i.json?console.log(JSON.stringify(t,null,2)):(n.newline(),t.countryPermissions&&t.countryPermissions.length>0?([...t.countryPermissions].sort((r,s)=>r.isoCode.localeCompare(s.isoCode)).forEach(r=>{let s=r.enabled?"\u2713 enabled":"\u2717 disabled",a=r.name.padEnd(30);n.info(`${r.isoCode.padEnd(4)} ${a} ${s}`)}),n.newline(),n.info("Enable a country: sinch sip countries enable <iso-code>"),n.info("Disable a country: sinch sip countries disable <iso-code>")):n.info("No country permissions found"))}catch(e){c.stop(),n.error(`Failed to list country permissions: ${e.message}`),process.exit(1)}});Et.command("get").description("Get a specific country permission by ISO code").argument("<iso-code>","ISO country code (e.g., US, CA, *)").option("--json","Output result as JSON").action(async(i,e)=>{try{let t=await In();c.start("Fetching country permission...");let o=await t.getCountryPermission(i.toUpperCase());c.succeed("Country permission retrieved"),e.json?console.log(JSON.stringify(o,null,2)):(n.newline(),$i(o))}catch(t){c.stop(),n.error(`Failed to get country permission: ${t.message}`),process.exit(1)}});Et.command("enable").description("Enable a country for dialing").argument("<iso-code>","ISO country code (e.g., US, CA, *)").option("--json","Output result as JSON").action(async(i,e)=>{try{let t=await In();c.start(`Enabling country ${i.toUpperCase()}...`);let o=await t.updateCountryPermission(i.toUpperCase(),!0);c.succeed(`Country ${i.toUpperCase()} enabled for dialing`),e.json?console.log(JSON.stringify(o,null,2)):(n.newline(),$i(o),n.newline(),n.info(`Country ${i.toUpperCase()} is now enabled for dialing`))}catch(t){c.stop(),n.error(`Failed to enable country: ${t.message}`),process.exit(1)}});Et.command("disable").description("Disable a country for dialing").argument("<iso-code>","ISO country code (e.g., US, CA, *)").option("--json","Output result as JSON").action(async(i,e)=>{try{let t=await In();c.start(`Disabling country ${i.toUpperCase()}...`);let o=await t.updateCountryPermission(i.toUpperCase(),!1);c.succeed(`Country ${i.toUpperCase()} disabled for dialing`),e.json?console.log(JSON.stringify(o,null,2)):(n.newline(),$i(o),n.newline(),n.info(`Country ${i.toUpperCase()} is now disabled for dialing`))}catch(t){c.stop(),n.error(`Failed to disable country: ${t.message}`),process.exit(1)}});as.exports=Et});var ps=N((uu,ds)=>{"use strict";var ls=require("commander");T();R();E();Ye();async function Ec(){await f.load(),await f.hasCredentials()||(n.error('Not authenticated. Run "sinch auth login" first.'),process.exit(1));let e=f.getApiConfig();return new oe({projectId:e.projectId,credentials:e.credentials})}var Pi=new ls.Command("credential-lists");Pi.description("Manage credential list relationships");Pi.command("trunks").description("Get trunks using a credential list").argument("<credential-list-id>","Credential list ID").option("-l, --limit <number>","Limit number of results",parseInt,50).option("--json","Output result as JSON").action(async(i,e)=>{try{let t=await Ec();c.start("Fetching trunks using credential list...");let o=await t.getCredentialListTrunks(i,{pageSize:e.limit});c.succeed(`Retrieved ${o.trunks?.length||0} trunk(s)`),e.json?console.log(JSON.stringify(o,null,2)):(n.newline(),o.trunks&&o.trunks.length>0?(n.info(`Trunks using credential list ${i}:`),n.newline(),o.trunks.forEach(r=>{n.info(`[${r.id}] ${r.name}`),r.hostName&&n.info(` Host: ${r.hostName}`),n.info(` Caller ID: ${r.enableCallerId?"enabled":"disabled"}`),n.newline()}),o.totalItems&&n.info(`Total: ${o.totalItems} trunk(s)`)):n.info("No trunks found using this credential list"))}catch(t){c.stop(),n.error(`Failed to get trunks for credential list: ${t.message}`),process.exit(1)}});ds.exports=Pi});var gs=N((Su,en)=>{"use strict";var us=require("commander");T();R();E();Ye();It();async function fs(){await f.load(),await f.hasCredentials()||(n.error('Not authenticated. Run "sinch auth login" first.'),process.exit(1));let e=f.getApiConfig();return new oe({projectId:e.projectId,credentials:e.credentials})}function ms(i){if(!i){let t=new Date;return`>=${new Date(t.getTime()-1440*60*1e3).toISOString()}`}if(i.startsWith(">=")||i.startsWith("<=")||i.startsWith(">")||i.startsWith("<"))return i;let e=i.split("-");if(e.length===1&&e[0]){let t=e[0];return`>=${t}-01-01T00:00:00Z,<=${t}-12-31T23:59:59Z`}else if(e.length===2&&e[0]&&e[1]){let t=e[0],o=e[1],r=new Date(parseInt(t),parseInt(o),0).getDate();return`>=${t}-${o}-01T00:00:00Z,<=${t}-${o}-${r.toString().padStart(2,"0")}T23:59:59Z`}else return`>=${i}T00:00:00Z,<=${i}T23:59:59Z`}function $n(i){if(i===void 0||i===0)return"-";let e=Math.floor(i/3600),t=Math.floor(i%3600/60),o=i%60;return e>0?`${e}h ${t}m ${o}s`:t>0?`${t}m ${o}s`:`${o}s`}function Ai(i){return!i||!i.amount?"-":`${parseFloat(i.amount).toFixed(4)} ${i.currencyCode}`}function kc(i,e=!1){n.info(`Call ID: ${i.callId}`),n.info(`From: ${q(i.from)}`),n.info(`To: ${q(i.to)}`),n.info(`Direction: ${i.direction}`),n.info(`Status: ${i.callResult||"In Progress"}`),(e||i.durationSeconds)&&n.info(`Duration: ${$n(i.durationSeconds)}`),(e||i.billingDurationSeconds)&&n.info(`Billing Duration: ${$n(i.billingDurationSeconds)}`),i.price&&n.info(`Cost: ${Ai(i.price)}`),n.info(`Trunk ID: ${i.trunkId}`),n.info(`Created: ${new Date(i.createTime).toLocaleString()}`),i.answerTime&&n.info(`Answered: ${new Date(i.answerTime).toLocaleString()}`),i.endTime&&n.info(`Ended: ${new Date(i.endTime).toLocaleString()}`)}var Pn=new us.Command("calls");Pn.description("View call history and details");Pn.command("list").description("List calls with filtering options").option("--from <number>","Filter by originating phone number (supports partial matching)").option("--to <number>","Filter by destination phone number (supports partial matching)").option("--trunk-id <id>","Filter by trunk ID").option("--direction <direction>","Filter by direction (INBOUND or OUTBOUND)").option("--result <result>","Filter by call result (COMPLETED, NO_ANSWER, CANCEL, BUSY, FAILED)").option("--date <date>","Filter by date (YYYY-MM-DD, YYYY-MM, or YYYY). Defaults to last 24 hours.").option("--page <number>","Page number",parseInt).option("--page-size <number>","Number of results per page (max 1000)",parseInt,100).option("--json","Output result as JSON").action(async i=>{try{let e=await fs(),t={pageSize:i.pageSize};if(i.from&&(t.from=i.from),i.to&&(t.to=i.to),i.trunkId&&(t.trunkId=i.trunkId),i.direction&&(["INBOUND","OUTBOUND"].includes(i.direction.toUpperCase())||(n.error("Invalid direction. Must be INBOUND or OUTBOUND."),process.exit(1)),t.direction=i.direction.toUpperCase()),i.result){let r=["COMPLETED","NO_ANSWER","CANCEL","BUSY","FAILED"];r.includes(i.result.toUpperCase())||(n.error(`Invalid result. Must be one of: ${r.join(", ")}`),process.exit(1)),t.callResult=i.result.toUpperCase()}i.page&&(t.page=i.page),t.createTime=ms(i.date),c.start("Fetching calls...");let o=await e.findCalls(t);c.succeed(`Retrieved ${o.calls?.length||0} call(s)`),i.json?console.log(JSON.stringify(o,null,2)):(n.newline(),o.calls&&o.calls.length>0?(o.calls.forEach(r=>{let s=$n(r.durationSeconds),a=r.callResult||"In Progress",l=Ai(r.price);n.info(`${r.callId}`),n.info(` ${q(r.from)} \u2192 ${q(r.to)}`),n.info(` ${r.direction} | ${a} | ${s} | ${l}`),n.info(` ${new Date(r.createTime).toLocaleString()}`),n.newline()}),o.totalItems&&(n.info(`Total: ${o.totalItems} call(s)`),o.pageNumber&&n.info(`Page: ${o.pageNumber}`))):(n.info("No calls found matching the filters"),n.newline(),n.info("Try adjusting your filters or date range.")))}catch(e){c.fail("Failed to fetch calls"),n.error(e.message),process.exit(1)}});Pn.command("get").description("Get details of a specific call").argument("<call-id>","Call ID").option("--json","Output result as JSON").action(async(i,e)=>{try{let t=await fs();c.start(`Fetching call ${i}...`);let o=await t.getCall(i);c.succeed("Call retrieved"),e.json?console.log(JSON.stringify(o,null,2)):(n.newline(),kc(o,!0))}catch(t){c.fail("Failed to get call"),n.error(t.message),process.exit(1)}});en.exports=Pn;en.exports.parseDateFilter=ms;en.exports.formatDuration=$n;en.exports.formatPrice=Ai});var ws=N((bu,ys)=>{"use strict";var hs=require("commander"),Tc=Qr(),Nc=ns(),Rc=rs(),Dc=cs(),xc=ps(),Oc=gs(),Xe=new hs.Command("sip");Xe.description("Manage Elastic SIP Trunking resources");Xe.addCommand(Tc);Xe.addCommand(Nc);Xe.addCommand(Rc);Xe.addCommand(Dc);Xe.addCommand(xc);Xe.addCommand(Oc);ys.exports=Xe});var Ss=N((Eu,vs)=>{"use strict";var Cs=require("commander"),ve=y(require("inquirer"));T();R();E();It();async function An(){return await f.load(),await f.hasCredentials()||(n.error('Not authenticated. Run "sinch auth login" first.'),process.exit(1)),(await f.createSinchClient()).numbers}function Ei(i){n.info(`Phone Number: ${q(i.phoneNumber)}`),i.displayName&&n.info(`Display Name: ${i.displayName}`),n.info(`Region: ${i.regionCode}`),n.info(`Type: ${i.type}`),n.info(`Capabilities: ${i.capability?.join(", ")||"none"}`),i.money&&n.info(`Cost: ${i.money.amount} ${i.money.currencyCode}/month`),i.nextChargeDate&&n.info(`Next Charge: ${new Date(i.nextChargeDate).toLocaleDateString()}`),i.expireAt&&n.info(`Expires: ${new Date(i.expireAt).toLocaleDateString()}`),i.smsConfiguration&&(n.info(`SMS Service Plan: ${i.smsConfiguration.servicePlanId||"n/a"}`),i.smsConfiguration.campaignId&&n.info(`SMS Campaign: ${i.smsConfiguration.campaignId}`)),i.voiceConfiguration&&(n.info(`Voice Type: ${i.voiceConfiguration.type||"n/a"}`),i.voiceConfiguration.appId&&n.info(`Voice App: ${i.voiceConfiguration.appId}`),i.voiceConfiguration.trunkId&&n.info(`EST Trunk: ${i.voiceConfiguration.trunkId}`)),i.callbackUrl&&n.info(`Callback: ${i.callbackUrl}`)}var kt=new Cs.Command("active");kt.description("Manage your active phone numbers");kt.command("list").description("List all active numbers for this project").option("-r, --region <code>","Filter by region code (e.g. US, GB, SE)").option("-t, --type <type>","Filter by type: MOBILE, LOCAL, or TOLL_FREE").option("-c, --capability <cap...>","Filter by capability: SMS, VOICE").option("-p, --pattern <digits>","Filter by digit pattern").option("--search-pattern <mode>","Pattern match mode: START, CONTAINS, or END").option("-l, --limit <number>","Max results",parseInt).option("--order-by <field>","Sort by: phoneNumber or displayName").option("--non-interactive","Skip prompts, require all options as flags").option("--json","Output result as JSON").action(async i=>{try{let e=!i.nonInteractive,t=i.region,o=i.type;!t&&e&&(t=(await ve.default.prompt([{type:"input",name:"regionCode",message:"Region code to filter by (e.g. US, GB, SE) \u2014 leave blank for all:"}])).regionCode||void 0),!o&&e&&(o=(await ve.default.prompt([{type:"list",name:"type",message:"Filter by number type?",choices:[{name:"All types",value:""},{name:"MOBILE",value:"MOBILE"},{name:"LOCAL",value:"LOCAL"},{name:"TOLL_FREE",value:"TOLL_FREE"}]}])).type||void 0);let r=await An();c.start("Fetching active numbers...");let s=i.limit||100,a=[],l={};t&&(l.regionCode=t),o&&(l.type=o),i.capability&&(l.capability=i.capability),i.pattern&&(l["numberPattern.pattern"]=i.pattern),i.searchPattern&&(l["numberPattern.searchPattern"]=i.searchPattern),i.limit&&(l.pageSize=i.limit),i.orderBy&&(l.orderBy=i.orderBy);for await(let d of r.list(l))if(a.push(d),a.length>=s)break;let p=a.length;c.succeed(`Found ${p} active number(s)`),i.json?console.log(JSON.stringify(a,null,2)):(n.newline(),p>0?a.forEach(d=>{let u=d.capability?.join(", ")||"",m=d.displayName?` "${d.displayName}"`:"";console.log(`${q(d.phoneNumber)}${m} [${d.regionCode}] ${d.type} ${u}`)}):(n.info("No active numbers found for this project."),n.newline(),n.info("Search for available numbers: sinch numbers available search")))}catch(e){c.stop(),n.error(`Failed to list active numbers: ${e.message}`),process.exit(1)}});kt.command("get").description("Get details for a specific active number").argument("[phone-number]","Phone number in E.164 format (e.g. +12025550134)").option("--non-interactive","Skip prompts").option("--json","Output result as JSON").action(async(i,e)=>{try{let t=!e.nonInteractive;i||(t?i=(await ve.default.prompt([{type:"input",name:"phoneNumber",message:"Enter the phone number (E.164 format, e.g. +12025550134):",validate:a=>a?a.startsWith("+")?!0:"Phone number must start with + (E.164 format)":"Phone number is required"}])).phoneNumber:(n.error("Phone number is required. Usage: sinch numbers active get <phone-number>"),process.exit(1)));let o=await An();c.start(`Fetching number ${i}...`);let r=await o.get({phoneNumber:i});c.succeed("Number retrieved"),e.json?console.log(JSON.stringify(r,null,2)):(n.newline(),Ei(r))}catch(t){c.stop(),n.error(`Failed to get number: ${t.message}`),process.exit(1)}});kt.command("update").description("Update an active phone number (display name, SMS/Voice config)").argument("[phone-number]","Phone number in E.164 format").option("-d, --display-name <name>","New display name").option("--sms-service-plan <id>","SMS service plan ID (empty string to unlink)").option("--sms-campaign <id>","SMS campaign ID").option("--voice-app <id>","Voice app ID").option("--callback-url <url>","Callback URL for provisioning events").option("--non-interactive","Skip prompts").option("--json","Output result as JSON").action(async(i,e)=>{try{let t=!e.nonInteractive;i||(t?i=(await ve.default.prompt([{type:"input",name:"phoneNumber",message:"Which number do you want to update? (E.164 format):",validate:h=>h?h.startsWith("+")?!0:"Phone number must start with + (E.164 format)":"Phone number is required"}])).phoneNumber:(n.error("Phone number is required. Usage: sinch numbers active update <phone-number>"),process.exit(1)));let o=await An();c.start(`Fetching current details for ${i}...`);let r=await o.get({phoneNumber:i});c.stop();let s=e.displayName,a=e.smsServicePlan,l=e.smsCampaign,p=e.voiceApp,d=e.callbackUrl;if(t){n.newline(),n.info(`Current configuration for ${i}:`),Ei(r),n.newline(),s===void 0&&(s=(await ve.default.prompt([{type:"input",name:"displayName",message:"Display name:",default:r.displayName||""}])).displayName||void 0),d===void 0&&(d=(await ve.default.prompt([{type:"input",name:"callbackUrl",message:"Callback URL (leave blank to keep current):",default:r.callbackUrl||""}])).callbackUrl||void 0);let w=await ve.default.prompt([{type:"checkbox",name:"configure",message:"Which configurations do you want to update?",choices:[{name:"SMS Configuration",value:"sms"},{name:"Voice Configuration",value:"voice"}]}]);if(w.configure.includes("sms")&&a===void 0){let h=await ve.default.prompt([{type:"input",name:"servicePlanId",message:"SMS service plan ID (empty to unlink):",default:r.smsConfiguration?.servicePlanId||""},{type:"input",name:"campaignId",message:"SMS campaign ID (for US numbers):",default:r.smsConfiguration?.campaignId||""}]);a=h.servicePlanId,l=h.campaignId||void 0}w.configure.includes("voice")&&p===void 0&&(p=(await ve.default.prompt([{type:"input",name:"appId",message:"Voice app ID:",default:r.voiceConfiguration?.appId||""}])).appId||void 0)}let u={};if(s!==void 0&&(u.displayName=s),d!==void 0&&(u.callbackUrl=d),a!==void 0&&(u.smsConfiguration={servicePlanId:a},l&&(u.smsConfiguration.campaignId=l)),p!==void 0&&(u.voiceConfiguration={type:"RTC",appId:p}),Object.keys(u).length===0){n.info("No changes specified. Nothing to update.");return}c.start(`Updating ${i}...`);let m=await o.update({phoneNumber:i,updateActiveNumberRequestBody:u});c.succeed("Number updated successfully!"),e.json?console.log(JSON.stringify(m,null,2)):(n.newline(),Ei(m))}catch(t){c.stop(),n.error(`Failed to update number: ${t.message}`),process.exit(1)}});kt.command("release").description("Release (cancel subscription for) an active number").argument("[phone-number]","Phone number in E.164 format").option("-f, --force","Skip confirmation prompt").option("--non-interactive","Skip prompts").option("--json","Output result as JSON").action(async(i,e)=>{try{let t=!e.nonInteractive;if(i||(t?i=(await ve.default.prompt([{type:"input",name:"phoneNumber",message:"Which number do you want to release? (E.164 format):",validate:a=>a?a.startsWith("+")?!0:"Phone number must start with + (E.164 format)":"Phone number is required"}])).phoneNumber:(n.error("Phone number is required. Usage: sinch numbers active release <phone-number>"),process.exit(1))),!e.force){let{confirm:s}=await ve.default.prompt([{type:"confirm",name:"confirm",message:`Are you sure you want to release ${i}? This will cancel your subscription.`,default:!1}]);if(!s){n.info("Release cancelled");return}}let o=await An();c.start(`Releasing ${i}...`);let r=await o.release({phoneNumber:i});c.succeed(`Number ${i} released`),e.json?console.log(JSON.stringify(r,null,2)):(n.newline(),n.info(`${i} has been released from your project.`))}catch(t){c.stop(),n.error(`Failed to release number: ${t.message}`),process.exit(1)}});vs.exports=kt});var As=N((xu,Ps)=>{"use strict";var bs=require("commander"),A=y(require("inquirer"));T();R();E();Ye();It();async function Fc(){let i=f.getApiConfig();return new oe({projectId:i.projectId,credentials:i.credentials})}async function Is(){try{c.start("Fetching EST trunks...");let e=await(await Fc()).listTrunks({pageSize:50});c.stop();let t=e.trunks||[];if(t.length===0){console.log("No trunks found. You can create one with: sinch sip trunks create");let{trunkId:s}=await A.default.prompt([{type:"input",name:"trunkId",message:"Enter trunk ID manually:",validate:a=>a?!0:"Trunk ID is required for EST"}]);return s}let o=t.map(s=>({name:`${s.name||s.id}${s.hostName?` (${s.hostName})`:""}`,value:s.id}));o.push(new A.default.Separator),o.push({name:"Enter trunk ID manually",value:"__manual__"});let{selected:r}=await A.default.prompt([{type:"list",name:"selected",message:"Select a trunk:",choices:o}]);if(r==="__manual__"){let{trunkId:s}=await A.default.prompt([{type:"input",name:"trunkId",message:"Enter trunk ID:",validate:a=>a?!0:"Trunk ID is required"}]);return s}return r}catch{c.stop();let{trunkId:i}=await A.default.prompt([{type:"input",name:"trunkId",message:"EST trunk ID (could not fetch trunk list):",validate:e=>e?!0:"Trunk ID is required for EST"}]);return i}}async function $s(){try{c.start("Fetching fax services...");let i=await f.createSinchClient(),e=[];for await(let r of i.fax.services.list({projectId:f.getApiConfig().projectId}))e.push(r);if(c.stop(),e.length===0){console.log("No fax services found.");let{serviceId:r}=await A.default.prompt([{type:"input",name:"serviceId",message:"Enter fax service ID manually:",validate:s=>s?!0:"Service ID is required for FAX"}]);return r}let t=e.map(r=>({name:`${r.name||r.id}${r.defaultForProject?" (default)":""}`,value:r.id}));t.push(new A.default.Separator),t.push({name:"Enter service ID manually",value:"__manual__"});let{selected:o}=await A.default.prompt([{type:"list",name:"selected",message:"Select a fax service:",choices:t}]);if(o==="__manual__"){let{serviceId:r}=await A.default.prompt([{type:"input",name:"serviceId",message:"Enter fax service ID:",validate:s=>s?!0:"Service ID is required"}]);return r}return o}catch{c.stop();let{serviceId:i}=await A.default.prompt([{type:"input",name:"serviceId",message:"Fax service ID (could not fetch service list):",validate:e=>e?!0:"Service ID is required for FAX"}]);return i}}async function kn(){return await f.load(),await f.hasCredentials()||(n.error('Not authenticated. Run "sinch auth login" first.'),process.exit(1)),(await f.createSinchClient()).numbers}function En(i){let e=i.capability?.join(", ")||"",t=i.setupPrice?`${i.setupPrice.amount} ${i.setupPrice.currencyCode} setup`:"",o=i.monthlyPrice?`${i.monthlyPrice.amount} ${i.monthlyPrice.currencyCode}/mo`:"",r=[t,o].filter(Boolean).join(" + "),s=i.supportingDocumentationRequired?" [docs required]":"";return`${q(i.phoneNumber)} ${e} ${r}${s}`}async function jc(i,e){let t,o,r,{configureSms:s}=await A.default.prompt([{type:"confirm",name:"configureSms",message:"Configure SMS for this number?",default:!1}]);if(s){let m=await A.default.prompt([{type:"input",name:"servicePlanId",message:"SMS service plan ID:",validate:w=>w?!0:"Service plan ID is required for SMS"},{type:"input",name:"campaignId",message:"SMS campaign ID (required for US, optional otherwise):"}]);t={servicePlanId:m.servicePlanId},m.campaignId&&(t.campaignId=m.campaignId)}let{voiceType:a}=await A.default.prompt([{type:"list",name:"voiceType",message:"Voice configuration:",choices:[{name:"None (configure later)",value:"none"},{name:"RTC \u2014 Real-time Communication",value:"RTC"},{name:"EST \u2014 Elastic SIP Trunking",value:"EST"},{name:"FAX",value:"FAX"}]}]);if(a==="RTC"){let{appId:m}=await A.default.prompt([{type:"input",name:"appId",message:"Voice app ID:",validate:w=>w?!0:"Voice app ID is required"}]);o={type:"RTC",appId:m}}else a==="EST"?o={type:"EST",trunkId:await Is()}:a==="FAX"&&(o={type:"FAX",serviceId:await $s()});r=(await A.default.prompt([{type:"input",name:"callbackUrl",message:"Callback URL for provisioning events (optional):"}])).callbackUrl||void 0;let{confirm:p}=await A.default.prompt([{type:"confirm",name:"confirm",message:`Rent ${q(e)}? This will activate it on your project.`,default:!0}]);if(!p){console.log("Rental cancelled.");return}let d={};t&&(d.smsConfiguration=t),o&&(d.voiceConfiguration=o),r&&(d.callbackUrl=r),c.start(`Renting ${e}...`);let u=await i.rent({phoneNumber:e,rentNumberRequestBody:d});c.succeed(`${q(u.phoneNumber)} rented successfully!`),console.log(),console.log(` Phone Number: ${q(u.phoneNumber)}`),console.log(` Region: ${u.regionCode}`),console.log(` Type: ${u.type}`),console.log(` Capabilities: ${u.capability?.join(", ")}`),u.money&&console.log(` Cost: ${u.money.amount} ${u.money.currencyCode}/month`),console.log(),console.log(`Manage this number: sinch numbers active get ${e}`)}var Tt=new bs.Command("available");Tt.description("Search and rent available phone numbers");Tt.command("search").description("Search for available phone numbers to rent").option("-r, --region <code>","Region code (required, e.g. US, GB, SE)").option("-t, --type <type>","Number type (required): MOBILE, LOCAL, or TOLL_FREE").option("-c, --capabilities <cap...>","Capabilities: SMS, VOICE").option("-p, --pattern <digits>","Digit pattern to match").option("--search-pattern <mode>","Pattern match: START, CONTAINS, or END").option("-s, --size <number>","Max results",parseInt).option("--non-interactive","Skip prompts, require all options as flags").option("--json","Output result as JSON").action(async i=>{try{let e=!i.nonInteractive,t=i.region,o=i.type,r=i.capabilities;if(t||(e?t=(await A.default.prompt([{type:"input",name:"regionCode",message:"Region code (e.g. US, GB, SE):",default:"US"}])).regionCode.toUpperCase():(n.error("Region code is required. Use --region <code>"),process.exit(1))),o||(e?o=(await A.default.prompt([{type:"list",name:"type",message:"What type of number?",choices:[{name:"LOCAL \u2014 assigned to a geographic region",value:"LOCAL"},{name:"MOBILE \u2014 belongs to a mobile range",value:"MOBILE"},{name:"TOLL_FREE \u2014 free for the caller",value:"TOLL_FREE"}]}])).type:(n.error("Number type is required. Use --type <MOBILE|LOCAL|TOLL_FREE>"),process.exit(1))),!r&&e){let u=await A.default.prompt([{type:"checkbox",name:"capabilities",message:"Required capabilities:",choices:[{name:"SMS",value:"SMS",checked:!0},{name:"VOICE",value:"VOICE"}]}]);r=u.capabilities.length>0?u.capabilities:void 0}let s=i.pattern,a=i.searchPattern;!s&&e&&(s=(await A.default.prompt([{type:"input",name:"pattern",message:"Digit pattern to search for (leave blank for any):"}])).pattern||void 0,s&&!a&&(a=(await A.default.prompt([{type:"list",name:"searchPattern",message:"Where should the pattern appear?",choices:[{name:"Starts with these digits",value:"START"},{name:"Contains these digits",value:"CONTAINS"},{name:"Ends with these digits",value:"END"}]}])).searchPattern));let l=await kn();c.start(`Searching for ${o} numbers in ${t}...`);let p=await l.searchForAvailableNumbers({regionCode:t,type:o,capabilities:r,"numberPattern.pattern":s,"numberPattern.searchPattern":a,size:i.size}),d=p.availableNumbers?.length||0;if(c.succeed(`Found ${d} available number(s)`),i.json)console.log(JSON.stringify(p,null,2));else if(d===0)console.log(),console.log("No numbers found matching your criteria."),console.log("Try a different region, type, or relax your pattern filter.");else if(e){let u=p.availableNumbers.map(w=>({name:En(w),value:w.phoneNumber}));u.push(new A.default.Separator),u.push({name:"Exit without renting",value:""});let{selected:m}=await A.default.prompt([{type:"list",name:"selected",message:`Select a number to rent (${d} available):`,choices:u,pageSize:Math.min(d+2,20)}]);m&&await jc(l,m)}else console.log(),p.availableNumbers.forEach(u=>console.log(En(u)))}catch(e){c.stop(),n.error(`Failed to search numbers: ${e.message}`),process.exit(1)}});Tt.command("check").description("Check if a specific phone number is available").argument("[phone-number]","Phone number in E.164 format").option("--non-interactive","Skip prompts").option("--json","Output result as JSON").action(async(i,e)=>{try{let t=!e.nonInteractive;i||(t?i=(await A.default.prompt([{type:"input",name:"phoneNumber",message:"Enter the phone number to check (E.164, e.g. +12025550134):",validate:a=>a?a.startsWith("+")?!0:"Must be in E.164 format (starts with +)":"Phone number is required"}])).phoneNumber:(n.error("Phone number is required. Usage: sinch numbers available check <phone-number>"),process.exit(1)));let o=await kn();c.start(`Checking availability for ${i}...`);let r=await o.checkAvailability({phoneNumber:i});c.succeed("Number is available!"),e.json?console.log(JSON.stringify(r,null,2)):(console.log(),console.log(En(r)),console.log(),console.log(`Rent this number: sinch numbers available rent ${i}`))}catch(t){c.stop(),n.error(`${t.message}`),process.exit(1)}});Tt.command("rent").description("Rent (activate) a specific phone number").argument("[phone-number]","Phone number in E.164 format").option("--sms-service-plan <id>","SMS service plan ID").option("--sms-campaign <id>","SMS campaign ID (for US numbers)").option("--voice-app <id>","Voice app ID (for RTC)").option("--voice-type <type>","Voice config type: RTC, EST, or FAX").option("--trunk-id <id>","EST trunk ID (when voice-type is EST)").option("--callback-url <url>","Callback URL for provisioning events").option("-f, --force","Skip confirmation").option("--non-interactive","Skip all prompts").option("--json","Output result as JSON").action(async(i,e)=>{try{let t=!e.nonInteractive;i||(t?i=(await A.default.prompt([{type:"input",name:"phoneNumber",message:"Which number do you want to rent? (E.164 format):",validate:u=>u?u.startsWith("+")?!0:"Must be in E.164 format (starts with +)":"Phone number is required"}])).phoneNumber:(n.error("Phone number is required. Usage: sinch numbers available rent <phone-number>"),process.exit(1)));let o=await kn();if(t){c.start(`Checking availability for ${i}...`);try{let d=await o.checkAvailability({phoneNumber:i});c.succeed("Number is available"),console.log(),console.log(En(d)),console.log()}catch{c.fail("Number may not be available"),n.warn("Could not verify availability. Proceeding anyway..."),n.newline()}}let r,s,a=e.callbackUrl;if(e.smsServicePlan&&(r={servicePlanId:e.smsServicePlan},e.smsCampaign&&(r.campaignId=e.smsCampaign)),(e.voiceApp||e.trunkId)&&(s={type:e.voiceType||"RTC"},e.voiceApp&&(s.appId=e.voiceApp),e.trunkId&&(s.trunkId=e.trunkId)),t&&!r&&!s){let{configureSms:d}=await A.default.prompt([{type:"confirm",name:"configureSms",message:"Configure SMS for this number?",default:!1}]);if(d){let m=await A.default.prompt([{type:"input",name:"servicePlanId",message:"SMS service plan ID:",validate:w=>w?!0:"Service plan ID is required for SMS"},{type:"input",name:"campaignId",message:"SMS campaign ID (required for US, optional otherwise):"}]);r={servicePlanId:m.servicePlanId},m.campaignId&&(r.campaignId=m.campaignId)}let{voiceType:u}=await A.default.prompt([{type:"list",name:"voiceType",message:"Voice configuration:",choices:[{name:"None (configure later)",value:"none"},{name:"RTC \u2014 Real-time Communication",value:"RTC"},{name:"EST \u2014 Elastic SIP Trunking",value:"EST"},{name:"FAX",value:"FAX"}]}]);if(u==="RTC"){let{appId:m}=await A.default.prompt([{type:"input",name:"appId",message:"Voice app ID:",validate:w=>w?!0:"Voice app ID is required"}]);s={type:"RTC",appId:m}}else u==="EST"?s={type:"EST",trunkId:await Is()}:u==="FAX"&&(s={type:"FAX",serviceId:await $s()});a||(a=(await A.default.prompt([{type:"input",name:"callbackUrl",message:"Callback URL for provisioning events (optional):"}])).callbackUrl||void 0)}if(!e.force){let{confirm:d}=await A.default.prompt([{type:"confirm",name:"confirm",message:`Rent ${i}? This will activate it on your project.`,default:!0}]);if(!d){n.info("Rental cancelled");return}}let l={};r&&(l.smsConfiguration=r),s&&(l.voiceConfiguration=s),a&&(l.callbackUrl=a),c.start(`Renting ${i}...`);let p=await o.rent({phoneNumber:i,rentNumberRequestBody:l});c.succeed(`Number ${i} rented successfully!`),e.json?console.log(JSON.stringify(p,null,2)):(console.log(),console.log(` Phone Number: ${q(p.phoneNumber)}`),console.log(` Region: ${p.regionCode}`),console.log(` Type: ${p.type}`),console.log(` Capabilities: ${p.capability?.join(", ")}`),p.money&&console.log(` Cost: ${p.money.amount} ${p.money.currencyCode}/month`),console.log(),console.log(`Manage this number: sinch numbers active get ${i}`))}catch(t){c.stop(),n.error(`Failed to rent number: ${t.message}`),process.exit(1)}});Tt.command("rent-any").description("Rent any number matching your criteria (US LOCAL only)").option("-r, --region <code>","Region code (required)").option("-t, --type <type>","Number type (required): MOBILE, LOCAL, or TOLL_FREE").option("-c, --capabilities <cap...>","Capabilities: SMS, VOICE").option("-p, --pattern <digits>","Digit pattern to match").option("--search-pattern <mode>","Pattern match: START, CONTAINS, or END").option("--sms-service-plan <id>","SMS service plan ID").option("--sms-campaign <id>","SMS campaign ID").option("--voice-app <id>","Voice app ID").option("--callback-url <url>","Callback URL").option("-f, --force","Skip confirmation").option("--non-interactive","Skip all prompts").option("--json","Output result as JSON").action(async i=>{try{let e=!i.nonInteractive,t=i.region,o=i.type,r=i.capabilities;if(t||(e?t=(await A.default.prompt([{type:"input",name:"regionCode",message:"Region code (e.g. US, GB, SE):",default:"US"}])).regionCode.toUpperCase():(n.error("Region code is required. Use --region <code>"),process.exit(1))),o||(e?o=(await A.default.prompt([{type:"list",name:"type",message:"Number type:",choices:[{name:"LOCAL",value:"LOCAL"},{name:"MOBILE",value:"MOBILE"},{name:"TOLL_FREE",value:"TOLL_FREE"}]}])).type:(n.error("Number type is required. Use --type <MOBILE|LOCAL|TOLL_FREE>"),process.exit(1))),!r&&e){let m=await A.default.prompt([{type:"checkbox",name:"capabilities",message:"Required capabilities:",choices:[{name:"SMS",value:"SMS",checked:!0},{name:"VOICE",value:"VOICE"}]}]);r=m.capabilities.length>0?m.capabilities:void 0}let s,a;if(i.smsServicePlan)s={servicePlanId:i.smsServicePlan},i.smsCampaign&&(s.campaignId=i.smsCampaign);else if(e&&(await A.default.prompt([{type:"confirm",name:"configureSms",message:"Configure SMS for this number?",default:!1}])).configureSms){let w=await A.default.prompt([{type:"input",name:"servicePlanId",message:"SMS service plan ID:",validate:h=>h?!0:"Required"},{type:"input",name:"campaignId",message:"SMS campaign ID (optional):"}]);s={servicePlanId:w.servicePlanId},w.campaignId&&(s.campaignId=w.campaignId)}i.voiceApp&&(a={type:"RTC",appId:i.voiceApp});let l=i.callbackUrl;if(!l&&e&&(l=(await A.default.prompt([{type:"input",name:"callbackUrl",message:"Callback URL (optional):"}])).callbackUrl||void 0),!i.force){let{confirm:m}=await A.default.prompt([{type:"confirm",name:"confirm",message:`Rent any available ${o} number in ${t}?`,default:!0}]);if(!m){n.info("Rental cancelled");return}}let p=await kn(),d={regionCode:t,type:o};r&&(d.capabilities=r),i.pattern&&(d.numberPattern={pattern:i.pattern,searchPattern:i.searchPattern||"CONTAINS"}),s&&(d.smsConfiguration=s),a&&(d.voiceConfiguration=a),l&&(d.callbackUrl=l),c.start(`Finding and renting a ${o} number in ${t}...`);let u=await p.rentAny({rentAnyNumberRequestBody:d});c.succeed(`Rented ${u.phoneNumber}!`),i.json?console.log(JSON.stringify(u,null,2)):(console.log(),console.log(` Phone Number: ${q(u.phoneNumber)}`),console.log(` Region: ${u.regionCode}`),console.log(` Type: ${u.type}`),console.log(` Capabilities: ${u.capability?.join(", ")}`),u.money&&console.log(` Cost: ${u.money.amount} ${u.money.currencyCode}/month`),console.log(),console.log(`Manage this number: sinch numbers active get ${u.phoneNumber}`))}catch(e){c.stop(),n.error(`Failed to rent number: ${e.message}`),process.exit(1)}});Ps.exports=Tt});var Ts=N((Lu,ks)=>{"use strict";var Es=require("commander");T();R();E();async function Lc(){return await f.load(),await f.hasCredentials()||(n.error('Not authenticated. Run "sinch auth login" first.'),process.exit(1)),(await f.createSinchClient()).numbers}var ki=new Es.Command("regions");ki.description("List regions where numbers are available");ki.command("list").description("List all available regions for phone numbers").option("-t, --types <type...>","Filter by number type: MOBILE, LOCAL, TOLL_FREE").option("--json","Output result as JSON").action(async i=>{try{let e=await Lc();c.start("Fetching available regions...");let t=await e.availableRegions.list({types:i.types}),o=t.availableRegions?.length||0;c.succeed(`Found ${o} region(s)`),i.json?console.log(JSON.stringify(t,null,2)):(n.newline(),o>0?t.availableRegions.forEach(r=>{console.log(`${r.regionCode} ${r.regionName} [${r.types?.join(", ")}]`)}):n.info("No regions found."))}catch(e){c.stop(),n.error(`Failed to list regions: ${e.message}`),process.exit(1)}});ks.exports=ki});var Ds=N((_u,Rs)=>{"use strict";var Ns=require("commander"),_c=Ss(),Uc=As(),Mc=Ts(),tn=new Ns.Command("numbers");tn.description("Manage Sinch phone numbers \u2014 search, rent, update, and release");tn.addCommand(_c);tn.addCommand(Uc);tn.addCommand(Mc);Rs.exports=tn});async function ye(i){let e={};for(let t of i){if(t.when!==void 0&&!(typeof t.when=="function"?await t.when(e):t.when))continue;let o;switch(t.type){case"input":{let r=await(0,Ae.input)({message:t.message,default:t.default,validate:t.validate});t.filter&&(r=t.filter(r)),o=r;break}case"password":o=await(0,Ae.password)({message:t.message,validate:t.validate});break;case"confirm":o=await(0,Ae.confirm)({message:t.message,default:t.default});break;case"list":o=await(0,Ae.select)({message:t.message,choices:(t.choices||[]).map(r=>typeof r=="string"?{name:r,value:r}:r),default:t.default,pageSize:t.pageSize});break;case"checkbox":o=await(0,Ae.checkbox)({message:t.message,choices:(t.choices||[]).map(r=>typeof r=="string"?{name:r,value:r}:r),pageSize:t.pageSize});break;default:throw new Error(`Unsupported prompt type: ${t.type}`)}e[t.name]=o}return e}var Ae,xs=G(()=>{"use strict";Ae=require("@inquirer/prompts")});var Os,Ti,Ni,Fs=G(()=>{"use strict";Os=require("@sinch/sdk-core");E();Ti=class{client=null;initialized=!1;async initialize(){if(!(this.initialized&&this.client))try{await f.load();let e=await f.getCredentials();if(!e)throw new Error("Not authenticated. Please run: sinch auth login");this.client=new Os.SinchClient({projectId:e.projectId,keyId:e.keyId,keySecret:e.keySecret}),this.initialized=!0}catch(e){throw new Error(`Failed to initialize fax client: ${e.message}`)}}async getClient(){return this.initialized||await this.initialize(),this.client}isInitialized(){return this.initialized}async getServiceConfig(){return await f.load(),{serviceId:f.getFaxServiceId(),senderNumber:f.getFaxSenderNumber()}}async validateConfig(){let e=await this.getServiceConfig(),t=[];return e.serviceId||t.push("fax service ID (set with: sinch config set fax service-id <id>)"),{valid:t.length===0,missing:t}}},Ni=new Ti});var Js={};xe(Js,{FaxManager:()=>Tn,default:()=>Bc,getFaxClient:()=>Us,getFaxManager:()=>Ee});async function Us(){try{return await f.load(),await f.hasCredentials()||(n.error("Not authenticated. Please run: sinch auth login"),process.exit(1)),await Ni.initialize(),await Ni.getClient()}catch(i){n.error(`Failed to initialize fax client: ${i.message}`),process.exit(1)}}async function Ee(){let i=await Us(),e=await f.getFaxCredentials();return new Tn(i,e)}function on(i){n.newline(),n.info("\u{1F4E0} Fax Status"),n.info("\u2550".repeat(50)),n.info(`Status: ${i.status||"N/A"}`),n.info(`ID: ${i.id||"N/A"}`),n.info(`To: ${i.to||"N/A"}`),n.info(`From: ${i.from||"N/A"}`),n.info(`Pages: ${i.numberOfPages??i.pages??"N/A"}`),(i.createTime||i.createdAt)&&n.info(`Created: ${i.createTime||i.createdAt}`),(i.completedTime||i.completedAt)&&n.info(`Completed: ${i.completedTime||i.completedAt}`),i.duration&&n.info(`Duration: ${i.duration}s`),i.attempts!==void 0&&n.info(`Attempts: ${i.attempts}`),i.errorCode&&n.info(`Error Code: ${i.errorCode}`),i.errorMessage&&n.info(`Error: ${i.errorMessage}`),n.info("\u2550".repeat(50)),n.newline()}function Ms(i){n.newline(),n.info("\u{1F4E0} Fax Details"),n.info("\u2550".repeat(50)),n.info(`ID: ${i.id||"N/A"}`),n.info(`Status: ${i.status||"N/A"}`),i.direction&&n.info(`Direction: ${i.direction}`),n.info(`To: ${i.to||"N/A"}`),n.info(`From: ${i.from||"N/A"}`),n.info(`Pages: ${i.numberOfPages??i.pages??"N/A"}`),i.projectId&&n.info(`Project ID: ${i.projectId}`),i.serviceId&&n.info(`Service ID: ${i.serviceId}`),(i.createTime||i.createdAt)&&n.info(`Created: ${i.createTime||i.createdAt}`),(i.startTime||i.startedAt)&&n.info(`Started: ${i.startTime||i.startedAt}`),(i.completedTime||i.completedAt)&&n.info(`Completed: ${i.completedTime||i.completedAt}`),i.duration&&n.info(`Duration: ${i.duration}s`),i.attempts!==void 0&&n.info(`Attempts: ${i.attempts}`),i.maxRetries!==void 0&&n.info(`Max Retries: ${i.maxRetries}`),i.retryDelaySeconds!==void 0&&n.info(`Retry Delay: ${i.retryDelaySeconds}s`),i.resolution&&n.info(`Resolution: ${i.resolution}`),i.imageConversionMethod&&n.info(`Conversion Method: ${i.imageConversionMethod}`),i.headerPageNumbers!==void 0&&n.info(`Header Page Numbers: ${i.headerPageNumbers}`),i.headerText!==void 0&&n.info(`Header Text: ${i.headerText||"(empty)"}`),i.headerTimeZone&&n.info(`Header Timezone: ${i.headerTimeZone}`),i.contentUrl&&n.info(`Content URL: ${i.contentUrl}`),i.hasFile!==void 0&&n.info(`Has File: ${i.hasFile}`),i.callbackUrl&&n.info(`Callback URL: ${i.callbackUrl}`),i.callbackUrlContentType&&n.info(`Callback Type: ${i.callbackUrlContentType}`),i.callId&&n.info(`Call ID: ${i.callId}`),i.price?n.info(`Price: ${i.price.amount} ${i.price.currency_code}`):i.amount&&i.currencyCode?n.info(`Price: ${i.amount} ${i.currencyCode}`):i.pricePerPage&&n.info(`Price Per Page: ${i.pricePerPage}`),i.errorCode&&n.info(`Error Code: ${i.errorCode}`),i.errorMessage&&n.info(`Error: ${i.errorMessage}`),n.info("\u2550".repeat(50)),n.newline()}async function qc(i,e,t){let o=parseInt(t.timeout||"300",10),r=Date.now(),s=5e3;for(t.json||(n.newline(),c.start(`Waiting for fax ${e} to complete (timeout: ${o}s)...`));;)try{let a=await i.getFaxStatus(e,t.serviceId);if(a.status==="completed"||a.status==="failed"){t.json?console.log(JSON.stringify(a,null,2)):(c.succeed(`Fax ${a.status}!`),on(a));return}if((Date.now()-r)/1e3>=o){t.json?console.log(JSON.stringify({...a,timedOut:!0},null,2)):(c.warn(`Timeout reached after ${o}s. Current status:`),on(a));return}await new Promise(p=>setTimeout(p,s))}catch(a){t.json?console.error(JSON.stringify({error:a.message},null,2)):(c.fail("Failed to get fax status"),n.error(a.message)),process.exit(1)}}async function Jc(i,e,t){let o=parseInt(t.interval||"5",10),r=o*1e3;if(t.json){let s=!0,a=setInterval(async()=>{try{let l=await i.getFaxStatus(e,t.serviceId);s||console.log(""),console.log(JSON.stringify(l,null,2)),s=!1,(l.status==="completed"||l.status==="failed")&&(clearInterval(a),process.exit(0))}catch(l){clearInterval(a),console.error(JSON.stringify({error:l.message},null,2)),process.exit(1)}},r);try{let l=await i.getFaxStatus(e,t.serviceId);console.log(JSON.stringify(l,null,2)),(l.status==="completed"||l.status==="failed")&&(clearInterval(a),process.exit(0))}catch(l){clearInterval(a),console.error(JSON.stringify({error:l.message},null,2)),process.exit(1)}}else{n.newline(),n.info(`\u{1F441}\uFE0F Watching fax ${e} (press Ctrl+C to exit)`),n.info(`Polling every ${o}s...`),n.newline(),process.on("SIGINT",()=>{n.newline(),n.info("Watch stopped by user"),n.newline(),process.exit(0)});let s=async()=>{try{let a=await i.getFaxStatus(e,t.serviceId);process.stdout.isTTY&&process.stdout.write("\x1B[2J\x1B[0f"),n.info(`\u{1F441}\uFE0F Watching fax ${e} (press Ctrl+C to exit)`),n.info(`Polling every ${o}s...`),n.info(`Last updated: ${new Date().toLocaleTimeString()}`),on(a),(a.status==="completed"||a.status==="failed")&&(n.info(`Fax ${a.status}. Exiting watch mode.`),n.newline(),process.exit(0))}catch(a){n.newline(),n.error(`Failed to get fax status: ${a.message}`),process.exit(1)}};await s(),setInterval(s,r)}}async function Vc(){let i=Ls.platform();try{if(i==="darwin")return(0,nn.execSync)(`osascript -e '${`
|
|
122
126
|
set fileTypes to {"pdf", "tif", "tiff", "doc", "docx", "txt", "html", "htm"}
|
|
123
127
|
set theFile to choose file with prompt "Select a file to send:" of type fileTypes
|
|
124
128
|
return POSIX path of theFile
|
|
125
|
-
`.replace(/'/g,"'\\''")}' 2>/dev/null`,{encoding:"utf8",stdio:["pipe","pipe","pipe"]}).trim()||null;if(i==="win32")return(0,
|
|
129
|
+
`.replace(/'/g,"'\\''")}' 2>/dev/null`,{encoding:"utf8",stdio:["pipe","pipe","pipe"]}).trim()||null;if(i==="win32")return(0,nn.execSync)(`powershell -Command "${`
|
|
126
130
|
Add-Type -AssemblyName System.Windows.Forms
|
|
127
131
|
$dialog = New-Object System.Windows.Forms.OpenFileDialog
|
|
128
132
|
$dialog.Filter = "Fax Files|*.pdf;*.tif;*.tiff;*.doc;*.docx;*.txt;*.html;*.htm"
|
|
@@ -131,75 +135,75 @@ ${p.display_name||"No name"}`)),p.channel_identities&&p.channel_identities.lengt
|
|
|
131
135
|
if ($result -eq 'OK') {
|
|
132
136
|
Write-Output $dialog.FileName
|
|
133
137
|
}
|
|
134
|
-
`.replace(/"/g,'\\"')}"`,{encoding:"utf8",stdio:["pipe","pipe","pipe"]}).trim()||null;try{return(0,
|
|
138
|
+
`.replace(/"/g,'\\"')}"`,{encoding:"utf8",stdio:["pipe","pipe","pipe"]}).trim()||null;try{return(0,nn.execSync)(`zenity --file-selection --title="Select a file to send" --file-filter='Fax Files | *.pdf *.tif *.tiff *.doc *.docx *.txt *.html *.htm' 2>/dev/null`,{encoding:"utf8",stdio:["pipe","pipe","pipe"]}).trim()||null}catch{return(0,nn.execSync)('kdialog --getopenfilename ~ "*.pdf *.tif *.tiff *.doc *.docx *.txt *.html *.htm|Fax Files" 2>/dev/null',{encoding:"utf8",stdio:["pipe","pipe","pipe"]}).trim()||null}}catch{return null}}async function qs(){let{inputMethod:i}=await ye([{type:"list",name:"inputMethod",message:"How would you like to select the file?",choices:[{name:"\u{1F4C1} Browse files",value:"browse"},{name:"\u2328\uFE0F Enter file path manually",value:"manual"}]}]);if(i==="browse"){let e=await Vc();if(e)return n.info(`Selected: ${e}`),e;{n.warn("File selection cancelled or unavailable, please enter path manually");let{file:t}=await ye([{type:"input",name:"file",message:"Enter the path to the file you want to send:",validate:o=>!o||o.trim().length===0?"File path is required":!0}]);return t}}else{let{file:e}=await ye([{type:"input",name:"file",message:"Enter the path to the file you want to send:",validate:t=>!t||t.trim().length===0?"File path is required":!0}]);return e}}var js,Nt,dt,Ls,nn,_s,Ri,Tn,Je,Bc,Vs=G(()=>{"use strict";js=require("commander");T();R();xs();Fs();E();Nt=y(require("fs-extra")),dt=y(require("path")),Ls=y(require("os")),nn=require("child_process");It();_s=y(require("form-data")),Ri=y(require("axios")),Tn=class{credentials;constructor(e,t){this.credentials=t}async validateFile(e){let t=dt.resolve(e);if(!await Nt.pathExists(t))throw new Error(`File not found: ${e}`);let r=await Nt.stat(t);if(!r.isFile())throw new Error(`Path is not a file: ${e}`);let s=dt.extname(t).toLowerCase(),a=[".pdf",".tif",".tiff",".doc",".docx",".txt",".html",".htm"];if(!a.includes(s))throw new Error(`Unsupported file type: ${s}. Supported types: ${a.join(", ")}`);let l=20*1024*1024;if(r.size>l)throw new Error(`File too large: ${(r.size/1024/1024).toFixed(2)}MB. Maximum size: 20MB`)}validateUrl(e){try{let t=new URL(e);if(!["http:","https:"].includes(t.protocol))throw new Error("URL must use HTTP or HTTPS protocol")}catch(t){throw new Error(`Invalid URL: ${t.message}`)}}async sendFax(e){let{to:t,from:o,file:r,contentUrl:s,serviceId:a}=e;if(!r&&!s)throw new Error("Either --file or --content-url must be provided");let l=a||f.getFaxServiceId();if(!l)throw new Error("Fax service ID is required. Set it with: sinch config --set fax serviceID=<id>");let p=o||f.getFaxSenderNumber();if(r&&await this.validateFile(r),s){let h=Array.isArray(s)?s:[s];for(let C of h)this.validateUrl(C)}let d=new _s.default;if(d.append("to",t),p&&d.append("from",p),d.append("serviceId",l),r){let h=dt.resolve(r),C=Nt.createReadStream(h),v=dt.basename(h);d.append("file",C,v)}s&&(Array.isArray(s)?d.append("contentUrl",s.join(",")):d.append("contentUrl",s));let u=this.credentials||await f.getCredentials();if(!u)throw new Error("Not authenticated. Please run: sinch auth login");let w=`https://fax.api.sinch.com/v3/projects/${u.projectId}/faxes`;try{return(await Ri.default.post(w,d,{headers:{...d.getHeaders()},auth:{username:u.keyId,password:u.keySecret},maxContentLength:1/0,maxBodyLength:1/0})).data}catch(h){if(h.response){let C=h.response.status,v=h.response.data,k=`HTTP ${C}`;if(h.response.statusText&&(k+=` ${h.response.statusText}`),v)if(typeof v=="string"&&v.trim()?k+=`: ${v}`:v.message&&(k+=`: ${v.message}`),v.details&&Array.isArray(v.details))for(let j of v.details)if(j.fieldViolations&&Array.isArray(j.fieldViolations)){k+=`
|
|
135
139
|
|
|
136
|
-
Validation Errors:`;for(let
|
|
137
|
-
\u2022 ${
|
|
138
|
-
${
|
|
140
|
+
Validation Errors:`;for(let M of j.fieldViolations)k+=`
|
|
141
|
+
\u2022 ${M.field}: ${M.description}`}else j.message&&(k+=`
|
|
142
|
+
${j.message}`);else v.error?k+=`: ${v.error}`:v.errorMessage&&(k+=`: ${v.errorMessage}`);throw v?.details?.some(j=>j.fieldViolations?.length>0)||(C===401?k+=`
|
|
139
143
|
|
|
140
|
-
\u2192 Authentication failed. Please verify your credentials with: sinch auth login`:C===403?
|
|
144
|
+
\u2192 Authentication failed. Please verify your credentials with: sinch auth login`:C===403?k+=`
|
|
141
145
|
|
|
142
|
-
\u2192 Permission denied. Please check that your API credentials have access to the Fax API and that the service ID is correct.`:C===404?
|
|
146
|
+
\u2192 Permission denied. Please check that your API credentials have access to the Fax API and that the service ID is correct.`:C===404?k+=`
|
|
143
147
|
|
|
144
|
-
\u2192 Resource not found. Please verify your project ID and service ID.`:C===400?
|
|
148
|
+
\u2192 Resource not found. Please verify your project ID and service ID.`:C===400?k+=`
|
|
145
149
|
|
|
146
|
-
\u2192 Invalid request. Please check your phone numbers and file format.`:C===422&&(
|
|
150
|
+
\u2192 Invalid request. Please check your phone numbers and file format.`:C===422&&(k+=`
|
|
147
151
|
|
|
148
|
-
\u2192 Validation failed. Common issues:`,
|
|
149
|
-
\u2022 Phone numbers must be in E.164 format (e.g., +12025551234)`,
|
|
150
|
-
\u2022 Service ID must be valid`,
|
|
151
|
-
\u2022 From number must be a number that belongs to your project`)),new Error(R)}else throw h.request?new Error(`No response from Fax API: ${h.message}`):new Error(`Failed to send fax: ${h.message}`)}}async listFaxes(e){let{serviceId:t}=e;if(!(t||f.getFaxServiceId()))throw new Error("Fax service ID is required. Set it with: sinch config set fax service-id <id>");return[]}async getFax(e,t){let o=t||f.getFaxServiceId();if(!o)throw new Error("Fax service ID is required. Set it with: sinch config set fax service-id <id>");return{id:e,status:"completed",serviceId:o}}async cancelFax(e,t){if(!(t||f.getFaxServiceId()))throw new Error("Fax service ID is required. Set it with: sinch config set fax service-id <id>")}displayFaxDetails(e){n.newline(),n.info("Fax Details:"),n.info(`ID: ${e.id}`),n.info(`To: ${e.to?_(e.to):"N/A"}`),n.info(`From: ${e.from?_(e.from):"N/A"}`),n.info(`Status: ${e.status||"N/A"}`),n.info(`Created: ${e.createdAt||e.created_at||"N/A"}`),n.newline()}};Ge=new Ds.Command("fax");Ge.description("Manage Sinch Fax API");Ge.action(async()=>{try{n.newline();let{action:i}=await me([{type:"list",name:"action",message:"What would you like to do?",choices:[{name:"\u{1F4E4} Send a fax",value:"send"},{name:"\u{1F4CB} List faxes",value:"list"},{name:"\u{1F50D} Get fax details",value:"get"},{name:"\u{1F6AB} Cancel a fax",value:"cancel"},{name:"\u{1F4CA} Check status",value:"status"}]}]);if(i==="send"){let e=await me([{type:"input",name:"to",message:"Who would you like to send this fax to?",validate:a=>!a||a.trim().length===0?"Recipient fax number is required":/^\+?[1-9]\d{1,14}$/.test(a.trim())?!0:"Please enter a valid phone number in E.164 format (e.g., +12025551234)"},{type:"list",name:"contentType",message:"How would you like to provide the fax content?",choices:[{name:"File",value:"file"},{name:"URL",value:"url"}]}]),t,o;e.contentType==="file"?t=await Ls():o=(await me([{type:"input",name:"contentUrl",message:"Enter the URL of the content to send:",validate:l=>{if(!l||l.trim().length===0)return"Content URL is required";try{return new URL(l),!0}catch{return"Please enter a valid URL (e.g., https://example.com/document.pdf)"}}}])).contentUrl;let r=await Le();n.newline(),c.start("Sending fax...");let s=await r.sendFax({to:e.to,file:t,contentUrl:o});c.succeed("Fax sent successfully!"),n.newline(),n.info("Fax Details:"),n.info(`ID: ${s.id}`),n.info(`To: ${_(s.to)}`),n.info(`From: ${_(s.from)}`),n.info(`Status: ${s.status}`),n.info(`Service ID: ${s.serviceId}`),n.info(`Created: ${s.createTime}`),n.newline(),n.info('\u{1F4A1} Tip: Use "sinch fax get <fax-id>" to check fax status'),n.newline()}else if(i==="list")await Le(),n.newline(),n.info("\u{1F4E0} Coming soon!"),n.newline();else if(i==="get"){let{faxId:e}=await me([{type:"input",name:"faxId",message:"Enter the fax ID:",validate:t=>!t||t.trim().length===0?"Fax ID is required":!0}]);await Le(),n.newline(),n.info("\u{1F4E0} Coming soon!"),n.newline()}else if(i==="cancel"){let{faxId:e}=await me([{type:"input",name:"faxId",message:"Enter the fax ID to cancel:",validate:t=>!t||t.trim().length===0?"Fax ID is required":!0}]);await Le(),n.newline(),n.info("\u{1F4E0} Coming soon!"),n.newline()}else if(i==="status"){await f.load();let e=await f.hasFaxCredentials(),t=f.getFaxPublicCredentialInfo(),o=f.getFaxServiceId(),r=f.getFaxSenderNumber();n.newline(),e?(n.info("\u2713 Fax service authenticated"),n.info(`Project ID: ${t.projectId||"N/A"}`),n.info(`Key ID: ${t.keyId||"N/A"}`),n.info(`Service ID: ${o||"Not configured"}`),n.info(`Sender Number: ${r?_(r):"Not configured"}`),n.info(`Source: ${t.source}`)):(n.info("\u2717 Not authenticated"),n.info("Run: sinch auth login")),n.newline()}}catch(i){c.fail("Operation failed"),n.error(i.message),process.exit(1)}});Ge.command("send").description("Send a fax").option("-t, --to <number>","Recipient fax number").option("-f, --file <path>","Path to file to send").option("-u, --content-url <url>","URL to content to send",(i,e)=>e?[...Array.isArray(e)?e:[e],i]:i).option("--from <number>","Sender fax number (uses default if not specified)").option("--service-id <id>","Fax service ID (uses default if not specified)").option("--json","Output result as JSON").action(async i=>{try{let e=i.to,t=i.file,o=i.contentUrl;i.json?(e||(console.error(JSON.stringify({error:"Recipient number (-t, --to) is required in JSON mode"},null,2)),process.exit(1)),!t&&!o&&(console.error(JSON.stringify({error:"Either --file or --content-url must be provided"},null,2)),process.exit(1))):(e||(e=(await me([{type:"input",name:"to",message:"Who would you like to send this fax to?",validate:l=>!l||l.trim().length===0?"Recipient fax number is required":/^\+?[1-9]\d{1,14}$/.test(l.trim())?!0:"Please enter a valid phone number in E.164 format (e.g., +12025551234)"}])).to),!t&&!o&&((await me([{type:"list",name:"contentType",message:"How would you like to provide the fax content?",choices:[{name:"File",value:"file"},{name:"URL",value:"url"}]}])).contentType==="file"?t=await Ls():o=(await me([{type:"input",name:"contentUrl",message:"Enter the URL of the content to send:",validate:p=>{if(!p||p.trim().length===0)return"Content URL is required";try{return new URL(p),!0}catch{return"Please enter a valid URL (e.g., https://example.com/document.pdf)"}}}])).contentUrl));let r=await Le();i.json||(n.newline(),c.start("Sending fax..."));let s=await r.sendFax({to:e,from:i.from,file:t,contentUrl:o,serviceId:i.serviceId});i.json?console.log(JSON.stringify(s,null,2)):(c.succeed("Fax sent successfully!"),n.newline(),n.info("Fax Details:"),n.info(`ID: ${s.id}`),n.info(`To: ${s.to}`),n.info(`From: ${s.from}`),n.info(`Status: ${s.status}`),n.info(`Service ID: ${s.serviceId}`),n.info(`Created: ${s.createTime}`),n.newline(),n.info('\u{1F4A1} Tip: Use "sinch fax get <fax-id>" to check fax status'),n.newline())}catch(e){i.json?console.error(JSON.stringify({error:e.message},null,2)):(c.fail("Failed to send fax"),n.error(e.message)),process.exit(1)}});Ge.command("list").description("List sent faxes").option("-l, --limit <number>","Maximum number of faxes to return","10").option("--service-id <id>","Fax service ID (uses default if not specified)").option("--json","Output result as JSON").action(async i=>{try{await Le(),n.newline(),n.info("\u{1F4E0} Coming soon!"),n.newline()}catch(e){n.error(`Failed to list faxes: ${e.message}`),process.exit(1)}});Ge.command("get").description("Get fax details").argument("<fax-id>","Fax ID").option("--service-id <id>","Fax service ID (uses default if not specified)").option("--json","Output result as JSON").action(async(i,e)=>{try{await Le(),n.newline(),n.info("\u{1F4E0} Coming soon!"),n.newline()}catch(t){n.error(`Failed to get fax: ${t.message}`),process.exit(1)}});Ge.command("cancel").description("Cancel a pending fax").argument("<fax-id>","Fax ID to cancel").option("--service-id <id>","Fax service ID (uses default if not specified)").action(async(i,e)=>{try{await Le(),n.newline(),n.info("\u{1F4E0} Coming soon!"),n.newline()}catch(t){n.error(`Failed to cancel fax: ${t.message}`),process.exit(1)}});Ge.command("status").description("Check fax service authentication status").action(async()=>{try{await f.load();let i=await f.hasFaxCredentials(),e=f.getFaxPublicCredentialInfo(),t=f.getFaxServiceId(),o=f.getFaxSenderNumber();n.newline(),i?(n.info("\u2713 Fax service authenticated"),n.info(`Project ID: ${e.projectId||"N/A"}`),n.info(`Key ID: ${e.keyId||"N/A"}`),n.info(`Service ID: ${t||"Not configured"}`),n.info(`Sender Number: ${o?_(o):"Not configured"}`),n.info(`Source: ${e.source}`)):(n.info("\u2717 Not authenticated"),n.info("Run: sinch auth login")),n.newline()}catch(i){n.error(`Failed to check status: ${i.message}`),process.exit(1)}});_c=Ge});var Ei={};Te(Ei,{checkAndPromptTos:()=>Uc});async function Uc(i){let{api:e,keyId:t,nonInteractive:o=!1,spinner:r}=i,s=await e.getTosStatus();if(s.hasAccepted)return{accepted:!0,version:s.tosVersion,acceptedAt:s.acceptedAt};if(r&&r.stop(),o)return console.error(An.default.red(`
|
|
152
|
+
\u2192 Validation failed. Common issues:`,k+=`
|
|
153
|
+
\u2022 Phone numbers must be in E.164 format (e.g., +12025551234)`,k+=`
|
|
154
|
+
\u2022 Service ID must be valid`,k+=`
|
|
155
|
+
\u2022 From number must be a number that belongs to your project`)),new Error(k)}else throw h.request?new Error(`No response from Fax API: ${h.message}`):new Error(`Failed to send fax: ${h.message}`)}}async listFaxes(e){let{serviceId:t}=e;if(!(t||f.getFaxServiceId()))throw new Error("Fax service ID is required. Set it with: sinch config set fax service-id <id>");return[]}async getFaxStatus(e,t){let o=this.credentials||await f.getCredentials();if(!o)throw new Error("Not authenticated. Please run: sinch auth login");let s=`https://fax.api.sinch.com/v3/projects/${o.projectId}/faxes/${e}`;try{return(await Ri.default.get(s,{auth:{username:o.keyId,password:o.keySecret}})).data}catch(a){if(a.response){let l=a.response.status,p=a.response.data,d=`HTTP ${l}`;throw l===404?new Error(`Fax not found: ${e}`):l===401?new Error("Authentication failed. Please verify your credentials with: sinch auth login"):l===403?new Error("Permission denied. Please check that your API credentials have access to the Fax API."):(p?.message&&(d+=`: ${p.message}`),new Error(d))}throw new Error(`Failed to get fax status: ${a.message}`)}}async getFax(e,t){return this.getFaxStatus(e,t)}async cancelFax(e,t){if(!(t||f.getFaxServiceId()))throw new Error("Fax service ID is required. Set it with: sinch config set fax service-id <id>")}};Je=new js.Command("fax");Je.description("Manage Sinch Fax API");Je.action(async()=>{try{n.newline();let{action:i}=await ye([{type:"list",name:"action",message:"What would you like to do?",choices:[{name:"\u{1F4E4} Send a fax",value:"send"},{name:"\u{1F4CB} List faxes",value:"list"},{name:"\u{1F50D} Get fax details",value:"get"},{name:"\uFFFD Check fax status",value:"status"},{name:"\u{1F6AB} Cancel a fax",value:"cancel"},{name:"\u{1F510} Check authentication",value:"auth-status"}]}]);if(i==="send"){let e=await ye([{type:"input",name:"to",message:"Who would you like to send this fax to?",validate:a=>!a||a.trim().length===0?"Recipient fax number is required":/^\+?[1-9]\d{1,14}$/.test(a.trim())?!0:"Please enter a valid phone number in E.164 format (e.g., +12025551234)"},{type:"list",name:"contentType",message:"How would you like to provide the fax content?",choices:[{name:"File",value:"file"},{name:"URL",value:"url"}]}]),t,o;e.contentType==="file"?t=await qs():o=(await ye([{type:"input",name:"contentUrl",message:"Enter the URL of the content to send:",validate:l=>{if(!l||l.trim().length===0)return"Content URL is required";try{return new URL(l),!0}catch{return"Please enter a valid URL (e.g., https://example.com/document.pdf)"}}}])).contentUrl;let r=await Ee();n.newline(),c.start("Sending fax...");let s=await r.sendFax({to:e.to,file:t,contentUrl:o});c.succeed("Fax sent successfully!"),n.newline(),n.info("Fax Details:"),n.info(`ID: ${s.id}`),n.info(`To: ${q(s.to)}`),n.info(`From: ${q(s.from)}`),n.info(`Status: ${s.status}`),n.info(`Service ID: ${s.serviceId}`),n.info(`Created: ${s.createTime}`),n.newline(),n.info('\u{1F4A1} Tip: Use "sinch fax get <fax-id>" to check fax status'),n.newline()}else if(i==="list")await Ee(),n.newline(),n.info("\u{1F4E0} Coming soon!"),n.newline();else if(i==="get"){let{faxId:e}=await ye([{type:"input",name:"faxId",message:"Enter the fax ID:",validate:o=>!o||o.trim().length===0?"Fax ID is required":!0}]),t=await Ee();n.newline(),c.start("Fetching fax details...");try{let o=await t.getFax(e);c.succeed("Fax details retrieved!"),Ms(o)}catch(o){c.fail("Failed to get fax details"),n.error(o.message)}n.newline()}else if(i==="status"){let{faxId:e}=await ye([{type:"input",name:"faxId",message:"Enter the fax ID:",validate:o=>!o||o.trim().length===0?"Fax ID is required":!0}]),t=await Ee();n.newline(),c.start("Fetching fax status...");try{let o=await t.getFaxStatus(e);c.succeed("Status retrieved!"),on(o)}catch(o){c.fail("Failed to get fax status"),n.error(o.message)}n.newline()}else if(i==="cancel"){let{faxId:e}=await ye([{type:"input",name:"faxId",message:"Enter the fax ID to cancel:",validate:t=>!t||t.trim().length===0?"Fax ID is required":!0}]);await Ee(),n.newline(),n.info("\u{1F4E0} Coming soon!"),n.newline()}else if(i==="auth-status"){await f.load();let e=await f.hasFaxCredentials(),t=f.getFaxPublicCredentialInfo(),o=f.getFaxServiceId(),r=f.getFaxSenderNumber();n.newline(),e?(n.info("\u2713 Fax service authenticated"),n.info(`Project ID: ${t.projectId||"N/A"}`),n.info(`Key ID: ${t.keyId||"N/A"}`),n.info(`Service ID: ${o||"Not configured"}`),n.info(`Sender Number: ${r?q(r):"Not configured"}`),n.info(`Source: ${t.source}`)):(n.info("\u2717 Not authenticated"),n.info("Run: sinch auth login")),n.newline()}}catch(i){c.fail("Operation failed"),n.error(i.message),process.exit(1)}});Je.command("send").description("Send a fax").option("-t, --to <number>","Recipient fax number").option("-f, --file <path>","Path to file to send").option("-u, --content-url <url>","URL to content to send",(i,e)=>e?[...Array.isArray(e)?e:[e],i]:i).option("--from <number>","Sender fax number (uses default if not specified)").option("--service-id <id>","Fax service ID (uses default if not specified)").option("--json","Output result as JSON").action(async i=>{try{let e=i.to,t=i.file,o=i.contentUrl;i.json?(e||(console.error(JSON.stringify({error:"Recipient number (-t, --to) is required in JSON mode"},null,2)),process.exit(1)),!t&&!o&&(console.error(JSON.stringify({error:"Either --file or --content-url must be provided"},null,2)),process.exit(1))):(e||(e=(await ye([{type:"input",name:"to",message:"Who would you like to send this fax to?",validate:l=>!l||l.trim().length===0?"Recipient fax number is required":/^\+?[1-9]\d{1,14}$/.test(l.trim())?!0:"Please enter a valid phone number in E.164 format (e.g., +12025551234)"}])).to),!t&&!o&&((await ye([{type:"list",name:"contentType",message:"How would you like to provide the fax content?",choices:[{name:"File",value:"file"},{name:"URL",value:"url"}]}])).contentType==="file"?t=await qs():o=(await ye([{type:"input",name:"contentUrl",message:"Enter the URL of the content to send:",validate:p=>{if(!p||p.trim().length===0)return"Content URL is required";try{return new URL(p),!0}catch{return"Please enter a valid URL (e.g., https://example.com/document.pdf)"}}}])).contentUrl));let r=await Ee();i.json||(n.newline(),c.start("Sending fax..."));let s=await r.sendFax({to:e,from:i.from,file:t,contentUrl:o,serviceId:i.serviceId});i.json?console.log(JSON.stringify(s,null,2)):(c.succeed("Fax sent successfully!"),n.newline(),n.info("Fax Details:"),n.info(`ID: ${s.id}`),n.info(`To: ${s.to}`),n.info(`From: ${s.from}`),n.info(`Status: ${s.status}`),n.info(`Service ID: ${s.serviceId}`),n.info(`Created: ${s.createTime}`),n.newline(),n.info('\u{1F4A1} Tip: Use "sinch fax get <fax-id>" to check fax status'),n.newline())}catch(e){i.json?console.error(JSON.stringify({error:e.message},null,2)):(c.fail("Failed to send fax"),n.error(e.message)),process.exit(1)}});Je.command("list").description("List sent faxes").option("-l, --limit <number>","Maximum number of faxes to return","10").option("--service-id <id>","Fax service ID (uses default if not specified)").option("--json","Output result as JSON").action(async i=>{try{await Ee(),n.newline(),n.info("\u{1F4E0} Coming soon!"),n.newline()}catch(e){n.error(`Failed to list faxes: ${e.message}`),process.exit(1)}});Je.command("get").description("Get fax details").argument("<fax-id>","Fax ID").option("--service-id <id>","Fax service ID (uses default if not specified)").option("--json","Output result as JSON").action(async(i,e)=>{try{let o=await(await Ee()).getFax(i,e.serviceId);e.json?console.log(JSON.stringify(o,null,2)):Ms(o)}catch(t){e.json?console.error(JSON.stringify({error:t.message},null,2)):n.error(`Failed to get fax: ${t.message}`),process.exit(1)}});Je.command("cancel").description("Cancel a pending fax").argument("<fax-id>","Fax ID to cancel").option("--service-id <id>","Fax service ID (uses default if not specified)").action(async(i,e)=>{try{await Ee(),n.newline(),n.info("\u{1F4E0} Coming soon!"),n.newline()}catch(t){n.error(`Failed to cancel fax: ${t.message}`),process.exit(1)}});Je.command("auth-status").description("Check fax service authentication status").action(async()=>{try{await f.load();let i=await f.hasFaxCredentials(),e=f.getFaxPublicCredentialInfo(),t=f.getFaxServiceId(),o=f.getFaxSenderNumber();n.newline(),i?(n.info("\u2713 Fax service authenticated"),n.info(`Project ID: ${e.projectId||"N/A"}`),n.info(`Key ID: ${e.keyId||"N/A"}`),n.info(`Service ID: ${t||"Not configured"}`),n.info(`Sender Number: ${o?q(o):"Not configured"}`),n.info(`Source: ${e.source}`)):(n.info("\u2717 Not authenticated"),n.info("Run: sinch auth login")),n.newline()}catch(i){n.error(`Failed to check status: ${i.message}`),process.exit(1)}});Je.command("status").description("Get the status of a fax").argument("<fax-id>","Fax ID (e.g., 01K5SJVRNRXM6FP4J9M9HQ5J18)").option("--service-id <id>","Fax service ID (uses default if not specified)").option("--json","Output result as JSON").option("--wait","Wait for fax to complete or fail").option("--timeout <seconds>","Timeout in seconds for --wait mode (default: 300)","300").option("--watch","Watch fax status in real-time").option("--interval <seconds>","Polling interval in seconds for --watch mode (default: 5)","5").action(async(i,e)=>{try{let t=await Ee();if(e.wait&&e.watch&&(e.json?console.error(JSON.stringify({error:"Cannot use --wait and --watch together"},null,2)):n.error("Cannot use --wait and --watch together"),process.exit(1)),e.watch)await Jc(t,i,e);else if(e.wait)await qc(t,i,e);else{let o=await t.getFaxStatus(i,e.serviceId);e.json?console.log(JSON.stringify(o,null,2)):on(o)}}catch(t){e.json?console.error(JSON.stringify({error:t.message},null,2)):n.error(`Failed to get fax status: ${t.message}`),process.exit(1)}});Bc=Je});var Di={};xe(Di,{checkAndPromptTos:()=>Kc});async function Kc(i){let{api:e,keyId:t,nonInteractive:o=!1,spinner:r}=i,s=await e.getTosStatus();if(s.hasAccepted)return{accepted:!0,version:s.tosVersion,acceptedAt:s.acceptedAt};if(r&&r.stop(),o)return console.error(Nn.default.red(`
|
|
152
156
|
Terms of Service not accepted
|
|
153
157
|
`)),console.error("This project requires Terms of Service acceptance before use."),console.error(`Please run 'sinch auth login' interactively to accept the ToS.
|
|
154
|
-
`),console.error("After acceptance, you can use these credentials in CI/CD environments."),{accepted:!1};console.log(
|
|
158
|
+
`),console.error("After acceptance, you can use these credentials in CI/CD environments."),{accepted:!1};console.log(Nn.default.blue(`
|
|
155
159
|
Terms of Service
|
|
156
160
|
`)),console.log(`Before using Sinch Functions, you must accept our Terms of Service.
|
|
157
161
|
`),console.log("Key points:"),console.log(" - Usage-based billing for compute time"),console.log(" - You are responsible for function code and its behavior"),console.log(" - We may suspend service for policy violations"),console.log(` - Data processing per Sinch privacy policy
|
|
158
|
-
`),console.log(
|
|
159
|
-
`));let{accepted:a}=await
|
|
162
|
+
`),console.log(Nn.default.cyan(`Full terms: https://sinch.com/functions/terms
|
|
163
|
+
`));let{accepted:a}=await Bs.default.prompt([{type:"confirm",name:"accepted",message:"Do you accept the Terms of Service?",default:!1}]);if(!a)return{accepted:!1};let l=await e.acceptTos(t,s.currentVersion);return{accepted:!0,version:l.tosVersion,acceptedAt:l.acceptedAt}}var Nn,Bs,xi=G(()=>{"use strict";Nn=y(require("chalk")),Bs=y(require("inquirer"))});var rn=require("commander"),g=y(require("chalk")),Ze=y(require("fs-extra")),Rn=y(require("path")),Oi=y(require("os")),Hs=require("child_process");var Qe=y(require("fs")),Dn=y(require("path")),xn=y(require("chalk")),ea=18e5,ta="https://registry.npmjs.org/@sinch/cli";function na(){if(process.platform!=="win32")try{if(Qe.default.existsSync("/.dockerenv"))return!0;let i=Qe.default.readFileSync("/proc/1/cgroup","utf8");return i.includes("docker")||i.includes("containerd")}catch{return!1}return!!process.env.DOCKER_CONTAINER}function ia(){return!!process.env.CI}function oa(){return na()||ia()}function ra(i){return i.includes("-dev.")?"dev":parseInt(i.split(".")[0]||"0")>=1?"latest":"beta"}function sa(i){try{if(!Qe.default.existsSync(i))return!0;let e=parseInt(Qe.default.readFileSync(i,"utf8"));return Date.now()-e>ea}catch{return!0}}function aa(i,e){let t=i.replace(/^v/,"").split("-")[0]||"0.0.0",o=e.replace(/^v/,"").split("-")[0]||"0.0.0",r=t.split(".").map(a=>parseInt(a)||0),s=o.split(".").map(a=>parseInt(a)||0);for(let a=0;a<3;a++){let l=r[a]||0,p=s[a]||0;if(p>l)return!0;if(p<l)return!1}if(i.includes("-dev.")&&e.includes("-dev.")){let a=parseInt(i.split("-dev.")[1]||"0");return parseInt(e.split("-dev.")[1]||"0")>a}return!1}async function ca(i){try{let e=await fetch(ta,{signal:AbortSignal.timeout(3e3)});return e.ok&&(await e.json())["dist-tags"]?.[i]||null}catch{return null}}async function la(i,e){let t=Ot().version,o=ra(t);try{let r=await ca(o);if(!r)return;aa(t,r)&&(console.log(xn.default.yellow(`
|
|
160
164
|
\u{1F4E6} Update available: ${t} \u2192 ${r}`)),console.log(xn.default.cyan(`Run: npm install -g @sinch/cli@${o}
|
|
161
|
-
`))),
|
|
165
|
+
`))),Qe.default.mkdirSync(i,{recursive:!0}),Qe.default.writeFileSync(e,Date.now().toString())}catch{}}function _i(){if(oa())return;let i=Dn.default.join(require("os").homedir(),".sinch"),e=Dn.default.join(i,".last-update-check");sa(e)&&la(i,e).catch(()=>{})}ut();var Ui=require("@opentelemetry/sdk-node"),Mi=require("@opentelemetry/exporter-trace-otlp-http"),qi=require("@opentelemetry/auto-instrumentations-node"),Ji=require("@opentelemetry/resources"),ln=require("@opentelemetry/semantic-conventions"),da=Ot(),pa="https://otlp-gateway-prod-us-east-3.grafana.net/otlp",ua="Basic MTUyNjc0OTpnbGNfZXlKdklqb2lNVFkzTURBME1pSXNJbTRpT2lKNWIzVnlMV2R5WVdaaGJtRXRkRzlyWlc0aUxDSnJJam9pZERSRE5qSXdORFUxWW5reGVsSkJTRXMyV1dRNGFreGxJaXdpYlNJNmV5SnlJam9pY0hKdlpDMTFjeTFsWVhOMExUTWlmWDA9",cn=null;function On(){try{return process.env.OTEL_METRICS_EXPORTER="none",process.env.OTEL_LOGS_EXPORTER="none",cn=new Ui.NodeSDK({resource:(0,Ji.resourceFromAttributes)({[ln.ATTR_SERVICE_NAME]:"sinch-cli",[ln.ATTR_SERVICE_VERSION]:da.version}),traceExporter:new Mi.OTLPTraceExporter({url:`${pa}/v1/traces`,headers:{Authorization:ua}}),instrumentations:[(0,qi.getNodeAutoInstrumentations)({"@opentelemetry/instrumentation-fs":{enabled:!1},"@opentelemetry/instrumentation-dns":{enabled:!1},"@opentelemetry/instrumentation-net":{enabled:!1},"@opentelemetry/instrumentation-http":{ignoreOutgoingRequestHook:i=>{let e=i.hostname||i.host||"";return!e.includes("sinch")&&!e.includes("grafana.net")},headersToSpanAttributes:{client:{requestHeaders:[],responseHeaders:[]},server:{requestHeaders:[],responseHeaders:[]}}}})]}),cn.start(),!0}catch{return!1}}async function ft(){if(cn)try{await cn.shutdown()}catch{}}var mt=require("@opentelemetry/api");var fa=Ot();function Vi(i){return{"cli.command":ma(i),"cli.version":fa.version,"cli.sdk_version":ga(),"cli.node_version":process.version,"cli.os":process.platform,"cli.arch":process.arch,"cli.auth_method":ha(),"cli.is_ci":ya()}}function ma(i){let e=[],t=i;for(;t&&t.name()!=="sinch";)e.unshift(t.name()),t=t.parent;return e.join(" ")||"help"}function ga(){try{return require("@sinch/sdk-core/package.json").version}catch{return"not_installed"}}function ha(){return process.env.SINCH_KEY_ID&&process.env.SINCH_KEY_SECRET?"env":process.env.SINCH_AUTH_TOKEN?"token":"config"}function ya(){return!!(process.env.CI||process.env.GITHUB_ACTIONS||process.env.GITLAB_CI||process.env.JENKINS_URL||process.env.CIRCLECI||process.env.TRAVIS)}var wa=mt.trace.getTracer("sinch-cli"),Bi=new WeakMap;function Fn(i){i.hook("preAction",(e,t)=>{let o=Vi(t),r=wa.startSpan(`sinch ${o["cli.command"]}`,{attributes:o});Bi.set(t,{span:r,startTime:Date.now()})}),i.hook("postAction",(e,t)=>{let o=Bi.get(t);if(!o)return;let r=Date.now()-o.startTime;o.span.setAttribute("cli.duration_ms",r),o.span.setAttribute("cli.exit_code",0),o.span.setStatus({code:mt.SpanStatusCode.OK}),o.span.end()})}function Ft(i,e){let t=mt.trace.getActiveSpan();t&&(t.recordException(i),t.setAttribute("cli.exit_code",e),t.setStatus({code:mt.SpanStatusCode.ERROR,message:i.message}),t.end())}process.env.NODE_NO_WARNINGS||(process.env.NODE_NO_WARNINGS="1",process.removeAllListeners("warning"));var Hc=On();_i();var Wc=Ot(),zc=dr(),Gc=fr(),Yc=yr(),Xc=vr(),Zc=Ar(),Qc=Yr(),el=ws(),tl=Ds(),Ks=(Vs(),F(Js)),nl=Ks.default||Ks,W=new rn.Command;W.name("sinch").description("Sinch Functions - Serverless function platform for voice applications").version(Wc.version,"-V, --version","output the version number").helpOption("-h, --help","Display help for command").option("--profile <name>","Use a specific credential profile");W.addCommand(zc);W.addCommand(Gc);W.addCommand(Yc);W.addCommand(Xc);W.addCommand(Zc);W.addCommand(Qc);W.addCommand(el);W.addCommand(tl);W.addCommand(nl);Hc&&Fn(W);var sn=new rn.Command("auth");sn.description("Authentication management for Sinch Voice API");sn.command("login").description("Authenticate with Sinch Voice API").option("-f, --credentials-file <path>","Path to credentials JSON file").action(async i=>{let{config:e}=(E(),F(Oe)),t=require("inquirer");try{let o=W.opts().profile;if(o&&e.setProfileOverride(o),await e.load(),i.credentialsFile){console.log(g.default.blue(`
|
|
162
166
|
\u{1F510} Sinch Voice API Authentication`)),console.log(g.default.gray(`Loading credentials from: ${i.credentialsFile}
|
|
163
|
-
`)),
|
|
164
|
-
Expected format:`)),console.error(g.default.gray(JSON.stringify({projectId:"your-project-id",keyId:"your-key-id",keySecret:"your-key-secret",applicationKey:"(optional) your-app-key",applicationSecret:"(optional) your-app-secret"},null,2))),process.exit(
|
|
165
|
-
Terms of Service acceptance is required to use Sinch Functions.`)),process.exit(
|
|
167
|
+
`)),Ze.default.existsSync(i.credentialsFile)||(console.error(g.default.red(`\u274C Credentials file not found: ${i.credentialsFile}`)),process.exit(I.NO_INPUT));try{let d=Ze.default.readFileSync(i.credentialsFile,"utf-8"),u=JSON.parse(d),w=["projectId","keyId","keySecret"].filter(v=>!u[v]);w.length>0&&(console.error(g.default.red(`\u274C Missing required fields in credentials file: ${w.join(", ")}`)),console.error(g.default.gray(`
|
|
168
|
+
Expected format:`)),console.error(g.default.gray(JSON.stringify({projectId:"your-project-id",keyId:"your-key-id",keySecret:"your-key-secret",applicationKey:"(optional) your-app-key",applicationSecret:"(optional) your-app-secret"},null,2))),process.exit(I.DATA_ERROR));let h={projectId:u.projectId,keyId:u.keyId,keySecret:u.keySecret,applicationKey:u.applicationKey||void 0,applicationSecret:u.applicationSecret||void 0},{spinner:C}=(R(),F(yt));C.start("Verifying credentials...");try{C.update("Obtaining OAuth access token...");let{SinchAPI:v}=(Q(),F(et)),k=new v({apiUrl:e.get("apiUrl"),projectId:h.projectId,credentials:e._credentials}),re=await k.authenticateOAuth(h.keyId,h.keySecret);if(C.succeed("OAuth token obtained successfully!"),h.applicationKey&&h.applicationSecret){C.start("Testing Voice API connection...");let{SinchClient:j}=require("@sinch/sdk-core");await new j({applicationKey:h.applicationKey,applicationSecret:h.applicationSecret}).voice.applications.getCallbackURLs({applicationkey:h.applicationKey}),C.succeed("Voice credentials verified!")}else console.log(g.default.gray(" Voice credentials not provided (can be added later)"));await e._credentials.storeOAuthToken(re),C.start("Checking Terms of Service...");try{let{checkAndPromptTos:j}=(xi(),F(Di)),M=await j({api:k,keyId:h.keyId,nonInteractive:!!process.env.CI,spinner:C});M.accepted||(console.log(g.default.yellow(`
|
|
169
|
+
Terms of Service acceptance is required to use Sinch Functions.`)),process.exit(I.NO_PERMISSION)),C.succeed("Terms of Service accepted"),M.version&&(e.set("tosVersion",M.version),e.set("tosAcceptedAt",M.acceptedAt),await e.save())}catch(j){if(j.message?.includes("not found")||j.message?.includes("404"))C.info("Terms of Service check not available yet");else throw j}await e._credentials.store(h),console.log(g.default.green(`
|
|
166
170
|
\u2705 Authentication successful!`));return}catch(v){C.fail(g.default.red("Authentication failed")),console.error(g.default.red(`
|
|
167
|
-
\u274C ${v.message||"Failed to authenticate with provided credentials"}`)),process.exit(
|
|
171
|
+
\u274C ${v.message||"Failed to authenticate with provided credentials"}`)),process.exit(I.AUTH_FAILED)}}catch(d){console.error(g.default.red(`\u274C Failed to parse credentials file: ${d.message}`)),process.exit(I.DATA_ERROR)}}let r=await e.getCredentials(),s=e.getPublicCredentialInfo();console.log(g.default.blue(`
|
|
168
172
|
\u{1F510} Sinch API Authentication`)),console.log(r?g.default.gray(`Found existing credentials. Press Enter to reuse them or enter new values.
|
|
169
173
|
`):g.default.gray(`Enter your Sinch API credentials (from the Sinch Dashboard)
|
|
170
|
-
`));let a=await t.prompt([{type:"input",name:"projectId",message:"Project ID (from Sinch Dashboard):",default:s?.projectId||void 0,validate:d=>!d&&s?.projectId?!0:d.length>0||"Project ID is required"},{type:"input",name:"keyId",message:"Key ID (from Project \u2192 Access Keys):",default:s?.keyId||void 0,validate:d=>!d&&s?.keyId?!0:d.length>0||"Key ID is required"},{type:"password",name:"keySecret",message:"Key Secret:",default:r?.keySecret||void 0,validate:d=>!d&&r?.keySecret?!0:d.length>0||"Key Secret is required"}]),l={projectId:a.projectId||s?.projectId,keyId:a.keyId||s?.keyId,keySecret:a.keySecret||r?.keySecret},{spinner:p}=(
|
|
174
|
+
`));let a=await t.prompt([{type:"input",name:"projectId",message:"Project ID (from Sinch Dashboard):",default:s?.projectId||void 0,validate:d=>!d&&s?.projectId?!0:d.length>0||"Project ID is required"},{type:"input",name:"keyId",message:"Key ID (from Project \u2192 Access Keys):",default:s?.keyId||void 0,validate:d=>!d&&s?.keyId?!0:d.length>0||"Key ID is required"},{type:"password",name:"keySecret",message:"Key Secret:",default:r?.keySecret||void 0,validate:d=>!d&&r?.keySecret?!0:d.length>0||"Key Secret is required"}]),l={projectId:a.projectId||s?.projectId,keyId:a.keyId||s?.keyId,keySecret:a.keySecret||r?.keySecret},{spinner:p}=(R(),F(yt));p.start("Verifying credentials...");try{p.update("Obtaining OAuth access token...");let{SinchAPI:d}=(Q(),F(et)),u=new d({apiUrl:e.get("apiUrl"),projectId:l.projectId||e.get("projectId"),credentials:e._credentials}),m=await u.authenticateOAuth(l.keyId,l.keySecret);p.succeed("API credentials verified!"),await e._credentials.storeOAuthToken(m),p.start("Checking Terms of Service...");try{let{checkAndPromptTos:C}=(xi(),F(Di)),v=await C({api:u,keyId:l.keyId,nonInteractive:process.argv.includes("--non-interactive")||!!process.env.CI,spinner:p});v.accepted||(console.log(g.default.yellow(`
|
|
171
175
|
Terms of Service acceptance is required to use Sinch Functions.`)),process.exit(1)),p.succeed("Terms of Service accepted"),v.version&&(e.set("tosVersion",v.version),e.set("tosAcceptedAt",v.acceptedAt),await e.save())}catch(C){if(C.message?.includes("not found")||C.message?.includes("404"))p.info("Terms of Service check not available yet");else throw C}let w=s?.applicationKey&&r?.applicationSecret,{addVoice:h}=await t.prompt([{type:"confirm",name:"addVoice",message:"Add Voice application credentials? (for voice templates and callbacks)",default:w||!1}]);if(h){let C=await t.prompt([{type:"input",name:"applicationKey",message:"Voice Application Key:",default:s?.applicationKey||void 0,validate:v=>!v&&s?.applicationKey?!0:v.length>0||"Application Key is required"},{type:"password",name:"applicationSecret",message:"Voice Application Secret:",default:r?.applicationSecret||void 0,validate:v=>!v&&r?.applicationSecret?!0:v.length>0||"Application Secret is required"}]);l.applicationKey=C.applicationKey||s?.applicationKey,l.applicationSecret=C.applicationSecret||r?.applicationSecret,p.start("Testing Voice API connection...");try{let{SinchClient:v}=require("@sinch/sdk-core");await new v({applicationKey:l.applicationKey,applicationSecret:l.applicationSecret}).voice.applications.getCallbackURLs({applicationkey:l.applicationKey}),p.succeed("Voice credentials verified!")}catch(v){p.fail("Voice API test failed"),console.log(g.default.yellow(` ${v.message}`)),console.log(g.default.gray(" Voice credentials will be saved but may not work."))}}await e._credentials.store(l),console.log(g.default.green(`
|
|
172
176
|
\u2705 Authentication successful!`))}catch(d){p.fail("Authentication failed"),console.error(g.default.red(`
|
|
173
177
|
\u274C Error: ${d.message}`)),console.log(g.default.yellow(`
|
|
174
|
-
\u{1F4A1} Please check your credentials and try again`)),process.exit(
|
|
175
|
-
\u{1F510} Authentication Status`)),e&&t){console.log(g.default.green("\u2705 Authenticated")),console.log(` Project ID: ${t.projectId}`),console.log(` Key ID: ${t.keyId}`),t.source==="environment"?console.log(g.default.gray(" (Credentials from environment variables)")):console.log(g.default.gray(" (Secrets stored securely in OS keychain)")),t.applicationKey?console.log(` Voice App Key: ${t.applicationKey}`):(console.log(g.default.gray(" Voice credentials: Not configured")),console.log(g.default.gray(" (Add with: sinch auth login)")));try{let r=(
|
|
178
|
+
\u{1F4A1} Please check your credentials and try again`)),process.exit(I.AUTH_FAILED)}}catch(o){console.error(g.default.red(`Authentication failed: ${o.message}`)),process.exit(I.AUTH_FAILED)}});sn.command("status").description("Show current authentication status").action(async()=>{let{config:i}=(E(),F(Oe));try{await i.load();let e=await i.hasCredentials(),t=i.getPublicCredentialInfo();if(console.log(g.default.blue(`
|
|
179
|
+
\u{1F510} Authentication Status`)),e&&t){console.log(g.default.green("\u2705 Authenticated")),console.log(` Project ID: ${t.projectId}`),console.log(` Key ID: ${t.keyId}`),t.source==="environment"?console.log(g.default.gray(" (Credentials from environment variables)")):console.log(g.default.gray(" (Secrets stored securely in OS keychain)")),t.applicationKey?console.log(` Voice App Key: ${t.applicationKey}`):(console.log(g.default.gray(" Voice credentials: Not configured")),console.log(g.default.gray(" (Add with: sinch auth login)")));try{let r=(Q(),F(et)).default,s=i.getApiConfig();await new r(s).authenticate(),console.log(g.default.green(" OAuth Token: Valid"))}catch{console.log(g.default.yellow(" OAuth Token: Expired or invalid (will auto-refresh on next API call)"))}let o=await i.getApplicationCredentials();if(o){let{spinner:r}=(R(),F(yt));r.start("Testing Voice API connection...");try{let{SinchClient:s}=require("@sinch/sdk-core");await new s({applicationKey:o.applicationKey,applicationSecret:o.applicationSecret}).voice.applications.getCallbackURLs({applicationkey:o.applicationKey}),r.succeed("Voice connection active")}catch{r.fail("Voice connection failed"),console.log(g.default.yellow("\u26A0\uFE0F Voice credentials may be expired or invalid"))}}try{let{SinchAPI:r}=(Q(),F(et)),s=i.getApiConfig(),l=await new r(s).getTosStatus();console.log(g.default.blue(`
|
|
176
180
|
Terms of Service:`)),l.hasAccepted?(console.log(g.default.green(" Accepted")),l.tosVersion&&console.log(` Version: ${l.tosVersion}`),l.acceptedAt&&console.log(` Accepted: ${new Date(l.acceptedAt).toLocaleString()}`)):(console.log(g.default.yellow(" Not accepted")),console.log(g.default.yellow(' Run "sinch auth login" to accept the Terms of Service')))}catch{let s=i.get("tosVersion");if(s){console.log(g.default.blue(`
|
|
177
|
-
Terms of Service:`)),console.log(g.default.gray(` Last accepted version: ${s}`));let a=i.get("tosAcceptedAt");a&&console.log(g.default.gray(` Accepted: ${new Date(a).toLocaleString()}`)),console.log(g.default.gray(" (Could not verify with API)"))}}}else console.log(g.default.red("\u274C Not authenticated")),console.log(g.default.gray('Run "sinch auth login" to authenticate'))}catch(e){console.error(g.default.red(`Failed to check status: ${e.message}`)),process.exit(1)}});
|
|
181
|
+
Terms of Service:`)),console.log(g.default.gray(` Last accepted version: ${s}`));let a=i.get("tosAcceptedAt");a&&console.log(g.default.gray(` Accepted: ${new Date(a).toLocaleString()}`)),console.log(g.default.gray(" (Could not verify with API)"))}}}else console.log(g.default.red("\u274C Not authenticated")),console.log(g.default.gray('Run "sinch auth login" to authenticate'))}catch(e){console.error(g.default.red(`Failed to check status: ${e.message}`)),process.exit(1)}});sn.command("logout").description("Clear stored authentication credentials").action(async()=>{let{config:i}=(E(),F(Oe)),e=require("inquirer");try{(await e.prompt([{type:"confirm",name:"confirm",message:"Are you sure you want to logout and clear credentials?",default:!1}])).confirm?(await i.load(),await i.clearCredentials(),console.log(g.default.green("\u2705 Logged out successfully")),console.log(g.default.gray("All credentials cleared from secure storage"))):console.log(g.default.gray("Logout cancelled"))}catch(t){console.error(g.default.red(`Logout failed: ${t.message}`)),process.exit(1)}});W.addCommand(sn);var pt=new rn.Command("config");pt.description("Configuration management");pt.command("set <args...>").description("Set configuration value (key=value or fax serviceID=value)").action(async i=>{let{config:e}=(E(),F(Oe)),t=W.opts().profile;t&&e.setProfileOverride(t);try{if(await e.load(),i[0]==="fax"&&i.length===2){let[o,...r]=i[1].split("="),s=r.join("=");(!o||!s)&&(console.error(g.default.red("Invalid format. Use: sinch config set fax serviceID=<value>")),process.exit(1));let a=o.toLowerCase().replace(/-/g,"");a==="serviceid"?(await e.setFaxServiceId(s),console.log(g.default.green(`Set fax service-id = ${s}`))):a==="sendernumber"?(await e.setFaxSenderNumber(s),console.log(g.default.green(`Set fax sender-number = ${s}`))):(console.error(g.default.red(`Unknown fax config key: ${o}`)),console.error(g.default.gray("Valid fax config keys: serviceID (or service-id), senderNumber (or sender-number)")),process.exit(1))}else{let[o,...r]=i[0].split("="),s=r.join("=");(!o||!s)&&(console.error(g.default.red("Invalid format. Use: sinch config set key=value")),process.exit(1)),e.set(o,s),await e.save(),console.log(g.default.green(`Set ${o} = ${s}`))}}catch(o){console.error(g.default.red(`Failed to set config: ${o.message}`)),process.exit(1)}});pt.command("get <args...>").description("Get configuration value").action(async i=>{let{config:e}=(E(),F(Oe)),t=W.opts().profile;t&&e.setProfileOverride(t);try{if(await e.load(),i[0]==="fax"&&i.length===2){let o=i[1],r=o.toLowerCase().replace(/-/g,"");if(r==="serviceid"){let s=e.getFaxServiceId();console.log(s!==null?s:g.default.gray("(not set)"))}else if(r==="sendernumber"){let s=e.getFaxSenderNumber();console.log(s!==null?s:g.default.gray("(not set)"))}else console.error(g.default.red(`Unknown fax config key: ${o}`)),process.exit(1)}else{let o=i.join(" "),r=e.get(o);console.log(r!==null?r:g.default.gray("(not set)"))}}catch(o){console.error(g.default.red(`Failed to get config: ${o.message}`)),process.exit(1)}});pt.command("list").description("List all configuration values").action(async()=>{let{config:i}=(E(),F(Oe)),e=W.opts().profile;e&&i.setProfileOverride(e);try{await i.load(),console.log(g.default.blue(`
|
|
178
182
|
Configuration (profile: ${i.getActiveProfileName()}):`));let t=i.getApiConfig();Object.entries(t).forEach(([s,a])=>{console.log(s==="credentials"?` ${s}: ${g.default.gray("(secure)")}`:` ${s}: ${a}`)});let o=i.getFaxServiceId(),r=i.getFaxSenderNumber();(o||r)&&(console.log(g.default.blue(`
|
|
179
|
-
Fax Configuration:`)),o&&console.log(` serviceID: ${o}`),r&&console.log(` senderNumber: ${r}`))}catch(t){console.error(g.default.red(`Failed to list config: ${t.message}`)),process.exit(1)}});var
|
|
183
|
+
Fax Configuration:`)),o&&console.log(` serviceID: ${o}`),r&&console.log(` senderNumber: ${r}`))}catch(t){console.error(g.default.red(`Failed to list config: ${t.message}`)),process.exit(1)}});var Rt=new rn.Command("profile");Rt.description("Manage credential profiles for multi-project workflows");Rt.command("create <name>").description("Create a new credential profile").action(async i=>{let e=require("inquirer"),{profileManager:t}=(ht(),F(Ut));try{await t.init(),await t.create(i),console.log(g.default.green(`Profile '${i}' created.`));let{switchNow:o}=await e.prompt([{type:"confirm",name:"switchNow",message:`Switch to profile '${i}' now?`,default:!0}]);if(o){await t.use(i),console.log(g.default.green(`Switched to profile '${i}'.`));let{authNow:r}=await e.prompt([{type:"confirm",name:"authNow",message:"Authenticate now?",default:!0}]);r&&await W.parseAsync(["auth","login","--profile",i],{from:"user"})}}catch(o){console.error(g.default.red(`Failed to create profile: ${o.message}`)),process.exit(1)}});Rt.command("use <name>").description("Switch the active credential profile").action(async i=>{let{profileManager:e}=(ht(),F(Ut));try{await e.init(),await e.use(i),console.log(g.default.green(`Switched to profile '${i}'.`))}catch(t){console.error(g.default.red(`Failed to switch profile: ${t.message}`)),process.exit(1)}});Rt.command("list").description("List all credential profiles").action(async()=>{let{profileManager:i}=(ht(),F(Ut)),{logger:e}=(T(),F(eo));try{await i.init();let t=await i.list();if(t.length===0){console.log(g.default.gray("No profiles configured."));return}console.log(g.default.blue(`
|
|
180
184
|
Credential Profiles:
|
|
181
|
-
`));let o=["Name","Project ID","Key ID","Active"],r=t.map(s=>[s.name,s.projectId||g.default.gray("(not set)"),s.keyId||g.default.gray("(not set)"),s.active?g.default.green("*"):""]);e.table(o,r),console.log("")}catch(t){console.error(g.default.red(`Failed to list profiles: ${t.message}`)),process.exit(1)}});
|
|
185
|
+
`));let o=["Name","Project ID","Key ID","Active"],r=t.map(s=>[s.name,s.projectId||g.default.gray("(not set)"),s.keyId||g.default.gray("(not set)"),s.active?g.default.green("*"):""]);e.table(o,r),console.log("")}catch(t){console.error(g.default.red(`Failed to list profiles: ${t.message}`)),process.exit(1)}});Rt.command("delete <name>").description("Delete a credential profile").action(async i=>{let e=require("inquirer"),{profileManager:t}=(ht(),F(Ut));try{await t.init();let{confirm:o}=await e.prompt([{type:"confirm",name:"confirm",message:`Delete profile '${i}'? This cannot be undone.`,default:!1}]);if(!o){console.log(g.default.gray("Cancelled."));return}await t.delete(i),console.log(g.default.green(`Profile '${i}' deleted.`))}catch(o){console.error(g.default.red(`Failed to delete profile: ${o.message}`)),process.exit(1)}});pt.addCommand(Rt);pt.action(async()=>{console.log(g.default.blue(`
|
|
182
186
|
Configuration Management`)),console.log(g.default.gray(`Use "sinch config --help" for available commands
|
|
183
|
-
`)),console.log(" sinch config set key=value Set a config value"),console.log(" sinch config get <key> Get a config value"),console.log(" sinch config list List all config values"),console.log(" sinch config profile list List profiles"),console.log(" sinch config profile create <name> Create a profile"),console.log(" sinch config profile use <name> Switch profile"),console.log(" sinch config profile delete <name> Delete a profile"),console.log("")});
|
|
187
|
+
`)),console.log(" sinch config set key=value Set a config value"),console.log(" sinch config get <key> Get a config value"),console.log(" sinch config list List all config values"),console.log(" sinch config profile list List profiles"),console.log(" sinch config profile create <name> Create a profile"),console.log(" sinch config profile use <name> Switch profile"),console.log(" sinch config profile delete <name> Delete a profile"),console.log("")});W.addCommand(pt);W.command("health").description("Check API connection and health").action(async()=>{let{SinchAPI:i}=(Q(),F(et)),{config:e}=(E(),F(Oe)),{spinner:t}=(R(),F(yt));try{await e.load();let o=new i(e.getApiConfig());t.start("Checking API health...");let r=await o.checkHealth();t.succeed("API is healthy"),console.log(g.default.blue(`
|
|
184
188
|
\u{1F3E5} Health Status:`)),console.log(` Status: ${g.default.green(r.status)}`),console.log(` API URL: ${e.get("apiUrl")}`),console.log(` Project ID: ${e.get("projectId")}`)}catch(o){t.fail("API health check failed"),console.error(g.default.red(`
|
|
185
|
-
\u274C ${o.message}`)),process.exit(1)}});
|
|
186
|
-
\u{1F4A5} Uncaught Exception: ${i.message}`)),process.env.SINCH_DEBUG&&console.error(i.stack);let e=i instanceof D?i.exitCode
|
|
187
|
-
\u{1F4A5} Unhandled Rejection: ${i}`)),process.env.SINCH_DEBUG&&console.error(i);let e=i instanceof D?i.exitCode
|
|
188
|
-
\u274C Authentication required`)),console.error(`Please set up authentication first with: ${d}`),console.error("Or provide credentials via environment variables for CI/CD"),process.exit(
|
|
189
|
+
\u274C ${o.message}`)),process.exit(1)}});W.command("completion").description("Generate shell completion scripts").option("--shell <shell>","Shell type (powershell, bash, zsh)","powershell").option("--install","Automatically install completion (PowerShell only)").action(async i=>{let e=i.shell.toLowerCase();i.install&&e==="powershell"?await ol():e==="powershell"?al():e==="bash"?cl():e==="zsh"?ll():(console.error(g.default.red(`Unsupported shell: ${e}`)),console.log("Supported shells: powershell, bash, zsh"),process.exit(1))});process.on("uncaughtException",i=>{console.error(g.default.red(`
|
|
190
|
+
\u{1F4A5} Uncaught Exception: ${i.message}`)),process.env.SINCH_DEBUG&&console.error(i.stack);let e=i instanceof D?i.exitCode:I.SOFTWARE;Ft(i,e),ft().finally(()=>process.exit(e))});process.on("unhandledRejection",i=>{console.error(g.default.red(`
|
|
191
|
+
\u{1F4A5} Unhandled Rejection: ${i}`)),process.env.SINCH_DEBUG&&console.error(i);let e=i instanceof D?i.exitCode:I.SOFTWARE,t=i instanceof Error?i:new Error(String(i));Ft(t,e),ft().finally(()=>process.exit(e))});async function il(){let i=process.argv.slice(2),e=i[0],t=["auth","config","help","completion","--help","-h","--version","-V"],o=i.includes("--non-interactive");if(e&&!t.includes(e)&&!t.some(r=>i.includes(r))){let{config:r}=(E(),F(Oe)),s=i.indexOf("--profile");s!==-1&&i[s+1]&&r.setProfileOverride(i[s+1]),await r.load();let a=e==="fax",l=!1,p="Sinch",d="sinch auth login";if(l=await r.hasCredentials(),a&&(p="Sinch Fax API"),!l){o&&(console.error(g.default.red(`
|
|
192
|
+
\u274C Authentication required`)),console.error(`Please set up authentication first with: ${d}`),console.error("Or provide credentials via environment variables for CI/CD"),process.exit(I.AUTH_REQUIRED));let u=require("inquirer");console.log(g.default.yellow(`
|
|
189
193
|
\u26A0\uFE0F Authentication Required`)),console.log(`You need to authenticate with ${p} to use the CLI.
|
|
190
194
|
`);let{shouldLogin:m}=await u.prompt([{type:"confirm",name:"shouldLogin",message:"Would you like to login now?",default:!0}]);m?process.argv.splice(2,process.argv.length-2,"auth","login"):(console.log(`
|
|
191
195
|
You can authenticate anytime with:`),console.log(` ${g.default.cyan(d)}
|
|
192
|
-
`),process.exit(0))}}await
|
|
196
|
+
`),process.exit(0))}}await W.parseAsync(process.argv),process.argv.slice(2).length||(console.log(g.default.blue.bold(`
|
|
193
197
|
\u{1F3AF} Sinch Functions CLI`)),console.log(g.default.gray(`Serverless function platform for voice applications
|
|
194
|
-
`)),console.log("Quick start:"),console.log(` ${g.default.cyan("sinch auth login")} # Authenticate with Sinch Voice API`),console.log(` ${g.default.cyan("sinch templates list")} # Browse available templates`),console.log(` ${g.default.cyan("sinch functions init")} # Create a new function`),console.log(` ${g.default.cyan("sinch functions dev")} # Start local development`),console.log(` ${g.default.cyan("sinch voice callback-url")} # Update webhook URL for live testing`),console.log(` ${g.default.cyan("sinch functions deploy")} # Deploy to production`),console.log(` ${g.default.cyan("sinch functions status [id]")} # Check deployment status`),console.log(` ${g.default.cyan("sinch secrets list")} # Manage custom secrets`),console.log(""),
|
|
198
|
+
`)),console.log("Quick start:"),console.log(` ${g.default.cyan("sinch auth login")} # Authenticate with Sinch Voice API`),console.log(` ${g.default.cyan("sinch templates list")} # Browse available templates`),console.log(` ${g.default.cyan("sinch functions init")} # Create a new function`),console.log(` ${g.default.cyan("sinch functions dev")} # Start local development`),console.log(` ${g.default.cyan("sinch voice callback-url")} # Update webhook URL for live testing`),console.log(` ${g.default.cyan("sinch functions deploy")} # Deploy to production`),console.log(` ${g.default.cyan("sinch functions status [id]")} # Check deployment status`),console.log(` ${g.default.cyan("sinch secrets list")} # Manage custom secrets`),console.log(""),W.help())}il().then(()=>ft()).catch(async i=>{console.error(g.default.red("Error:"),i.message),Ft(i instanceof Error?i:new Error(String(i)),1),await ft(),process.exit(1)});async function ol(){let{spinner:i}=(R(),F(yt));try{i.start("Installing PowerShell completion...");let e=Rn.default.join(Oi.default.homedir(),"Documents","PowerShell"),t=Rn.default.join(e,"sinch-completion.ps1");await Ze.default.ensureDir(e),i.update("Creating completion script...");let o=sl();await Ze.default.writeFile(t,o),i.update("Updating PowerShell profile...");let r=await rl(),s="";await Ze.default.pathExists(r)&&(s=await Ze.default.readFile(r,"utf8"));let a='. "$env:USERPROFILE\\Documents\\PowerShell\\sinch-completion.ps1"';if(s.includes("sinch-completion.ps1"))i.info("PowerShell completion already installed"),console.log(g.default.blue(`
|
|
195
199
|
\u2139\uFE0F Completion is already installed`)),console.log(g.default.gray("If tab completion isn't working, try restarting PowerShell"));else{let l=s+(s?`
|
|
196
200
|
`:"")+`# Sinch Functions CLI completion
|
|
197
201
|
`+a+`
|
|
198
|
-
`;await
|
|
202
|
+
`;await Ze.default.writeFile(r,l),i.succeed("PowerShell completion installed successfully!"),console.log(g.default.green(`
|
|
199
203
|
\u2705 Installation Complete!`)),console.log(g.default.blue("\u{1F4C1} Files created:")),console.log(` ${g.default.gray(t)}`),console.log(` ${g.default.gray("Updated:")} ${r}`),console.log(g.default.yellow(`
|
|
200
204
|
\u26A1 To activate completion:`)),console.log(" 1. Restart PowerShell, OR"),console.log(" 2. Run: "+g.default.cyan(". $PROFILE")),console.log(g.default.gray(`
|
|
201
205
|
\u{1F4A1} Test with: sinch functions <TAB>`))}}catch(e){i.fail("Failed to install PowerShell completion"),console.error(g.default.red(`\u274C Error: ${e.message}`)),console.log(g.default.yellow(`
|
|
202
|
-
\u{1F4A1} Try manual installation with: sinch completion`)),process.exit(1)}}async function
|
|
206
|
+
\u{1F4A1} Try manual installation with: sinch completion`)),process.exit(1)}}async function rl(){return new Promise(i=>{let e=t=>new Promise(o=>{let r=(0,Hs.spawn)(t,["-Command","$PROFILE"],{stdio:["ignore","pipe","pipe"]}),s="";r.stdout.on("data",a=>{s+=a.toString()}),r.on("close",a=>{o(a===0?{success:!0,path:s.trim(),version:t}:{success:!1})}),r.on("error",()=>{o({success:!1})})});e("pwsh").then(t=>{t.success&&t.path?(console.log(g.default.gray(` Detected PowerShell 7 profile: ${t.path}`)),i(t.path)):e("powershell").then(o=>{if(o.success&&o.path)console.log(g.default.gray(` Detected Windows PowerShell profile: ${o.path}`)),i(o.path);else{let r=Rn.default.join(Oi.default.homedir(),"Documents","PowerShell","Microsoft.PowerShell_profile.ps1");console.log(g.default.gray(` Using fallback profile path: ${r}`)),i(r)}})})})}function sl(){return`# PowerShell completion for Sinch Functions CLI
|
|
203
207
|
# Auto-generated by 'sinch completion --install'
|
|
204
208
|
# Compatible with both PowerShell 7 and Windows PowerShell 5.1
|
|
205
209
|
|
|
@@ -246,7 +250,7 @@ Register-ArgumentCompleter -Native -CommandName sinch -ScriptBlock {
|
|
|
246
250
|
# Silently fail if there are any errors in completion
|
|
247
251
|
# This prevents PowerShell startup errors
|
|
248
252
|
}
|
|
249
|
-
}`}function
|
|
253
|
+
}`}function al(){let i=`
|
|
250
254
|
# PowerShell completion for Sinch Functions CLI
|
|
251
255
|
Register-ArgumentCompleter -Native -CommandName sinch -ScriptBlock {
|
|
252
256
|
param($wordToComplete, $commandAst, $cursorPosition)
|
|
@@ -297,7 +301,7 @@ Register-ArgumentCompleter -Native -CommandName sinch -ScriptBlock {
|
|
|
297
301
|
#
|
|
298
302
|
# To find your profile location, run: $PROFILE
|
|
299
303
|
`;console.log(g.default.blue("\u{1F527} PowerShell Completion Script")),console.log(g.default.gray(`Copy and save this to your PowerShell profile:
|
|
300
|
-
`)),console.log(i),console.log(g.default.yellow("Installation Instructions:")),console.log(g.default.green("\u{1F680} Easy way: ")+g.default.cyan("sinch completion --install")),console.log(g.default.gray("\u{1F4DD} Manual way:")),console.log("1. Save this script as sinch-completion.ps1 in your Documents\\PowerShell folder"),console.log("2. Add this line to your PowerShell profile:"),console.log(g.default.cyan(' . "$env:USERPROFILE\\\\Documents\\\\PowerShell\\\\sinch-completion.ps1"')),console.log("3. Restart PowerShell or run: . $PROFILE")}function
|
|
304
|
+
`)),console.log(i),console.log(g.default.yellow("Installation Instructions:")),console.log(g.default.green("\u{1F680} Easy way: ")+g.default.cyan("sinch completion --install")),console.log(g.default.gray("\u{1F4DD} Manual way:")),console.log("1. Save this script as sinch-completion.ps1 in your Documents\\PowerShell folder"),console.log("2. Add this line to your PowerShell profile:"),console.log(g.default.cyan(' . "$env:USERPROFILE\\\\Documents\\\\PowerShell\\\\sinch-completion.ps1"')),console.log("3. Restart PowerShell or run: . $PROFILE")}function cl(){let i=`
|
|
301
305
|
# Bash completion for Sinch Functions CLI
|
|
302
306
|
_sinch_completion() {
|
|
303
307
|
local cur prev commands
|
|
@@ -338,7 +342,7 @@ complete -F _sinch_completion sinch
|
|
|
338
342
|
|
|
339
343
|
# To install: Add this to your ~/.bashrc or ~/.bash_profile
|
|
340
344
|
`;console.log(g.default.blue("\u{1F527} Bash Completion Script")),console.log(g.default.gray(`Add this to your ~/.bashrc or ~/.bash_profile:
|
|
341
|
-
`)),console.log(i)}function
|
|
345
|
+
`)),console.log(i)}function ll(){let i=`
|
|
342
346
|
#compdef sinch
|
|
343
347
|
|
|
344
348
|
_sinch() {
|