appoiint 4.11.0 → 4.13.0
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/api.js +1 -1
- package/dist/commands/admin.js +1 -1
- package/dist/commands/bookings.js +1 -1
- package/dist/commands/domains.js +1 -1
- package/dist/main.js +1 -1
- package/package.json +1 -1
package/dist/api.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
const https=require("https"),http=require("http"),BASE="/saas/api/v1/sdk";function request(e,t,n,s,a){return new Promise((i,o)=>{const r=new URL(s,e),p="https:"===r.protocol,c=p?https:http,u={"Content-Type":"application/json"};t&&(u.Authorization=`Bearer ${t}`);const d=a?JSON.stringify(a):null;d&&(u["Content-Length"]=Buffer.byteLength(d));const E=c.request({hostname:r.hostname,port:r.port||(p?443:80),path:r.pathname+r.search,method:n,headers:u,timeout:3e4},e=>{let t="";e.on("data",e=>t+=e),e.on("end",()=>{try{const n=JSON.parse(t);e.statusCode>=400?o(new Error(n.message||n.error||`HTTP ${e.statusCode}`)):i(n.data||n)}catch{e.statusCode>=400?o(new Error(`HTTP ${e.statusCode}: ${t.slice(0,200)}`)):i(t)}})});E.on("error",o),E.on("timeout",()=>{E.destroy(),o(new Error("Request timeout (30s)"))}),d&&E.write(d),E.end()})}function api(e){const{baseUrl:t,apiKey:n}=e,s=(e,s,a)=>request(t,n,e,s,a);return{signup:e=>request(t,"","POST",`${BASE}/tai/agent/signup`,e),signin:e=>request(t,"","POST",`${BASE}/auth/signin`,e),activate:e=>request(t,"","POST",`${BASE}/tai/agent/activate`,e),createRoom:e=>s("POST",`${BASE}/tai/agent/rooms`,e),listRooms:()=>s("GET",`${BASE}/tai/agent/rooms`),roomStatus:e=>s("GET",`${BASE}/tai/agent/rooms/${e}`),endRoom:e=>s("DELETE",`${BASE}/tai/agent/rooms/${e}`),invite:(e,t)=>s("POST",`${BASE}/tai/agent/rooms/${e}/invite`,t),transcript:(e,t)=>s("GET",`${BASE}/tai/agent/rooms/${e}/transcript?format=${t||"json"}`),joinMeeting:e=>s("POST",`${BASE}/tai/agent/meeting/join`,e),leaveMeeting:e=>s("POST",`${BASE}/tai/agent/meeting/leave`,e),events:()=>s("GET",e.userId?`${BASE}/scheduling/event-types/by-user/${e.userId}`:`${BASE}/scheduling/event-types/public`),slots:(e,t,n)=>s("GET",`${BASE}/availability/slots/publicinverse?email=${e}&date=${t}&timezone=${n||"UTC"}`),book:e=>s("POST",`${BASE}/scheduling/bookings`,e),bookingsByHost:e=>s("GET",`${BASE}/scheduling/bookings/by-host/${e}`),getBooking:e=>s("GET",`${BASE}/scheduling/bookings/${e}`),cancelBooking:(e,t)=>s("POST",`${BASE}/scheduling/bookings/${e}/cancel`,t),rescheduleBooking:(e,t)=>s("POST",`${BASE}/scheduling/bookings/${e}/reschedule`,t),domains:()=>s("GET",`${BASE}/domains${e.userId?`?tenantId=${e.userId}&tenantType=user`:""}`),domainRegister:e=>s("POST",`${BASE}/domains`,e),domainGet:e=>s("GET",`${BASE}/domains/${encodeURIComponent(e)}`),domainDelete:e=>s("DELETE",`${BASE}/domains/${encodeURIComponent(e)}`),domainVerify:e=>s("POST",`${BASE}/domains/${encodeURIComponent(e)}/verify`),domainDnsStatus:e=>s("GET",`${BASE}/domains/${encodeURIComponent(e)}/dns-status`),domainResolve:e=>s("GET",`${BASE}/domains/resolve?hostname=${encodeURIComponent(e)}`),profileGet:()=>s("GET",`${BASE}/auth/user-profile`),profileBySlug:e=>request(t,"","GET",`/card/api/profile/${encodeURIComponent(e)}`),profileUpdate:e=>s("PUT",`${BASE}/auth/user-profile`,e),synthesize:e=>s("POST",`${BASE}/tts/synthesize`,e),voices:()=>s("GET",`${BASE}/tts/voices`),status:()=>request(t,"","GET",`${BASE.replace("/sdk","/public")}/tai/status`),sttStatus:()=>s("GET",`${BASE}/stt/status`),adminUsers:()=>s("GET","/superadmin/api/users"),adminUserCreate:e=>s("POST","/superadmin/api/users",e),adminUserReset:(e,t)=>s("POST","/superadmin/api/users/reset-password",{email:e,...t}),adminUserDelete:e=>s("DELETE",`/superadmin/api/users/${encodeURIComponent(e)}`),adminTenants:()=>s("GET","/superadmin/api/tenants"),adminTenantView:e=>s("GET",`/superadmin/api/tenants/${e}`),adminTenantCreate:e=>s("POST","/superadmin/api/tenants",e),adminTenantPlan:(e,t)=>s("POST",`/superadmin/api/tenants/${e}/plan`,{plan:t}),adminTenantVerify:e=>s("POST",`/superadmin/api/tenants/${e}/verify`),adminTenantSuspend:e=>s("POST",`/superadmin/api/tenants/${e}/suspend`),adminTenantActivate:e=>s("POST",`/superadmin/api/tenants/${e}/activate`),adminTenantDelete:e=>s("DELETE",`/superadmin/api/tenants/${e}`),adminBilling:()=>s("GET","/superadmin/api/revenue"),adminDiscount:e=>s("POST","/superadmin/api/discount",e),platformStats:()=>s("GET","/superadmin/api/stats"),funnel:()=>s("GET","/superadmin/api/funnel"),signups:e=>s("GET","/superadmin/api/signups"+(e?"?days="+e:"")),revenue:()=>s("GET","/superadmin/api/revenue"),tickets:e=>s("GET","/superadmin/api/tickets"+(e?"?status="+e:"")),ticketShow:e=>s("GET",`/superadmin/api/tickets/${e}`),ticketReply:(e,t)=>s("POST",`/superadmin/api/tickets/${e}/reply`,{message:t}),ticketClose:e=>s("POST",`/superadmin/api/tickets/${e}/close`),audit:e=>s("GET","/superadmin/api/audit"+(e?"?"+e:"")),auditExport:e=>s("GET",`/superadmin/api/audit/export?format=${e||"json"}`),notifications:e=>s("GET","/superadmin/api/notifications"+(e?"?since="+e:"")),costs:()=>s("GET",`${BASE}/costs`),costsByRoom:e=>s("GET",`${BASE}/costs/${e}`),costsPricing:()=>s("GET",`${BASE}/costs/pricing`),costsModels:()=>s("GET",`${BASE}/costs/models`),costsUsers:()=>s("GET",`${BASE}/costs/users`),costsTimeseries:e=>s("GET",`${BASE}/costs/timeseries${e?"?bucket="+e:""}`),agentCreate:e=>s("POST",`${BASE}/tai/agent/create`,e),agentList:()=>s("GET",`${BASE}/tai/agent/list`),agentRevoke:e=>s("DELETE",`${BASE}/tai/agent/${encodeURIComponent(e)}`),channelSend:e=>s("POST",`${BASE}/channels/send`,e),channelInbox:()=>s("GET",`${BASE}/channels/inbox`),channelHistory:(e,t)=>s("GET",`${BASE}/channels/history/${e}${t?"?limit="+t:""}`),channelAck:e=>s("POST",`${BASE}/channels/ack/${e}`),channelAgents:()=>s("GET",`${BASE}/channels/agents`),wall:()=>s("GET",`${BASE}/channels/wall`),notificationsDigest:()=>s("GET",`${BASE}/channels/notifications`),groupCreate:(e,t)=>s("POST",`${BASE}/channels/channel/create`,{name:e,topic:t}),groupJoin:e=>s("POST",`${BASE}/channels/channel/join`,{name:e}),groupLeave:e=>s("POST",`${BASE}/channels/channel/leave`,{name:e}),groupList:()=>s("GET",`${BASE}/channels/channel/list`),groupSend:(e,t)=>s("POST",`${BASE}/channels/channel/${encodeURIComponent(e)}/send`,t),groupHistory:(e,t)=>s("GET",`${BASE}/channels/channel/${encodeURIComponent(e)}/history${t?"?limit="+t:""}`)}}function streamChannels(e,t){const n=new URL(`${BASE}/channels/stream`,e.baseUrl),s="https:"===n.protocol,a=(s?https:http).request({hostname:n.hostname,port:n.port||(s?443:80),path:n.pathname,method:"GET",headers:{Authorization:`Bearer ${e.apiKey}`,Accept:"text/event-stream"}},e=>{if(e.statusCode>=400)return void t("error",{status:e.statusCode});let n="";e.setEncoding("utf8"),e.on("data",e=>{let s;for(n+=e;-1!==(s=n.indexOf("\n\n"));){const e=n.slice(0,s);n=n.slice(s+2);let a="message",i="";for(const t of e.split("\n"))t.startsWith("event: ")?a=t.slice(7).trim():t.startsWith("data: ")&&(i+=t.slice(6));if(i)try{t(a,JSON.parse(i))}catch{t(a,{raw:i})}}}),e.on("end",()=>t("end",{}))});return a.on("error",e=>t("error",{message:e.message})),a.end(),a}function rawApi(e){return(t,n,s)=>request(e.baseUrl,e.apiKey,t,n,s)}module.exports={api:api,request:request,rawApi:rawApi,streamChannels:streamChannels};
|
|
1
|
+
const https=require("https"),http=require("http"),BASE="/saas/api/v1/sdk";function request(e,t,n,a,s){return new Promise((o,i)=>{const r=new URL(a,e),p="https:"===r.protocol,m=p?https:http,u={"Content-Type":"application/json"};t&&(u.Authorization=`Bearer ${t}`);const c=s?JSON.stringify(s):null;c&&(u["Content-Length"]=Buffer.byteLength(c));const d=m.request({hostname:r.hostname,port:r.port||(p?443:80),path:r.pathname+r.search,method:n,headers:u,timeout:3e4},e=>{let t="";e.on("data",e=>t+=e),e.on("end",()=>{try{const n=JSON.parse(t);e.statusCode>=400?i(new Error(n.message||n.error||`HTTP ${e.statusCode}`)):o(n.data||n)}catch{e.statusCode>=400?i(new Error(`HTTP ${e.statusCode}: ${t.slice(0,200)}`)):o(t)}})});d.on("error",i),d.on("timeout",()=>{d.destroy(),i(new Error("Request timeout (30s)"))}),c&&d.write(c),d.end()})}function api(e){const{baseUrl:t,apiKey:n}=e,a=(e,a,s)=>request(t,n,e,a,s);return{signup:e=>request(t,"","POST",`${BASE}/tai/agent/signup`,e),signin:e=>request(t,"","POST",`${BASE}/auth/signin`,e),activate:e=>request(t,"","POST",`${BASE}/tai/agent/activate`,e),createRoom:e=>a("POST",`${BASE}/tai/agent/rooms`,e),listRooms:()=>a("GET",`${BASE}/tai/agent/rooms`),roomStatus:e=>a("GET",`${BASE}/tai/agent/rooms/${e}`),endRoom:e=>a("DELETE",`${BASE}/tai/agent/rooms/${e}`),invite:(e,t)=>a("POST",`${BASE}/tai/agent/rooms/${e}/invite`,t),transcript:(e,t)=>a("GET",`${BASE}/tai/agent/rooms/${e}/transcript?format=${t||"json"}`),joinMeeting:e=>a("POST",`${BASE}/tai/agent/meeting/join`,e),leaveMeeting:e=>a("POST",`${BASE}/tai/agent/meeting/leave`,e),events:()=>a("GET",e.userId?`${BASE}/scheduling/event-types/by-user/${e.userId}`:`${BASE}/scheduling/event-types/public`),slots:(e,t,n)=>a("GET",`${BASE}/availability/slots/publicinverse?email=${e}&date=${t}&timezone=${n||"UTC"}`),book:e=>a("POST",`${BASE}/scheduling/bookings`,e),createEvent:e=>a("POST",`${BASE}/eventtypes`,e),updateEvent:(e,t)=>a("PUT",`${BASE}/eventtypes/${encodeURIComponent(e)}`,t),deleteEvent:(e,t)=>a("DELETE",`${BASE}/eventtypes/${encodeURIComponent(e)}${t?"?softDelete=true":""}`),availabilityGet:e=>a("GET",`${BASE}/availability/${encodeURIComponent(e)}`),availabilityUpdate:(e,t)=>a("PUT",`${BASE}/availability/${encodeURIComponent(e)}`,t),availabilityCreate:(e,t)=>a("POST",`${BASE}/availability/users/${encodeURIComponent(e)}`,t),bookingsByHost:e=>a("GET",`${BASE}/scheduling/bookings/by-host/${e}`),getBooking:e=>a("GET",`${BASE}/scheduling/bookings/${e}`),cancelBooking:(e,t)=>a("POST",`${BASE}/scheduling/bookings/${e}/cancel`,t),rescheduleBooking:(e,t)=>a("POST",`${BASE}/scheduling/bookings/${e}/reschedule`,t),domains:()=>a("GET",`${BASE}/domains${e.userId?`?tenantId=${e.userId}&tenantType=user`:""}`),domainRegister:e=>a("POST",`${BASE}/domains`,e),domainGet:e=>a("GET",`${BASE}/domains/${encodeURIComponent(e)}`),domainDelete:e=>a("DELETE",`${BASE}/domains/${encodeURIComponent(e)}`),domainVerify:e=>a("POST",`${BASE}/domains/${encodeURIComponent(e)}/verify`),domainActivate:e=>a("PUT",`${BASE}/domains/${encodeURIComponent(e)}`,{status:"active"}),domainDnsStatus:e=>a("GET",`${BASE}/domains/${encodeURIComponent(e)}/dns-status`),domainResolve:e=>a("GET",`${BASE}/domains/resolve?hostname=${encodeURIComponent(e)}`),profileGet:()=>a("GET",`${BASE}/auth/user-profile`),profileBySlug:e=>request(t,"","GET",`/card/api/profile/${encodeURIComponent(e)}`),profileUpdate:e=>a("PUT",`${BASE}/auth/user-profile`,e),uploadImage:({userId:a,type:s,buffer:o,filename:i,mime:r})=>uploadProfileImage({baseUrl:t,token:n,userId:a||e.userId,type:s,buffer:o,filename:i,mime:r}),synthesize:e=>a("POST",`${BASE}/tts/synthesize`,e),voices:()=>a("GET",`${BASE}/tts/voices`),status:()=>request(t,"","GET",`${BASE.replace("/sdk","/public")}/tai/status`),sttStatus:()=>a("GET",`${BASE}/stt/status`),adminUsers:()=>a("GET","/superadmin/api/users"),adminUserCreate:e=>a("POST","/superadmin/api/users",e),adminUserReset:(e,t)=>a("POST","/superadmin/api/users/reset-password",{email:e,...t}),adminUserDelete:e=>a("DELETE",`/superadmin/api/users/${encodeURIComponent(e)}`),adminTenants:()=>a("GET","/superadmin/api/tenants"),adminTenantView:e=>a("GET",`/superadmin/api/tenants/${e}`),adminTenantCreate:e=>a("POST","/superadmin/api/tenants",e),adminTenantPlan:(e,t)=>a("POST",`/superadmin/api/tenants/${e}/plan`,{plan:t}),adminTenantVerify:e=>a("POST",`/superadmin/api/tenants/${e}/verify`),adminTenantSuspend:e=>a("POST",`/superadmin/api/tenants/${e}/suspend`),adminTenantActivate:e=>a("POST",`/superadmin/api/tenants/${e}/activate`),adminTenantDelete:e=>a("DELETE",`/superadmin/api/tenants/${e}`),adminBilling:()=>a("GET","/superadmin/api/revenue"),adminDiscount:e=>a("POST","/superadmin/api/discount",e),platformStats:()=>a("GET","/superadmin/api/stats"),funnel:()=>a("GET","/superadmin/api/funnel"),signups:e=>a("GET","/superadmin/api/signups"+(e?"?days="+e:"")),revenue:()=>a("GET","/superadmin/api/revenue"),tickets:e=>a("GET","/superadmin/api/tickets"+(e?"?status="+e:"")),ticketShow:e=>a("GET",`/superadmin/api/tickets/${e}`),ticketReply:(e,t)=>a("POST",`/superadmin/api/tickets/${e}/reply`,{message:t}),ticketClose:e=>a("POST",`/superadmin/api/tickets/${e}/close`),audit:e=>a("GET","/superadmin/api/audit"+(e?"?"+e:"")),auditExport:e=>a("GET",`/superadmin/api/audit/export?format=${e||"json"}`),notifications:e=>a("GET","/superadmin/api/notifications"+(e?"?since="+e:"")),costs:()=>a("GET",`${BASE}/costs`),costsByRoom:e=>a("GET",`${BASE}/costs/${e}`),costsPricing:()=>a("GET",`${BASE}/costs/pricing`),costsModels:()=>a("GET",`${BASE}/costs/models`),costsUsers:()=>a("GET",`${BASE}/costs/users`),costsTimeseries:e=>a("GET",`${BASE}/costs/timeseries${e?"?bucket="+e:""}`),agentCreate:e=>a("POST",`${BASE}/tai/agent/create`,e),agentList:()=>a("GET",`${BASE}/tai/agent/list`),agentRevoke:e=>a("DELETE",`${BASE}/tai/agent/${encodeURIComponent(e)}`),channelSend:e=>a("POST",`${BASE}/channels/send`,e),channelInbox:()=>a("GET",`${BASE}/channels/inbox`),channelHistory:(e,t)=>a("GET",`${BASE}/channels/history/${e}${t?"?limit="+t:""}`),channelAck:e=>a("POST",`${BASE}/channels/ack/${e}`),channelAgents:()=>a("GET",`${BASE}/channels/agents`),wall:()=>a("GET",`${BASE}/channels/wall`),notificationsDigest:()=>a("GET",`${BASE}/channels/notifications`),groupCreate:(e,t)=>a("POST",`${BASE}/channels/channel/create`,{name:e,topic:t}),groupJoin:e=>a("POST",`${BASE}/channels/channel/join`,{name:e}),groupLeave:e=>a("POST",`${BASE}/channels/channel/leave`,{name:e}),groupList:()=>a("GET",`${BASE}/channels/channel/list`),groupSend:(e,t)=>a("POST",`${BASE}/channels/channel/${encodeURIComponent(e)}/send`,t),groupHistory:(e,t)=>a("GET",`${BASE}/channels/channel/${encodeURIComponent(e)}/history${t?"?limit="+t:""}`)}}function streamChannels(e,t){const n=new URL(`${BASE}/channels/stream`,e.baseUrl),a="https:"===n.protocol,s=(a?https:http).request({hostname:n.hostname,port:n.port||(a?443:80),path:n.pathname,method:"GET",headers:{Authorization:`Bearer ${e.apiKey}`,Accept:"text/event-stream"}},e=>{if(e.statusCode>=400)return void t("error",{status:e.statusCode});let n="";e.setEncoding("utf8"),e.on("data",e=>{let a;for(n+=e;-1!==(a=n.indexOf("\n\n"));){const e=n.slice(0,a);n=n.slice(a+2);let s="message",o="";for(const t of e.split("\n"))t.startsWith("event: ")?s=t.slice(7).trim():t.startsWith("data: ")&&(o+=t.slice(6));if(o)try{t(s,JSON.parse(o))}catch{t(s,{raw:o})}}}),e.on("end",()=>t("end",{}))});return s.on("error",e=>t("error",{message:e.message})),s.end(),s}function rawApi(e){return(t,n,a)=>request(e.baseUrl,e.apiKey,t,n,a)}function fetchBytes(e,t=0){return new Promise((n,a)=>{if(t>5)return a(new Error("Too many redirects fetching image"));const s=new URL(e),o=("https:"===s.protocol?https:http).get({hostname:s.hostname,port:s.port||("https:"===s.protocol?443:80),path:s.pathname+s.search,headers:{"User-Agent":"apo-cli/image-fetch"},timeout:3e4},s=>{if(s.statusCode>=300&&s.statusCode<400&&s.headers.location)return s.resume(),n(fetchBytes(new URL(s.headers.location,e).href,t+1));if(s.statusCode>=400)return s.resume(),a(new Error(`HTTP ${s.statusCode} fetching image`));const o=[];s.on("data",e=>o.push(e)),s.on("end",()=>n({buffer:Buffer.concat(o),mime:s.headers["content-type"]||"application/octet-stream"}))});o.on("error",a),o.on("timeout",()=>{o.destroy(),a(new Error("Timeout fetching image"))})})}async function resolveImageSource(e){if(/^https?:\/\//i.test(e)){const{buffer:t,mime:n}=await fetchBytes(e),a=new URL(e).pathname.split("/").pop()||"image";return{buffer:t,mime:n,filename:a.includes(".")?a:`${a}.jpg`}}const t=require("fs"),n=require("path");return{buffer:t.readFileSync(e),mime:{".jpg":"image/jpeg",".jpeg":"image/jpeg",".png":"image/png",".gif":"image/gif",".webp":"image/webp",".svg":"image/svg+xml"}[n.extname(e).toLowerCase()]||"application/octet-stream",filename:n.basename(e)}}function uploadProfileImage({baseUrl:e,token:t,userId:n,type:a,buffer:s,filename:o,mime:i}){return new Promise((r,p)=>{const m="----apoCLI"+Date.now().toString(16)+Math.random().toString(16).slice(2),u=Buffer.from(`--${m}\r\nContent-Disposition: form-data; name="avatar"; filename="${o}"\r\nContent-Type: ${i}\r\n\r\n`),c=Buffer.from(`\r\n--${m}--\r\n`),d=Buffer.concat([u,s,c]),l=`${BASE}/userProfileAvatar/upload-profile-image?userId=${encodeURIComponent(n)}&type=${encodeURIComponent(a||"cover")}`,E=new URL(l,e),$="https:"===E.protocol,h=($?https:http).request({hostname:E.hostname,port:E.port||($?443:80),path:E.pathname+E.search,method:"POST",headers:{Authorization:`Bearer ${t}`,"Content-Type":`multipart/form-data; boundary=${m}`,"Content-Length":d.length},timeout:6e4},e=>{let t="";e.on("data",e=>t+=e),e.on("end",()=>{let n;try{n=JSON.parse(t)}catch{n={raw:t}}e.statusCode>=400?p(new Error(n.message||n.error||`HTTP ${e.statusCode}: ${t.slice(0,200)}`)):r(n)})});h.on("error",p),h.on("timeout",()=>{h.destroy(),p(new Error("Upload timeout (60s)"))}),h.write(d),h.end()})}function deleteProfileImage({baseUrl:e,token:t,userId:n,type:a}){return request(e,t,"DELETE",`${BASE}/userProfileAvatar/upload-profile-image?userId=${encodeURIComponent(n)}&type=${encodeURIComponent(a||"cover")}`)}module.exports={api:api,request:request,rawApi:rawApi,streamChannels:streamChannels,resolveImageSource:resolveImageSource,uploadProfileImage:uploadProfileImage,deleteProfileImage:deleteProfileImage};
|
package/dist/commands/admin.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
const{getFlag:getFlag,positionalArgs:positionalArgs}=require("../config"),fmt=require("../format");async function run(t,e,o,n){const s=positionalArgs(e),a=s[0];if("ice"===a||"turn"===a)return require("./ice").run(n,e,o);if("tenants"===a){const e=await t.adminTenants();if(o)return console.log(JSON.stringify(e,null,2));const n=e.tenants||e.data||e;return Array.isArray(n)&&n.length?(console.log(`\n[1mTenants (${n.length})[0m\n`),void n.forEach(t=>{const e=t.plan||"free",o=t.suspended?"[31msuspended[0m":"[32mactive[0m";console.log(` ${(t.slug||t.name||"?").padEnd(20)} ${e.padEnd(12)} ${o} ${t.email||""}`)})):fmt.info("No tenants.")}if("tenant-view"===a){const e=s[1];e||(fmt.err("Usage: apo admin tenant-view SLUG"),process.exit(1));const n=await t.adminTenantView(e);if(o)return console.log(JSON.stringify(n,null,2));const a=n.tenant||n.data||n;return console.log(`\n[1m${a.name||a.slug}[0m`),console.log(` Slug: ${a.slug}`),console.log(` Plan: ${a.plan||"free"}`),console.log(` Email: ${a.email||"—"}`),console.log(" Status: "+(a.suspended?"suspended":"active")),console.log(` Created: ${a.createdAt||"—"}`),void(a.stats&&(console.log(` Rooms: ${a.stats.rooms||0}`),console.log(` Bookings: ${a.stats.bookings||0}`),console.log(` Users: ${a.stats.users||0}`)))}if("tenant-create"===a){const n=s[1],a=getFlag(e,"plan")||"starter",r=getFlag(e,"email");n||(fmt.err("Usage: apo admin tenant-create SLUG [--plan X] [--email X]"),process.exit(1));const l=await t.adminTenantCreate({slug:n,plan:a,email:r});return o?console.log(JSON.stringify(l,null,2)):(fmt.ok(`Tenant created: ${n} (${a})`),void(l.apiKey&&console.log(` API Key: ${l.apiKey}`)))}if("tenant-plan"===a){const o=s[1],n=getFlag(e,"plan");return o&&n||(fmt.err("Usage: apo admin tenant-plan SLUG --plan X"),process.exit(1)),await t.adminTenantPlan(o,n),void fmt.ok(`Plan changed: ${o} → ${n}`)}if("tenant-verify"===a){const e=s[1];return e||(fmt.err("Usage: apo admin tenant-verify SLUG"),process.exit(1)),await t.adminTenantVerify(e),void fmt.ok(`Payment verified for: ${e}`)}if("tenant-suspend"===a){const e=s[1];return e||(fmt.err("Usage: apo admin tenant-suspend SLUG"),process.exit(1)),await t.adminTenantSuspend(e),void fmt.ok(`Tenant suspended: ${e}`)}if("tenant-activate"===a){const e=s[1];return e||(fmt.err("Usage: apo admin tenant-activate SLUG"),process.exit(1)),await t.adminTenantActivate(e),void fmt.ok(`Tenant activated: ${e}`)}if("tenant-delete"===a){const e=s[1];return e||(fmt.err("Usage: apo admin tenant-delete SLUG"),process.exit(1)),await t.adminTenantDelete(e),void fmt.ok(`Tenant deleted: ${e}`)}if("users"===a){const e=await t.adminUsers();if(o)return console.log(JSON.stringify(e,null,2));const n=e.users||e.data||e;return Array.isArray(n)&&n.length?(console.log(`\n[1mUsers (${n.length})[0m\n`),void n.forEach(t=>{const e=t.role||"user",o=t.locked?"[31mlocked[0m":"[32mactive[0m";console.log(` ${(t.email||"?").padEnd(30)} ${e.padEnd(10)} ${o}`)})):fmt.info("No users.")}if("user-create"===a){const n=getFlag(e,"email"),s=getFlag(e,"password")||getFlag(e,"p"),a=getFlag(e,"tenant"),r=getFlag(e,"role")||"user";n&&s||(fmt.err("Usage: apo admin user-create --email X --password X [--tenant SLUG] [--role X]"),process.exit(1));const l=await t.adminUserCreate({email:n,password:s,tenant:a,role:r});return o?console.log(JSON.stringify(l,null,2)):void fmt.ok(`User created: ${n}`)}if("user-reset"===a){const o=s[1],n=getFlag(e,"password")||getFlag(e,"p");return o&&n||(fmt.err("Usage: apo admin user-reset EMAIL --password NEWPASS"),process.exit(1)),await t.adminUserReset(o,{password:n}),void fmt.ok(`Password reset for: ${o}`)}if("user-delete"===a){const e=s[1];return e||(fmt.err("Usage: apo admin user-delete EMAIL"),process.exit(1)),await t.adminUserDelete(e),void fmt.ok(`User deleted: ${e}`)}if("billing"===a){const e=await t.adminBilling();if(o)return console.log(JSON.stringify(e,null,2));const n=e.data||e;return console.log("\n[1mBilling[0m\n"),console.log(` MRR: $${n.mrr||0}`),console.log(` ARR: $${n.arr||0}`),console.log(` Revenue: $${n.totalRevenue||0}`),console.log(` Fees: $${n.fees||0}`),void console.log(` Payouts: $${n.payouts||0}`)}if("discount"===a){const n=s[1],a=getFlag(e,"plan"),r=getFlag(e,"months")||"1";n||(fmt.err("Usage: apo admin discount SLUG [--plan X] [--months N]"),process.exit(1));const l=await t.adminDiscount({slug:n,plan:a,months:parseInt(r)});return o?console.log(JSON.stringify(l,null,2)):void fmt.ok(`Discount created: ${l.code||"done"}`)}if("costs"===a){const e=s[1];if(e){const n=await t.costsByRoom(e);if(o)return console.log(JSON.stringify(n,null,2));const s=n.data||n;return console.log(`\n[1mCosts: ${e}[0m\n`),console.log(` STT: $${(s.stt?.cost||0).toFixed(6)} (${s.stt?.requests||0} requests, ${s.stt?.provider||"—"})`),console.log(` TTS: $${(s.tts?.cost||0).toFixed(6)} (${s.tts?.requests||0} requests, ${s.tts?.provider||"—"})`),console.log(` LLM: $${(s.llm?.cost||0).toFixed(6)} (${s.llm?.requests||0} requests, ${s.llm?.provider||"—"})`),void console.log(` [1mTotal: $${(s.total||0).toFixed(6)}[0m`)}const n=await t.costs();if(o)return console.log(JSON.stringify(n,null,2));const a=n.data||n;return console.log("\n[1mPlatform Costs[0m\n"),console.log(` Rooms tracked: ${a.rooms||0}`),console.log(` STT total: $${(a.stt||0).toFixed(6)}`),console.log(` TTS total: $${(a.tts||0).toFixed(6)}`),console.log(` LLM total: $${(a.llm||0).toFixed(6)}`),console.log(` [1mTotal: $${(a.total||0).toFixed(6)}[0m`),void(a.byRoom?.length&&(console.log("\n Top rooms:"),a.byRoom.slice(0,10).forEach(t=>{console.log(` ${t.roomId.slice(0,12)}... $${t.total.toFixed(6)} (STT:$${t.stt.toFixed(6)} TTS:$${t.tts.toFixed(6)} LLM:$${t.llm.toFixed(6)})`)})))}if("models"===a){const e=await t.costsModels();if(o)return console.log(JSON.stringify(e,null,2));const n=e.data||e,s=n.models||[];return console.log(`\n[1mSpend by Provider / Model[0m Total: $${(n.total||0).toFixed(6)}\n`),s.length?(console.log(` ${"TYPE".padEnd(5)} ${"PROVIDER".padEnd(14)} ${"MODEL".padEnd(20)} ${"REQ".padStart(6)} ${"IN TOK".padStart(10)} ${"OUT TOK".padStart(10)} ${"COST".padStart(12)}`),void s.forEach(t=>{console.log(` ${(t.type||"").toUpperCase().padEnd(5)} ${(t.provider||"—").padEnd(14)} ${(t.model||"—").padEnd(20)} ${String(t.requests||0).padStart(6)} ${String(t.inputTokens||0).padStart(10)} ${String(t.outputTokens||0).padStart(10)} ${("$"+(t.cost||0).toFixed(6)).padStart(12)}`)})):fmt.info("No usage recorded yet.")}if("users-cost"===a||"usage"===a){const e=await t.costsUsers();if(o)return console.log(JSON.stringify(e,null,2));const n=e.data||e,s=n.users||[];return console.log(`\n[1mSpend by User[0m Total: $${(n.total||0).toFixed(6)}\n`),s.length?(console.log(` ${"USER".padEnd(28)} ${"REQ".padStart(6)} ${"LLM".padStart(12)} ${"STT".padStart(12)} ${"TTS".padStart(12)} ${"TOTAL".padStart(12)}`),void s.forEach(t=>{console.log(` ${String(t.userId||"—").padEnd(28)} ${String(t.requests||0).padStart(6)} ${("$"+(t.llm||0).toFixed(6)).padStart(12)} ${("$"+(t.stt||0).toFixed(6)).padStart(12)} ${("$"+(t.tts||0).toFixed(6)).padStart(12)} ${("$"+(t.cost||0).toFixed(6)).padStart(12)}`)})):fmt.info("No usage recorded yet.")}if("timeseries"===a){const n=getFlag(e,"bucket")||"hour",s=await t.costsTimeseries(n);if(o)return console.log(JSON.stringify(s,null,2));const a=s.data||s,r=a.buckets||[];return console.log(`\n[1mSpend Over Time (${a.bucket||n})[0m\n`),r.length?(console.log(` ${"WHEN".padEnd(20)} ${"LLM".padStart(12)} ${"STT".padStart(12)} ${"TTS".padStart(12)} ${"TOTAL".padStart(12)}`),void r.forEach(t=>{const e=new Date(t.t).toISOString().replace("T"," ").slice(0,16);console.log(` ${e.padEnd(20)} ${("$"+(t.llm||0).toFixed(6)).padStart(12)} ${("$"+(t.stt||0).toFixed(6)).padStart(12)} ${("$"+(t.tts||0).toFixed(6)).padStart(12)} ${("$"+(t.total||0).toFixed(6)).padStart(12)}`)})):fmt.info("No usage recorded yet.")}if("pricing"===a){const e=await t.costsPricing();if(o)return console.log(JSON.stringify(e,null,2));const n=e.data||e;return console.log("\n[1mPricing Table[0m\n"),console.log(" STT:"),Object.entries(n.stt||{}).forEach(([t,e])=>console.log(` ${t.padEnd(16)} $${e.perMinute}/min`)),console.log(" TTS:"),Object.entries(n.tts||{}).forEach(([t,e])=>console.log(` ${t.padEnd(16)} $${e.perChar}/char`)),console.log(" LLM (per MTok, in/out):"),void Object.entries(n.llm||{}).forEach(([t,e])=>{Object.entries(e||{}).forEach(([e,o])=>{if(!o||null==o.perInputMTok)return;const n="_default"===e?`${t} (default)`:`${t}/${e}`;console.log(` ${n.padEnd(28)} $${o.perInputMTok}/$${o.perOutputMTok}`)})})}fmt.err("Usage: apo admin [tenants|tenant-view|tenant-create|tenant-plan|tenant-verify|tenant-suspend|tenant-activate|tenant-delete|users|user-create|user-reset|user-delete|billing|discount|costs|costs ROOM_ID|models|usage|timeseries|pricing|ice]"),process.exit(1)}module.exports={run:run};
|
|
1
|
+
const{getFlag:getFlag,positionalArgs:positionalArgs}=require("../config"),fmt=require("../format");async function run(e,t,o,s){const a=positionalArgs(t),n=a[0];if("ice"===n||"turn"===n)return require("./ice").run(s,t,o);if("tenants"===n){const t=await e.adminTenants();if(o)return console.log(JSON.stringify(t,null,2));const s=t.tenants||t.data||t;return Array.isArray(s)&&s.length?(console.log(`\n[1mTenants (${s.length})[0m\n`),void s.forEach(e=>{const t=e.plan||"free",o=e.suspended?"[31msuspended[0m":"[32mactive[0m";console.log(` ${(e.slug||e.name||"?").padEnd(20)} ${t.padEnd(12)} ${o} ${e.email||""}`)})):fmt.info("No tenants.")}if("tenant-view"===n){const t=a[1];t||(fmt.err("Usage: apo admin tenant-view SLUG"),process.exit(1));const s=await e.adminTenantView(t);if(o)return console.log(JSON.stringify(s,null,2));const n=s.tenant||s.data||s;return console.log(`\n[1m${n.name||n.slug}[0m`),console.log(` Slug: ${n.slug}`),console.log(` Plan: ${n.plan||"free"}`),console.log(` Email: ${n.email||"—"}`),console.log(" Status: "+(n.suspended?"suspended":"active")),console.log(` Created: ${n.createdAt||"—"}`),void(n.stats&&(console.log(` Rooms: ${n.stats.rooms||0}`),console.log(` Bookings: ${n.stats.bookings||0}`),console.log(` Users: ${n.stats.users||0}`)))}if("tenant-create"===n){const s=a[1],n=getFlag(t,"plan")||"starter",r=getFlag(t,"email");s||(fmt.err("Usage: apo admin tenant-create SLUG [--plan X] [--email X]"),process.exit(1));const l=await e.adminTenantCreate({slug:s,plan:n,email:r});return o?console.log(JSON.stringify(l,null,2)):(fmt.ok(`Tenant created: ${s} (${n})`),void(l.apiKey&&console.log(` API Key: ${l.apiKey}`)))}if("tenant-plan"===n){const o=a[1],s=getFlag(t,"plan");return o&&s||(fmt.err("Usage: apo admin tenant-plan SLUG --plan X"),process.exit(1)),await e.adminTenantPlan(o,s),void fmt.ok(`Plan changed: ${o} → ${s}`)}if("tenant-verify"===n){const t=a[1];return t||(fmt.err("Usage: apo admin tenant-verify SLUG"),process.exit(1)),await e.adminTenantVerify(t),void fmt.ok(`Payment verified for: ${t}`)}if("tenant-suspend"===n){const t=a[1];return t||(fmt.err("Usage: apo admin tenant-suspend SLUG"),process.exit(1)),await e.adminTenantSuspend(t),void fmt.ok(`Tenant suspended: ${t}`)}if("tenant-activate"===n){const t=a[1];return t||(fmt.err("Usage: apo admin tenant-activate SLUG"),process.exit(1)),await e.adminTenantActivate(t),void fmt.ok(`Tenant activated: ${t}`)}if("tenant-delete"===n){const t=a[1];return t||(fmt.err("Usage: apo admin tenant-delete SLUG"),process.exit(1)),await e.adminTenantDelete(t),void fmt.ok(`Tenant deleted: ${t}`)}if("users"===n){const t=await e.adminUsers();if(o)return console.log(JSON.stringify(t,null,2));const s=t.users||t.data||t;return Array.isArray(s)&&s.length?(console.log(`\n[1mUsers (${s.length})[0m\n`),void s.forEach(e=>{const t=e.role||"user",o=e.locked?"[31mlocked[0m":"[32mactive[0m";console.log(` ${(e.email||"?").padEnd(30)} ${t.padEnd(10)} ${o}`)})):fmt.info("No users.")}if("user-create"===n){const s=getFlag(t,"email"),a=getFlag(t,"password")||getFlag(t,"p"),n=getFlag(t,"tenant"),r=getFlag(t,"role")||"user";s&&a||(fmt.err("Usage: apo admin user-create --email X --password X [--tenant SLUG] [--role X]"),process.exit(1));const l=await e.adminUserCreate({email:s,password:a,tenant:n,role:r});return o?console.log(JSON.stringify(l,null,2)):void fmt.ok(`User created: ${s}`)}if("user-reset"===n){const o=a[1],s=getFlag(t,"password")||getFlag(t,"p");return o&&s||(fmt.err("Usage: apo admin user-reset EMAIL --password NEWPASS"),process.exit(1)),await e.adminUserReset(o,{password:s}),void fmt.ok(`Password reset for: ${o}`)}if("user-delete"===n){const t=a[1];return t||(fmt.err("Usage: apo admin user-delete EMAIL"),process.exit(1)),await e.adminUserDelete(t),void fmt.ok(`User deleted: ${t}`)}if("profile-cover"===n||"profile-avatar"===n){const e="profile-avatar"===n?"avatar":getFlag(t,"type")||"cover",r=(a[2]||a[1],getFlag(t,"password")||getFlag(t,"p")),l=getFlag(t,"tenants"),i=getFlag(t,"tenants-file");let d=[];d=i?require("fs").readFileSync(i,"utf8").split("\n").map(e=>e.trim()).filter(e=>e&&!e.startsWith("#")).map(e=>{const[t,o]=e.split(/[,:\s]+/);return{email:t,password:o||r}}):l?l.split(",").map(e=>({email:e.trim(),password:r})):[{email:a[1],password:r}];const c=l||i?a[1]:a[2];c&&!d.some(e=>!e.email||!e.password)||(fmt.err("Usage (single): apo admin profile-cover EMAIL <URL|file> --password PASS [--type cover|avatar]"),fmt.err("Usage (bulk): apo admin profile-cover <URL|file> --tenants a@x,b@y --password PASS [--type cover|avatar]"),fmt.err(" or: apo admin profile-cover <URL|file> --tenants-file list.txt [--password SHARED]"),process.exit(1));const{ledger:u,allVerified:g}=await coverOrchestrate({baseUrl:s.baseUrl,type:e,source:c,targets:d});if(o)return console.log(JSON.stringify(u,null,2)),process.exit(g?0:1);console.log(`\n[1m${e} rollout — ${d.length} tenant(s)[0m\n`);for(const e of u.rows){const t="verified"===e.status?"[32m✓[0m":e.status.startsWith("rolled_back")?"[33m↩[0m":"[31m✗[0m";console.log(` ${t} ${e.email.padEnd(24)} ${e.status}${e.note?" — "+e.note:""}`)}const p=u.rows.filter(e=>"verified"===e.status).length,m=u.rows.filter(e=>e.status.startsWith("rolled_back")).length,f=u.rows.length-p-m;return console.log(`\n [1m${p} verified, ${m} rolled back, ${f} failed[0m`),console.log(` ledger: ${u.path}\n`),process.exit(g?0:1)}if("profile-website"===n&&(fmt.err("Website is not settable via the SDK yet: PUT /user-profile silently drops the `website` field."),fmt.err("Tracked upstream as tyga-run BUG-2026-0821-0007. The VISIT WEBSITE CTA stays blank until the SDK adds support."),process.exit(2)),"billing"===n){const t=await e.adminBilling();if(o)return console.log(JSON.stringify(t,null,2));const s=t.data||t;return console.log("\n[1mBilling[0m\n"),console.log(` MRR: $${s.mrr||0}`),console.log(` ARR: $${s.arr||0}`),console.log(` Revenue: $${s.totalRevenue||0}`),console.log(` Fees: $${s.fees||0}`),void console.log(` Payouts: $${s.payouts||0}`)}if("discount"===n){const s=a[1],n=getFlag(t,"plan"),r=getFlag(t,"months")||"1";s||(fmt.err("Usage: apo admin discount SLUG [--plan X] [--months N]"),process.exit(1));const l=await e.adminDiscount({slug:s,plan:n,months:parseInt(r)});return o?console.log(JSON.stringify(l,null,2)):void fmt.ok(`Discount created: ${l.code||"done"}`)}if("costs"===n){const t=a[1];if(t){const s=await e.costsByRoom(t);if(o)return console.log(JSON.stringify(s,null,2));const a=s.data||s;return console.log(`\n[1mCosts: ${t}[0m\n`),console.log(` STT: $${(a.stt?.cost||0).toFixed(6)} (${a.stt?.requests||0} requests, ${a.stt?.provider||"—"})`),console.log(` TTS: $${(a.tts?.cost||0).toFixed(6)} (${a.tts?.requests||0} requests, ${a.tts?.provider||"—"})`),console.log(` LLM: $${(a.llm?.cost||0).toFixed(6)} (${a.llm?.requests||0} requests, ${a.llm?.provider||"—"})`),void console.log(` [1mTotal: $${(a.total||0).toFixed(6)}[0m`)}const s=await e.costs();if(o)return console.log(JSON.stringify(s,null,2));const n=s.data||s;return console.log("\n[1mPlatform Costs[0m\n"),console.log(` Rooms tracked: ${n.rooms||0}`),console.log(` STT total: $${(n.stt||0).toFixed(6)}`),console.log(` TTS total: $${(n.tts||0).toFixed(6)}`),console.log(` LLM total: $${(n.llm||0).toFixed(6)}`),console.log(` [1mTotal: $${(n.total||0).toFixed(6)}[0m`),void(n.byRoom?.length&&(console.log("\n Top rooms:"),n.byRoom.slice(0,10).forEach(e=>{console.log(` ${e.roomId.slice(0,12)}... $${e.total.toFixed(6)} (STT:$${e.stt.toFixed(6)} TTS:$${e.tts.toFixed(6)} LLM:$${e.llm.toFixed(6)})`)})))}if("models"===n){const t=await e.costsModels();if(o)return console.log(JSON.stringify(t,null,2));const s=t.data||t,a=s.models||[];return console.log(`\n[1mSpend by Provider / Model[0m Total: $${(s.total||0).toFixed(6)}\n`),a.length?(console.log(` ${"TYPE".padEnd(5)} ${"PROVIDER".padEnd(14)} ${"MODEL".padEnd(20)} ${"REQ".padStart(6)} ${"IN TOK".padStart(10)} ${"OUT TOK".padStart(10)} ${"COST".padStart(12)}`),void a.forEach(e=>{console.log(` ${(e.type||"").toUpperCase().padEnd(5)} ${(e.provider||"—").padEnd(14)} ${(e.model||"—").padEnd(20)} ${String(e.requests||0).padStart(6)} ${String(e.inputTokens||0).padStart(10)} ${String(e.outputTokens||0).padStart(10)} ${("$"+(e.cost||0).toFixed(6)).padStart(12)}`)})):fmt.info("No usage recorded yet.")}if("users-cost"===n||"usage"===n){const t=await e.costsUsers();if(o)return console.log(JSON.stringify(t,null,2));const s=t.data||t,a=s.users||[];return console.log(`\n[1mSpend by User[0m Total: $${(s.total||0).toFixed(6)}\n`),a.length?(console.log(` ${"USER".padEnd(28)} ${"REQ".padStart(6)} ${"LLM".padStart(12)} ${"STT".padStart(12)} ${"TTS".padStart(12)} ${"TOTAL".padStart(12)}`),void a.forEach(e=>{console.log(` ${String(e.userId||"—").padEnd(28)} ${String(e.requests||0).padStart(6)} ${("$"+(e.llm||0).toFixed(6)).padStart(12)} ${("$"+(e.stt||0).toFixed(6)).padStart(12)} ${("$"+(e.tts||0).toFixed(6)).padStart(12)} ${("$"+(e.cost||0).toFixed(6)).padStart(12)}`)})):fmt.info("No usage recorded yet.")}if("timeseries"===n){const s=getFlag(t,"bucket")||"hour",a=await e.costsTimeseries(s);if(o)return console.log(JSON.stringify(a,null,2));const n=a.data||a,r=n.buckets||[];return console.log(`\n[1mSpend Over Time (${n.bucket||s})[0m\n`),r.length?(console.log(` ${"WHEN".padEnd(20)} ${"LLM".padStart(12)} ${"STT".padStart(12)} ${"TTS".padStart(12)} ${"TOTAL".padStart(12)}`),void r.forEach(e=>{const t=new Date(e.t).toISOString().replace("T"," ").slice(0,16);console.log(` ${t.padEnd(20)} ${("$"+(e.llm||0).toFixed(6)).padStart(12)} ${("$"+(e.stt||0).toFixed(6)).padStart(12)} ${("$"+(e.tts||0).toFixed(6)).padStart(12)} ${("$"+(e.total||0).toFixed(6)).padStart(12)}`)})):fmt.info("No usage recorded yet.")}if("pricing"===n){const t=await e.costsPricing();if(o)return console.log(JSON.stringify(t,null,2));const s=t.data||t;return console.log("\n[1mPricing Table[0m\n"),console.log(" STT:"),Object.entries(s.stt||{}).forEach(([e,t])=>console.log(` ${e.padEnd(16)} $${t.perMinute}/min`)),console.log(" TTS:"),Object.entries(s.tts||{}).forEach(([e,t])=>console.log(` ${e.padEnd(16)} $${t.perChar}/char`)),console.log(" LLM (per MTok, in/out):"),void Object.entries(s.llm||{}).forEach(([e,t])=>{Object.entries(t||{}).forEach(([t,o])=>{if(!o||null==o.perInputMTok)return;const s="_default"===t?`${e} (default)`:`${e}/${t}`;console.log(` ${s.padEnd(28)} $${o.perInputMTok}/$${o.perOutputMTok}`)})})}fmt.err("Usage: apo admin [tenants|tenant-view|tenant-create|tenant-plan|tenant-verify|tenant-suspend|tenant-activate|tenant-delete|users|user-create|user-reset|user-delete|profile-cover|profile-avatar|billing|discount|costs|costs ROOM_ID|models|usage|timeseries|pricing|ice]"),process.exit(1)}async function coverOrchestrate({baseUrl:e,type:t,source:o,targets:s}){const{api:a,resolveImageSource:n,uploadProfileImage:r,deleteProfileImage:l}=require("../api"),i=e=>(e&&(e.images||e.user&&e.user.images)||[]).find(e=>e.type===t)||null,d=e=>e&&(e.fileId||e.url)||"",c=await n(o),u=[];for(const o of s){u.length&&await new Promise(e=>setTimeout(e,600));const s={email:o.email,userId:null,before:null,after:null,status:"pending",note:""};u.push(s);try{const u=a({baseUrl:e,apiKey:""}).signin;let g,p;for(let e=0;e<4;e++){e&&await new Promise(t=>setTimeout(t,1500*e));try{g=await u({email:o.email,password:o.password});break}catch(e){p=e}}if(!g)throw p;const m=g.token||g.accessToken||g.apiKey;let f=g.userId||g.user?.id||g.user?._id;if(!f&&m&&m.includes("."))try{const e=JSON.parse(Buffer.from(m.split(".")[1],"base64").toString());f=e.userId||e.id||e.sub}catch{}if(!m||!f){s.status="auth_failed",s.note="no token/userId";continue}s.userId=f;const $=a({baseUrl:e,apiKey:m}),S=i(await $.profileGet().catch(()=>null));s.before=S?S.url:null,await r({baseUrl:e,token:m,userId:f,type:t,buffer:c.buffer,filename:c.filename,mime:c.mime});const v=i(await $.profileGet().catch(()=>null));if(s.after=v?v.url:null,v&&d(v)!==d(S)&&/\/(cover|avatar)\//.test(v.url||"")){s.status="verified";continue}s.note="gate failed (cover did not move); rolling back";try{if(S&&S.url){const o=await n(S.url);await r({baseUrl:e,token:m,userId:f,type:t,buffer:o.buffer,filename:o.filename,mime:o.mime}),s.status="rolled_back"}else await l({baseUrl:e,token:m,userId:f,type:t}),s.status="rolled_back_to_default"}catch(e){s.status="rollback_failed",s.note=`gate failed AND rollback failed: ${e.message}`}}catch(e){s.status="pending"===s.status?"apply_failed":s.status,s.note=s.note||e.message}}const g=require("fs"),p=require("path"),m=require("os"),f=p.join(m.homedir(),".appoiint","ledgers");g.mkdirSync(f,{recursive:!0});const $=p.join(f,`cover-${t}-${Date.now()}.json`),S={at:(new Date).toISOString(),type:t,source:o,rows:u,path:$};return g.writeFileSync($,JSON.stringify(S,null,2)),{ledger:S,allVerified:u.every(e=>"verified"===e.status)}}module.exports={run:run};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
const{getFlag:getFlag,loadConfig:loadConfig}=require("../config"),fmt=require("../format");function unwrap(
|
|
1
|
+
const{getFlag:getFlag,loadConfig:loadConfig}=require("../config"),fmt=require("../format");function unwrap(e){let t=e;for(;t&&"object"==typeof t&&t.data&&!Array.isArray(t)&&!t.bookingId&&!t.bookings;)t=t.data;return t||{}}function bookingList(e){const t=unwrap(e);return Array.isArray(t)?t:t.bookings||(Array.isArray(t.data)?t.data:[])||[]}function roomNameOf(e){const t=(e.customer&&e.customer.customFields||[]).find(e=>"meetingRoomName"===e.name);return t?t.value:null}function hostUrlOf(e){const t=(e.customer&&e.customer.customFields||[]).find(e=>"meetingHostUrl"===e.name);return t?t.value:null}async function book(e,t,o){const n=getFlag(t,"event")||getFlag(t,"e"),a=getFlag(t,"date")||getFlag(t,"d"),s=getFlag(t,"email"),i=getFlag(t,"name")||getFlag(t,"n")||"Guest",r=getFlag(t,"timezone")||getFlag(t,"z")||"UTC";a&&s||(fmt.err("Usage: apo book --event EVENT_ID --date 2026-06-15T14:00:00Z --email jane@co.com [--host host@co.com]"),process.exit(1));const l=getFlag(t,"host"),g=l?void 0:loadConfig([]).userId;l||g||(fmt.err("No host: pass --host host@co.com or run `apo init` (userId missing from config)"),process.exit(1));const c=await e.book({eventTypeId:n,hostEmail:l,hostId:g,scheduledAt:a,duration:30,customer:{name:i,email:s},timezone:r,location:{type:"video"}});if(o)return console.log(JSON.stringify(c,null,2));const d=unwrap(c);fmt.ok(`Booking created: ${d.bookingId||d.id||d._id||"(id unavailable)"}`);const u=roomNameOf(d);u&&console.log(fmt.dim(` room: ${u} — join with: apo join ${d.bookingId||u}`))}async function bookings(e,t,o){const n=getFlag(t,"host")||loadConfig([]).userId;n||(fmt.err("No host: run `apo signin` / `apo init` or pass --host USER_ID"),process.exit(1));let a=bookingList(await e.bookingsByHost(n));const s=getFlag(t,"status")||getFlag(t,"s");return s&&(a=a.filter(e=>(e.status||"").toLowerCase()===s.toLowerCase())),o?console.log(JSON.stringify(a,null,2)):a.length?void a.sort((e,t)=>new Date(e.scheduledAt||0)-new Date(t.scheduledAt||0)).forEach(e=>console.log(fmt.bookingLine(e))):fmt.info("No bookings found.")}async function bookingShow(e,t,o){const n=t.find(e=>!e.startsWith("-"));n||(fmt.err("Usage: apo booking BOOKING_ID"),process.exit(1));const a=unwrap(await e.getBooking(n));if(o)return console.log(JSON.stringify(a,null,2));console.log(fmt.bold(a.bookingId||n)),console.log(` when: ${a.scheduledAt} (${a.timezone||"UTC"}, ${a.duration||"?"}min)`),console.log(` status: ${a.status||"?"}`),a.customer&&console.log(` customer: ${a.customer.name||""} <${a.customer.email||""}>`),a.eventType&&console.log(` event: ${a.eventType.name||a.eventType.slug||""}`);const s=roomNameOf(a);s&&console.log(` room: ${s}`),a.location&&a.location.joinUrl&&console.log(` join: ${a.location.joinUrl}`);const i=hostUrlOf(a);i&&console.log(` hostUrl: ${i}`),s&&console.log(fmt.dim(`\n Jump in: apo join ${a.bookingId||s}`))}async function cancel(e,t,o){const n=t.find(e=>!e.startsWith("-"));n||(fmt.err('Usage: apo cancel BOOKING_ID [--reason "text"]'),process.exit(1));const a=getFlag(t,"reason")||getFlag(t,"r")||"Cancelled via CLI",s=await e.cancelBooking(n,{reason:a});if(o)return console.log(JSON.stringify(s,null,2));fmt.ok(`Cancelled ${n}`),a&&console.log(fmt.dim(` reason: ${a}`))}async function reschedule(e,t,o){const n=t.find(e=>!e.startsWith("-")),a=getFlag(t,"date")||getFlag(t,"d");n&&a||(fmt.err('Usage: apo reschedule BOOKING_ID --date 2026-08-25T14:00:00Z [--reason "text"]'),process.exit(1));const s=getFlag(t,"reason")||getFlag(t,"r"),i={newDate:a,newScheduledAt:a};s&&(i.reason=s);const r=await e.rescheduleBooking(n,i);if(o)return console.log(JSON.stringify(r,null,2));fmt.ok(`Rescheduled ${n} → ${a}`)}async function events(e,t,o){const n=await e.events(),a=Array.isArray(n)?n:n.eventTypes||n.data&&(Array.isArray(n.data)?n.data:n.data.eventTypes)||[];return o?console.log(JSON.stringify(a,null,2)):a.length?void a.forEach(e=>console.log(fmt.eventLine(e))):fmt.info("No event types found.")}async function eventCreate(e,t,o){const n=getFlag(t,"name")||getFlag(t,"n");n||(fmt.err('Usage: apo event-create --name "Title" [--duration 30] [--slug my-slug] [--description "..."] [--timezone Europe/London] [--price 0] [--currency USD]'),process.exit(1));const a=parseInt(getFlag(t,"duration")||getFlag(t,"d")||"30",10),s=getFlag(t,"slug")||n.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,""),i=getFlag(t,"description")||"",r=getFlag(t,"timezone")||getFlag(t,"z")||"Europe/London",l=parseFloat(getFlag(t,"price")||"0")||0,g=getFlag(t,"currency")||"USD",c=loadConfig([]).userId;c||(fmt.err("No userId in config — run `apo init` or `apo login --key KEY --user USERID`"),process.exit(1));const d={userId:c,name:n,slug:s,duration:a,description:i,availability:{type:"inherit",timezone:r},pricing:{enabled:l>0,amount:l,currency:g}},u=await e.createEvent(d);if(o)return console.log(JSON.stringify(u,null,2));const f=unwrap(u);fmt.ok(`Event type created: ${f.name||n}`),console.log(fmt.dim(` id: ${f.eventTypeId||f.id||f._id||"(id unavailable)"} slug: ${f.slug||s} ${a}min`))}const DAY_NAMES=["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],DAY_INDEX={sun:0,mon:1,tue:2,wed:3,thu:4,fri:5,sat:6};function parseDays(e){if(!e)return[1,2,3,4,5];const t=new Set;return e.toLowerCase().split(",").forEach(e=>{const o=e.trim().match(/^([a-z]{3})-([a-z]{3})$/);if(o&&null!=DAY_INDEX[o[1]]&&null!=DAY_INDEX[o[2]])for(let e=DAY_INDEX[o[1]];e<=DAY_INDEX[o[2]];e++)t.add(e);else null!=DAY_INDEX[e.trim()]&&t.add(DAY_INDEX[e.trim()])}),[...t].sort()}async function eventDelete(e,t,o){const n=getFlag(t,"id")||t.find(e=>!e.startsWith("-"));n||(fmt.err("Usage: apo event-delete EVENT_TYPE_ID [--soft] [--force] (id from `apo events`)"),process.exit(1));const a=t.includes("--soft"),s=t.includes("--force")||t.includes("-f");let i=null;try{const t=await e.events();i=(Array.isArray(t)?t:t.eventTypes||t.data&&(Array.isArray(t.data)?t.data:t.data.eventTypes)||[]).find(e=>e.id===n||e._id===n||e.eventTypeId===n||e.slug===n)}catch{}const r=i&&Number.isFinite(i.bookingCount)?i.bookingCount:null,l=i&&(i.name||i.slug)||n;!a&&!s&&r>0&&(fmt.err(`Refusing to delete "${l}" — it has ${r} booking(s) attached.`),fmt.info("Those meetings would be orphaned. Options:"),fmt.info(" • apo event-delete "+n+" --soft (deactivate, keep bookings)"),fmt.info(" • apo event-delete "+n+" --force (hard delete anyway)"),process.exit(1));const g=await e.deleteEvent(n,a);if(o)return console.log(JSON.stringify(g,null,2));a?fmt.ok(`Event type deactivated (soft-deleted, bookings preserved): ${l}`):fmt.ok(`Event type deleted: ${l}${r?` (${r} booking(s) removed)`:""}`)}async function resolveOrgId(e,t){try{const o=unwrap(await e.availabilityGet(t)),n=o.settings&&o.settings.organizationId||o.organizationId;if(n)return n}catch{}try{const t=await e.events(),o=(Array.isArray(t)?t:t.eventTypes||t.data&&(Array.isArray(t.data)?t.data:t.data.eventTypes)||[]).find(e=>e.organization&&e.organization.id);if(o)return o.organization.id}catch{}return null}async function availability(e,t,o){const n=t[0]&&!t[0].startsWith("-")?t[0]:"get",a=n===t[0]?t.slice(1):t,s=getFlag(a,"user")||loadConfig([]).userId;if(s||(fmt.err("No userId — run `apo init` or pass --user USERID"),process.exit(1)),"get"===n){const t=unwrap(await e.availabilityGet(s));if(o)return console.log(JSON.stringify(t,null,2));const n=t.settings&&t.settings.workingHours||t.workingHours||[],a=t.settings&&t.settings.timezone||t.timezone||"UTC";return n.length?(fmt.ok(`Availability (${a})`),void n.filter(e=>e.isAvailable).forEach(e=>{const t=(e.timeSlots||[]).map(e=>`${e.startTime}-${e.endTime}`).join(", ");console.log(` ${DAY_NAMES[e.dayOfWeek]||e.dayOfWeek}: ${t}`)})):fmt.info("No availability set.")}if("set"===n){const t=getFlag(a,"from")||"09:00",n=getFlag(a,"to")||"17:00",i=getFlag(a,"timezone")||getFlag(a,"z")||"Europe/London",r=parseDays(getFlag(a,"days"));/^\d{2}:\d{2}$/.test(t)&&/^\d{2}:\d{2}$/.test(n)||(fmt.err("Times must be HH:MM (e.g. --from 09:00 --to 17:00)"),process.exit(1));const l=[0,1,2,3,4,5,6].map(e=>({dayOfWeek:e,isAvailable:r.includes(e),timeSlots:r.includes(e)?[{startTime:t,endTime:n}]:[]})),g=getFlag(a,"org")||await resolveOrgId(e,s);g||(fmt.err("Could not resolve organizationId — pass --org ORG_ID"),process.exit(1));const c={userId:s,organizationId:g,workingHours:l,timezone:i},d=await e.availabilityUpdate(s,c);return o?console.log(JSON.stringify(d,null,2)):void fmt.ok(`Availability set — ${r.map(e=>DAY_NAMES[e]).join(",")} ${t}-${n} (${i})`)}fmt.err(`Unknown availability subcommand: ${n} (use: get | set)`),process.exit(1)}async function slots(e,t,o){const n=getFlag(t,"email")||getFlag(t,"e"),a=getFlag(t,"date")||getFlag(t,"d"),s=getFlag(t,"timezone")||getFlag(t,"z")||"UTC";n&&a||(fmt.err("Usage: apo slots --email host@co.com --date 2026-06-15"),process.exit(1));const i=await e.slots(n,a,s),r=i.slots||i.data||[];return o?console.log(JSON.stringify(r,null,2)):r.length?void r.forEach(e=>console.log(` ${e.startTime||e.start} — ${e.endTime||e.end}`)):fmt.info("No available slots.")}module.exports={book:book,bookings:bookings,bookingShow:bookingShow,cancel:cancel,reschedule:reschedule,events:events,slots:slots,eventCreate:eventCreate,eventDelete:eventDelete,availability:availability,roomNameOf:roomNameOf,unwrap:unwrap};
|
package/dist/commands/domains.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
const https=require("https"),http=require("http"),{getFlag:getFlag,hasFlag:hasFlag,loadConfig:loadConfig}=require("../config"),fmt=require("../format");function unwrap(e){let t=e;for(;t&&"object"==typeof t&&t.data&&!Array.isArray(t);)t=t.data;return t||{}}function domainArray(e){const t=unwrap(e);return Array.isArray(t)?t:t.domains||t.tenantDomains||[]}function idOf(e){return e.tenantDomainId||e._id||e.id||"?"}function domainLine(e){const t=e.status||"?",o="active"===t?"[32m":"pending"===t?"[33m":"[31m",n=e.ssl&&e.ssl.status?`ssl:${e.ssl.status}`:"";return` ${fmt.bold(e.hostname||"?")} ${o}${t}[0m ${fmt.dim(e.domainType||"")} ${fmt.dim(n)} ${fmt.dim(idOf(e))}`}async function findDomain(e,t){return domainArray(await e.domains()).find(e=>e.hostname===t||idOf(e)===t)||null}async function list(e,t,o){const n=domainArray(await e.domains());if(o)return console.log(JSON.stringify(n,null,2));n.length?n.forEach(e=>console.log(domainLine(e))):fmt.info("No custom domains. Add one: apo domain add meetings.yourdomain.com")}async function add(e,t,o){const n=t.find(e=>!e.startsWith("--"));n&&/^[a-zA-Z0-9][a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/.test(n)||(fmt.err("Usage: apo domain add meetings.yourdomain.com"),process.exit(1));const s=loadConfig([]).userId;s||(fmt.err("No userId in config. Run `apo signin` or `apo login --key K --user ID`."),process.exit(1));const i=await e.domainRegister({hostname:n,domainType:"custom",tenantId:s,tenantType:"user",baseDomain:"appoiint.ai"});if(o)return console.log(JSON.stringify(i,null,2));const a=unwrap(i);fmt.ok(`Domain registered: ${n} (${idOf(a)})`);const r=a.dnsVerification&&a.dnsVerification.expectedValue;r?(console.log("\n Add this DNS record at your registrar:\n"),console.log(` ${fmt.bold(n)} CNAME ${fmt.bold(r)}\n`),console.log(fmt.dim(` Then run: apo domain verify ${n}`))):fmt.info("SDK did not return a CNAME target — check `apo domain show "+n+"`.")}async function show(e,t,o){const n=t.find(e=>!e.startsWith("--"));n||(fmt.err("Usage: apo domain show HOSTNAME|DOMAIN_ID"),process.exit(1));const s=await findDomain(e,n);s||(fmt.err(`Domain not found: ${n}`),process.exit(1));const i=unwrap(await e.domainGet(idOf(s)));if(o)return console.log(JSON.stringify(i,null,2));console.log(domainLine(i.hostname?i:s));const a=i.dnsVerification||s.dnsVerification||{};a.expectedValue&&console.log(` CNAME target: ${fmt.bold(a.expectedValue)} ${fmt.dim(a.verified?"verified":"unverified")}`),(i.slug||s.slug)&&console.log(fmt.dim(` slug: ${i.slug||s.slug}`))}async function verify(e,t,o){const n=t.find(e=>!e.startsWith("--"));n||(fmt.err("Usage: apo domain verify HOSTNAME|DOMAIN_ID"),process.exit(1));const s=await findDomain(e,n);s||(fmt.err(`Domain not found: ${n}`),process.exit(1));const i=await e.domainVerify(idOf(s));if(o)return console.log(JSON.stringify(i,null,2));const a=unwrap(i);a.verified||i.success&&"active"===a.status?fmt.ok(`DNS verified for ${s.hostname} — SSL provisioning follows automatically.`):(fmt.info(`DNS not verified yet for ${s.hostname}. CNAME may still be propagating — retry in a few minutes.`),!0!==o&&console.log(fmt.dim(" Status: apo domain status "+s.hostname)))}async function dnsStatus(e,t,o){const n=t.find(e=>!e.startsWith("--"));n||(fmt.err("Usage: apo domain status HOSTNAME|DOMAIN_ID"),process.exit(1));const s=await findDomain(e,n);s||(fmt.err(`Domain not found: ${n}`),process.exit(1));const i=await e.domainDnsStatus(idOf(s));if(o)return console.log(JSON.stringify(i,null,2));const a=unwrap(i);console.log(` ${fmt.bold(s.hostname)} dns:${a.dnsStatus||a.status||"?"} ${fmt.dim("ssl:"+(a.ssl&&a.ssl.status||a.sslStatus||"?"))}`)}async function remove(e,t,o){const n=t.find(e=>!e.startsWith("--"));n||(fmt.err("Usage: apo domain remove HOSTNAME|DOMAIN_ID --yes"),process.exit(1)),hasFlag(t,"yes")||(fmt.err("Refusing to delete without --yes (this cannot be undone)."),process.exit(1));const s=await findDomain(e,n);s||(fmt.err(`Domain not found: ${n}`),process.exit(1));const i=await e.domainDelete(idOf(s));if(o)return console.log(JSON.stringify(i,null,2));fmt.ok(`Domain removed: ${s.hostname}`)}function pickAvatar(e){if(!Array.isArray(e))return"";const t=e.find(e=>e&&"avatar"===e.type);return t&&(t.displayUrl||t.url)||""}async function pageShow(e,t,o){const n=await e.profileGet(),s=n.user||unwrap(n);if(s&&(s.fullName||s.firstName)||(fmt.err("Could not load profile."),process.exit(1)),o)return console.log(JSON.stringify(s,null,2));const i=s.profile||{};console.log(` ${fmt.bold(s.fullName||`${s.firstName||""} ${s.lastName||""}`.trim())}`),console.log(` title: ${i.title||s.title||s.position||fmt.dim("(unset)")}`),console.log(` company: ${s.company||i.company||fmt.dim("(unset)")}`),console.log(` website: ${i.website||s.website||fmt.dim("(unset)")}`),console.log(` bio: ${i.bio||fmt.dim("(unset)")}`),console.log(` slug: ${s.slug||fmt.dim("(unset)")}`),console.log(` avatar: ${pickAvatar(s.images)||fmt.dim("(none — OG image falls back)")}`);const a=(s.domains||[]).map(e=>e.hostname).filter(Boolean);a.length&&console.log(` domains: ${a.join(", ")}`),console.log(fmt.dim("\n Edit: apo page set --first F --last L --title T --company C --phone N"))}async function pageSet(e,t,o){const n={},s=getFlag(t,"first"),i=getFlag(t,"last"),a=getFlag(t,"company"),r=getFlag(t,"title"),l=getFlag(t,"phone");null!==s&&(n.firstName=s),null!==i&&(n.lastName=i),null!==a&&(n.company=a),null!==r&&(n.position=r),null!==l&&(n.mobile_no=l);const c=["website","bio","linkedin","timezone"].filter(e=>null!==getFlag(t,e));c.length&&(fmt.err(`Not yet writable via the SDK: --${c.join(", --")} (PUT /user-profile drops nested profile fields — SDK team notified). Use the dashboard for now.`),Object.keys(n).length||process.exit(1)),Object.keys(n).length||(fmt.err("Usage: apo page set [--first F] [--last L] [--title T] [--company C] [--phone N]"),process.exit(1));const m=await e.profileUpdate(n);if(o)return console.log(JSON.stringify(m,null,2));fmt.ok("Meetings page updated: "+Object.keys(n).join(", ")),console.log(fmt.dim(" Verify what visitors/crawlers see: apo page check HOSTNAME"))}function fetchPage(e,t=0){return new Promise((o,n)=>{if(t>3)return n(new Error("Too many redirects"));const s=new URL(e),i=("https:"===s.protocol?https:http).get({hostname:s.hostname,port:s.port,path:s.pathname+s.search,headers:{"User-Agent":"apo-cli page-check (LinkedInBot-like)"},timeout:15e3},n=>{if(n.statusCode>=300&&n.statusCode<400&&n.headers.location)return n.resume(),o(fetchPage(new URL(n.headers.location,e).href,t+1));let s="";n.setEncoding("utf8"),n.on("data",e=>{s.length<5e5&&(s+=e)}),n.on("end",()=>o({status:n.statusCode,body:s}))});i.on("error",n),i.on("timeout",()=>{i.destroy(),n(new Error("Timeout fetching "+e))})})}function metaContent(e,t,o){const n=new RegExp(`<meta[^>]+${t}=["']${o}["'][^>]+content=["']([^"']*)["']`,"i"),s=new RegExp(`<meta[^>]+content=["']([^"']*)["'][^>]+${t}=["']${o}["']`,"i"),i=e.match(n)||e.match(s);return i?i[1]:""}async function pageCheck(e,t,o){let n=t.find(e=>!e.startsWith("--"));if(!n){const t=domainArray(await e.domains());n=t.length?t[0].hostname:null,n||(fmt.err("Usage: apo page check HOSTNAME (no custom domains found on this account)"),process.exit(1))}n=n.replace(/^https?:\/\//,"").replace(/\/.*$/,"");const s={hostname:n,checks:{}};try{const t=unwrap(await e.domainResolve(n));s.checks.routing={ok:"active"===t.status,status:t.status,slug:t.slug,tenantId:t.tenantId}}catch(e){s.checks.routing={ok:!1,error:e.message}}try{const e=await fetchPage(`https://${n}/`),t=e.body,o=t.match(/<title[^>]*>([^<]*)<\/title>/i);s.checks.page={ok:200===e.status,httpStatus:e.status},s.checks.og={title:metaContent(t,"property","og:title"),description:metaContent(t,"property","og:description"),image:metaContent(t,"property","og:image"),url:metaContent(t,"property","og:url"),twitterCard:metaContent(t,"name","twitter:card"),pageTitle:o?o[1].trim():"",robotsNoindex:/<meta[^>]+name=["']robots["'][^>]+noindex/i.test(t)},s.checks.og.ok=!(!s.checks.og.title||!s.checks.og.description||s.checks.og.robotsNoindex),s.checks.og.imageIsRaster=!!s.checks.og.image&&!/\.svg(\?|$)/i.test(s.checks.og.image)}catch(e){s.checks.page={ok:!1,error:e.message}}const i=s.checks.routing&&s.checks.routing.slug;if(i)try{const t=await e.profileBySlug(i),o=t.data||t;s.checks.profile={ok:!!o.fullName,fullName:o.fullName,title:o.title,company:o.company,hasAvatar:!!pickAvatar(o.images)}}catch(e){s.checks.profile={ok:!1,error:e.message}}if(o)return console.log(JSON.stringify(s,null,2));const a=e=>e?"[32m✓[0m":"[31m✗[0m",r=s.checks;console.log(`\n ${fmt.bold("https://"+n+"/")}\n`),console.log(` ${a(r.routing&&r.routing.ok)} routing ${r.routing&&r.routing.ok?`active → slug ${r.routing.slug}`:r.routing&&(r.routing.error||r.routing.status)||"failed"}`),console.log(` ${a(r.page&&r.page.ok)} page ${r.page&&r.page.ok?"HTTP 200":r.page&&(r.page.error||"HTTP "+r.page.httpStatus)||"failed"}`),r.og&&(console.log(` ${a(r.og.ok)} og tags ${r.og.title?`"${r.og.title}"`:"MISSING og:title"}`),r.og.description&&console.log(` ${fmt.dim(r.og.description)}`),console.log(` ${a(r.og.imageIsRaster)} og image ${r.og.image?r.og.image+(r.og.imageIsRaster?"":" (SVG — LinkedIn will not render it)"):"none (upload an avatar in your profile)"}`),r.og.robotsNoindex&&console.log(` ${a(!1)} robots noindex present — crawlers will skip this page`)),r.profile&&(console.log(` ${a(r.profile.ok)} profile ${r.profile.ok?`${r.profile.fullName}${r.profile.title?" — "+r.profile.title:""}${r.profile.company?" @ "+r.profile.company:""}`:r.profile.error||"not found"}`),r.profile.ok&&!r.profile.hasAvatar&&console.log(` ${fmt.dim("no avatar image — page + link previews look better with one")}`)),console.log(""),[r.routing,r.page,r.og,r.profile].filter(Boolean).every(e=>e.ok)?fmt.ok("Meetings page is fully optimized — share it anywhere (LinkedIn, email signature, bio)."):fmt.info("Fix the ✗ items above, then re-run: apo page check "+n)}async function domainRun(e,t,o){const n=t[0],s=t.slice(1);switch(n){case"add":return add(e,s,o);case"show":return show(e,s,o);case"verify":return verify(e,s,o);case"status":return dnsStatus(e,s,o);case"remove":case"rm":case"delete":return remove(e,s,o);case"list":case void 0:return list(e,s,o);default:fmt.err("Usage: apo domain [list|add|show|verify|status|remove] ..."),process.exit(1)}}async function pageRun(e,t,o){const n=t[0],s=t.slice(1);switch(n){case"set":return pageSet(e,s,o);case"check":return pageCheck(e,s,o);case"show":case void 0:return pageShow(e,s,o);default:fmt.err("Usage: apo page [show|set|check] ..."),process.exit(1)}}module.exports={list:list,domainRun:domainRun,pageRun:pageRun};
|
|
1
|
+
const https=require("https"),http=require("http"),{getFlag:getFlag,hasFlag:hasFlag,loadConfig:loadConfig}=require("../config"),fmt=require("../format");function unwrap(e){let t=e;for(;t&&"object"==typeof t&&t.data&&!Array.isArray(t);)t=t.data;return t||{}}function domainArray(e){const t=unwrap(e);return Array.isArray(t)?t:t.domains||t.tenantDomains||[]}function idOf(e){return e.tenantDomainId||e._id||e.id||"?"}function domainLine(e){const t=e.status||"?",o="active"===t?"[32m":"pending"===t?"[33m":"[31m",n=e.ssl&&e.ssl.status?`ssl:${e.ssl.status}`:"";return` ${fmt.bold(e.hostname||"?")} ${o}${t}[0m ${fmt.dim(e.domainType||"")} ${fmt.dim(n)} ${fmt.dim(idOf(e))}`}async function findDomain(e,t){return domainArray(await e.domains()).find(e=>e.hostname===t||idOf(e)===t)||null}async function list(e,t,o){const n=domainArray(await e.domains());if(o)return console.log(JSON.stringify(n,null,2));n.length?n.forEach(e=>console.log(domainLine(e))):fmt.info("No custom domains. Add one: apo domain add meetings.yourdomain.com")}async function add(e,t,o){const n=t.find(e=>!e.startsWith("--"));n&&/^[a-zA-Z0-9][a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/.test(n)||(fmt.err("Usage: apo domain add meetings.yourdomain.com"),process.exit(1));const a=loadConfig([]).userId;a||(fmt.err("No userId in config. Run `apo signin` or `apo login --key K --user ID`."),process.exit(1));const i=await e.domainRegister({hostname:n,domainType:"custom",tenantId:a,tenantType:"user",baseDomain:"appoiint.ai"});if(o)return console.log(JSON.stringify(i,null,2));const s=unwrap(i);fmt.ok(`Domain registered: ${n} (${idOf(s)})`);const r=s.dnsVerification&&s.dnsVerification.expectedValue;r?(console.log("\n Add this DNS record at your registrar:\n"),console.log(` ${fmt.bold(n)} CNAME ${fmt.bold(r)}\n`),console.log(fmt.dim(` Then run: apo domain verify ${n}`))):fmt.info("SDK did not return a CNAME target — check `apo domain show "+n+"`.")}async function show(e,t,o){const n=t.find(e=>!e.startsWith("--"));n||(fmt.err("Usage: apo domain show HOSTNAME|DOMAIN_ID"),process.exit(1));const a=await findDomain(e,n);a||(fmt.err(`Domain not found: ${n}`),process.exit(1));const i=unwrap(await e.domainGet(idOf(a)));if(o)return console.log(JSON.stringify(i,null,2));console.log(domainLine(i.hostname?i:a));const s=i.dnsVerification||a.dnsVerification||{};s.expectedValue&&console.log(` CNAME target: ${fmt.bold(s.expectedValue)} ${fmt.dim(s.verified?"verified":"unverified")}`),(i.slug||a.slug)&&console.log(fmt.dim(` slug: ${i.slug||a.slug}`))}async function verify(e,t,o){const n=t.find(e=>!e.startsWith("--"));n||(fmt.err("Usage: apo domain verify HOSTNAME|DOMAIN_ID"),process.exit(1));const a=await findDomain(e,n);a||(fmt.err(`Domain not found: ${n}`),process.exit(1));const i=await e.domainVerify(idOf(a)),s=unwrap(i),r=s.verified||s.dnsVerification&&s.dnsVerification.verified||i.success&&"active"===s.status;let c=null;if(r&&"active"!==s.status)try{c=unwrap(await e.domainActivate(idOf(a)))}catch(e){c={error:e.message}}if(o)return console.log(JSON.stringify({verify:i,activate:c},null,2));r?c&&"active"===c.status?fmt.ok(`${a.hostname} verified and ACTIVE — resolves to the tenant meeting page.`):c&&c.error?(fmt.ok(`DNS verified for ${a.hostname}.`),fmt.err(` Activation failed: ${c.error} — retry: apo domain activate ${a.hostname}`)):fmt.ok(`${a.hostname} verified and active.`):(fmt.info(`DNS not verified yet for ${a.hostname}. CNAME may still be propagating — retry in a few minutes.`),!0!==o&&console.log(fmt.dim(" Status: apo domain status "+a.hostname)))}async function activate(e,t,o){const n=t.find(e=>!e.startsWith("--"));n||(fmt.err("Usage: apo domain activate HOSTNAME|DOMAIN_ID"),process.exit(1));const a=await findDomain(e,n);a||(fmt.err(`Domain not found: ${n}`),process.exit(1));const i=await e.domainActivate(idOf(a));if(o)return console.log(JSON.stringify(i,null,2));const s=unwrap(i);"active"===s.status?fmt.ok(`${a.hostname} is ACTIVE — resolves to the tenant meeting page.`):fmt.info(`${a.hostname} status: ${s.status||"?"}`)}async function dnsStatus(e,t,o){const n=t.find(e=>!e.startsWith("--"));n||(fmt.err("Usage: apo domain status HOSTNAME|DOMAIN_ID"),process.exit(1));const a=await findDomain(e,n);a||(fmt.err(`Domain not found: ${n}`),process.exit(1));const i=await e.domainDnsStatus(idOf(a));if(o)return console.log(JSON.stringify(i,null,2));const s=unwrap(i);console.log(` ${fmt.bold(a.hostname)} dns:${s.dnsStatus||s.status||"?"} ${fmt.dim("ssl:"+(s.ssl&&s.ssl.status||s.sslStatus||"?"))}`)}async function remove(e,t,o){const n=t.find(e=>!e.startsWith("--"));n||(fmt.err("Usage: apo domain remove HOSTNAME|DOMAIN_ID --yes"),process.exit(1)),hasFlag(t,"yes")||(fmt.err("Refusing to delete without --yes (this cannot be undone)."),process.exit(1));const a=await findDomain(e,n);a||(fmt.err(`Domain not found: ${n}`),process.exit(1));const i=await e.domainDelete(idOf(a));if(o)return console.log(JSON.stringify(i,null,2));fmt.ok(`Domain removed: ${a.hostname}`)}function pickAvatar(e){if(!Array.isArray(e))return"";const t=e.find(e=>e&&"avatar"===e.type);return t&&(t.displayUrl||t.url)||""}async function pageShow(e,t,o){const n=await e.profileGet(),a=n.user||unwrap(n);if(a&&(a.fullName||a.firstName)||(fmt.err("Could not load profile."),process.exit(1)),o)return console.log(JSON.stringify(a,null,2));const i=a.profile||{};console.log(` ${fmt.bold(a.fullName||`${a.firstName||""} ${a.lastName||""}`.trim())}`),console.log(` title: ${i.title||a.title||a.position||fmt.dim("(unset)")}`),console.log(` company: ${a.company||i.company||fmt.dim("(unset)")}`),console.log(` website: ${i.website||a.website||fmt.dim("(unset)")}`),console.log(` bio: ${i.bio||fmt.dim("(unset)")}`),console.log(` slug: ${a.slug||fmt.dim("(unset)")}`),console.log(` avatar: ${pickAvatar(a.images)||fmt.dim("(none — OG image falls back)")}`);const s=(a.domains||[]).map(e=>e.hostname).filter(Boolean);s.length&&console.log(` domains: ${s.join(", ")}`),console.log(fmt.dim("\n Edit: apo page set --first F --last L --title T --company C --phone N"))}async function pageSet(e,t,o){const n={},a=getFlag(t,"first"),i=getFlag(t,"last"),s=getFlag(t,"company"),r=getFlag(t,"title"),c=getFlag(t,"phone");null!==a&&(n.firstName=a),null!==i&&(n.lastName=i),null!==s&&(n.company=s),null!==r&&(n.position=r),null!==c&&(n.mobile_no=c);const l=["website","bio","linkedin","timezone"].filter(e=>null!==getFlag(t,e));l.length&&(fmt.err(`Not yet writable via the SDK: --${l.join(", --")} (PUT /user-profile drops nested profile fields — SDK team notified). Use the dashboard for now.`),Object.keys(n).length||process.exit(1)),Object.keys(n).length||(fmt.err("Usage: apo page set [--first F] [--last L] [--title T] [--company C] [--phone N]"),process.exit(1));const m=await e.profileUpdate(n);if(o)return console.log(JSON.stringify(m,null,2));fmt.ok("Meetings page updated: "+Object.keys(n).join(", ")),console.log(fmt.dim(" Verify what visitors/crawlers see: apo page check HOSTNAME"))}async function pageCover(e,t,o){const{resolveImageSource:n}=require("../api"),a=t.find(e=>!e.startsWith("--")),i=getFlag(t,"type")||"cover";let s;a||(fmt.err("Usage: apo page cover <URL|file> [--type cover|avatar]"),process.exit(1));try{s=await n(a)}catch(e){fmt.err(`Could not read image source: ${e.message}`),process.exit(1)}const r=await e.uploadImage({type:i,buffer:s.buffer,filename:s.filename,mime:s.mime}),c=r.avatar?.url||r.cover?.url||r.url||r.user?.images?.find?.(e=>e.type===i)?.url;if(o)return console.log(JSON.stringify(r,null,2));fmt.ok(`Meetings page ${i} updated${c?": "+c:""}`),console.log(fmt.dim(" Verify what visitors see: apo page check HOSTNAME"))}function fetchPage(e,t=0){return new Promise((o,n)=>{if(t>3)return n(new Error("Too many redirects"));const a=new URL(e),i=("https:"===a.protocol?https:http).get({hostname:a.hostname,port:a.port,path:a.pathname+a.search,headers:{"User-Agent":"apo-cli page-check (LinkedInBot-like)"},timeout:15e3},n=>{if(n.statusCode>=300&&n.statusCode<400&&n.headers.location)return n.resume(),o(fetchPage(new URL(n.headers.location,e).href,t+1));let a="";n.setEncoding("utf8"),n.on("data",e=>{a.length<5e5&&(a+=e)}),n.on("end",()=>o({status:n.statusCode,body:a}))});i.on("error",n),i.on("timeout",()=>{i.destroy(),n(new Error("Timeout fetching "+e))})})}function metaContent(e,t,o){const n=new RegExp(`<meta[^>]+${t}=["']${o}["'][^>]+content=["']([^"']*)["']`,"i"),a=new RegExp(`<meta[^>]+content=["']([^"']*)["'][^>]+${t}=["']${o}["']`,"i"),i=e.match(n)||e.match(a);return i?i[1]:""}async function pageCheck(e,t,o){let n=t.find(e=>!e.startsWith("--"));if(!n){const t=domainArray(await e.domains());n=t.length?t[0].hostname:null,n||(fmt.err("Usage: apo page check HOSTNAME (no custom domains found on this account)"),process.exit(1))}n=n.replace(/^https?:\/\//,"").replace(/\/.*$/,"");const a={hostname:n,checks:{}};try{const t=unwrap(await e.domainResolve(n));a.checks.routing={ok:"active"===t.status,status:t.status,slug:t.slug,tenantId:t.tenantId}}catch(e){a.checks.routing={ok:!1,error:e.message}}try{const e=await fetchPage(`https://${n}/`),t=e.body,o=t.match(/<title[^>]*>([^<]*)<\/title>/i);a.checks.page={ok:200===e.status,httpStatus:e.status},a.checks.og={title:metaContent(t,"property","og:title"),description:metaContent(t,"property","og:description"),image:metaContent(t,"property","og:image"),url:metaContent(t,"property","og:url"),twitterCard:metaContent(t,"name","twitter:card"),pageTitle:o?o[1].trim():"",robotsNoindex:/<meta[^>]+name=["']robots["'][^>]+noindex/i.test(t)},a.checks.og.ok=!(!a.checks.og.title||!a.checks.og.description||a.checks.og.robotsNoindex),a.checks.og.imageIsRaster=!!a.checks.og.image&&!/\.svg(\?|$)/i.test(a.checks.og.image)}catch(e){a.checks.page={ok:!1,error:e.message}}const i=a.checks.routing&&a.checks.routing.slug;if(i)try{const t=await e.profileBySlug(i),o=t.data||t;a.checks.profile={ok:!!o.fullName,fullName:o.fullName,title:o.title,company:o.company,hasAvatar:!!pickAvatar(o.images)}}catch(e){a.checks.profile={ok:!1,error:e.message}}if(o)return console.log(JSON.stringify(a,null,2));const s=e=>e?"[32m✓[0m":"[31m✗[0m",r=a.checks;console.log(`\n ${fmt.bold("https://"+n+"/")}\n`),console.log(` ${s(r.routing&&r.routing.ok)} routing ${r.routing&&r.routing.ok?`active → slug ${r.routing.slug}`:r.routing&&(r.routing.error||r.routing.status)||"failed"}`),console.log(` ${s(r.page&&r.page.ok)} page ${r.page&&r.page.ok?"HTTP 200":r.page&&(r.page.error||"HTTP "+r.page.httpStatus)||"failed"}`),r.og&&(console.log(` ${s(r.og.ok)} og tags ${r.og.title?`"${r.og.title}"`:"MISSING og:title"}`),r.og.description&&console.log(` ${fmt.dim(r.og.description)}`),console.log(` ${s(r.og.imageIsRaster)} og image ${r.og.image?r.og.image+(r.og.imageIsRaster?"":" (SVG — LinkedIn will not render it)"):"none (upload an avatar in your profile)"}`),r.og.robotsNoindex&&console.log(` ${s(!1)} robots noindex present — crawlers will skip this page`)),r.profile&&(console.log(` ${s(r.profile.ok)} profile ${r.profile.ok?`${r.profile.fullName}${r.profile.title?" — "+r.profile.title:""}${r.profile.company?" @ "+r.profile.company:""}`:r.profile.error||"not found"}`),r.profile.ok&&!r.profile.hasAvatar&&console.log(` ${fmt.dim("no avatar image — page + link previews look better with one")}`)),console.log(""),[r.routing,r.page,r.og,r.profile].filter(Boolean).every(e=>e.ok)?fmt.ok("Meetings page is fully optimized — share it anywhere (LinkedIn, email signature, bio)."):fmt.info("Fix the ✗ items above, then re-run: apo page check "+n)}async function domainRun(e,t,o){const n=t[0],a=t.slice(1);switch(n){case"add":return add(e,a,o);case"show":return show(e,a,o);case"verify":return verify(e,a,o);case"activate":return activate(e,a,o);case"status":return dnsStatus(e,a,o);case"remove":case"rm":case"delete":return remove(e,a,o);case"list":case void 0:return list(e,a,o);default:fmt.err("Usage: apo domain [list|add|show|verify|activate|status|remove] ..."),process.exit(1)}}async function pageRun(e,t,o){const n=t[0],a=t.slice(1);switch(n){case"set":return pageSet(e,a,o);case"cover":case"avatar":return pageCover(e,"avatar"===n?["--type","avatar",...a]:a,o);case"check":return pageCheck(e,a,o);case"show":case void 0:return pageShow(e,a,o);default:fmt.err("Usage: apo page [show|set|cover|avatar|check] ..."),process.exit(1)}}module.exports={list:list,domainRun:domainRun,pageRun:pageRun};
|
package/dist/main.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
const{loadConfig:loadConfig,hasFlag:hasFlag,getFlag:getFlag}=require("./config"),{api:api,rawApi:rawApi}=require("./api"),fmt=require("./format"),args=process.argv.slice(2),command=args[0],subArgs=args.slice(1),jsonMode=hasFlag(args,"json"),NO_AUTH=["signup","signin","activate","login","logout","config","help","--help","-h","status","version","--version","-v","mcp-serve","man","renderer","init"],config=loadConfig(args);NO_AUTH.includes(command)||config.apiKey||(fmt.err("No API key. Run: apo signup --email you@co.com --password Pass123!"),fmt.err("Or: apo login --key YOUR_KEY --user YOUR_USERID"),fmt.err("Or set APO_API_KEY environment variable."),process.exit(1));const client=config.apiKey?api(config):null,raw=config.apiKey?rawApi(config):null,HELP='\n[1mAppoiint CLI[0m — Agent-first meeting platform\n\n[1mAuth:[0m\n apo signup --email E --password P Sign up (free 7-day trial, card required)\n apo signin --email E --password P Sign in as a human seat (email/password)\n apo activate [SUBSCRIPTION_ID] Get API key after card setup\n apo login --key KEY [--user USERID] Save API key to config\n apo logout Clear config\n apo config Show active config\n\n[1mRooms:[0m\n apo room "Title" Create meeting room\n apo rooms List active rooms\n apo room-status ROOM_ID Room status + participants\n apo room-end ROOM_ID End meeting\n apo invite ROOM_ID --email E --name N Invite human or agent\n apo transcript ROOM_ID [--format F] Get transcript (json|text|srt)\n\n[1mMeetings:[0m\n apo join ROOM_ID|BOOKING_ID [--name N] Join room (or bkg_ id → resolves room), streams transcript, Ctrl-C to leave\n apo join ROOM_ID --say "msg" Join, send one message, leave\n apo join ROOM_ID --say "msg" --voice cfo Speak out loud (assistant.bz TTS) + leave\n apo leave ROOM_ID Leave room\n\n[1mScheduling:[0m\n apo book --date D --email E Create booking\n apo bookings [--status S] [--host ID] List bookings (as host)\n apo booking BOOKING_ID Show booking (room + join links)\n apo cancel BOOKING_ID [--reason R] Cancel a booking\n apo reschedule BOOKING_ID --date D Move a booking to a new time\n apo events List event types\n apo slots --email E --date D Check availability\n\n[1mMeetings Page (custom domain):[0m\n apo domains List your custom domains\n apo domain add meetings.you.com Link a domain (returns CNAME to add)\n apo domain verify HOSTNAME Trigger DNS verification\n apo domain status HOSTNAME DNS + SSL status\n apo domain show HOSTNAME Domain details\n apo domain remove HOSTNAME --yes Unlink a domain\n apo page Show your meetings-page profile\n apo page set --title T --company C Update page fields (--first --last --phone)\n apo page check [HOSTNAME] Audit live page: routing, OG tags, image, profile\n\n[1mTTS:[0m\n apo tts "text" --voice cfo Synthesize speech\n apo voices List available voices\n\n[1mAdmin:[0m\n apo admin tenants List all tenants\n apo admin tenant-view SLUG Full tenant detail\n apo admin tenant-create SLUG Create tenant\n apo admin tenant-suspend SLUG Suspend tenant\n apo admin tenant-activate SLUG Reactivate tenant\n apo admin tenant-delete SLUG Delete tenant\n apo admin users List all users\n apo admin user-reset EMAIL -p PASS Reset user password\n apo admin billing MRR, ARR, revenue\n apo admin costs Platform cost summary (STT/TTS/LLM)\n apo admin costs ROOM_ID Per-meeting cost breakdown\n apo admin models Spend by provider/model + tokens\n apo admin usage Spend by user\n apo admin timeseries [--bucket day] Spend over time (hour|day)\n apo admin pricing Current provider pricing table\n apo admin ice Probe live STUN/TURN (control-gated)\n apo admin ice --url turn:IP:3478 Probe one server ad-hoc (--user --pass)\n\n[1mAnalytics:[0m\n apo stats Platform overview\n apo revenue Revenue breakdown\n apo funnel Signup funnel\n apo signups [--days 7] Recent signups\n\n[1mSupport:[0m\n apo tickets [--status open] List support tickets\n apo ticket show NUMBER Ticket detail\n apo ticket reply NUMBER MESSAGE Reply to ticket\n apo ticket close NUMBER Close ticket\n\n[1mAudit:[0m\n apo audit [--action X] [--limit N] Activity trail\n apo audit export [--format csv] Export audit log\n\n[1mHelpdesk (+$4.99/mo):[0m\n apo helpdesk tickets List tickets\n apo helpdesk ticket show ID Ticket detail + messages\n apo helpdesk ticket create "Subject" Create ticket\n apo helpdesk ticket reply ID "msg" Reply to ticket\n apo helpdesk ticket close ID Close ticket\n apo helpdesk ticket assign ID --agent X Assign ticket\n apo helpdesk kb List KB articles\n apo helpdesk stats Helpdesk statistics\n\n[1mCRM (+$4.99/mo):[0m\n apo crm leads List leads\n apo crm lead show ID Lead detail\n apo crm lead create "Name" --email X Create lead\n apo crm lead convert ID Convert lead → opportunity\n apo crm opps List opportunities\n apo crm opp show ID Opportunity detail\n apo crm opp create "Deal" --value X Create opportunity\n apo crm pipelines List pipelines\n apo crm stats CRM statistics\n\n[1mAgents (multi-agent identities):[0m\n apo agent create ci-bot Create named agent under your account\n apo agent list List your agents (plan quota: 3/5/10/∞)\n apo agent use ci-bot Act as @ci-bot (channels route by handle)\n apo agent use --account Switch back to account identity\n apo agent whoami Show active identity\n apo agent revoke ci-bot Revoke agent key\n --agent HANDLE / APO_AGENT env One-off identity override for any command\n\n[1mMessaging (agent-to-agent):[0m\n apo wall All threads (DMs + channels) w/ unread badges\n apo dm @AGENT ["msg"] [--watch] Read/send a DM (--watch = live stream)\n apo notifications Unread digest across all threads\n apo channel create NAME [--topic T] Create a named channel\n apo channel join|leave NAME Join / leave a channel\n apo channel list List channels (membership + unread)\n apo channel post NAME "msg" Post to a channel\n apo channel history <NAME|@AGENT> Channel or DM history (reading = ack)\n apo channel send @AGENT "msg" Send 1:1 message (legacy form of apo dm)\n apo channel inbox Unread messages\n apo channel agents List agent contacts\n\n[1mDiagnostics:[0m\n apo diagnose ROOM_ID Full room diagnostic (peers, events, relay)\n\n[1mManual:[0m\n apo man renderer Chat bubble renderer capabilities + formats\n apo renderer Same as above (shorthand)\n\n[1mOptions:[0m\n --json Output JSON (for agents)\n --key KEY Override API key\n --help Show this help\n\n[2mhttps://appoiint.com/docs/quickstart.html[0m\n';async function run(){switch(command){case"signup":return require("./commands/auth").signup(subArgs,config.baseUrl);case"signin":return require("./commands/auth").signin(subArgs,config.baseUrl);case"activate":return require("./commands/auth").activate(subArgs,config);case"login":return require("./commands/auth").login(subArgs);case"logout":return require("./commands/auth").logout(subArgs);case"config":return require("./commands/auth").showConfig(config);case"room":return require("./commands/rooms").create(client,subArgs,jsonMode,config);case"rooms":return require("./commands/rooms").list(client,subArgs,jsonMode);case"room-status":return require("./commands/rooms").status(client,subArgs,jsonMode);case"room-end":return require("./commands/rooms").end(client,subArgs,jsonMode);case"invite":return require("./commands/rooms").invite(client,subArgs,jsonMode);case"transcript":return require("./commands/rooms").transcript(client,subArgs,jsonMode);case"join":return require("./commands/meeting").join(client,subArgs,jsonMode,config);case"leave":return subArgs[0]||(fmt.err("Usage: apo leave ROOM_ID"),process.exit(1)),client.leaveMeeting({roomId:subArgs[0],agentId:"cli-agent"}).then(e=>jsonMode?console.log(JSON.stringify(e,null,2)):fmt.ok(`Left room ${subArgs[0]}`));case"book":return require("./commands/bookings").book(client,subArgs,jsonMode);case"bookings":return require("./commands/bookings").bookings(client,subArgs,jsonMode);case"booking":return require("./commands/bookings").bookingShow(client,subArgs,jsonMode);case"cancel":return require("./commands/bookings").cancel(client,subArgs,jsonMode);case"reschedule":return require("./commands/bookings").reschedule(client,subArgs,jsonMode);case"events":return require("./commands/bookings").events(client,subArgs,jsonMode);case"slots":return require("./commands/bookings").slots(client,subArgs,jsonMode);case"domains":return require("./commands/domains").list(client,subArgs,jsonMode);case"domain":return require("./commands/domains").domainRun(client,subArgs,jsonMode);case"page":return require("./commands/domains").pageRun(client,subArgs,jsonMode);case"tts":return require("./commands/tts").synthesize(client,subArgs,jsonMode);case"voices":return require("./commands/tts").voices(client,subArgs,jsonMode);case"status":{const e=await api({baseUrl:config.baseUrl,apiKey:""}).status();return jsonMode?console.log(JSON.stringify(e,null,2)):void fmt.ok(`Appoiint ${e.version||"?"} — ${e.available?"online":"offline"}`)}case"version":case"--version":case"-v":return void console.log(require("../package.json").version);case"admin":return require("./commands/admin").run(client,subArgs,jsonMode,config);case"stats":return require("./commands/stats").run(client,jsonMode);case"funnel":return require("./commands/stats").funnel(client,jsonMode);case"signups":return require("./commands/stats").signups(client,subArgs,jsonMode);case"revenue":return require("./commands/stats").revenue(client,jsonMode);case"tickets":return require("./commands/tickets").list(client,subArgs,jsonMode);case"ticket":const e=subArgs[0];if("show"===e)return require("./commands/tickets").show(client,subArgs.slice(1),jsonMode);if("reply"===e)return require("./commands/tickets").reply(client,subArgs.slice(1),jsonMode);if("close"===e)return require("./commands/tickets").close(client,subArgs.slice(1),jsonMode);fmt.err("Usage: apo ticket [show|reply|close] NUMBER"),process.exit(1);case"audit":return require("./commands/audit").run(client,subArgs,jsonMode);case"helpdesk":return require("./commands/helpdesk").run(client,subArgs,jsonMode,raw);case"crm":return require("./commands/crm").run(client,subArgs,jsonMode,raw);case"agent":return require("./commands/agent").run(config,subArgs,jsonMode);case"channel":return require("./commands/channels").run(client,subArgs,jsonMode);case"wall":return require("./commands/wall").wall(client,subArgs,jsonMode);case"dm":return require("./commands/wall").dm(client,subArgs,jsonMode,config);case"notifications":return require("./commands/wall").notifications(client,subArgs,jsonMode);case"diagnose":return require("./commands/diagnose").run(client,subArgs,jsonMode,config);case"init":return require("./commands/init").run(subArgs);case"man":case"renderer":const n="man"===command?subArgs[0]:command;return"renderer"===n?require("./commands/renderer").run(subArgs.slice("man"===command?1:0),jsonMode):void fmt.err("Unknown manual page: "+(n||"(none)")+". Available: renderer");case"mcp-serve":return require("./mcp").serve();case"help":case"--help":case"-h":case void 0:return void console.log(HELP);default:fmt.err(`Unknown command: ${command}`),console.log(HELP),process.exit(1)}}run().catch(e=>{fmt.err(e.message),process.exit(1)});
|
|
1
|
+
const{loadConfig:loadConfig,hasFlag:hasFlag,getFlag:getFlag}=require("./config"),{api:api,rawApi:rawApi}=require("./api"),fmt=require("./format"),args=process.argv.slice(2),command=args[0],subArgs=args.slice(1),jsonMode=hasFlag(args,"json"),NO_AUTH=["signup","signin","activate","login","logout","config","help","--help","-h","status","version","--version","-v","mcp-serve","man","renderer","init"],config=loadConfig(args);NO_AUTH.includes(command)||config.apiKey||(fmt.err("No API key. Run: apo signup --email you@co.com --password Pass123!"),fmt.err("Or: apo login --key YOUR_KEY --user YOUR_USERID"),fmt.err("Or set APO_API_KEY environment variable."),process.exit(1));const client=config.apiKey?api(config):null,raw=config.apiKey?rawApi(config):null,HELP='\n[1mAppoiint CLI[0m — Agent-first meeting platform\n\n[1mAuth:[0m\n apo signup --email E --password P Sign up (free 7-day trial, card required)\n apo signin --email E --password P Sign in as a human seat (email/password)\n apo activate [SUBSCRIPTION_ID] Get API key after card setup\n apo login --key KEY [--user USERID] Save API key to config\n apo logout Clear config\n apo config Show active config\n\n[1mRooms:[0m\n apo room "Title" Create meeting room\n apo rooms List active rooms\n apo room-status ROOM_ID Room status + participants\n apo room-end ROOM_ID End meeting\n apo invite ROOM_ID --email E --name N Invite human or agent\n apo transcript ROOM_ID [--format F] Get transcript (json|text|srt)\n\n[1mMeetings:[0m\n apo join ROOM_ID|BOOKING_ID [--name N] Join room (or bkg_ id → resolves room), streams transcript, Ctrl-C to leave\n apo join ROOM_ID --say "msg" Join, send one message, leave\n apo join ROOM_ID --say "msg" --voice cfo Speak out loud (assistant.bz TTS) + leave\n apo leave ROOM_ID Leave room\n\n[1mScheduling:[0m\n apo book --date D --email E Create booking\n apo bookings [--status S] [--host ID] List bookings (as host)\n apo booking BOOKING_ID Show booking (room + join links)\n apo cancel BOOKING_ID [--reason R] Cancel a booking\n apo reschedule BOOKING_ID --date D Move a booking to a new time\n apo events List event types\n apo event-create --name "Title" Create an event type (--duration --slug --price)\n apo event-delete EVENT_TYPE_ID Delete an event type (blocks if bookings exist; --soft --force)\n apo availability get Show weekly availability\n apo availability set --days mon-fri Set availability (--from 09:00 --to 17:00 --timezone TZ)\n apo slots --email E --date D Check availability\n\n[1mMeetings Page (custom domain):[0m\n apo domains List your custom domains\n apo domain add meetings.you.com Link a domain (returns CNAME to add)\n apo domain verify HOSTNAME Trigger DNS verification\n apo domain status HOSTNAME DNS + SSL status\n apo domain show HOSTNAME Domain details\n apo domain remove HOSTNAME --yes Unlink a domain\n apo page Show your meetings-page profile\n apo page set --title T --company C Update page fields (--first --last --phone)\n apo page cover <URL|file> Set your meetings-page cover image (--type cover|avatar)\n apo page check [HOSTNAME] Audit live page: routing, OG tags, image, profile\n\n[1mTTS:[0m\n apo tts "text" --voice cfo Synthesize speech\n apo voices List available voices\n\n[1mAdmin:[0m\n apo admin tenants List all tenants\n apo admin tenant-view SLUG Full tenant detail\n apo admin tenant-create SLUG Create tenant\n apo admin tenant-suspend SLUG Suspend tenant\n apo admin tenant-activate SLUG Reactivate tenant\n apo admin tenant-delete SLUG Delete tenant\n apo admin users List all users\n apo admin user-reset EMAIL -p PASS Reset user password\n apo admin profile-cover EMAIL <SRC> -p PASS Set one tenant\'s cover image (--type cover|avatar)\n apo admin profile-cover <SRC> --tenants a@x,b@y -p PASS Gated bulk rollout (snapshot→apply→verify→rollback→ledger)\n apo admin billing MRR, ARR, revenue\n apo admin costs Platform cost summary (STT/TTS/LLM)\n apo admin costs ROOM_ID Per-meeting cost breakdown\n apo admin models Spend by provider/model + tokens\n apo admin usage Spend by user\n apo admin timeseries [--bucket day] Spend over time (hour|day)\n apo admin pricing Current provider pricing table\n apo admin ice Probe live STUN/TURN (control-gated)\n apo admin ice --url turn:IP:3478 Probe one server ad-hoc (--user --pass)\n\n[1mAnalytics:[0m\n apo stats Platform overview\n apo revenue Revenue breakdown\n apo funnel Signup funnel\n apo signups [--days 7] Recent signups\n\n[1mSupport:[0m\n apo tickets [--status open] List support tickets\n apo ticket show NUMBER Ticket detail\n apo ticket reply NUMBER MESSAGE Reply to ticket\n apo ticket close NUMBER Close ticket\n\n[1mAudit:[0m\n apo audit [--action X] [--limit N] Activity trail\n apo audit export [--format csv] Export audit log\n\n[1mHelpdesk (+$4.99/mo):[0m\n apo helpdesk tickets List tickets\n apo helpdesk ticket show ID Ticket detail + messages\n apo helpdesk ticket create "Subject" Create ticket\n apo helpdesk ticket reply ID "msg" Reply to ticket\n apo helpdesk ticket close ID Close ticket\n apo helpdesk ticket assign ID --agent X Assign ticket\n apo helpdesk kb List KB articles\n apo helpdesk stats Helpdesk statistics\n\n[1mCRM (+$4.99/mo):[0m\n apo crm leads List leads\n apo crm lead show ID Lead detail\n apo crm lead create "Name" --email X Create lead\n apo crm lead convert ID Convert lead → opportunity\n apo crm opps List opportunities\n apo crm opp show ID Opportunity detail\n apo crm opp create "Deal" --value X Create opportunity\n apo crm pipelines List pipelines\n apo crm stats CRM statistics\n\n[1mAgents (multi-agent identities):[0m\n apo agent create ci-bot Create named agent under your account\n apo agent list List your agents (plan quota: 3/5/10/∞)\n apo agent use ci-bot Act as @ci-bot (channels route by handle)\n apo agent use --account Switch back to account identity\n apo agent whoami Show active identity\n apo agent revoke ci-bot Revoke agent key\n --agent HANDLE / APO_AGENT env One-off identity override for any command\n\n[1mMessaging (agent-to-agent):[0m\n apo wall All threads (DMs + channels) w/ unread badges\n apo dm @AGENT ["msg"] [--watch] Read/send a DM (--watch = live stream)\n apo notifications Unread digest across all threads\n apo channel create NAME [--topic T] Create a named channel\n apo channel join|leave NAME Join / leave a channel\n apo channel list List channels (membership + unread)\n apo channel post NAME "msg" Post to a channel\n apo channel history <NAME|@AGENT> Channel or DM history (reading = ack)\n apo channel send @AGENT "msg" Send 1:1 message (legacy form of apo dm)\n apo channel inbox Unread messages\n apo channel agents List agent contacts\n\n[1mDiagnostics:[0m\n apo diagnose ROOM_ID Full room diagnostic (peers, events, relay)\n\n[1mManual:[0m\n apo man renderer Chat bubble renderer capabilities + formats\n apo renderer Same as above (shorthand)\n\n[1mOptions:[0m\n --json Output JSON (for agents)\n --key KEY Override API key\n --help Show this help\n\n[2mhttps://appoiint.com/docs/quickstart.html[0m\n';async function run(){switch(command){case"signup":return require("./commands/auth").signup(subArgs,config.baseUrl);case"signin":return require("./commands/auth").signin(subArgs,config.baseUrl);case"activate":return require("./commands/auth").activate(subArgs,config);case"login":return require("./commands/auth").login(subArgs);case"logout":return require("./commands/auth").logout(subArgs);case"config":return require("./commands/auth").showConfig(config);case"room":return require("./commands/rooms").create(client,subArgs,jsonMode,config);case"rooms":return require("./commands/rooms").list(client,subArgs,jsonMode);case"room-status":return require("./commands/rooms").status(client,subArgs,jsonMode);case"room-end":return require("./commands/rooms").end(client,subArgs,jsonMode);case"invite":return require("./commands/rooms").invite(client,subArgs,jsonMode);case"transcript":return require("./commands/rooms").transcript(client,subArgs,jsonMode);case"join":return require("./commands/meeting").join(client,subArgs,jsonMode,config);case"leave":return subArgs[0]||(fmt.err("Usage: apo leave ROOM_ID"),process.exit(1)),client.leaveMeeting({roomId:subArgs[0],agentId:"cli-agent"}).then(e=>jsonMode?console.log(JSON.stringify(e,null,2)):fmt.ok(`Left room ${subArgs[0]}`));case"book":return require("./commands/bookings").book(client,subArgs,jsonMode);case"bookings":return require("./commands/bookings").bookings(client,subArgs,jsonMode);case"booking":return require("./commands/bookings").bookingShow(client,subArgs,jsonMode);case"cancel":return require("./commands/bookings").cancel(client,subArgs,jsonMode);case"reschedule":return require("./commands/bookings").reschedule(client,subArgs,jsonMode);case"events":return require("./commands/bookings").events(client,subArgs,jsonMode);case"event-create":return require("./commands/bookings").eventCreate(client,subArgs,jsonMode);case"event-delete":return require("./commands/bookings").eventDelete(client,subArgs,jsonMode);case"availability":return require("./commands/bookings").availability(client,subArgs,jsonMode);case"slots":return require("./commands/bookings").slots(client,subArgs,jsonMode);case"domains":return require("./commands/domains").list(client,subArgs,jsonMode);case"domain":return require("./commands/domains").domainRun(client,subArgs,jsonMode);case"page":return require("./commands/domains").pageRun(client,subArgs,jsonMode);case"tts":return require("./commands/tts").synthesize(client,subArgs,jsonMode);case"voices":return require("./commands/tts").voices(client,subArgs,jsonMode);case"status":{const e=await api({baseUrl:config.baseUrl,apiKey:""}).status();return jsonMode?console.log(JSON.stringify(e,null,2)):void fmt.ok(`Appoiint ${e.version||"?"} — ${e.available?"online":"offline"}`)}case"version":case"--version":case"-v":return void console.log(require("../package.json").version);case"admin":return require("./commands/admin").run(client,subArgs,jsonMode,config);case"stats":return require("./commands/stats").run(client,jsonMode);case"funnel":return require("./commands/stats").funnel(client,jsonMode);case"signups":return require("./commands/stats").signups(client,subArgs,jsonMode);case"revenue":return require("./commands/stats").revenue(client,jsonMode);case"tickets":return require("./commands/tickets").list(client,subArgs,jsonMode);case"ticket":const e=subArgs[0];if("show"===e)return require("./commands/tickets").show(client,subArgs.slice(1),jsonMode);if("reply"===e)return require("./commands/tickets").reply(client,subArgs.slice(1),jsonMode);if("close"===e)return require("./commands/tickets").close(client,subArgs.slice(1),jsonMode);fmt.err("Usage: apo ticket [show|reply|close] NUMBER"),process.exit(1);case"audit":return require("./commands/audit").run(client,subArgs,jsonMode);case"helpdesk":return require("./commands/helpdesk").run(client,subArgs,jsonMode,raw);case"crm":return require("./commands/crm").run(client,subArgs,jsonMode,raw);case"agent":return require("./commands/agent").run(config,subArgs,jsonMode);case"channel":return require("./commands/channels").run(client,subArgs,jsonMode);case"wall":return require("./commands/wall").wall(client,subArgs,jsonMode);case"dm":return require("./commands/wall").dm(client,subArgs,jsonMode,config);case"notifications":return require("./commands/wall").notifications(client,subArgs,jsonMode);case"diagnose":return require("./commands/diagnose").run(client,subArgs,jsonMode,config);case"init":return require("./commands/init").run(subArgs);case"man":case"renderer":const n="man"===command?subArgs[0]:command;return"renderer"===n?require("./commands/renderer").run(subArgs.slice("man"===command?1:0),jsonMode):void fmt.err("Unknown manual page: "+(n||"(none)")+". Available: renderer");case"mcp-serve":return require("./mcp").serve();case"help":case"--help":case"-h":case void 0:return void console.log(HELP);default:fmt.err(`Unknown command: ${command}`),console.log(HELP),process.exit(1)}}run().catch(e=>{fmt.err(e.message),process.exit(1)});
|