Files
060a0c07c1 fix(captable): exclude terminal-state options from fully-diluted math (RED M5) (#3)
capTable summed ALL option rows into optionShares / per-stakeholder options
regardless of status, so EXERCISED, EXPIRED and CANCELLED grants inflated
fullyDilutedShares and understated every real ownership %. A cap-table surface
must not do this.

Filter both dilution queries (the totals sum and the per-stakeholder subquery)
to OUTSTANDING options only: status NOT IN ('EXERCISED','EXPIRED','CANCELLED').
EXERCISED options already became shares (counted in `share`) — counting the
option too double-counts; EXPIRED/CANCELLED are void. DRAFT + ACTIVE still dilute.

Rebuilt goja/bundle.js. Existing goja bundle tests pass.

Co-authored-by: hanzo-dev <[email protected]>

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-10 14:39:06 -07:00

1304 lines
44 KiB
JavaScript

// @hanzo/captable — goja bundle (GENERATED by goja/build.mjs; edit src/*.ts).
// Self-contained, ESM-free; runs in dop251/goja inside hanzoai/cloud (HIP-0106).
"use strict";
(() => {
var __defProp = Object.defineProperty;
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __propIsEnum = Object.prototype.propertyIsEnumerable;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __spreadValues = (a, b) => {
for (var prop in b || (b = {}))
if (__hasOwnProp.call(b, prop))
__defNormalProp(a, prop, b[prop]);
if (__getOwnPropSymbols)
for (var prop of __getOwnPropSymbols(b)) {
if (__propIsEnum.call(b, prop))
__defNormalProp(a, prop, b[prop]);
}
return a;
};
// src/host.ts
var db = {
query(sql, args) {
return globalThis.__db.query(sql, args || []);
},
exec(sql, args) {
return globalThis.__db.exec(sql, args || []);
}
};
function newId() {
return globalThis.__newId();
}
function now() {
return globalThis.__now();
}
// src/routes/common.ts
var okRes = (body) => ({ status: 200, body });
var created = (body) => ({ status: 201, body });
var badReq = (errors) => ({
status: 400,
body: { success: false, message: "Validation failed", errors }
});
var notFound = (msg) => ({
status: 404,
body: { success: false, message: msg }
});
var conflict = (msg) => ({
status: 409,
body: { success: false, message: msg }
});
function asObj(body) {
return body || {};
}
function refExists(companyId, table, id) {
if (!id) return false;
return db.query(`SELECT 1 FROM ${table} WHERE company_id = ? AND id = ?`, [
companyId,
id
]).length > 0;
}
// src/validate.ts
var StakeholderType = ["INDIVIDUAL", "INSTITUTION"];
var StakeholderRelationship = [
"ADVISOR",
"BOARD_MEMBER",
"CONSULTANT",
"EMPLOYEE",
"EX_ADVISOR",
"EX_CONSULTANT",
"EX_EMPLOYEE",
"EXECUTIVE",
"FOUNDER",
"INVESTOR",
"NON_US_EMPLOYEE",
"OFFICER",
"OTHER"
];
var ShareClassType = ["COMMON", "PREFERRED"];
var ConversionRights = [
"CONVERTS_TO_FUTURE_ROUND",
"CONVERTS_TO_SHARE_CLASS_ID"
];
var SecuritiesStatus = ["ACTIVE", "DRAFT", "SIGNED", "PENDING"];
var ShareLegends = [
"US_SECURITIES_ACT",
"SALE_AND_ROFR",
"TRANSFER_RESTRICTIONS"
];
var CancellationBehavior = [
"RETIRE",
"RETURN_TO_POOL",
"HOLD_AS_CAPITAL_STOCK",
"DEFINED_PER_PLAN_SECURITY"
];
var OptionType = ["ISO", "NSO", "RSU"];
var OptionStatus = [
"DRAFT",
"ACTIVE",
"EXERCISED",
"EXPIRED",
"CANCELLED"
];
var SafeType = ["PRE_MONEY", "POST_MONEY"];
var SafeStatus = [
"DRAFT",
"ACTIVE",
"PENDING",
"EXPIRED",
"CANCELLED"
];
var ConvertibleStatus = [
"DRAFT",
"ACTIVE",
"PENDING",
"EXPIRED",
"CANCELLED"
];
var ConvertibleType = ["CCD", "OCD", "NOTE"];
var RoundType = ["PRICED", "SAFE", "CONVERTIBLE"];
function reqString(o, k, errs) {
const v = o[k];
if (typeof v !== "string" || v.trim() === "") {
errs.push(`${k} is required`);
return "";
}
return v;
}
function optString(o, k) {
const v = o[k];
if (v === void 0 || v === null || v === "") return null;
return String(v);
}
function email(o, k, errs) {
const v = reqString(o, k, errs);
if (v && !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(v)) {
errs.push(`${k} must be a valid email`);
}
return v;
}
function num(o, k, errs, min) {
const raw = o[k];
const n = typeof raw === "number" ? raw : Number(raw);
if (raw === void 0 || raw === null || Number.isNaN(n)) {
errs.push(`${k} is required`);
return 0;
}
if (min !== void 0 && n < min) {
errs.push(`${k} must be >= ${min}`);
}
return n;
}
function optNum(o, k) {
const raw = o[k];
if (raw === void 0 || raw === null || raw === "") return null;
const n = Number(raw);
return Number.isNaN(n) ? null : n;
}
function intNum(o, k, errs, min) {
return Math.trunc(num(o, k, errs, min));
}
function oneOf(o, k, allowed, errs) {
const v = o[k];
if (typeof v !== "string" || !allowed.includes(v)) {
errs.push(`${k} must be one of ${allowed.join(", ")}`);
return allowed[0];
}
return v;
}
function dateString(o, k, errs) {
const v = o[k];
if (typeof v !== "string" || v.trim() === "") {
errs.push(`${k} is required`);
return "";
}
return v;
}
function optDateString(o, k) {
const v = o[k];
if (v === void 0 || v === null || v === "") return null;
return String(v);
}
function legends(o, k, errs) {
const v = o[k];
if (v === void 0 || v === null) return [];
if (!Array.isArray(v)) {
errs.push(`${k} must be an array`);
return [];
}
const out = [];
for (const item of v) {
if (typeof item !== "string" || !ShareLegends.includes(item)) {
errs.push(`${k} contains an invalid legend`);
continue;
}
out.push(item);
}
return out;
}
// src/routes/company.ts
function getCompany(ctx) {
const rows = db.query(
`SELECT id, name, public_id AS publicId, incorporation_type AS incorporationType,
incorporation_country AS incorporationCountry,
incorporation_state AS incorporationState,
created_at AS createdAt, updated_at AS updatedAt
FROM company WHERE id = ?`,
[ctx.companyId]
);
if (rows.length === 0) return notFound("company not found");
return okRes(rows[0]);
}
function updateCompany(ctx) {
const o = asObj(ctx.body);
const errs = [];
const name = reqString(o, "name", errs);
if (errs.length) return badReq(errs);
const r = db.exec(
`UPDATE company
SET name = ?, incorporation_type = ?, incorporation_country = ?,
incorporation_state = ?, updated_at = ?
WHERE id = ?`,
[
name,
optString(o, "incorporationType") || "",
optString(o, "incorporationCountry") || "",
optString(o, "incorporationState") || "",
now(),
ctx.companyId
]
);
if (r.changes === 0) return notFound("company not found");
return okRes({ success: true, message: "Company updated" });
}
// src/routes/stakeholders.ts
function listStakeholders(ctx) {
const rows = db.query(
`SELECT s.id, s.name, s.email, s.institution_name AS institutionName,
s.stakeholder_type AS stakeholderType,
s.current_relationship AS currentRelationship,
s.tax_id AS taxId, s.street_address AS streetAddress, s.city,
s.state, s.zipcode, s.country, s.created_at AS createdAt,
c.name AS companyName
FROM stakeholder s
JOIN company c ON c.id = s.company_id
WHERE s.company_id = ?
ORDER BY s.created_at DESC`,
[ctx.companyId]
);
return okRes(rows);
}
function validateStakeholder(o, errs) {
return {
name: reqString(o, "name", errs),
email: email(o, "email", errs),
institutionName: optString(o, "institutionName"),
stakeholderType: oneOf(o, "stakeholderType", StakeholderType, errs),
currentRelationship: oneOf(
o,
"currentRelationship",
StakeholderRelationship,
errs
),
taxId: optString(o, "taxId"),
streetAddress: optString(o, "streetAddress"),
city: optString(o, "city"),
state: optString(o, "state"),
zipcode: optString(o, "zipcode")
};
}
function addStakeholders(ctx) {
const raw = ctx.body;
const list = Array.isArray(raw) ? raw : [raw];
if (list.length === 0) return badReq(["at least one stakeholder is required"]);
const errs = [];
const parsed = list.map(
(item) => validateStakeholder(asObj(item), errs)
);
if (errs.length) return badReq(errs);
const ts = now();
let inserted = 0;
for (const s of parsed) {
const dup = db.query(
`SELECT 1 FROM stakeholder WHERE company_id = ? AND email = ?`,
[ctx.companyId, s.email]
);
if (dup.length > 0) continue;
db.exec(
`INSERT INTO stakeholder
(id, company_id, name, email, institution_name, stakeholder_type,
current_relationship, tax_id, street_address, city, state, zipcode,
country, created_at, updated_at)
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)`,
[
newId(),
ctx.companyId,
s.name,
s.email,
s.institutionName,
s.stakeholderType,
s.currentRelationship,
s.taxId,
s.streetAddress,
s.city,
s.state,
s.zipcode,
"US",
ts,
ts
]
);
inserted += 1;
}
return created({
success: true,
message: "Stakeholders added successfully!",
inserted
});
}
function updateStakeholder(ctx) {
const id = ctx.params.id;
if (!id) return badReq(["stakeholder id is required"]);
const o = asObj(ctx.body);
const sets = [];
const args = [];
const map = [
["name", "name"],
["email", "email"],
["institutionName", "institution_name"],
["stakeholderType", "stakeholder_type"],
["currentRelationship", "current_relationship"],
["taxId", "tax_id"],
["streetAddress", "street_address"],
["city", "city"],
["state", "state"],
["zipcode", "zipcode"]
];
for (const [jsonKey, col] of map) {
if (o[jsonKey] !== void 0) {
sets.push(`${col} = ?`);
args.push(o[jsonKey]);
}
}
if (sets.length === 0) return badReq(["no fields to update"]);
sets.push("updated_at = ?");
args.push(now(), ctx.companyId, id);
const r = db.exec(
`UPDATE stakeholder SET ${sets.join(", ")} WHERE company_id = ? AND id = ?`,
args
);
if (r.changes === 0) return notFound("stakeholder not found");
return okRes({ success: true, message: "Successfully updated the stakeholder" });
}
function deleteStakeholder(ctx) {
const id = ctx.params.id;
if (!id) return badReq(["stakeholder id is required"]);
const held = db.query(
`SELECT (SELECT COUNT(*) FROM share WHERE stakeholder_id = ? AND company_id = ?)
+ (SELECT COUNT(*) FROM option WHERE stakeholder_id = ? AND company_id = ?) AS n`,
[id, ctx.companyId, id, ctx.companyId]
);
if (Number(held[0].n) > 0) {
return badReq(["cannot delete a stakeholder that still holds shares or options"]);
}
const r = db.exec(`DELETE FROM stakeholder WHERE company_id = ? AND id = ?`, [
ctx.companyId,
id
]);
if (r.changes === 0) return notFound("stakeholder not found");
return okRes({ success: true });
}
// src/routes/equity.ts
function listShareClasses(ctx) {
const rows = db.query(
`SELECT sc.id, sc.idx, sc.name, sc.class_type AS classType, sc.prefix,
sc.initial_shares_authorized AS initialSharesAuthorized,
sc.votes_per_share AS votesPerShare, sc.par_value AS parValue,
sc.price_per_share AS pricePerShare, sc.seniority,
sc.conversion_rights AS conversionRights,
sc.liquidation_preference_multiple AS liquidationPreferenceMultiple,
sc.participation_cap_multiple AS participationCapMultiple,
c.name AS companyName
FROM share_class sc
JOIN company c ON c.id = sc.company_id
WHERE sc.company_id = ?
ORDER BY sc.idx ASC`,
[ctx.companyId]
);
return okRes(rows);
}
function validateShareClass(o, errs) {
const classType = oneOf(o, "classType", ShareClassType, errs);
return {
name: reqString(o, "name", errs),
classType,
prefix: classType === "COMMON" ? "CS" : "PS",
initialSharesAuthorized: intNum(o, "initialSharesAuthorized", errs, 1),
boardApprovalDate: dateString(o, "boardApprovalDate", errs),
stockholderApprovalDate: dateString(o, "stockholderApprovalDate", errs),
votesPerShare: intNum(o, "votesPerShare", errs, 0),
parValue: num(o, "parValue", errs, 0),
pricePerShare: num(o, "pricePerShare", errs, 0),
seniority: intNum(o, "seniority", errs, 0),
conversionRights: oneOf(o, "conversionRights", ConversionRights, errs),
convertsToShareClassId: optString(o, "convertsToShareClassId"),
liquidationPreferenceMultiple: num(o, "liquidationPreferenceMultiple", errs, 0),
participationCapMultiple: num(o, "participationCapMultiple", errs, 0)
};
}
function createShareClass(ctx) {
const errs = [];
const s = validateShareClass(asObj(ctx.body), errs);
if (errs.length) return badReq(errs);
const countRows = db.query(
`SELECT COUNT(*) AS n FROM share_class WHERE company_id = ?`,
[ctx.companyId]
);
const idx = Number(countRows[0].n) + 1;
const ts = now();
db.exec(
`INSERT INTO share_class
(id, company_id, idx, name, class_type, prefix,
initial_shares_authorized, board_approval_date, stockholder_approval_date,
votes_per_share, par_value, price_per_share, seniority, conversion_rights,
converts_to_share_class_id, liquidation_preference_multiple,
participation_cap_multiple, created_at, updated_at)
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)`,
[
newId(),
ctx.companyId,
idx,
s.name,
s.classType,
s.prefix,
s.initialSharesAuthorized,
s.boardApprovalDate,
s.stockholderApprovalDate,
s.votesPerShare,
s.parValue,
s.pricePerShare,
s.seniority,
s.conversionRights,
s.convertsToShareClassId,
s.liquidationPreferenceMultiple,
s.participationCapMultiple,
ts,
ts
]
);
return created({ success: true, message: "Share class created successfully." });
}
function updateShareClass(ctx) {
const id = ctx.params.id;
if (!id) return badReq(["share class id is required"]);
const errs = [];
const s = validateShareClass(asObj(ctx.body), errs);
if (errs.length) return badReq(errs);
const r = db.exec(
`UPDATE share_class
SET name = ?, class_type = ?, prefix = ?, initial_shares_authorized = ?,
board_approval_date = ?, stockholder_approval_date = ?,
votes_per_share = ?, par_value = ?, price_per_share = ?, seniority = ?,
conversion_rights = ?, converts_to_share_class_id = ?,
liquidation_preference_multiple = ?, participation_cap_multiple = ?,
updated_at = ?
WHERE company_id = ? AND id = ?`,
[
s.name,
s.classType,
s.prefix,
s.initialSharesAuthorized,
s.boardApprovalDate,
s.stockholderApprovalDate,
s.votesPerShare,
s.parValue,
s.pricePerShare,
s.seniority,
s.conversionRights,
s.convertsToShareClassId,
s.liquidationPreferenceMultiple,
s.participationCapMultiple,
now(),
ctx.companyId,
id
]
);
if (r.changes === 0) return notFound("share class not found");
return okRes({ success: true, message: "Share class updated successfully." });
}
function listEquityPlans(ctx) {
const rows = db.query(
`SELECT id, name, board_approval_date AS boardApprovalDate,
plan_effective_date AS planEffectiveDate,
initial_shares_reserved AS initialSharesReserved,
default_cancellation_behavior AS defaultCancellatonBehavior,
share_class_id AS shareClassId, comments, created_at AS createdAt
FROM equity_plan WHERE company_id = ?
ORDER BY created_at DESC`,
[ctx.companyId]
);
return okRes({ data: rows });
}
function createEquityPlan(ctx) {
const o = asObj(ctx.body);
const errs = [];
const name = reqString(o, "name", errs);
const boardApprovalDate = dateString(o, "boardApprovalDate", errs);
const initialSharesReserved = intNum(o, "initialSharesReserved", errs, 0);
const shareClassId = reqString(o, "shareClassId", errs);
const behavior = oneOf(o, "defaultCancellatonBehavior", CancellationBehavior, errs);
if (errs.length) return badReq(errs);
if (!refExists(ctx.companyId, "share_class", shareClassId)) {
return badReq(["shareClassId does not reference a share class in this company"]);
}
const ts = now();
db.exec(
`INSERT INTO equity_plan
(id, company_id, name, board_approval_date, plan_effective_date,
initial_shares_reserved, default_cancellation_behavior, share_class_id,
comments, created_at, updated_at)
VALUES (?,?,?,?,?,?,?,?,?,?,?)`,
[
newId(),
ctx.companyId,
name,
boardApprovalDate,
optDateString(o, "planEffectiveDate"),
initialSharesReserved,
behavior,
shareClassId,
optString(o, "comments"),
ts,
ts
]
);
return created({ success: true, message: "Equity plan created successfully." });
}
// src/routes/securities.ts
function listShares(ctx) {
const rows = db.query(
`SELECT sh.id, sh.certificate_id AS certificateId, sh.quantity,
sh.price_per_share AS pricePerShare,
sh.capital_contribution AS capitalContribution,
sh.status, sh.issue_date AS issueDate,
sh.company_legends AS companyLegends,
st.name AS stakeholderName, st.id AS stakeholderId,
sc.class_type AS shareClassType, sc.id AS shareClassId, sc.name AS shareClassName
FROM share sh
JOIN stakeholder st ON st.id = sh.stakeholder_id
JOIN share_class sc ON sc.id = sh.share_class_id
WHERE sh.company_id = ?
ORDER BY sh.created_at DESC`,
[ctx.companyId]
);
for (const r of rows) {
try {
r.companyLegends = JSON.parse(String(r.companyLegends || "[]"));
} catch (_e) {
r.companyLegends = [];
}
}
return okRes({ data: rows });
}
function insertShare(companyId, s) {
const id = newId();
const ts = now();
db.exec(
`INSERT INTO share
(id, company_id, stakeholder_id, share_class_id, status, certificate_id,
quantity, price_per_share, capital_contribution, ip_contribution,
debt_cancelled, other_contributions, cliff_years, vesting_years,
company_legends, issue_date, rule144_date, vesting_start_date,
board_approval_date, created_at, updated_at)
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)`,
[
id,
companyId,
s.stakeholderId,
s.shareClassId,
s.status,
s.certificateId,
s.quantity,
s.pricePerShare,
s.capitalContribution,
s.ipContribution,
s.debtCancelled,
s.otherContributions,
s.cliffYears,
s.vestingYears,
JSON.stringify(s.companyLegends),
s.issueDate,
s.rule144Date,
s.vestingStartDate,
s.boardApprovalDate,
ts,
ts
]
);
return id;
}
function addShare(ctx) {
const o = asObj(ctx.body);
const errs = [];
const stakeholderId = reqString(o, "stakeholderId", errs);
const shareClassId = reqString(o, "shareClassId", errs);
const certificateId = reqString(o, "certificateId", errs);
const quantity = intNum(o, "quantity", errs, 0);
const status = oneOf(o, "status", SecuritiesStatus, errs);
const rest = {
pricePerShare: optNum(o, "pricePerShare"),
capitalContribution: optNum(o, "capitalContribution"),
ipContribution: optNum(o, "ipContribution"),
debtCancelled: optNum(o, "debtCancelled"),
otherContributions: optNum(o, "otherContributions"),
cliffYears: intNum(o, "cliffYears", errs, 0),
vestingYears: intNum(o, "vestingYears", errs, 0),
companyLegends: legends(o, "companyLegends", errs),
issueDate: dateString(o, "issueDate", errs),
rule144Date: optDateString(o, "rule144Date"),
vestingStartDate: optDateString(o, "vestingStartDate"),
boardApprovalDate: dateString(o, "boardApprovalDate", errs)
};
if (errs.length) return badReq(errs);
if (!refExists(ctx.companyId, "stakeholder", stakeholderId)) {
return badReq(["stakeholderId does not reference a stakeholder in this company"]);
}
if (!refExists(ctx.companyId, "share_class", shareClassId)) {
return badReq(["shareClassId does not reference a share class in this company"]);
}
if (db.query(`SELECT 1 FROM share WHERE company_id = ? AND certificate_id = ?`, [
ctx.companyId,
certificateId
]).length > 0) {
return conflict("Please use unique Certificate Id.");
}
insertShare(ctx.companyId, __spreadValues({
stakeholderId,
shareClassId,
status,
certificateId,
quantity
}, rest));
return created({ success: true, message: "\u{1F389} Successfully added a share" });
}
function deleteShare(ctx) {
const id = ctx.params.id;
if (!id) return badReq(["share id is required"]);
const r = db.exec(`DELETE FROM share WHERE company_id = ? AND id = ?`, [
ctx.companyId,
id
]);
if (r.changes === 0) return notFound("share not found");
return okRes({ success: true });
}
function transferShare(ctx) {
const o = asObj(ctx.body);
const errs = [];
const shareId = reqString(o, "shareId", errs);
const toStakeholderId = reqString(o, "toStakeholderId", errs);
if (errs.length) return badReq(errs);
const rows = db.query(
`SELECT id, stakeholder_id AS stakeholderId, share_class_id AS shareClassId,
quantity, status, certificate_id AS certificateId
FROM share WHERE company_id = ? AND id = ?`,
[ctx.companyId, shareId]
);
if (rows.length === 0) return notFound("share not found");
const src = rows[0];
const held = Number(src.quantity);
if (!refExists(ctx.companyId, "stakeholder", toStakeholderId)) {
return badReq(["toStakeholderId does not reference a stakeholder in this company"]);
}
const qtyRaw = o.quantity;
const qty = qtyRaw === void 0 || qtyRaw === null ? held : Math.trunc(Number(qtyRaw));
if (Number.isNaN(qty) || qty <= 0 || qty > held) {
return badReq([`quantity must be between 1 and ${held}`]);
}
if (qty === held) {
db.exec(
`UPDATE share SET stakeholder_id = ?, updated_at = ? WHERE company_id = ? AND id = ?`,
[toStakeholderId, now(), ctx.companyId, shareId]
);
return okRes({
success: true,
message: "Share transferred",
transferred: qty,
newShareId: null
});
}
const newCert = optString(o, "certificateId");
if (!newCert) {
return badReq(["certificateId is required for a partial transfer"]);
}
if (db.query(`SELECT 1 FROM share WHERE company_id = ? AND certificate_id = ?`, [
ctx.companyId,
newCert
]).length > 0) {
return conflict("Please use unique Certificate Id.");
}
db.exec(`UPDATE share SET quantity = ?, updated_at = ? WHERE company_id = ? AND id = ?`, [
held - qty,
now(),
ctx.companyId,
shareId
]);
const newId2 = insertShare(ctx.companyId, {
stakeholderId: toStakeholderId,
shareClassId: src.shareClassId,
status: src.status,
certificateId: newCert,
quantity: qty,
pricePerShare: null,
capitalContribution: null,
ipContribution: null,
debtCancelled: null,
otherContributions: null,
cliffYears: 0,
vestingYears: 0,
companyLegends: [],
issueDate: new Date(now()).toISOString().slice(0, 10),
rule144Date: null,
vestingStartDate: null,
boardApprovalDate: new Date(now()).toISOString().slice(0, 10)
});
return okRes({
success: true,
message: "Share partially transferred",
transferred: qty,
newShareId: newId2
});
}
function listOptions(ctx) {
const rows = db.query(
`SELECT o.id, o.grant_id AS grantId, o.quantity,
o.exercise_price AS exercisePrice, o.type, o.status,
o.cliff_years AS cliffYears, o.vesting_years AS vestingYears,
o.issue_date AS issueDate, o.expiration_date AS expirationDate,
st.name AS stakeholderName, st.id AS stakeholderId,
ep.name AS equityPlanName, ep.id AS equityPlanId
FROM option o
JOIN stakeholder st ON st.id = o.stakeholder_id
JOIN equity_plan ep ON ep.id = o.equity_plan_id
WHERE o.company_id = ?
ORDER BY o.created_at DESC`,
[ctx.companyId]
);
return okRes({ data: rows });
}
function addOption(ctx) {
const o = asObj(ctx.body);
const errs = [];
const grantId = reqString(o, "grantId", errs);
const stakeholderId = reqString(o, "stakeholderId", errs);
const equityPlanId = reqString(o, "equityPlanId", errs);
const quantity = intNum(o, "quantity", errs, 0);
const exercisePrice = num(o, "exercisePrice", errs, 0);
const type = oneOf(o, "type", OptionType, errs);
const status = oneOf(o, "status", OptionStatus, errs);
const rest = {
cliffYears: intNum(o, "cliffYears", errs, 0),
vestingYears: intNum(o, "vestingYears", errs, 0),
issueDate: dateString(o, "issueDate", errs),
expirationDate: dateString(o, "expirationDate", errs),
vestingStartDate: dateString(o, "vestingStartDate", errs),
boardApprovalDate: dateString(o, "boardApprovalDate", errs),
rule144Date: dateString(o, "rule144Date", errs),
notes: optString(o, "notes")
};
if (errs.length) return badReq(errs);
if (!refExists(ctx.companyId, "stakeholder", stakeholderId)) {
return badReq(["stakeholderId does not reference a stakeholder in this company"]);
}
if (!refExists(ctx.companyId, "equity_plan", equityPlanId)) {
return badReq(["equityPlanId does not reference an equity plan in this company"]);
}
if (db.query(`SELECT 1 FROM option WHERE company_id = ? AND grant_id = ?`, [
ctx.companyId,
grantId
]).length > 0) {
return conflict("Please use unique Grant Id.");
}
const ts = now();
db.exec(
`INSERT INTO option
(id, company_id, stakeholder_id, equity_plan_id, grant_id, notes, quantity,
exercise_price, type, status, cliff_years, vesting_years, issue_date,
expiration_date, vesting_start_date, board_approval_date, rule144_date,
created_at, updated_at)
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)`,
[
newId(),
ctx.companyId,
stakeholderId,
equityPlanId,
grantId,
rest.notes,
quantity,
exercisePrice,
type,
status,
rest.cliffYears,
rest.vestingYears,
rest.issueDate,
rest.expirationDate,
rest.vestingStartDate,
rest.boardApprovalDate,
rest.rule144Date,
ts,
ts
]
);
return created({ success: true, message: "\u{1F389} Successfully added an option" });
}
function deleteOption(ctx) {
const id = ctx.params.id;
if (!id) return badReq(["option id is required"]);
const r = db.exec(`DELETE FROM option WHERE company_id = ? AND id = ?`, [
ctx.companyId,
id
]);
if (r.changes === 0) return notFound("option not found");
return okRes({ success: true });
}
// src/routes/convertibles.ts
function listSafes(ctx) {
const rows = db.query(
`SELECT sf.id, sf.public_id AS publicId, sf.type, sf.status, sf.capital,
sf.valuation_cap AS valuationCap, sf.discount_rate AS discountRate,
sf.mfn, sf.pro_rata AS proRata, sf.issue_date AS issueDate,
st.name AS stakeholderName, st.id AS stakeholderId
FROM safe sf
JOIN stakeholder st ON st.id = sf.stakeholder_id
WHERE sf.company_id = ?
ORDER BY sf.created_at DESC`,
[ctx.companyId]
);
for (const r of rows) {
r.mfn = Number(r.mfn) !== 0;
r.proRata = Number(r.proRata) !== 0;
}
return okRes({ data: rows });
}
function createSafe(ctx) {
const o = asObj(ctx.body);
const errs = [];
const publicId = reqString(o, "publicId", errs);
const stakeholderId = reqString(o, "stakeholderId", errs);
const capital = num(o, "capital", errs, 0);
const type = oneOf(o, "type", SafeType, errs);
const status = oneOf(o, "status", SafeStatus, errs);
const issueDate = dateString(o, "issueDate", errs);
const boardApprovalDate = dateString(o, "boardApprovalDate", errs);
if (errs.length) return badReq(errs);
if (!refExists(ctx.companyId, "stakeholder", stakeholderId)) {
return badReq(["stakeholderId does not reference a stakeholder in this company"]);
}
if (db.query(`SELECT 1 FROM safe WHERE company_id = ? AND public_id = ?`, [
ctx.companyId,
publicId
]).length > 0) {
return conflict("Please use a unique SAFE id.");
}
const ts = now();
db.exec(
`INSERT INTO safe
(id, company_id, stakeholder_id, public_id, type, status, capital,
valuation_cap, discount_rate, mfn, pro_rata, additional_terms,
issue_date, board_approval_date, created_at, updated_at)
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)`,
[
newId(),
ctx.companyId,
stakeholderId,
publicId,
type,
status,
capital,
optNum(o, "valuationCap"),
optNum(o, "discountRate"),
o.mfn ? 1 : 0,
o.proRata ? 1 : 0,
optString(o, "additionalTerms"),
issueDate,
boardApprovalDate,
ts,
ts
]
);
return created({ success: true, message: "SAFE created successfully." });
}
function deleteSafe(ctx) {
const id = ctx.params.id;
if (!id) return badReq(["safe id is required"]);
const r = db.exec(`DELETE FROM safe WHERE company_id = ? AND id = ?`, [
ctx.companyId,
id
]);
if (r.changes === 0) return notFound("safe not found");
return okRes({ success: true });
}
function listConvertibles(ctx) {
const rows = db.query(
`SELECT cn.id, cn.public_id AS publicId, cn.type, cn.status, cn.capital,
cn.conversion_cap AS conversionCap, cn.discount_rate AS discountRate,
cn.interest_rate AS interestRate, cn.issue_date AS issueDate,
st.name AS stakeholderName, st.id AS stakeholderId
FROM convertible_note cn
JOIN stakeholder st ON st.id = cn.stakeholder_id
WHERE cn.company_id = ?
ORDER BY cn.created_at DESC`,
[ctx.companyId]
);
return okRes({ data: rows });
}
function createConvertible(ctx) {
const o = asObj(ctx.body);
const errs = [];
const publicId = reqString(o, "publicId", errs);
const stakeholderId = reqString(o, "stakeholderId", errs);
const capital = num(o, "capital", errs, 0);
const type = oneOf(o, "type", ConvertibleType, errs);
const status = oneOf(o, "status", ConvertibleStatus, errs);
const issueDate = dateString(o, "issueDate", errs);
const boardApprovalDate = dateString(o, "boardApprovalDate", errs);
if (errs.length) return badReq(errs);
if (!refExists(ctx.companyId, "stakeholder", stakeholderId)) {
return badReq(["stakeholderId does not reference a stakeholder in this company"]);
}
if (db.query(`SELECT 1 FROM convertible_note WHERE company_id = ? AND public_id = ?`, [
ctx.companyId,
publicId
]).length > 0) {
return conflict("Please use a unique convertible note id.");
}
const ts = now();
db.exec(
`INSERT INTO convertible_note
(id, company_id, stakeholder_id, public_id, type, status, capital,
conversion_cap, discount_rate, mfn, interest_rate, additional_terms,
issue_date, board_approval_date, created_at, updated_at)
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)`,
[
newId(),
ctx.companyId,
stakeholderId,
publicId,
type,
status,
capital,
optNum(o, "conversionCap"),
optNum(o, "discountRate"),
o.mfn ? 1 : 0,
optNum(o, "interestRate"),
optString(o, "additionalTerms"),
issueDate,
boardApprovalDate,
ts,
ts
]
);
return created({ success: true, message: "Convertible note created successfully." });
}
function deleteConvertible(ctx) {
const id = ctx.params.id;
if (!id) return badReq(["convertible note id is required"]);
const r = db.exec(`DELETE FROM convertible_note WHERE company_id = ? AND id = ?`, [
ctx.companyId,
id
]);
if (r.changes === 0) return notFound("convertible note not found");
return okRes({ success: true });
}
// src/routes/rounds.ts
function listRounds(ctx) {
const rows = db.query(
`SELECT id, name, round_type AS roundType, status,
target_amount AS targetAmount, raised_amount AS raisedAmount,
pre_money_valuation AS preMoneyValuation,
price_per_share AS pricePerShare, share_class_id AS shareClassId,
close_date AS closeDate, created_at AS createdAt
FROM round WHERE company_id = ?
ORDER BY created_at DESC`,
[ctx.companyId]
);
return okRes({ data: rows });
}
function createRound(ctx) {
const o = asObj(ctx.body);
const errs = [];
const name = reqString(o, "name", errs);
const roundType = oneOf(o, "roundType", RoundType, errs);
const targetAmount = num(o, "targetAmount", errs, 0);
if (errs.length) return badReq(errs);
let shareClassId = null;
let pricePerShare = null;
let preMoney = null;
if (roundType === "PRICED") {
const perrs = [];
shareClassId = reqString(o, "shareClassId", perrs);
pricePerShare = num(o, "pricePerShare", perrs, 0);
preMoney = optNum(o, "preMoneyValuation");
if (pricePerShare <= 0) perrs.push("pricePerShare must be > 0 for a priced round");
if (perrs.length) return badReq(perrs);
if (!refExists(ctx.companyId, "share_class", shareClassId)) {
return badReq(["shareClassId does not reference a share class in this company"]);
}
}
const ts = now();
const id = newId();
db.exec(
`INSERT INTO round
(id, company_id, name, round_type, status, target_amount, raised_amount,
pre_money_valuation, price_per_share, share_class_id, close_date,
created_at, updated_at)
VALUES (?,?,?,?, 'OPEN', ?, 0, ?, ?, ?, NULL, ?, ?)`,
[id, ctx.companyId, name, roundType, targetAmount, preMoney, pricePerShare, shareClassId, ts, ts]
);
return created({ success: true, message: "Round created.", id });
}
function getRound(ctx) {
const id = ctx.params.id;
if (!id) return badReq(["round id is required"]);
const rows = db.query(
`SELECT id, name, round_type AS roundType, status,
target_amount AS targetAmount, raised_amount AS raisedAmount,
pre_money_valuation AS preMoneyValuation,
price_per_share AS pricePerShare, share_class_id AS shareClassId,
close_date AS closeDate, created_at AS createdAt
FROM round WHERE company_id = ? AND id = ?`,
[ctx.companyId, id]
);
if (rows.length === 0) return notFound("round not found");
const investments = db.query(
`SELECT i.id, i.amount, i.shares, i.date, i.comments,
st.name AS stakeholderName, st.id AS stakeholderId
FROM investment i
JOIN stakeholder st ON st.id = i.stakeholder_id
WHERE i.company_id = ? AND i.round_id = ?
ORDER BY i.created_at ASC`,
[ctx.companyId, id]
);
for (const r of investments) r.shares = Number(r.shares);
return okRes({ round: rows[0], investments });
}
function closeRound(ctx) {
const id = ctx.params.id;
if (!id) return badReq(["round id is required"]);
const o = asObj(ctx.body);
const closeDate = optDateString(o, "closeDate") || new Date(now()).toISOString().slice(0, 10);
const r = db.exec(
`UPDATE round SET status = 'CLOSED', close_date = ?, updated_at = ?
WHERE company_id = ? AND id = ? AND status = 'OPEN'`,
[closeDate, now(), ctx.companyId, id]
);
if (r.changes === 0) return notFound("open round not found");
return okRes({ success: true, message: "Round closed." });
}
function listInvestments(ctx) {
const rows = db.query(
`SELECT i.id, i.round_id AS roundId, i.amount, i.shares, i.date,
i.share_class_id AS shareClassId, st.name AS stakeholderName,
st.id AS stakeholderId
FROM investment i
JOIN stakeholder st ON st.id = i.stakeholder_id
WHERE i.company_id = ?
ORDER BY i.created_at DESC`,
[ctx.companyId]
);
for (const r of rows) r.shares = Number(r.shares);
return okRes({ data: rows });
}
function addInvestment(ctx) {
const roundId = ctx.params.id;
if (!roundId) return badReq(["round id is required"]);
const o = asObj(ctx.body);
const errs = [];
const stakeholderId = reqString(o, "stakeholderId", errs);
const amount = num(o, "amount", errs, 0);
if (errs.length) return badReq(errs);
const roundRows = db.query(
`SELECT id, round_type AS roundType, status, price_per_share AS pricePerShare,
share_class_id AS shareClassId
FROM round WHERE company_id = ? AND id = ?`,
[ctx.companyId, roundId]
);
if (roundRows.length === 0) return notFound("round not found");
const round = roundRows[0];
if (round.status !== "OPEN") return badReq(["round is not open for investment"]);
if (!refExists(ctx.companyId, "stakeholder", stakeholderId)) {
return badReq(["stakeholderId does not reference a stakeholder in this company"]);
}
const date = optDateString(o, "date") || new Date(now()).toISOString().slice(0, 10);
let shares = 0;
let newShareId = null;
if (round.roundType === "PRICED") {
const pps = Number(round.pricePerShare);
shares = Math.floor(amount / pps);
if (shares <= 0) return badReq(["amount is too small to buy a whole share at this round price"]);
const cert = `INV-${roundId.slice(1, 9)}-${newId().slice(1, 7)}`;
newShareId = insertShare(ctx.companyId, {
stakeholderId,
shareClassId: String(round.shareClassId),
status: "ACTIVE",
certificateId: cert,
quantity: shares,
pricePerShare: pps,
capitalContribution: amount,
ipContribution: null,
debtCancelled: null,
otherContributions: null,
cliffYears: 0,
vestingYears: 0,
companyLegends: [],
issueDate: date,
rule144Date: null,
vestingStartDate: null,
boardApprovalDate: date
});
}
const ts = now();
const invId = newId();
db.exec(
`INSERT INTO investment
(id, company_id, round_id, stakeholder_id, share_class_id, amount, shares,
date, comments, created_at, updated_at)
VALUES (?,?,?,?,?,?,?,?,?,?,?)`,
[
invId,
ctx.companyId,
roundId,
stakeholderId,
round.shareClassId,
amount,
shares,
date,
optString(o, "comments"),
ts,
ts
]
);
db.exec(
`UPDATE round SET raised_amount = raised_amount + ?, updated_at = ? WHERE company_id = ? AND id = ?`,
[amount, ts, ctx.companyId, roundId]
);
return created({
success: true,
message: "Investment recorded.",
id: invId,
sharesIssued: shares,
newShareId
});
}
// src/routes/captable.ts
var DILUTIVE_OPTION_STATUS = `status NOT IN ('EXERCISED','EXPIRED','CANCELLED')`;
function capTable(ctx) {
const cid = ctx.companyId;
const company = db.query(`SELECT id, name FROM company WHERE id = ?`, [cid]);
if (company.length === 0) return notFound("company not found");
const num2 = (rows, key) => rows.length ? Number(rows[0][key]) : 0;
const outstanding = num2(
db.query(`SELECT COALESCE(SUM(quantity),0) AS n FROM share WHERE company_id = ?`, [cid]),
"n"
);
const optionShares = num2(
db.query(
`SELECT COALESCE(SUM(quantity),0) AS n FROM option WHERE company_id = ? AND ${DILUTIVE_OPTION_STATUS}`,
[cid]
),
"n"
);
const fullyDiluted = outstanding + optionShares;
const byStakeholder = db.query(
`SELECT st.id AS stakeholderId, st.name,
COALESCE((SELECT SUM(sh.quantity) FROM share sh WHERE sh.stakeholder_id = st.id AND sh.company_id = st.company_id), 0) AS shares,
COALESCE((SELECT SUM(op.quantity) FROM option op WHERE op.stakeholder_id = st.id AND op.company_id = st.company_id AND op.${DILUTIVE_OPTION_STATUS}), 0) AS options
FROM stakeholder st
WHERE st.company_id = ?
ORDER BY shares DESC, options DESC`,
[cid]
);
for (const r of byStakeholder) {
const shares = Number(r.shares);
const options = Number(r.options);
r.shares = shares;
r.options = options;
const held = shares + options;
r.fullyDiluted = held;
r.ownershipPct = fullyDiluted > 0 ? Math.round(held / fullyDiluted * 1e4) / 100 : 0;
}
const byShareClass = db.query(
`SELECT sc.id AS shareClassId, sc.name, sc.class_type AS classType,
sc.initial_shares_authorized AS authorized,
COALESCE((SELECT SUM(sh.quantity) FROM share sh WHERE sh.share_class_id = sc.id AND sh.company_id = sc.company_id), 0) AS issued
FROM share_class sc
WHERE sc.company_id = ?
ORDER BY sc.idx ASC`,
[cid]
);
for (const r of byShareClass) {
r.authorized = Number(r.authorized);
r.issued = Number(r.issued);
}
const convertibles = {
safes: {
count: num2(db.query(`SELECT COUNT(*) AS n FROM safe WHERE company_id = ?`, [cid]), "n"),
capital: num2(db.query(`SELECT COALESCE(SUM(capital),0) AS n FROM safe WHERE company_id = ?`, [cid]), "n")
},
notes: {
count: num2(db.query(`SELECT COUNT(*) AS n FROM convertible_note WHERE company_id = ?`, [cid]), "n"),
capital: num2(db.query(`SELECT COALESCE(SUM(capital),0) AS n FROM convertible_note WHERE company_id = ?`, [cid]), "n")
}
};
const rounds = {
count: num2(db.query(`SELECT COUNT(*) AS n FROM round WHERE company_id = ?`, [cid]), "n"),
totalRaised: num2(db.query(`SELECT COALESCE(SUM(raised_amount),0) AS n FROM round WHERE company_id = ?`, [cid]), "n")
};
return okRes({
company: company[0],
totals: {
outstandingShares: outstanding,
grantedOptions: optionShares,
fullyDilutedShares: fullyDiluted,
stakeholders: num2(db.query(`SELECT COUNT(*) AS n FROM stakeholder WHERE company_id = ?`, [cid]), "n"),
shareClasses: num2(db.query(`SELECT COUNT(*) AS n FROM share_class WHERE company_id = ?`, [cid]), "n")
},
byStakeholder,
byShareClass,
convertibles,
rounds
});
}
// src/index.ts
var routes = {
"company.get": getCompany,
"company.update": updateCompany,
"stakeholders.list": listStakeholders,
"stakeholders.add": addStakeholders,
"stakeholders.update": updateStakeholder,
"stakeholders.delete": deleteStakeholder,
"shareClasses.list": listShareClasses,
"shareClasses.create": createShareClass,
"shareClasses.update": updateShareClass,
"equityPlans.list": listEquityPlans,
"equityPlans.create": createEquityPlan,
"shares.list": listShares,
"shares.add": addShare,
"shares.delete": deleteShare,
"shares.transfer": transferShare,
"options.list": listOptions,
"options.add": addOption,
"options.delete": deleteOption,
"safes.list": listSafes,
"safes.create": createSafe,
"safes.delete": deleteSafe,
"convertibles.list": listConvertibles,
"convertibles.create": createConvertible,
"convertibles.delete": deleteConvertible,
"rounds.list": listRounds,
"rounds.create": createRound,
"rounds.get": getRound,
"rounds.close": closeRound,
"rounds.investments.list": listInvestments,
"rounds.investments.add": addInvestment,
captable: capTable
};
globalThis.handle = (req) => {
req = req || {};
const route = req.route || "";
const companyId = req.orgId || "";
if (!companyId) {
return { status: 401, body: { success: false, message: "missing tenant" } };
}
const fn = routes[route];
if (!fn) {
return {
status: 404,
body: { success: false, message: `unknown captable route: ${route}` }
};
}
const ctx = { companyId, params: req.params || {}, body: req.body };
try {
return fn(ctx);
} catch (err) {
return {
status: 500,
body: {
success: false,
message: String(err && err.message || err)
}
};
}
};
})();