New:Socket for Asana Is Now Available.Learn more
Get Started

frihet

Package Overview
Dependencies
Maintainers
1
Versions
7
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

frihet - npm Package Compare versions

Comparing version
1.0.0
to
1.0.1
+21
LICENSE
MIT License
Copyright (c) 2026 Frihet
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+602
-11
#!/usr/bin/env node
// src/index.ts
import { Command as Command6 } from "commander";
import { Command as Command10 } from "commander";

@@ -95,2 +95,8 @@ // src/commands/login.ts

}
function outputJson(data) {
console.log(JSON.stringify(data, null, 2));
}
function shouldOutputJson() {
return process.argv.includes("--json");
}

@@ -158,3 +164,3 @@ // src/commands/login.ts

}
var list = new Command2("list").description("List invoices").option("--status <status>", "Filter: draft, sent, paid, overdue, cancelled").option("--limit <n>", "Max results", "20").option("--from <date>", "From date (YYYY-MM-DD)").option("--to <date>", "To date (YYYY-MM-DD)").option("-q, --search <query>", "Search by client name or document number").action(async (opts) => {
var list = new Command2("list").description("List invoices").option("--status <status>", "Filter: draft, sent, paid, overdue, cancelled").option("--limit <n>", "Max results", "20").option("--from <date>", "From date (YYYY-MM-DD)").option("--to <date>", "To date (YYYY-MM-DD)").option("-q, --search <query>", "Search by client name or document number").option("--json", "Output as JSON").action(async (opts) => {
try {

@@ -170,2 +176,6 @@ const f = client();

const page = opts.search ? await f.invoices.search(opts.search, params) : await f.invoices.list(params);
if (shouldOutputJson()) {
outputJson(page);
return;
}
if (page.data.length === 0) {

@@ -190,5 +200,9 @@ console.log(dim("No invoices found."));

});
var get = new Command2("get").description("Get invoice details").argument("<id>", "Invoice ID or document number").action(async (id) => {
var get = new Command2("get").description("Get invoice details").argument("<id>", "Invoice ID or document number").option("--json", "Output as JSON").action(async (id) => {
try {
const inv = await client().invoices.retrieve(id);
if (shouldOutputJson()) {
outputJson(inv);
return;
}
console.log(bold(inv.documentNumber ?? inv.id));

@@ -247,2 +261,27 @@ console.log(`Client: ${inv.clientName}`);

});
var update = new Command2("update").description("Update an invoice").argument("<id>", "Invoice ID").option("--client <name>", "Client name").option("--status <status>", "Status: draft, sent, paid, overdue, cancelled").option("--due <date>", "Due date (YYYY-MM-DD)").option("--notes <text>", "Invoice notes").option("--tax <rate>", "Tax rate").option("--irpf <rate>", "IRPF rate").action(async (id, opts) => {
try {
const params = {};
if (opts.client !== void 0) params.clientName = opts.client;
if (opts.status !== void 0) params.status = opts.status;
if (opts.due !== void 0) params.dueDate = opts.due;
if (opts.notes !== void 0) params.notes = opts.notes;
if (opts.tax !== void 0) params.taxRate = parseFloat(opts.tax);
if (opts.irpf !== void 0) params.irpfRate = parseFloat(opts.irpf);
const inv = await client().invoices.update(id, params);
success(`Invoice ${bold(inv.documentNumber ?? inv.id)} updated`);
} catch (err) {
error(err instanceof Error ? err.message : String(err));
process.exit(1);
}
});
var del = new Command2("delete").description("Delete an invoice").argument("<id>", "Invoice ID").action(async (id) => {
try {
await client().invoices.del(id);
success(`Invoice ${bold(id)} deleted`);
} catch (err) {
error(err instanceof Error ? err.message : String(err));
process.exit(1);
}
});
var markPaid = new Command2("paid").description("Mark invoice as paid").argument("<id>", "Invoice ID").option("--date <date>", "Payment date (YYYY-MM-DD, defaults to today)").action(async (id, opts) => {

@@ -269,3 +308,15 @@ try {

});
var invoicesCommand = new Command2("invoices").description("Manage invoices").addCommand(list).addCommand(get).addCommand(create).addCommand(markPaid).addCommand(send);
var pdf = new Command2("pdf").description("Download invoice as PDF").argument("<id>", "Invoice ID").option("-o, --output <path>", "Output file path").action(async (id, opts) => {
try {
const { writeFileSync: writeFileSync2 } = await import("fs");
const buffer = await client().invoices.pdf(id);
const outPath = opts.output ?? `invoice-${id}.pdf`;
writeFileSync2(outPath, Buffer.from(buffer));
success(`PDF saved to ${bold(outPath)}`);
} catch (err) {
error(err instanceof Error ? err.message : String(err));
process.exit(1);
}
});
var invoicesCommand = new Command2("invoices").description("Manage invoices").addCommand(list).addCommand(get).addCommand(create).addCommand(update).addCommand(del).addCommand(markPaid).addCommand(send).addCommand(pdf);

@@ -278,3 +329,3 @@ // src/commands/expenses.ts

}
var list2 = new Command3("list").description("List expenses").option("--limit <n>", "Max results", "20").option("--from <date>", "From date (YYYY-MM-DD)").option("--to <date>", "To date (YYYY-MM-DD)").option("-q, --search <query>", "Search expenses").action(async (opts) => {
var list2 = new Command3("list").description("List expenses").option("--limit <n>", "Max results", "20").option("--from <date>", "From date (YYYY-MM-DD)").option("--to <date>", "To date (YYYY-MM-DD)").option("-q, --search <query>", "Search expenses").option("--json", "Output as JSON").action(async (opts) => {
try {

@@ -284,2 +335,6 @@ const f = client2();

const page = opts.search ? await f.expenses.search(opts.search, params) : await f.expenses.list(params);
if (shouldOutputJson()) {
outputJson(page);
return;
}
if (page.data.length === 0) {

@@ -306,2 +361,25 @@ console.log(dim("No expenses found."));

});
var get2 = new Command3("get").description("Get expense details").argument("<id>", "Expense ID").option("--json", "Output as JSON").action(async (id) => {
try {
const exp = await client2().expenses.retrieve(id);
if (shouldOutputJson()) {
outputJson(exp);
return;
}
console.log(bold(exp.description));
console.log(`ID: ${dim(exp.id)}`);
console.log(`Amount: ${eur(exp.amount)}`);
console.log(`Category: ${exp.category ?? dim("--")}`);
console.log(`Date: ${exp.date ?? dim("--")}`);
console.log(`Vendor: ${exp.vendor ?? dim("--")}`);
if (exp.invoiceNumber) console.log(`Invoice#: ${exp.invoiceNumber}`);
if (exp.tax !== void 0) console.log(`Tax: ${eur(exp.tax)}`);
if (exp.taxType) console.log(`Tax Type: ${exp.taxType}`);
if (exp.irpf !== void 0) console.log(`IRPF: ${eur(exp.irpf)}`);
if (exp.taxDeductible !== void 0) console.log(`Deductible: ${exp.taxDeductible ? "yes" : "no"}`);
} catch (err) {
error(err instanceof Error ? err.message : String(err));
process.exit(1);
}
});
var create2 = new Command3("create").description("Create a new expense").requiredOption("--desc <description>", "Description").requiredOption("--amount <amount>", "Amount in EUR").option("--category <cat>", "Category (office, travel, software, marketing, professional, equipment, insurance, other)").option("--vendor <name>", "Vendor name").option("--date <date>", "Date (YYYY-MM-DD)").option("--tax <rate>", "Tax amount").action(async (opts) => {

@@ -323,3 +401,31 @@ try {

});
var expensesCommand = new Command3("expenses").description("Manage expenses").addCommand(list2).addCommand(create2);
var update2 = new Command3("update").description("Update an expense").argument("<id>", "Expense ID").option("--desc <description>", "Description").option("--amount <amount>", "Amount in EUR").option("--category <cat>", "Category").option("--vendor <name>", "Vendor name").option("--date <date>", "Date (YYYY-MM-DD)").option("--tax <rate>", "Tax amount").option("--tax-type <type>", "Tax type: IVA, IGIC, IPSI, Exento").option("--irpf <amount>", "IRPF amount").option("--deductible <bool>", "Tax deductible (true/false)").action(async (id, opts) => {
try {
const params = {};
if (opts.desc !== void 0) params.description = opts.desc;
if (opts.amount !== void 0) params.amount = parseFloat(opts.amount);
if (opts.category !== void 0) params.category = opts.category;
if (opts.vendor !== void 0) params.vendor = opts.vendor;
if (opts.date !== void 0) params.date = opts.date;
if (opts.tax !== void 0) params.tax = parseFloat(opts.tax);
if (opts.taxType !== void 0) params.taxType = opts.taxType;
if (opts.irpf !== void 0) params.irpf = parseFloat(opts.irpf);
if (opts.deductible !== void 0) params.taxDeductible = opts.deductible === "true";
const exp = await client2().expenses.update(id, params);
success(`Expense ${bold(exp.id.slice(0, 8))} updated: ${exp.description}`);
} catch (err) {
error(err instanceof Error ? err.message : String(err));
process.exit(1);
}
});
var del2 = new Command3("delete").description("Delete an expense").argument("<id>", "Expense ID").action(async (id) => {
try {
await client2().expenses.del(id);
success(`Expense ${bold(id)} deleted`);
} catch (err) {
error(err instanceof Error ? err.message : String(err));
process.exit(1);
}
});
var expensesCommand = new Command3("expenses").description("Manage expenses").addCommand(list2).addCommand(get2).addCommand(create2).addCommand(update2).addCommand(del2);

@@ -332,3 +438,3 @@ // src/commands/clients.ts

}
var list3 = new Command4("list").description("List clients").option("--limit <n>", "Max results", "20").option("-q, --search <query>", "Search clients").action(async (opts) => {
var list3 = new Command4("list").description("List clients").option("--limit <n>", "Max results", "20").option("-q, --search <query>", "Search clients").option("--json", "Output as JSON").action(async (opts) => {
try {

@@ -338,2 +444,6 @@ const f = client3();

const page = opts.search ? await f.clients.search(opts.search, params) : await f.clients.list(params);
if (shouldOutputJson()) {
outputJson(page);
return;
}
if (page.data.length === 0) {

@@ -377,8 +487,480 @@ console.log(dim("No clients found."));

// src/commands/status.ts
// src/commands/quotes.ts
import { Command as Command5 } from "commander";
import { Frihet as Frihet5 } from "@frihet/sdk";
var statusCommand = new Command5("status").description("Quick business health check").option("--month <month>", "Month (YYYY-MM, defaults to current)").action(async (opts) => {
function client4() {
return new Frihet5({ apiKey: getApiKey(), baseUrl: getBaseUrl() });
}
function statusColor2(status) {
switch (status) {
case "accepted":
return green(status);
case "sent":
return yellow(status);
case "rejected":
return red(status);
case "expired":
return red(status);
case "draft":
return dim(status);
case "cancelled":
return dim(status);
default:
return status ?? dim("--");
}
}
var list4 = new Command5("list").description("List quotes").option("--status <status>", "Filter: draft, sent, accepted, rejected, expired, cancelled").option("--limit <n>", "Max results", "20").option("--from <date>", "From date (YYYY-MM-DD)").option("--to <date>", "To date (YYYY-MM-DD)").option("-q, --search <query>", "Search by client name or document number").option("--json", "Output as JSON").action(async (opts) => {
try {
const f = new Frihet5({ apiKey: getApiKey(), baseUrl: getBaseUrl() });
const f = client4();
const params = {
limit: parseInt(opts.limit),
status: opts.status,
from: opts.from,
to: opts.to,
q: opts.search
};
const page = opts.search ? await f.quotes.search(opts.search, params) : await f.quotes.list(params);
if (shouldOutputJson()) {
outputJson(page);
return;
}
if (page.data.length === 0) {
console.log(dim("No quotes found."));
return;
}
const rows = page.data.map((q) => [
q.documentNumber ?? q.id.slice(0, 8),
q.clientName,
eur(q.total),
statusColor2(q.status),
q.validUntil ?? dim("--")
]);
table(rows, ["Number", "Client", "Amount", "Status", "Valid Until"]);
console.log(dim(`
${page.total} total, showing ${page.data.length}`));
} catch (err) {
error(err instanceof Error ? err.message : String(err));
process.exit(1);
}
});
var get3 = new Command5("get").description("Get quote details").argument("<id>", "Quote ID or document number").option("--json", "Output as JSON").action(async (id) => {
try {
const q = await client4().quotes.retrieve(id);
if (shouldOutputJson()) {
outputJson(q);
return;
}
console.log(bold(q.documentNumber ?? q.id));
console.log(`Client: ${q.clientName}`);
console.log(`Status: ${statusColor2(q.status)}`);
console.log(`Amount: ${eur(q.total)}`);
console.log(`Valid Until: ${q.validUntil ?? dim("--")}`);
if (q.notes) console.log(`Notes: ${q.notes}`);
if (q.items?.length) {
console.log(dim("\nItems:"));
table(
q.items.map((item) => [
item.description,
String(item.quantity),
eur(item.unitPrice),
eur(item.quantity * item.unitPrice)
]),
["Description", "Qty", "Price", "Subtotal"]
);
}
} catch (err) {
error(err instanceof Error ? err.message : String(err));
process.exit(1);
}
});
var create4 = new Command5("create").description("Create a new quote").requiredOption("--client <name>", "Client name").requiredOption("--item <items...>", 'Items as "description,qty,price" (repeatable)').option("--valid-until <date>", "Valid until date (YYYY-MM-DD)").option("--tax <rate>", "Tax rate (e.g. 21)").option("--notes <text>", "Quote notes").option("--send <email>", "Send immediately to this email").action(async (opts) => {
try {
const items = opts.item.map((raw) => {
const parts = raw.split(",");
if (parts.length < 3) throw new Error(`Invalid item format: "${raw}". Use "description,qty,price"`);
return {
description: parts[0].trim(),
quantity: parseFloat(parts[1]),
unitPrice: parseFloat(parts[2])
};
});
const f = client4();
const q = await f.quotes.create({
clientName: opts.client,
items,
validUntil: opts.validUntil,
taxRate: opts.tax ? parseFloat(opts.tax) : void 0,
notes: opts.notes
});
success(`Quote ${bold(q.documentNumber ?? q.id)} created (${eur(q.total)})`);
if (opts.send) {
await f.quotes.send(q.id, { recipientEmail: opts.send });
success(`Sent to ${opts.send}`);
}
} catch (err) {
error(err instanceof Error ? err.message : String(err));
process.exit(1);
}
});
var update3 = new Command5("update").description("Update a quote").argument("<id>", "Quote ID").option("--client <name>", "Client name").option("--valid-until <date>", "Valid until date (YYYY-MM-DD)").option("--tax <rate>", "Tax rate").option("--notes <text>", "Notes").option("--status <status>", "Status: draft, sent, accepted, rejected, expired, cancelled").action(async (id, opts) => {
try {
const params = {};
if (opts.client !== void 0) params.clientName = opts.client;
if (opts.validUntil !== void 0) params.validUntil = opts.validUntil;
if (opts.tax !== void 0) params.taxRate = parseFloat(opts.tax);
if (opts.notes !== void 0) params.notes = opts.notes;
if (opts.status !== void 0) params.status = opts.status;
const q = await client4().quotes.update(id, params);
success(`Quote ${bold(q.documentNumber ?? q.id)} updated`);
} catch (err) {
error(err instanceof Error ? err.message : String(err));
process.exit(1);
}
});
var del3 = new Command5("delete").description("Delete a quote").argument("<id>", "Quote ID").action(async (id) => {
try {
await client4().quotes.del(id);
success(`Quote ${bold(id)} deleted`);
} catch (err) {
error(err instanceof Error ? err.message : String(err));
process.exit(1);
}
});
var pdf2 = new Command5("pdf").description("Download quote as PDF").argument("<id>", "Quote ID").option("-o, --output <path>", "Output file path").action(async (id, opts) => {
try {
const { writeFileSync: writeFileSync2 } = await import("fs");
const buffer = await client4().quotes.pdf(id);
const outPath = opts.output ?? `quote-${id}.pdf`;
writeFileSync2(outPath, Buffer.from(buffer));
success(`PDF saved to ${bold(outPath)}`);
} catch (err) {
error(err instanceof Error ? err.message : String(err));
process.exit(1);
}
});
var send2 = new Command5("send").description("Send quote by email").argument("<id>", "Quote ID").requiredOption("--to <email>", "Recipient email").option("--message <text>", "Custom message").action(async (id, opts) => {
try {
const result = await client4().quotes.send(id, {
recipientEmail: opts.to,
customMessage: opts.message
});
success(`Quote sent (message ID: ${dim(result.messageId)})`);
} catch (err) {
error(err instanceof Error ? err.message : String(err));
process.exit(1);
}
});
var quotesCommand = new Command5("quotes").description("Manage quotes").addCommand(list4).addCommand(get3).addCommand(create4).addCommand(update3).addCommand(del3).addCommand(pdf2).addCommand(send2);
// src/commands/products.ts
import { Command as Command6 } from "commander";
import { Frihet as Frihet6 } from "@frihet/sdk";
function client5() {
return new Frihet6({ apiKey: getApiKey(), baseUrl: getBaseUrl() });
}
var list5 = new Command6("list").description("List products").option("--limit <n>", "Max results", "20").option("-q, --search <query>", "Search products").option("--json", "Output as JSON").action(async (opts) => {
try {
const f = client5();
const params = { limit: parseInt(opts.limit), q: opts.search };
const page = opts.search ? await f.products.search(opts.search, params) : await f.products.list(params);
if (shouldOutputJson()) {
outputJson(page);
return;
}
if (page.data.length === 0) {
console.log(dim("No products found."));
return;
}
table(
page.data.map((p) => [
p.id.slice(0, 8),
p.name,
eur(p.unitPrice),
p.sku ?? dim("--"),
p.category ?? dim("--"),
p.isActive === false ? red("inactive") : green("active")
]),
["ID", "Name", "Price", "SKU", "Category", "Status"]
);
console.log(dim(`
${page.total} total, showing ${page.data.length}`));
} catch (err) {
error(err instanceof Error ? err.message : String(err));
process.exit(1);
}
});
var get4 = new Command6("get").description("Get product details").argument("<id>", "Product ID").option("--json", "Output as JSON").action(async (id) => {
try {
const p = await client5().products.retrieve(id);
if (shouldOutputJson()) {
outputJson(p);
return;
}
console.log(bold(p.name));
console.log(`ID: ${dim(p.id)}`);
console.log(`Price: ${eur(p.unitPrice)}`);
console.log(`SKU: ${p.sku ?? dim("--")}`);
console.log(`Category: ${p.category ?? dim("--")}`);
console.log(`Status: ${p.isActive === false ? red("inactive") : green("active")}`);
if (p.description) console.log(`Desc: ${p.description}`);
if (p.taxRate !== void 0) console.log(`Tax: ${p.taxRate}%`);
if (p.irpfRate !== void 0) console.log(`IRPF: ${p.irpfRate}%`);
} catch (err) {
error(err instanceof Error ? err.message : String(err));
process.exit(1);
}
});
var create5 = new Command6("create").description("Create a new product").requiredOption("--name <name>", "Product name").requiredOption("--price <price>", "Unit price in EUR").option("--sku <sku>", "SKU code").option("--category <cat>", "Category").option("--desc <description>", "Description").option("--tax <rate>", "Tax rate (e.g. 21)").action(async (opts) => {
try {
const p = await client5().products.create({
name: opts.name,
unitPrice: parseFloat(opts.price),
sku: opts.sku,
category: opts.category,
description: opts.desc,
taxRate: opts.tax ? parseFloat(opts.tax) : void 0
});
success(`Product ${bold(p.name)} created (${eur(p.unitPrice)}) ${dim(p.id.slice(0, 8))}`);
} catch (err) {
error(err instanceof Error ? err.message : String(err));
process.exit(1);
}
});
var update4 = new Command6("update").description("Update a product").argument("<id>", "Product ID").option("--name <name>", "Product name").option("--price <price>", "Unit price in EUR").option("--sku <sku>", "SKU code").option("--category <cat>", "Category").option("--desc <description>", "Description").option("--tax <rate>", "Tax rate").option("--active <bool>", "Active status (true/false)").action(async (id, opts) => {
try {
const params = {};
if (opts.name !== void 0) params.name = opts.name;
if (opts.price !== void 0) params.unitPrice = parseFloat(opts.price);
if (opts.sku !== void 0) params.sku = opts.sku;
if (opts.category !== void 0) params.category = opts.category;
if (opts.desc !== void 0) params.description = opts.desc;
if (opts.tax !== void 0) params.taxRate = parseFloat(opts.tax);
if (opts.active !== void 0) params.isActive = opts.active === "true";
const p = await client5().products.update(id, params);
success(`Product ${bold(p.name)} updated`);
} catch (err) {
error(err instanceof Error ? err.message : String(err));
process.exit(1);
}
});
var del4 = new Command6("delete").description("Delete a product").argument("<id>", "Product ID").action(async (id) => {
try {
await client5().products.del(id);
success(`Product ${bold(id)} deleted`);
} catch (err) {
error(err instanceof Error ? err.message : String(err));
process.exit(1);
}
});
var productsCommand = new Command6("products").description("Manage products").addCommand(list5).addCommand(get4).addCommand(create5).addCommand(update4).addCommand(del4);
// src/commands/vendors.ts
import { Command as Command7 } from "commander";
import { Frihet as Frihet7 } from "@frihet/sdk";
function client6() {
return new Frihet7({ apiKey: getApiKey(), baseUrl: getBaseUrl() });
}
var list6 = new Command7("list").description("List vendors").option("--limit <n>", "Max results", "20").option("-q, --search <query>", "Search vendors").option("--json", "Output as JSON").action(async (opts) => {
try {
const f = client6();
const params = { limit: parseInt(opts.limit), q: opts.search };
const page = opts.search ? await f.vendors.search(opts.search, params) : await f.vendors.list(params);
if (shouldOutputJson()) {
outputJson(page);
return;
}
if (page.data.length === 0) {
console.log(dim("No vendors found."));
return;
}
table(
page.data.map((v) => [
v.id.slice(0, 8),
v.name,
v.email ?? dim("--"),
v.phone ?? dim("--"),
v.taxId ?? dim("--")
]),
["ID", "Name", "Email", "Phone", "Tax ID"]
);
console.log(dim(`
${page.total} total, showing ${page.data.length}`));
} catch (err) {
error(err instanceof Error ? err.message : String(err));
process.exit(1);
}
});
var get5 = new Command7("get").description("Get vendor details").argument("<id>", "Vendor ID").option("--json", "Output as JSON").action(async (id) => {
try {
const v = await client6().vendors.retrieve(id);
if (shouldOutputJson()) {
outputJson(v);
return;
}
console.log(bold(v.name));
console.log(`ID: ${dim(v.id)}`);
console.log(`Email: ${v.email ?? dim("--")}`);
console.log(`Phone: ${v.phone ?? dim("--")}`);
console.log(`Tax ID: ${v.taxId ?? dim("--")}`);
if (v.address) {
const addr = typeof v.address === "string" ? v.address : [v.address.street, v.address.city, v.address.postalCode, v.address.country].filter(Boolean).join(", ");
console.log(`Address: ${addr}`);
}
} catch (err) {
error(err instanceof Error ? err.message : String(err));
process.exit(1);
}
});
var create6 = new Command7("create").description("Create a new vendor").requiredOption("--name <name>", "Vendor name").option("--email <email>", "Email").option("--phone <phone>", "Phone").option("--tax-id <taxId>", "Tax ID (NIF/VAT)").action(async (opts) => {
try {
const v = await client6().vendors.create({
name: opts.name,
email: opts.email,
phone: opts.phone,
taxId: opts.taxId
});
success(`Vendor ${bold(v.name)} created (${dim(v.id.slice(0, 8))})`);
} catch (err) {
error(err instanceof Error ? err.message : String(err));
process.exit(1);
}
});
var update5 = new Command7("update").description("Update a vendor").argument("<id>", "Vendor ID").option("--name <name>", "Vendor name").option("--email <email>", "Email").option("--phone <phone>", "Phone").option("--tax-id <taxId>", "Tax ID (NIF/VAT)").action(async (id, opts) => {
try {
const params = {};
if (opts.name !== void 0) params.name = opts.name;
if (opts.email !== void 0) params.email = opts.email;
if (opts.phone !== void 0) params.phone = opts.phone;
if (opts.taxId !== void 0) params.taxId = opts.taxId;
const v = await client6().vendors.update(id, params);
success(`Vendor ${bold(v.name)} updated`);
} catch (err) {
error(err instanceof Error ? err.message : String(err));
process.exit(1);
}
});
var del5 = new Command7("delete").description("Delete a vendor").argument("<id>", "Vendor ID").action(async (id) => {
try {
await client6().vendors.del(id);
success(`Vendor ${bold(id)} deleted`);
} catch (err) {
error(err instanceof Error ? err.message : String(err));
process.exit(1);
}
});
var vendorsCommand = new Command7("vendors").description("Manage vendors").addCommand(list6).addCommand(get5).addCommand(create6).addCommand(update5).addCommand(del5);
// src/commands/webhooks.ts
import { Command as Command8 } from "commander";
import { Frihet as Frihet8 } from "@frihet/sdk";
function client7() {
return new Frihet8({ apiKey: getApiKey(), baseUrl: getBaseUrl() });
}
function statusColor3(status) {
switch (status) {
case "active":
return green(status);
case "inactive":
return red(status);
case "paused":
return yellow(status);
default:
return status ?? dim("--");
}
}
var list7 = new Command8("list").description("List webhooks").option("--limit <n>", "Max results", "20").option("--json", "Output as JSON").action(async (opts) => {
try {
const page = await client7().webhooks.list({ limit: parseInt(opts.limit) });
if (shouldOutputJson()) {
outputJson(page);
return;
}
if (page.data.length === 0) {
console.log(dim("No webhooks found."));
return;
}
table(
page.data.map((w) => [
w.id.slice(0, 8),
w.name ?? dim("--"),
w.url.length > 50 ? w.url.slice(0, 47) + "..." : w.url,
statusColor3(w.status),
String(w.events.length) + " events"
]),
["ID", "Name", "URL", "Status", "Events"]
);
console.log(dim(`
${page.total} total, showing ${page.data.length}`));
} catch (err) {
error(err instanceof Error ? err.message : String(err));
process.exit(1);
}
});
var get6 = new Command8("get").description("Get webhook details").argument("<id>", "Webhook ID").option("--json", "Output as JSON").action(async (id) => {
try {
const w = await client7().webhooks.retrieve(id);
if (shouldOutputJson()) {
outputJson(w);
return;
}
console.log(bold(w.name ?? w.id));
console.log(`ID: ${dim(w.id)}`);
console.log(`URL: ${w.url}`);
console.log(`Status: ${statusColor3(w.status)}`);
console.log(`Events: ${w.events.join(", ")}`);
if (w.secret) console.log(`Secret: ${dim(w.secret.slice(0, 8) + "...")}`);
} catch (err) {
error(err instanceof Error ? err.message : String(err));
process.exit(1);
}
});
var create7 = new Command8("create").description("Create a new webhook").requiredOption("--url <url>", "Webhook endpoint URL").requiredOption("--events <events...>", "Events to listen for (e.g. invoice.created invoice.paid)").option("--name <name>", "Webhook name").option("--secret <secret>", "Signing secret").action(async (opts) => {
try {
const w = await client7().webhooks.create({
url: opts.url,
events: opts.events,
name: opts.name,
secret: opts.secret
});
success(`Webhook ${bold(w.name ?? w.id.slice(0, 8))} created`);
console.log(`URL: ${w.url}`);
console.log(`Events: ${w.events.join(", ")}`);
if (w.secret) console.log(`Secret: ${dim(w.secret)}`);
} catch (err) {
error(err instanceof Error ? err.message : String(err));
process.exit(1);
}
});
var update6 = new Command8("update").description("Update a webhook").argument("<id>", "Webhook ID").option("--url <url>", "Webhook endpoint URL").option("--events <events...>", "Events to listen for").option("--name <name>", "Webhook name").option("--status <status>", "Status: active, inactive, paused").option("--secret <secret>", "Signing secret").action(async (id, opts) => {
try {
const params = {};
if (opts.url !== void 0) params.url = opts.url;
if (opts.events !== void 0) params.events = opts.events;
if (opts.name !== void 0) params.name = opts.name;
if (opts.status !== void 0) params.status = opts.status;
if (opts.secret !== void 0) params.secret = opts.secret;
const w = await client7().webhooks.update(id, params);
success(`Webhook ${bold(w.name ?? w.id.slice(0, 8))} updated`);
} catch (err) {
error(err instanceof Error ? err.message : String(err));
process.exit(1);
}
});
var del6 = new Command8("delete").description("Delete a webhook").argument("<id>", "Webhook ID").action(async (id) => {
try {
await client7().webhooks.del(id);
success(`Webhook ${bold(id)} deleted`);
} catch (err) {
error(err instanceof Error ? err.message : String(err));
process.exit(1);
}
});
var webhooksCommand = new Command8("webhooks").description("Manage webhooks").addCommand(list7).addCommand(get6).addCommand(create7).addCommand(update6).addCommand(del6);
// src/commands/status.ts
import { Command as Command9 } from "commander";
import { Frihet as Frihet9 } from "@frihet/sdk";
var statusCommand = new Command9("status").description("Quick business health check").option("--month <month>", "Month (YYYY-MM, defaults to current)").option("--json", "Output as JSON").action(async (opts) => {
try {
const f = new Frihet9({ apiKey: getApiKey(), baseUrl: getBaseUrl() });
const [ctx, summary] = await Promise.all([

@@ -388,2 +970,6 @@ f.intelligence.context(),

]);
if (shouldOutputJson()) {
outputJson({ context: ctx, summary });
return;
}
const business = ctx.business;

@@ -429,3 +1015,4 @@ const plan = ctx.plan;

// src/index.ts
var program = new Command6().name("frihet").version("1.0.0").description("Frihet CLI \u2014 manage your business from the terminal");
var CLI_VERSION = true ? "1.0.1" : "0.0.0-dev";
var program = new Command10().name("frihet").version(CLI_VERSION).description("Frihet CLI \u2014 manage your business from the terminal");
program.addCommand(loginCommand);

@@ -435,3 +1022,7 @@ program.addCommand(invoicesCommand);

program.addCommand(clientsCommand);
program.addCommand(quotesCommand);
program.addCommand(productsCommand);
program.addCommand(vendorsCommand);
program.addCommand(webhooksCommand);
program.addCommand(statusCommand);
program.parse();
+5
-3
{
"name": "frihet",
"version": "1.0.0",
"version": "1.0.1",
"description": "Frihet CLI — manage your business from the terminal",

@@ -10,3 +10,4 @@ "type": "module",

"files": [
"dist"
"dist",
"LICENSE"
],

@@ -17,3 +18,4 @@ "scripts": {

"typecheck": "tsc --noEmit",
"dev": "tsx src/index.ts"
"dev": "tsx src/index.ts",
"prepublishOnly": "pnpm run build"
},

@@ -20,0 +22,0 @@ "keywords": [