@contfu/cli 0.0.2 → 0.0.4

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.
Files changed (3) hide show
  1. package/README.md +39 -0
  2. package/dist/main.js +11 -11
  3. package/package.json +2 -2
package/README.md ADDED
@@ -0,0 +1,39 @@
1
+ # @contfu/cli
2
+
3
+ Command-line tool for managing Contfu service resources.
4
+
5
+ ## Installation
6
+
7
+ ```sh
8
+ npm install -g @contfu/cli
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ```sh
14
+ contfu [--help] <command> [args...]
15
+ ```
16
+
17
+ ### Commands
18
+
19
+ ```
20
+ login [--no-browser] Authenticate with the Contfu service
21
+ logout Clear stored credentials
22
+ status Show resource summary
23
+
24
+ connections list|get|create|update|delete
25
+ collections list|get|create|update|delete
26
+ flows list|get|create|update|delete
27
+ consumers list|get|create|update|delete
28
+
29
+ connections types List valid connection types
30
+ collections types Generate TypeScript types for a collection
31
+ items query --collection <id> Query items
32
+ items count --collection <id> Count items
33
+ ```
34
+
35
+ ## Authentication
36
+
37
+ Credentials are stored locally after `contfu login`. The `CONTFU_TOKEN` environment variable can be used as an alternative to interactive login.
38
+
39
+ `CONTFU_URL` is only required for `items` commands — it specifies the base URL of the Contfu server that holds the data.
package/dist/main.js CHANGED
@@ -1,17 +1,17 @@
1
1
  #!/usr/bin/env node
2
- import{parseArgs as Io}from"node:util";var U={CLIENT:0,WEB:1,NOTION:20,STRAPI:21,CONTENTFUL:22};var w={NULL:0,STRING:2,STRINGS:4,NUMBER:8,NUMBERS:16,BOOLEAN:32,REF:64,REFS:128,FILE:256,FILES:512,DATE:1024,ENUM:2048,ENUMS:4096};function d(o){return Array.isArray(o)?o[0]:o}function P(o){return Array.isArray(o)?o[1]:void 0}function e(o){return o[0].toUpperCase()+o.slice(1)}function L(o,i){if(i==="lookup")return o.map((t)=>`ContfuCollections["${t}"]`).join(" | ");return o.map(e).join(" | ")}function R(o,i,t="interface",f){switch(o){case w.STRING:return"string";case w.STRINGS:return"string[]";case w.NUMBER:return"number";case w.NUMBERS:return"number[]";case w.BOOLEAN:return"boolean";case w.REF:if(i&&i.length>0)return L(i,t);return"string";case w.REFS:if(i&&i.length>0){let n=L(i,t);return i.length>1?`(${n})[]`:`${n}[]`}return"string[]";case w.FILE:return"{ url: string; alt?: string }";case w.FILES:return"{ url: string; alt?: string }[]";case w.DATE:return"string";case w.ENUM:if(f&&f.length>0)return f.map((n)=>JSON.stringify(n)).join(" | ");return"string";case w.ENUMS:if(f&&f.length>0){let n=f.map((g)=>JSON.stringify(g)).join(" | ");return f.length>1?`(${n})[]`:`${n}[]`}return"string[]";default:return"unknown"}}function u(o,i,t,f,n){let g=[`${f}| {`];for(let[r,c]of Object.entries(o))g.push(`${f} ${r}: ${R(d(c),i?.[r],t,P(c))};`);return g.push(`${f} }${n?";":""}`),g}function v(o){let i=new Set;return o.filter((t)=>{let f=JSON.stringify(Object.entries(t).sort(([n],[g])=>n.localeCompare(g)));if(i.has(f))return!1;return i.add(f),!0})}function S(o){let i=["// Auto-generated by Contfu — do not edit",""];i.push("export type ContfuCollections = {");for(let t of o){i.push(` /** ${t.displayName} */`);let f=t.inflowSchemas?v(t.inflowSchemas):[];if(f.length>=2){i.push(` ${t.name}:`);for(let n=0;n<f.length;n++)i.push(...u(f[n],t.refTargets,"lookup"," ",n===f.length-1))}else{i.push(` ${t.name}: {`);for(let[n,g]of Object.entries(t.schema))i.push(` ${n}: ${R(d(g),t.refTargets?.[n],"lookup",P(g))};`);i.push(" };")}}return i.push("};"),i.push(""),i.join(`
3
- `)}import{readFileSync as b}from"node:fs";import{join as oo}from"node:path";import{homedir as to}from"node:os";function io(){if(process.env.CONTFU_API_KEY)return process.env.CONTFU_API_KEY;try{let o=oo(to(),".config","contfu","config.json");return JSON.parse(b(o,"utf-8")).apiKey}catch{return}}function no(){return process.env.CONTFU_URL??"https://contfu.com"}function fo(o){let i=o.trim();if(!i)return null;try{let t=JSON.parse(i);if(typeof t.message==="string"&&t.message.trim())return t.message.trim()}catch{}return i}async function $(o,i){let t=io();if(!t)console.error("No API key configured. Set CONTFU_API_KEY or create ~/.config/contfu/config.json"),process.exit(1);let f=`${no()}${o}`,n=new Headers(i?.headers);n.set("Authorization",`Bearer ${t}`);let g=await fetch(f,{...i,headers:n});if(!g.ok){let r=await g.text(),c=fo(r);if(g.status===403){if(c&&c!=="Insufficient permissions")console.error(c);else console.error("Insufficient permissions. Your API key does not have the required scope for this action.");process.exit(1)}if(g.status===429)console.error("Rate limit exceeded. Please slow down and try again."),process.exit(1);console.error(`Error ${g.status}: ${c??r}`),process.exit(1)}return g}var go=["connections","collections","flows"];function K(o){return go.includes(o)}var ro={connections:["name"],collections:["display-name"],flows:["source-id","target-id"]};function z(o,i,t){if(i==="create"){let n=ro[o].filter((g)=>t[g]===void 0);if(n.length>0)console.error(`Missing required flag(s): ${n.map((g)=>`--${g}`).join(", ")}`),process.exit(1)}if(o==="connections"){let n={};if(t.name!==void 0)n.label=t.name;if(t.type!==void 0)n.providerId=t.type;else if(i==="create")n.providerId="notion";if(t.token!==void 0)n.token=t.token;return n}if(o==="flows"){let n={};if(t["source-id"]!==void 0)n.sourceId=Number(t["source-id"]);if(t["target-id"]!==void 0)n.targetId=Number(t["target-id"]);if(t["include-ref"]===!0)n.includeRef=!0;if(t["no-include-ref"]===!0)n.includeRef=!1;return n}let f={};if(t.name!==void 0)f.name=t.name;if(t["display-name"]!==void 0)f.displayName=t["display-name"];if(t["include-ref"]===!0)f.includeRef=!0;if(t["no-include-ref"]===!0)f.includeRef=!1;return f}var co=Object.fromEntries(Object.entries(w).map(([o,i])=>[i,o.toLowerCase()])),wo=Object.fromEntries(Object.entries(w).map(([o,i])=>[o.toLowerCase(),i]));function N(o){if(o===null||typeof o!=="object")return o;if(Array.isArray(o))return o.map(N);let i={};for(let[t,f]of Object.entries(o))if(t==="schema"&&f!==null&&typeof f==="object"&&!Array.isArray(f))i[t]=Object.fromEntries(Object.entries(f).map(([n,g])=>[n,typeof g==="string"?wo[g]??g:g]));else i[t]=N(f);return i}function H(o){if(o===null||typeof o!=="object")return o;if(Array.isArray(o))return o.map(H);let i={};for(let[t,f]of Object.entries(o))if(t==="schema"&&f!==null&&typeof f==="object"&&!Array.isArray(f))i[t]=Object.fromEntries(Object.entries(f).map(([n,g])=>{let r=d(g),c=co[r]??r,p=Array.isArray(g)?g[1]:void 0;return[n,p&&p.length>0?`${c}(${p.join("|")})`:c]}));else i[t]=H(f);return i}function O(o){console.log(JSON.stringify(H(o),null,2))}var po={connections:[{key:"id",header:"ID"},{key:"label",header:"Label"},{key:"providerId",header:"Provider"},{key:"accountId",header:"Account"},{key:"hasCredentials",header:"Credentials",format:(o)=>o?"yes":"no"}],collections:[{key:"id",header:"ID"},{key:"name",header:"Name"},{key:"displayName",header:"Display Name"},{key:"connectionId",header:"Connection"}],flows:[{key:"id",header:"ID"},{key:"sourceId",header:"Source"},{key:"targetId",header:"Target"},{key:"includeRef",header:"Ref",format:(o)=>o?"yes":"no"}]};function $o(o,i){if(o.length===0){console.log("(none)");return}let t=(n,g)=>n.format?n.format(g[n.key]):String(g[n.key]??""),f=i.map((n)=>Math.max(n.header.length,...o.map((g)=>t(n,g).length)));console.log(i.map((n,g)=>n.header.padEnd(f[g])).join(" ")),console.log(f.map((n)=>"-".repeat(n)).join(" "));for(let n of o)console.log(i.map((g,r)=>t(g,n).padEnd(f[r])).join(" "))}async function J(o,i){let f=await(await $(`/api/v1/${o}`)).json();if(i==="json")O(f);else $o(f,po[o])}async function W(o,i){let f=await(await $(`/api/v1/${o}/${i}`)).json();O(f)}async function X(o,i,t){let f=i?N(JSON.parse(i)):z(o,"create",t),g=await(await $(`/api/v1/${o}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(f)})).json();O(g)}async function Z(o,i,t,f){let n=t?N(JSON.parse(t)):z(o,"update",f),r=await(await $(`/api/v1/${o}/${i}`,{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify(n)})).json();O(r)}async function B(o,i){await $(`/api/v1/${o}/${i}`,{method:"DELETE"}),console.log(`Deleted ${o.slice(0,-1)} ${i}`)}function Q(){let o=Object.entries(U),i=o.filter(([,f])=>f<20).map(([f])=>f.toLowerCase()).sort(),t=o.filter(([,f])=>f>=20).map(([f])=>f.toLowerCase()).sort();if(i.length)process.stdout.write(i.join(`
2
+ import{parseArgs as Te}from"node:util";class y extends Error{status;constructor(e,n){super(n);this.status=e;this.name="ApiError"}}var m={CLIENT:0,WEB:1,NOTION:20,STRAPI:21,CONTENTFUL:22},F={[m.CLIENT]:{label:"client",editable:!0,source:!1,target:!0},[m.WEB]:{label:"web",editable:!1,source:!0,target:!1},[m.NOTION]:{label:"notion",editable:!1,source:!0,target:!1},[m.STRAPI]:{label:"strapi",editable:!1,source:!0,target:!1},[m.CONTENTFUL]:{label:"contentful",editable:!1,source:!0,target:!1}};var oe=["$id","$ref","$collection","$changedAt","$connectionType"],Qe=new Set(oe),ie=Symbol("FieldRef");function re(e){return typeof e==="object"&&e!==null&&ie in e}function U(e){if(re(e))return e.path;if(e===null)return"null";if(typeof e==="string")return`"${e}"`;if(typeof e==="boolean")return e?"true":"false";return String(e)}function C(e){return(n,o)=>`${U(n)} ${e} ${U(o)}`}var ze=C("="),Ze=C("!="),Ke=C(">"),Xe=C(">="),qe=C("<"),Ve=C("<="),en=C("~"),nn=C("!~"),tn=C("?=");var c={NULL:0,STRING:2,STRINGS:4,NUMBER:8,NUMBERS:16,BOOLEAN:32,REF:64,REFS:128,FILE:256,FILES:512,DATE:1024,ENUM:2048,ENUMS:4096};function S(e){return Array.isArray(e)?e[0]:e}function $(e){return Array.isArray(e)?e[1]:void 0}function ce(e){return e[0].toUpperCase()+e.slice(1)}function O(e,n){if(n==="lookup")return e.map((o)=>`ContfuCollections["${o}"]`).join(" | ");return e.map(ce).join(" | ")}function I(e,n,o="interface",t){switch(e){case c.STRING:return"string";case c.STRINGS:return"string[]";case c.NUMBER:return"number";case c.NUMBERS:return"number[]";case c.BOOLEAN:return"boolean";case c.REF:if(n&&n.length>0)return O(n,o);return"string";case c.REFS:if(n&&n.length>0){let i=O(n,o);return n.length>1?`(${i})[]`:`${i}[]`}return"string[]";case c.FILE:return"{ url: string; alt?: string }";case c.FILES:return"{ url: string; alt?: string }[]";case c.DATE:return"string";case c.ENUM:if(t&&t.length>0)return t.map((i)=>JSON.stringify(i)).join(" | ");return"string";case c.ENUMS:if(t&&t.length>0){let i=t.map((r)=>JSON.stringify(r)).join(" | ");return t.length>1?`(${i})[]`:`${i}[]`}return"string[]";default:return"unknown"}}function se(e,n,o,t,i){let r=[`${t}| {`];for(let[s,l]of Object.entries(e))r.push(`${t} ${s}: ${I(S(l),n?.[s],o,$(l))};`);return r.push(`${t} }${i?";":""}`),r}function le(e){let n=new Set;return e.filter((o)=>{let t=JSON.stringify(Object.entries(o).sort(([i],[r])=>i.localeCompare(r)));if(n.has(t))return!1;return n.add(t),!0})}function R(e){let n=["// Auto-generated by Contfu — do not edit",""];n.push("export type ContfuCollections = {");for(let o of e){n.push(` /** ${o.displayName} */`);let t=o.inflowSchemas?le(o.inflowSchemas):[];if(t.length>=2){n.push(` ${o.name}:`);for(let i=0;i<t.length;i++)n.push(...se(t[i],o.refTargets,"lookup"," ",i===t.length-1))}else{n.push(` ${o.name}: {`);for(let[i,r]of Object.entries(o.schema))n.push(` ${i}: ${I(S(r),o.refTargets?.[i],"lookup",$(r))};`);n.push(" };")}}return n.push("};"),n.push(""),n.join(`
3
+ `)}var En=[[c.NUMBER,c.STRING,"string"],[c.NUMBERS,c.STRINGS,"string"],[c.REF,c.STRING,"string"],[c.REFS,c.STRINGS,"string"],[c.BOOLEAN,c.STRING,"string"],[c.DATE,c.STRING,"string"],[c.STRING,c.ENUM,"enum"],[c.STRINGS,c.ENUMS,"enum"],[c.ENUM,c.STRING,"string"],[c.ENUMS,c.STRINGS,"string"]];async function de(e,n,o,t,i,r){let s={Authorization:`Bearer ${o}`};if(r!==void 0)s["Content-Type"]="application/json";let l=await e(`${n}${i}`,{method:t,headers:s,body:r!==void 0?JSON.stringify(r):void 0});if(!l.ok){let g=`HTTP ${l.status}`;try{let x=await l.text(),a=JSON.parse(x);if(a.message)g=a.message;else if(x)g=x}catch{}throw new y(l.status,g)}let p=await l.text();if(!p)return;return JSON.parse(p)}function L(e,n,o=globalThis.fetch){let t=(i,r,s)=>de(o,e,n,i,r,s);return{getStatus:()=>t("GET","/api/v1/status"),listConnections:()=>t("GET","/api/v1/connections"),getConnection:(i)=>t("GET",`/api/v1/connections/${i}`),createConnection:(i)=>t("POST","/api/v1/connections",i),updateConnection:(i,r)=>t("PATCH",`/api/v1/connections/${i}`,r),deleteConnection:(i)=>t("DELETE",`/api/v1/connections/${i}`),getConnectionTypes:(i)=>t("GET",`/api/v1/connections/${i}/types`),listCollections:()=>t("GET","/api/v1/collections"),getCollection:(i)=>t("GET",`/api/v1/collections/${i}`),createCollection:(i)=>t("POST","/api/v1/collections",i),updateCollection:(i,r)=>t("PATCH",`/api/v1/collections/${i}`,r),deleteCollection:(i)=>t("DELETE",`/api/v1/collections/${i}`),getCollectionTypes:(i)=>t("GET",`/api/v1/collections/${i}/types`),listFlows:()=>t("GET","/api/v1/flows"),getFlow:(i)=>t("GET",`/api/v1/flows/${i}`),createFlow:(i)=>t("POST","/api/v1/flows",i),updateFlow:(i,r)=>t("PATCH",`/api/v1/flows/${i}`,r),deleteFlow:(i)=>t("DELETE",`/api/v1/flows/${i}`)}}import{readFileSync as ue}from"node:fs";import{join as pe}from"node:path";import{homedir as ge}from"node:os";function me(){if(process.env.CONTFU_API_KEY)return process.env.CONTFU_API_KEY;try{let e=pe(ge(),".config","contfu","config.json");return JSON.parse(ue(e,"utf-8")).apiKey}catch{return}}function Ce(){return process.env.CONTFU_URL??"https://contfu.com"}function d(){let e=me();if(!e)console.error("No API key configured. Set CONTFU_API_KEY or create ~/.config/contfu/config.json"),process.exit(1);return L(Ce(),e)}function u(e){if(e instanceof y){if(e.status===403){let n=e.message;if(n&&n!=="Insufficient permissions")console.error(n);else console.error("Insufficient permissions. Your API key does not have the required scope for this action.");process.exit(1)}if(e.status===429)console.error("Rate limit exceeded. Please slow down and try again."),process.exit(1);console.error(`Error ${e.status}: ${e.message}`),process.exit(1)}throw e}var we=["connections","collections","flows"];function v(e){return we.includes(e)}var A={connections:["name"],collections:["display-name"],flows:["source-id","target-id"]};function ye(e){let n=A.connections.filter((r)=>e[r]===void 0);if(n.length>0)console.error(`Missing required flag(s): ${n.map((r)=>`--${r}`).join(", ")}`),process.exit(1);let o=e.type?.toLowerCase()??"notion",t=Object.entries(m).find(([r])=>r.toLowerCase()===o),i=t?t[1]:m.NOTION;return{name:e.name,type:i}}function Se(e){let n={};if(e.name!==void 0)n.name=e.name;if(e["include-ref"]===!0)n.includeRef=!0;if(e["no-include-ref"]===!0)n.includeRef=!1;return n}function xe(e){let n=A.collections.filter((t)=>e[t]===void 0);if(n.length>0)console.error(`Missing required flag(s): ${n.map((t)=>`--${t}`).join(", ")}`),process.exit(1);let o={displayName:e["display-name"]};if(e.name!==void 0)o.name=e.name;if(e["collection-id"]!==void 0)o.connectionId=Number(e["collection-id"]);if(e["include-ref"]===!0)o.includeRef=!0;if(e["no-include-ref"]===!0)o.includeRef=!1;return o}function he(e){let n={};if(e.name!==void 0)n.name=e.name;if(e["display-name"]!==void 0)n.displayName=e["display-name"];if(e["include-ref"]===!0)n.includeRef=!0;if(e["no-include-ref"]===!0)n.includeRef=!1;return n}function Re(e){let n=A.flows.filter((t)=>e[t]===void 0);if(n.length>0)console.error(`Missing required flag(s): ${n.map((t)=>`--${t}`).join(", ")}`),process.exit(1);let o={sourceId:Number(e["source-id"]),targetId:Number(e["target-id"])};if(e["include-ref"]===!0)o.includeRef=!0;if(e["no-include-ref"]===!0)o.includeRef=!1;return o}function $e(e){let n={};if(e["include-ref"]===!0)n.includeRef=!0;if(e["no-include-ref"]===!0)n.includeRef=!1;return n}var Fe=Object.fromEntries(Object.entries(c).map(([e,n])=>[n,e.toLowerCase()])),Ee=Object.fromEntries(Object.entries(c).map(([e,n])=>[e.toLowerCase(),n]));function w(e){if(e===null||typeof e!=="object")return e;if(Array.isArray(e))return e.map(w);let n={};for(let[o,t]of Object.entries(e))if(o==="schema"&&t!==null&&typeof t==="object"&&!Array.isArray(t))n[o]=Object.fromEntries(Object.entries(t).map(([i,r])=>[i,typeof r==="string"?Ee[r]??r:r]));else n[o]=w(t);return n}function _(e){return Object.fromEntries(Object.entries(e).map(([n,o])=>{let t=S(o),i=Fe[t]??String(t),r=Array.isArray(o)?o[1]:void 0;return[n,r&&r.length>0?`${i}(${r.join("|")})`:i]}))}function f(e){console.log(JSON.stringify(e,null,2))}var Ae=[{key:"id",header:"ID"},{key:"name",header:"Name"},{key:"type",header:"Type",format:(e)=>F[e]?.label??String(e)},{key:"accountId",header:"Account",format:(e)=>e??""},{key:"hasCredentials",header:"Credentials",format:(e)=>e?"yes":"no"}],Be=[{key:"id",header:"ID"},{key:"name",header:"Name"},{key:"displayName",header:"Display Name"},{key:"connectionId",header:"Connection",format:(e)=>e==null?"":String(e)}],be=[{key:"id",header:"ID"},{key:"sourceId",header:"Source"},{key:"targetId",header:"Target"},{key:"includeRef",header:"Ref",format:(e)=>e?"yes":"no"}];function E(e,n){if(e.length===0){console.log("(none)");return}let o=(i,r)=>i.format?i.format(r[i.key]):String(r[i.key]??""),t=n.map((i)=>Math.max(i.header.length,...e.map((r)=>o(i,r).length)));console.log(n.map((i,r)=>i.header.padEnd(t[r])).join(" ")),console.log(t.map((i)=>"-".repeat(i)).join(" "));for(let i of e)console.log(n.map((r,s)=>o(r,i).padEnd(t[s])).join(" "))}async function j(e,n){let o=d();try{if(e==="connections"){let t=await o.listConnections();if(n==="json")f(t);else E(t,Ae)}else if(e==="collections"){let t=await o.listCollections();if(n==="json")f(t.map((i)=>({...i,schema:i.schema?_(i.schema):null})));else E(t,Be)}else{let t=await o.listFlows();if(n==="json")f(t);else E(t,be)}}catch(t){u(t)}}async function G(e,n){let o=d();try{if(e==="connections")f(await o.getConnection(n));else if(e==="collections"){let t=await o.getCollection(n);f({...t,schema:t.schema?_(t.schema):null})}else f(await o.getFlow(n))}catch(t){u(t)}}async function T(e,n,o){let t=d();try{if(e==="connections"){let i=n?w(JSON.parse(n)):ye(o);f(await t.createConnection(i))}else if(e==="collections"){let i=n?w(JSON.parse(n)):xe(o);f(await t.createCollection(i))}else{let i=n?w(JSON.parse(n)):Re(o);f(await t.createFlow(i))}}catch(i){u(i)}}async function P(e,n,o,t){let i=d();try{if(e==="connections"){let r=o?w(JSON.parse(o)):Se(t);f(await i.updateConnection(n,r))}else if(e==="collections"){let r=o?w(JSON.parse(o)):he(t);f(await i.updateCollection(n,r))}else{let r=o?w(JSON.parse(o)):$e(t);f(await i.updateFlow(n,r))}}catch(r){u(r)}}async function J(e,n){let o=d();try{if(e==="connections")await o.deleteConnection(n);else if(e==="collections")await o.deleteCollection(n);else await o.deleteFlow(n);console.log(`Deleted ${e.slice(0,-1)} ${n}`)}catch(t){u(t)}}function M(){let e=Object.entries(m),n=e.filter(([,t])=>t<20).map(([t])=>t.toLowerCase()).sort(),o=e.filter(([,t])=>t>=20).map(([t])=>t.toLowerCase()).sort();if(n.length)process.stdout.write(n.join(`
4
4
  `)+`
5
- `);if(i.length&&t.length)process.stdout.write(`
6
- `);if(t.length)process.stdout.write(t.join(`
5
+ `);if(n.length&&o.length)process.stdout.write(`
6
+ `);if(o.length)process.stdout.write(o.join(`
7
7
  `)+`
8
- `)}async function h(o){let t=await(await $(`/api/v1/connections/${o}/types`)).json();if(t.length===0)console.error("No collections connected to this connection"),process.exit(1);process.stdout.write(S(t))}async function q(o){let t=await(await $(`/api/v1/collections/${o}/types`)).json();if(t.length===0)console.error("No types found for this collection"),process.exit(1);process.stdout.write(S(t))}import{parseArgs as _}from"node:util";async function A(o,i){let t=`${o}${i}`,f=await fetch(t);if(!f.ok){let n=await f.text();console.error(`Error ${f.status}: ${n}`),process.exit(1)}return f}function Y(o){let i=Object.entries(o).filter((t)=>t[1]!==void 0&&t[1]!=="");if(i.length===0)return"";return"?"+new URLSearchParams(i).toString()}async function M(o){let{values:i}=_({args:o,options:{"client-url":{type:"string",short:"u"},collection:{type:"string"},filter:{type:"string"},sort:{type:"string"},limit:{type:"string",default:"20"},offset:{type:"string",default:"0"},include:{type:"string"},fields:{type:"string"},flat:{type:"boolean",default:!1}},allowPositionals:!0}),t=i["client-url"];if(!t)console.error("Missing required --client-url flag"),process.exit(1);let f=i.collection?`/api/collections/${i.collection}/items`:"/api/items",n=Y({filter:i.filter,sort:i.sort,limit:i.limit,offset:i.offset,include:i.include,fields:i.fields,flat:i.flat?"true":void 0}),r=await(await A(t,`${f}${n}`)).json();console.log(JSON.stringify(r,null,2))}async function F(o){let{values:i}=_({args:o,options:{"client-url":{type:"string",short:"u"},collection:{type:"string"},filter:{type:"string"}},allowPositionals:!0}),t=i["client-url"];if(!t)console.error("Missing required --client-url flag"),process.exit(1);let f=i.collection?`/api/collections/${i.collection}/items`:"/api/items",n=Y({filter:i.filter,limit:"0"}),r=await(await A(t,`${f}${n}`)).json();console.log(r?.meta?.total??0)}import{createServer as E}from"node:http";import{randomBytes as mo}from"node:crypto";import{promises as s}from"node:fs";import{join as D}from"node:path";import{homedir as j}from"node:os";import{spawn as xo}from"node:child_process";var T=D(j(),".config","contfu","config.json");function Co(){return process.env.CONTFU_URL??"https://contfu.com"}async function No(o){let i=process.platform,[t,f]=i==="darwin"?["open",[o]]:i==="win32"?["cmd",["/c","start","",o]]:["xdg-open",[o]];await new Promise((n,g)=>{let r=xo(t,f,{stdio:"ignore",detached:!0});r.on("error",g),r.on("close",(c)=>c===0?n():g(Error(`exit ${c}`)))})}function Oo(){return new Promise((o,i)=>{let t=E();t.listen(0,"127.0.0.1",()=>{let f=t.address();t.close((n)=>{if(n)i(n);else o(f.port)})})})}function So(){return!!(process.env.SSH_CONNECTION||process.env.SSH_CLIENT||process.env.SSH_TTY)}async function Ho(o){let i=await Oo(),t=mo(16).toString("hex"),f=`http://localhost:${i}/callback`,n=`${o}/auth/cli?callback=${encodeURIComponent(f)}&state=${encodeURIComponent(t)}`,g=new Promise((r,c)=>{let p=setTimeout(()=>{x.close(),c(Error("Login timed out after 5 minutes"))},300000),x=E((l,m)=>{try{let C=new URL(l.url??"/",`http://localhost:${i}`);if(C.pathname!=="/callback"){m.writeHead(404),m.end("Not found");return}let I=C.searchParams.get("token");if(C.searchParams.get("state")!==t){m.writeHead(400),m.end("State mismatch"),clearTimeout(p),x.close(),c(Error("State mismatch — possible CSRF"));return}if(!I){m.writeHead(400),m.end("No token received"),clearTimeout(p),x.close(),c(Error("No token in callback"));return}m.writeHead(302,{Location:`${o}/auth/cli/success`}),m.end(),clearTimeout(p),x.close(),r(I)}catch(C){m.writeHead(500),m.end("Internal error"),clearTimeout(p),x.close(),c(C)}});x.listen(i,"127.0.0.1")});console.log(`Opening browser to ${n}`);try{await No(n)}catch{console.log(`Could not open browser automatically. Please visit:
9
- ${n}`)}return g}async function so(o){let i=`${o}/auth/cli?mode=code`;console.log(`Open this URL in your browser:
8
+ `)}async function k(e){let n=d(),o;try{o=await n.getConnectionTypes(e)}catch(t){u(t)}if(o.length===0)console.error("No collections connected to this connection"),process.exit(1);process.stdout.write(R(o))}async function H(e){let n=d(),o;try{o=await n.getCollectionTypes(e)}catch(t){u(t)}if(o.length===0)console.error("No types found for this collection"),process.exit(1);process.stdout.write(R(o))}import{parseArgs as W}from"node:util";async function Y(e,n){let o=`${e}${n}`,t=await fetch(o);if(!t.ok){let i=await t.text();console.error(`Error ${t.status}: ${i}`),process.exit(1)}return t}function D(e){let n=Object.entries(e).filter((o)=>o[1]!==void 0&&o[1]!=="");if(n.length===0)return"";return"?"+new URLSearchParams(n).toString()}async function Q(e){let{values:n}=W({args:e,options:{"client-url":{type:"string",short:"u"},collection:{type:"string"},filter:{type:"string"},sort:{type:"string"},limit:{type:"string",default:"20"},offset:{type:"string",default:"0"},include:{type:"string"},fields:{type:"string"},flat:{type:"boolean",default:!1}},allowPositionals:!0}),o=n["client-url"];if(!o)console.error("Missing required --client-url flag"),process.exit(1);let t=n.collection?`/api/collections/${n.collection}/items`:"/api/items",i=D({filter:n.filter,sort:n.sort,limit:n.limit,offset:n.offset,include:n.include,fields:n.fields,flat:n.flat?"true":void 0}),s=await(await Y(o,`${t}${i}`)).json();console.log(JSON.stringify(s,null,2))}async function z(e){let{values:n}=W({args:e,options:{"client-url":{type:"string",short:"u"},collection:{type:"string"},filter:{type:"string"}},allowPositionals:!0}),o=n["client-url"];if(!o)console.error("Missing required --client-url flag"),process.exit(1);let t=n.collection?`/api/collections/${n.collection}/items`:"/api/items",i=D({filter:n.filter,limit:"0"}),s=await(await Y(o,`${t}${i}`)).json();console.log(s?.meta?.total??0)}import{createServer as Z}from"node:http";import{randomBytes as Ne}from"node:crypto";import{promises as B}from"node:fs";import{join as K}from"node:path";import{homedir as X}from"node:os";import{spawn as Ue}from"node:child_process";var q=K(X(),".config","contfu","config.json");function Oe(){return process.env.CONTFU_URL??"https://contfu.com"}async function Ie(e){let n=process.platform,[o,t]=n==="darwin"?["open",[e]]:n==="win32"?["cmd",["/c","start","",e]]:["xdg-open",[e]];await new Promise((i,r)=>{let s=Ue(o,t,{stdio:"ignore",detached:!0});s.on("error",r),s.on("close",(l)=>l===0?i():r(Error(`exit ${l}`)))})}function Le(){return new Promise((e,n)=>{let o=Z();o.listen(0,"127.0.0.1",()=>{let t=o.address();o.close((i)=>{if(i)n(i);else e(t.port)})})})}function ve(){return!!(process.env.SSH_CONNECTION||process.env.SSH_CLIENT||process.env.SSH_TTY)}async function _e(e){let n=await Le(),o=Ne(16).toString("hex"),t=`http://localhost:${n}/callback`,i=`${e}/auth/cli?callback=${encodeURIComponent(t)}&state=${encodeURIComponent(o)}`,r=new Promise((s,l)=>{let p=setTimeout(()=>{g.close(),l(Error("Login timed out after 5 minutes"))},300000),g=Z((x,a)=>{try{let h=new URL(x.url??"/",`http://localhost:${n}`);if(h.pathname!=="/callback"){a.writeHead(404),a.end("Not found");return}let N=h.searchParams.get("token");if(h.searchParams.get("state")!==o){a.writeHead(400),a.end("State mismatch"),clearTimeout(p),g.close(),l(Error("State mismatch — possible CSRF"));return}if(!N){a.writeHead(400),a.end("No token received"),clearTimeout(p),g.close(),l(Error("No token in callback"));return}a.writeHead(302,{Location:`${e}/auth/cli/success`}),a.end(),clearTimeout(p),g.close(),s(N)}catch(h){a.writeHead(500),a.end("Internal error"),clearTimeout(p),g.close(),l(h)}});g.listen(n,"127.0.0.1")});console.log(`Opening browser to ${i}`);try{await Ie(i)}catch{console.log(`Could not open browser automatically. Please visit:
9
+ ${i}`)}return r}async function je(e){let n=`${e}/auth/cli?mode=code`;console.log(`Open this URL in your browser:
10
10
 
11
- ${i}
12
- `),process.stdout.write("Paste the code from the browser: ");let t=await new Promise((g)=>{process.stdin.resume(),process.stdin.setEncoding("utf-8");let r="";process.stdin.on("data",(c)=>{r+=c;let p=r.split(`
13
- `)[0].trim();if(p)process.stdin.pause(),g(p)})}),f=await fetch(`${o}/auth/cli/exchange?code=${encodeURIComponent(t)}`);if(!f.ok)throw Error(`Invalid or expired code (${f.status})`);let{token:n}=await f.json();return n}async function V(o={}){let i=Co(),f=o.noBrowser||So()?await so(i):await Ho(i);await a({apiKey:f,baseUrl:i}),console.log("Logged in successfully")}async function y(){try{let o=await Go();delete o.apiKey,await a(o),console.log("Logged out")}catch{console.log("Logged out (no config found)")}}async function Go(){try{let o=await s.readFile(T,"utf-8");return JSON.parse(o)}catch{return{}}}async function a(o){let i=D(j(),".config","contfu");await s.mkdir(i,{recursive:!0}),await s.writeFile(T,JSON.stringify(o,null,2)+`
14
- `,"utf-8")}async function k(o="table"){let t=await(await $("/api/v1/status")).json();if(o==="json"){console.log(JSON.stringify(t,null,2));return}console.log("contfu status"),console.log("-------------"),console.log(`connections ${t.connections}`),console.log(`collections ${t.collections}`),console.log(`flows ${t.flows}`)}function G(){console.error(`Usage: contfu [--help] <command> [args...]
11
+ ${n}
12
+ `),process.stdout.write("Paste the code from the browser: ");let o=await new Promise((r)=>{process.stdin.resume(),process.stdin.setEncoding("utf-8");let s="";process.stdin.on("data",(l)=>{s+=l;let p=s.split(`
13
+ `)[0].trim();if(p)process.stdin.pause(),r(p)})}),t=await fetch(`${e}/auth/cli/exchange?code=${encodeURIComponent(o)}`);if(!t.ok)throw Error(`Invalid or expired code (${t.status})`);let{token:i}=await t.json();return i}async function V(e={}){let n=Oe(),t=e.noBrowser||ve()?await je(n):await _e(n);await ne({apiKey:t,baseUrl:n}),console.log("Logged in successfully")}async function ee(){try{let e=await Ge();delete e.apiKey,await ne(e),console.log("Logged out")}catch{console.log("Logged out (no config found)")}}async function Ge(){try{let e=await B.readFile(q,"utf-8");return JSON.parse(e)}catch{return{}}}async function ne(e){let n=K(X(),".config","contfu");await B.mkdir(n,{recursive:!0}),await B.writeFile(q,JSON.stringify(e,null,2)+`
14
+ `,"utf-8")}async function te(e="table"){let n=d(),o;try{o=await n.getStatus()}catch(t){u(t)}if(e==="json"){console.log(JSON.stringify(o,null,2));return}console.log("contfu status"),console.log("-------------"),console.log(`connections ${o.connections}`),console.log(`collections ${o.collections}`),console.log(`flows ${o.flows}`)}function b(){console.error(`Usage: contfu [--help] <command> [args...]
15
15
 
16
16
  Commands:
17
17
  login [--no-browser] Authenticate
@@ -63,4 +63,4 @@ list options:
63
63
  -f, --format <fmt> Output format: table (default) | json
64
64
 
65
65
  Environment:
66
- CONTFU_API_KEY API key (overrides stored config)`)}async function Uo(){let{values:o,positionals:i}=Io({args:process.argv.slice(2),options:{help:{type:"boolean",short:"h"},data:{type:"string",short:"d"},"no-browser":{type:"boolean"},name:{type:"string",short:"n"},type:{type:"string",short:"t"},url:{type:"string"},"display-name":{type:"string"},"source-id":{type:"string"},"target-id":{type:"string"},"collection-id":{type:"string"},"include-ref":{type:"boolean"},"no-include-ref":{type:"boolean"},token:{type:"string"},format:{type:"string",short:"f"}},allowPositionals:!0,strict:!1}),t=i[0];if(o.help)G(),process.exit(0);if(!t)G(),process.exit(1);if(t==="login"){await V({noBrowser:o["no-browser"]});return}if(t==="logout"){await y();return}if(t==="status"){await k(o.format??"table");return}if(t==="items"){let f=i[1],n=process.argv.slice(process.argv.indexOf("items")+2);switch(f){case"query":case void 0:await M(n);return;case"count":await F(n);return;default:console.error(`Unknown items action: ${f}. Use query or count`),process.exit(1)}}if(K(t)){let f=i[1],n=i[2];if(f==="types"){if(t==="connections"){if(!n)Q();else await h(n);return}if(t==="collections"){if(!n)console.error("Missing id"),process.exit(1);await q(n);return}console.error(`'types' is not available for ${t}`),process.exit(1)}let g={name:o.name,type:o.type,url:o.url,"display-name":o["display-name"],"source-id":o["source-id"],"target-id":o["target-id"],"collection-id":o["collection-id"],"include-ref":o["include-ref"],"no-include-ref":o["no-include-ref"],token:o.token};switch(f){case"list":case void 0:await J(t,o.format??"table");return;case"get":if(!n)console.error("Missing id"),process.exit(1);await W(t,n);return;case"create":await X(t,o.data,g);return;case"update":case"set":if(!n)console.error("Missing id"),process.exit(1);await Z(t,n,o.data,g);return;case"delete":if(!n)console.error("Missing id"),process.exit(1);await B(t,n);return;default:console.error(`Unknown action: ${f}. Use list, get, create, update, or delete`),process.exit(1)}}console.error(`Unknown command: ${t}`),G(),process.exit(1)}Uo();
66
+ CONTFU_API_KEY API key (overrides stored config)`)}async function Pe(){let{values:e,positionals:n}=Te({args:process.argv.slice(2),options:{help:{type:"boolean",short:"h"},data:{type:"string",short:"d"},"no-browser":{type:"boolean"},name:{type:"string",short:"n"},type:{type:"string",short:"t"},url:{type:"string"},"display-name":{type:"string"},"source-id":{type:"string"},"target-id":{type:"string"},"collection-id":{type:"string"},"include-ref":{type:"boolean"},"no-include-ref":{type:"boolean"},token:{type:"string"},format:{type:"string",short:"f"}},allowPositionals:!0,strict:!1}),o=n[0];if(e.help)b(),process.exit(0);if(!o)b(),process.exit(1);if(o==="login"){await V({noBrowser:e["no-browser"]});return}if(o==="logout"){await ee();return}if(o==="status"){await te(e.format??"table");return}if(o==="items"){let t=n[1],i=process.argv.slice(process.argv.indexOf("items")+2);switch(t){case"query":case void 0:await Q(i);return;case"count":await z(i);return;default:console.error(`Unknown items action: ${t}. Use query or count`),process.exit(1)}}if(v(o)){let t=n[1],i=n[2];if(t==="types"){if(o==="connections"){if(!i)M();else await k(i);return}if(o==="collections"){if(!i)console.error("Missing id"),process.exit(1);await H(i);return}console.error(`'types' is not available for ${o}`),process.exit(1)}let r={name:e.name,type:e.type,url:e.url,"display-name":e["display-name"],"source-id":e["source-id"],"target-id":e["target-id"],"collection-id":e["collection-id"],"include-ref":e["include-ref"],"no-include-ref":e["no-include-ref"],token:e.token};switch(t){case"list":case void 0:await j(o,e.format??"table");return;case"get":if(!i)console.error("Missing id"),process.exit(1);await G(o,i);return;case"create":await T(o,e.data,r);return;case"update":case"set":if(!i)console.error("Missing id"),process.exit(1);await P(o,i,e.data,r);return;case"delete":if(!i)console.error("Missing id"),process.exit(1);await J(o,i);return;default:console.error(`Unknown action: ${t}. Use list, get, create, update, or delete`),process.exit(1)}}console.error(`Unknown command: ${o}`),b(),process.exit(1)}Pe();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contfu/cli",
3
- "version": "0.0.2",
3
+ "version": "0.0.4",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -21,6 +21,6 @@
21
21
  "test:e2e": "bun test e2e/"
22
22
  },
23
23
  "dependencies": {
24
- "@contfu/core": "0.0.2"
24
+ "@contfu/svc-api": "0.0.1"
25
25
  }
26
26
  }