// @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) } }; } }; })();