@agent-crm/cli 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,513 @@
1
+ import { createServer } from "node:http";
2
+ import { spawn } from "node:child_process";
3
+ import path from "node:path";
4
+ import { findWorkspace, openWorkspace } from "../workspace/open.js";
5
+ import { exec } from "../db/execute.js";
6
+ import { fail, setJsonMode } from "../output/json.js";
7
+ import { AcrmError, ERR } from "../lib/errors.js";
8
+ async function loadPeople(lix) {
9
+ const r = await exec(lix, `SELECT
10
+ p.record_id AS id,
11
+ v_name.value_json AS name_json,
12
+ v_role.value_json AS role_json,
13
+ v_li.value_json AS li_json,
14
+ v_ref.ref_record_id AS company_id
15
+ FROM acrm_record p
16
+ LEFT JOIN acrm_value v_name
17
+ ON v_name.record_id = p.record_id
18
+ AND v_name.attribute_slug = 'name'
19
+ AND v_name.active_until IS NULL
20
+ LEFT JOIN acrm_value v_role
21
+ ON v_role.record_id = p.record_id
22
+ AND v_role.attribute_slug = 'job_title'
23
+ AND v_role.active_until IS NULL
24
+ LEFT JOIN acrm_value v_li
25
+ ON v_li.record_id = p.record_id
26
+ AND v_li.attribute_slug = 'linkedin_url'
27
+ AND v_li.active_until IS NULL
28
+ LEFT JOIN acrm_value v_ref
29
+ ON v_ref.record_id = p.record_id
30
+ AND v_ref.attribute_slug = 'company'
31
+ AND v_ref.active_until IS NULL
32
+ WHERE p.object_slug = 'people'`);
33
+ const out = r.rows.map((row) => {
34
+ const nameObj = parseJson(row.name_json);
35
+ const roleObj = parseJson(row.role_json);
36
+ const liObj = parseJson(row.li_json);
37
+ return {
38
+ id: row.id,
39
+ name: nameObj?.full_name ?? null,
40
+ job_title: roleObj?.value ?? null,
41
+ linkedin_url: liObj?.value ?? null,
42
+ company_id: row.company_id ?? null,
43
+ };
44
+ });
45
+ out.sort((a, b) => (a.name ?? "").localeCompare(b.name ?? ""));
46
+ return out;
47
+ }
48
+ async function loadCompanies(lix) {
49
+ const r = await exec(lix, `SELECT
50
+ c.record_id AS id,
51
+ v_name.value_json AS name_json,
52
+ v_desc.value_json AS desc_json
53
+ FROM acrm_record c
54
+ LEFT JOIN acrm_value v_name
55
+ ON v_name.record_id = c.record_id
56
+ AND v_name.attribute_slug = 'name'
57
+ AND v_name.active_until IS NULL
58
+ LEFT JOIN acrm_value v_desc
59
+ ON v_desc.record_id = c.record_id
60
+ AND v_desc.attribute_slug = 'description'
61
+ AND v_desc.active_until IS NULL
62
+ WHERE c.object_slug = 'companies'`);
63
+ const out = r.rows.map((row) => {
64
+ const nameObj = parseJson(row.name_json);
65
+ const descObj = parseJson(row.desc_json);
66
+ return {
67
+ id: row.id,
68
+ name: nameObj?.value ?? null,
69
+ description: descObj?.value ?? null,
70
+ };
71
+ });
72
+ out.sort((a, b) => (a.name ?? "").localeCompare(b.name ?? ""));
73
+ return out;
74
+ }
75
+ async function loadCounts(lix) {
76
+ const r = await exec(lix, `SELECT object_slug, COUNT(*) AS n FROM acrm_record GROUP BY object_slug`);
77
+ const counts = { people: 0, companies: 0, deals: 0 };
78
+ for (const row of r.rows) {
79
+ const slug = row.object_slug;
80
+ const n = Number(row.n);
81
+ if (slug === "people")
82
+ counts.people = n;
83
+ else if (slug === "companies")
84
+ counts.companies = n;
85
+ else if (slug === "deals")
86
+ counts.deals = n;
87
+ }
88
+ return counts;
89
+ }
90
+ function parseJson(v) {
91
+ if (typeof v !== "string" || !v.length)
92
+ return null;
93
+ try {
94
+ return JSON.parse(v);
95
+ }
96
+ catch {
97
+ return null;
98
+ }
99
+ }
100
+ function escapeHtml(s) {
101
+ return s
102
+ .replace(/&/g, "&")
103
+ .replace(/</g, "&lt;")
104
+ .replace(/>/g, "&gt;")
105
+ .replace(/"/g, "&quot;")
106
+ .replace(/'/g, "&#39;");
107
+ }
108
+ function avatarColor(seed) {
109
+ let hash = 0;
110
+ for (let i = 0; i < seed.length; i++)
111
+ hash = (hash * 31 + seed.charCodeAt(i)) | 0;
112
+ const hue = Math.abs(hash) % 360;
113
+ return `hsl(${hue}, 38%, 32%)`;
114
+ }
115
+ function initials(name) {
116
+ const parts = name.trim().split(/\s+/).filter(Boolean);
117
+ if (parts.length === 0)
118
+ return "?";
119
+ if (parts.length === 1)
120
+ return parts[0].slice(0, 2).toUpperCase();
121
+ return (parts[0][0] + parts[parts.length - 1][0]).toUpperCase();
122
+ }
123
+ const STYLES = `
124
+ *, *::before, *::after { box-sizing: border-box; }
125
+ html, body { margin: 0; padding: 0; height: 100%; }
126
+ body {
127
+ font-family: "Inter", -apple-system, BlinkMacSystemFont, "SF Pro Display", system-ui, sans-serif;
128
+ font-size: 13px;
129
+ line-height: 1.45;
130
+ background: #0a0a0a;
131
+ color: #e6e6e6;
132
+ -webkit-font-smoothing: antialiased;
133
+ -moz-osx-font-smoothing: grayscale;
134
+ letter-spacing: -0.005em;
135
+ }
136
+ .app { display: grid; grid-template-columns: 220px 1fr; height: 100vh; }
137
+ .sidebar {
138
+ background: #0a0a0a;
139
+ border-right: 1px solid rgba(255,255,255,0.06);
140
+ padding: 14px 8px;
141
+ overflow-y: auto;
142
+ }
143
+ .workspace {
144
+ padding: 4px 10px 14px;
145
+ display: flex;
146
+ align-items: center;
147
+ gap: 8px;
148
+ font-size: 13px;
149
+ font-weight: 600;
150
+ color: #ededed;
151
+ }
152
+ .workspace-icon {
153
+ width: 18px; height: 18px;
154
+ border-radius: 5px;
155
+ background: linear-gradient(135deg, #5e6ad2 0%, #4a8af4 100%);
156
+ flex: none;
157
+ }
158
+ .nav-section { margin-top: 10px; }
159
+ .nav-label {
160
+ font-size: 11px;
161
+ color: #6a6a6a;
162
+ padding: 4px 10px 6px;
163
+ font-weight: 500;
164
+ }
165
+ .nav-item {
166
+ display: flex;
167
+ align-items: center;
168
+ justify-content: space-between;
169
+ padding: 5px 10px;
170
+ border-radius: 5px;
171
+ color: #c0c0c0;
172
+ text-decoration: none;
173
+ font-size: 13px;
174
+ }
175
+ .nav-item:hover { background: rgba(255,255,255,0.04); color: #e6e6e6; }
176
+ .nav-item.active { background: rgba(255,255,255,0.06); color: #fff; }
177
+ .nav-item .left { display: flex; align-items: center; gap: 8px; }
178
+ .nav-item .icon { width: 14px; height: 14px; opacity: 0.75; flex: none; }
179
+ .nav-item.active .icon { opacity: 1; }
180
+ .nav-item .count { font-size: 11px; color: #6a6a6a; font-variant-numeric: tabular-nums; }
181
+ .main { overflow: auto; }
182
+ .topbar {
183
+ height: 48px;
184
+ border-bottom: 1px solid rgba(255,255,255,0.06);
185
+ display: flex;
186
+ align-items: center;
187
+ padding: 0 24px;
188
+ gap: 10px;
189
+ position: sticky;
190
+ top: 0;
191
+ background: #0a0a0a;
192
+ z-index: 1;
193
+ }
194
+ .topbar h1 { font-size: 13px; font-weight: 600; margin: 0; letter-spacing: -0.01em; }
195
+ .topbar .count {
196
+ font-size: 12px;
197
+ color: #6a6a6a;
198
+ font-variant-numeric: tabular-nums;
199
+ }
200
+ table {
201
+ width: 100%;
202
+ border-collapse: collapse;
203
+ font-size: 13px;
204
+ }
205
+ thead tr { border-bottom: 1px solid rgba(255,255,255,0.06); }
206
+ th {
207
+ text-align: left;
208
+ font-weight: 500;
209
+ color: #8a8a8a;
210
+ font-size: 12px;
211
+ padding: 10px 16px;
212
+ background: #0a0a0a;
213
+ position: sticky;
214
+ top: 48px;
215
+ z-index: 1;
216
+ }
217
+ tbody tr { border-bottom: 1px solid rgba(255,255,255,0.04); }
218
+ tbody tr:last-child { border-bottom: none; }
219
+ tbody tr:hover { background: rgba(255,255,255,0.025); }
220
+ td {
221
+ padding: 10px 16px;
222
+ color: #d8d8d8;
223
+ vertical-align: middle;
224
+ white-space: nowrap;
225
+ overflow: hidden;
226
+ text-overflow: ellipsis;
227
+ max-width: 360px;
228
+ }
229
+ td.muted { color: #555; }
230
+ .avatar {
231
+ display: inline-flex;
232
+ align-items: center;
233
+ justify-content: center;
234
+ width: 22px; height: 22px;
235
+ border-radius: 50%;
236
+ color: rgba(255,255,255,0.95);
237
+ font-size: 10px;
238
+ font-weight: 600;
239
+ margin-right: 10px;
240
+ vertical-align: middle;
241
+ flex: none;
242
+ }
243
+ .name-cell { display: flex; align-items: center; min-width: 0; }
244
+ .name-cell span:last-child { overflow: hidden; text-overflow: ellipsis; }
245
+ a { color: #6e9fff; text-decoration: none; }
246
+ a:hover { text-decoration: underline; }
247
+ .mono {
248
+ font-family: "JetBrains Mono", "SF Mono", ui-monospace, Menlo, monospace;
249
+ font-size: 12px;
250
+ color: #9a9a9a;
251
+ }
252
+ .empty {
253
+ padding: 80px 40px;
254
+ text-align: center;
255
+ color: #6a6a6a;
256
+ }
257
+ .empty h2 { font-size: 14px; font-weight: 500; color: #a0a0a0; margin: 0 0 6px; }
258
+ .empty p { margin: 0; font-size: 12px; }
259
+ `;
260
+ const ICON_PEOPLE = `<svg class="icon" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.4"><circle cx="8" cy="6" r="2.5"/><path d="M3 13c0-2.5 2.2-4 5-4s5 1.5 5 4"/></svg>`;
261
+ const ICON_COMPANIES = `<svg class="icon" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.4"><rect x="3" y="3" width="10" height="10" rx="1"/><path d="M6 6h1M9 6h1M6 9h1M9 9h1"/></svg>`;
262
+ const ICON_DEALS = `<svg class="icon" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.4"><path d="M8 2l5 4-5 8-5-8z"/></svg>`;
263
+ function renderShell(opts) {
264
+ const { workspace, active, counts, body } = opts;
265
+ const navItem = (href, key, label, icon, count) => `<a class="nav-item ${active === key ? "active" : ""}" href="${href}">
266
+ <span class="left">${icon}<span>${label}</span></span>
267
+ <span class="count">${count}</span>
268
+ </a>`;
269
+ return `<!doctype html>
270
+ <html lang="en">
271
+ <head>
272
+ <meta charset="utf-8">
273
+ <meta name="viewport" content="width=device-width,initial-scale=1">
274
+ <title>${escapeHtml(workspace)} — Agent CRM</title>
275
+ <style>${STYLES}</style>
276
+ </head>
277
+ <body>
278
+ <div class="app">
279
+ <aside class="sidebar">
280
+ <div class="workspace">
281
+ <span class="workspace-icon"></span>
282
+ <span>${escapeHtml(workspace)}</span>
283
+ </div>
284
+ <div class="nav-section">
285
+ <div class="nav-label">Objects</div>
286
+ ${navItem("/people", "people", "People", ICON_PEOPLE, counts.people)}
287
+ ${navItem("/companies", "companies", "Companies", ICON_COMPANIES, counts.companies)}
288
+ ${navItem("/deals", "deals", "Deals", ICON_DEALS, counts.deals)}
289
+ </div>
290
+ </aside>
291
+ <main class="main">${body}</main>
292
+ </div>
293
+ </body>
294
+ </html>`;
295
+ }
296
+ function renderPeoplePage(people, companyById, workspace, counts) {
297
+ const rows = people
298
+ .map((p) => {
299
+ const display = p.name ?? "(unnamed)";
300
+ const color = avatarColor(p.id);
301
+ const company = p.company_id && companyById.get(p.company_id)
302
+ ? escapeHtml(companyById.get(p.company_id))
303
+ : `<span class="muted">—</span>`;
304
+ const role = p.job_title
305
+ ? escapeHtml(p.job_title)
306
+ : `<span class="muted">—</span>`;
307
+ const linkedin = p.linkedin_url
308
+ ? `<a class="mono" href="https://${escapeHtml(p.linkedin_url)}" target="_blank" rel="noreferrer noopener">${escapeHtml(p.linkedin_url)}</a>`
309
+ : `<span class="muted">—</span>`;
310
+ return `<tr>
311
+ <td><div class="name-cell"><span class="avatar" style="background:${color}">${escapeHtml(initials(display))}</span><span>${escapeHtml(display)}</span></div></td>
312
+ <td>${role}</td>
313
+ <td>${company}</td>
314
+ <td>${linkedin}</td>
315
+ </tr>`;
316
+ })
317
+ .join("");
318
+ const body = `
319
+ <div class="topbar">
320
+ <h1>People</h1>
321
+ <span class="count">${people.length}</span>
322
+ </div>
323
+ ${people.length
324
+ ? `<table>
325
+ <thead><tr><th>Name</th><th>Role</th><th>Company</th><th>LinkedIn</th></tr></thead>
326
+ <tbody>${rows}</tbody>
327
+ </table>`
328
+ : `<div class="empty"><h2>No people yet</h2><p>Run <span class="mono">acrm import csv ./leads.csv</span> to add some.</p></div>`}
329
+ `;
330
+ return renderShell({ workspace, active: "people", counts, body });
331
+ }
332
+ function renderCompaniesPage(companies, peopleByCompany, workspace, counts) {
333
+ const rows = companies
334
+ .map((c) => {
335
+ const display = c.name ?? "(unnamed)";
336
+ const color = avatarColor(c.id);
337
+ const desc = c.description
338
+ ? escapeHtml(c.description)
339
+ : `<span class="muted">—</span>`;
340
+ const headcount = peopleByCompany.get(c.id) ?? 0;
341
+ return `<tr>
342
+ <td><div class="name-cell"><span class="avatar" style="background:${color}">${escapeHtml(initials(display))}</span><span>${escapeHtml(display)}</span></div></td>
343
+ <td>${desc}</td>
344
+ <td>${headcount === 0 ? `<span class="muted">0</span>` : headcount}</td>
345
+ </tr>`;
346
+ })
347
+ .join("");
348
+ const body = `
349
+ <div class="topbar">
350
+ <h1>Companies</h1>
351
+ <span class="count">${companies.length}</span>
352
+ </div>
353
+ ${companies.length
354
+ ? `<table>
355
+ <thead><tr><th>Name</th><th>Type</th><th>People</th></tr></thead>
356
+ <tbody>${rows}</tbody>
357
+ </table>`
358
+ : `<div class="empty"><h2>No companies yet</h2><p>Run <span class="mono">acrm import csv ./leads.csv</span> to add some.</p></div>`}
359
+ `;
360
+ return renderShell({ workspace, active: "companies", counts, body });
361
+ }
362
+ function renderDealsPage(workspace, counts) {
363
+ const body = `
364
+ <div class="topbar">
365
+ <h1>Deals</h1>
366
+ <span class="count">${counts.deals}</span>
367
+ </div>
368
+ <div class="empty">
369
+ <h2>No deals yet</h2>
370
+ <p>Deals appear here once imported or created.</p>
371
+ </div>
372
+ `;
373
+ return renderShell({ workspace, active: "deals", counts, body });
374
+ }
375
+ async function handleRequest(lix, workspaceLabel, req, res) {
376
+ const url = new URL(req.url ?? "/", "http://localhost");
377
+ const pathname = url.pathname;
378
+ if (pathname === "/") {
379
+ res.statusCode = 302;
380
+ res.setHeader("Location", "/people");
381
+ res.end();
382
+ return;
383
+ }
384
+ const counts = await loadCounts(lix);
385
+ if (pathname === "/people") {
386
+ const [people, companies] = await Promise.all([
387
+ loadPeople(lix),
388
+ loadCompanies(lix),
389
+ ]);
390
+ const companyById = new Map(companies.filter((c) => c.name).map((c) => [c.id, c.name]));
391
+ const html = renderPeoplePage(people, companyById, workspaceLabel, counts);
392
+ res.statusCode = 200;
393
+ res.setHeader("Content-Type", "text/html; charset=utf-8");
394
+ res.end(html);
395
+ return;
396
+ }
397
+ if (pathname === "/companies") {
398
+ const [companies, people] = await Promise.all([
399
+ loadCompanies(lix),
400
+ loadPeople(lix),
401
+ ]);
402
+ const peopleByCompany = new Map();
403
+ for (const p of people) {
404
+ if (!p.company_id)
405
+ continue;
406
+ peopleByCompany.set(p.company_id, (peopleByCompany.get(p.company_id) ?? 0) + 1);
407
+ }
408
+ const html = renderCompaniesPage(companies, peopleByCompany, workspaceLabel, counts);
409
+ res.statusCode = 200;
410
+ res.setHeader("Content-Type", "text/html; charset=utf-8");
411
+ res.end(html);
412
+ return;
413
+ }
414
+ if (pathname === "/deals") {
415
+ res.statusCode = 200;
416
+ res.setHeader("Content-Type", "text/html; charset=utf-8");
417
+ res.end(renderDealsPage(workspaceLabel, counts));
418
+ return;
419
+ }
420
+ res.statusCode = 404;
421
+ res.setHeader("Content-Type", "text/plain; charset=utf-8");
422
+ res.end("Not found");
423
+ }
424
+ function openInBrowser(url) {
425
+ const cmd = process.platform === "darwin"
426
+ ? "open"
427
+ : process.platform === "win32"
428
+ ? "start"
429
+ : "xdg-open";
430
+ try {
431
+ spawn(cmd, [url], { detached: true, stdio: "ignore" }).unref();
432
+ }
433
+ catch {
434
+ // fine — user can click the URL
435
+ }
436
+ }
437
+ export function startUiServer(lix, workspaceLabel, opts) {
438
+ const server = createServer((req, res) => {
439
+ handleRequest(lix, workspaceLabel, req, res).catch((err) => {
440
+ res.statusCode = 500;
441
+ res.setHeader("Content-Type", "text/plain; charset=utf-8");
442
+ res.end(err instanceof Error ? err.message : String(err));
443
+ });
444
+ });
445
+ server.on("error", (err) => {
446
+ fail(err.message, ERR.UI);
447
+ process.exit(1);
448
+ });
449
+ const url = `http://localhost:${opts.port}`;
450
+ server.listen(opts.port, "127.0.0.1", () => {
451
+ process.stdout.write(`acrm ui — ${workspaceLabel}\n`);
452
+ process.stdout.write(` ${url}\n`);
453
+ process.stdout.write(` Ctrl+C to stop\n`);
454
+ if (opts.open)
455
+ openInBrowser(url);
456
+ });
457
+ const shutdown = async () => {
458
+ server.close();
459
+ try {
460
+ await lix.close();
461
+ }
462
+ catch {
463
+ // ignore
464
+ }
465
+ process.exit(0);
466
+ };
467
+ process.on("SIGINT", shutdown);
468
+ process.on("SIGTERM", shutdown);
469
+ }
470
+ export function registerUi(program) {
471
+ program
472
+ .command("ui")
473
+ .description("launch a basic local browser UI to validate the .acrm file (read-only; tables for people, companies, deals)")
474
+ .option("-p, --port <port>", "port to listen on", "3737")
475
+ .option("--no-open", "do not auto-open the browser")
476
+ .addHelpText("after", `
477
+ This UI is intentionally minimal — just enough to eyeball that an import landed
478
+ correctly. It is read-only, has no filters, search, or edit affordances.
479
+
480
+ Claude Code is expected to extend it as needed. The implementation is a single
481
+ file (src/commands/ui.ts): a node:http server with server-rendered HTML and
482
+ inline CSS, no client framework, no build step. To add a view, filter, or
483
+ detail drawer, edit that file directly.
484
+ `)
485
+ .action(async (opts) => {
486
+ const root = program.opts();
487
+ setJsonMode(root.json);
488
+ const port = Number(opts.port);
489
+ if (!Number.isInteger(port) || port <= 0 || port > 65535) {
490
+ fail(`invalid port: ${opts.port}`, ERR.INVALID_INPUT);
491
+ process.exit(1);
492
+ }
493
+ let lix;
494
+ try {
495
+ lix = await openWorkspace({ workspace: root.workspace });
496
+ }
497
+ catch (e) {
498
+ if (e instanceof AcrmError)
499
+ fail(e.message, e.code, e.hint);
500
+ else
501
+ fail(e instanceof Error ? e.message : String(e), ERR.UI);
502
+ process.exit(1);
503
+ }
504
+ const resolved = root.workspace
505
+ ? root.workspace.endsWith(".acrm")
506
+ ? root.workspace
507
+ : root.workspace + ".acrm"
508
+ : (findWorkspace() ?? "workspace.acrm");
509
+ const workspaceLabel = path.basename(resolved);
510
+ startUiServer(lix, workspaceLabel, { port, open: opts.open });
511
+ });
512
+ }
513
+ //# sourceMappingURL=ui.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ui.js","sourceRoot":"","sources":["../../src/commands/ui.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ import { isLixError } from "@lix-js/sdk";
2
+ import { AcrmError } from "../lib/errors.js";
3
+ export async function exec(lix, sql, params = []) {
4
+ try {
5
+ const result = await lix.execute(sql, params);
6
+ const rows = result.rows.map((r) => r.toObject());
7
+ return { rows, rowsAffected: result.rowsAffected };
8
+ }
9
+ catch (e) {
10
+ if (isLixError(e)) {
11
+ // Surface the engine's own code + hint instead of collapsing to a single
12
+ // ACRM_ERROR_*. The lix engine speaks Postgres-style errors:
13
+ // `message` says what's wrong, `hint` (when present) says how to fix it.
14
+ throw new AcrmError(e.message, e.code, e.hint, e.details);
15
+ }
16
+ throw e;
17
+ }
18
+ }
19
+ export async function execOne(lix, sql, params = []) {
20
+ const { rows } = await exec(lix, sql, params);
21
+ return rows[0] ?? null;
22
+ }
23
+ export async function execScalar(lix, sql, params = []) {
24
+ const row = await execOne(lix, sql, params);
25
+ if (!row)
26
+ return null;
27
+ const keys = Object.keys(row);
28
+ return keys.length ? row[keys[0]] : null;
29
+ }
30
+ //# sourceMappingURL=execute.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"execute.js","sourceRoot":"","sources":["../../src/db/execute.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAI7C,MAAM,CAAC,KAAK,UAAU,IAAI,CACxB,GAAQ,EACR,GAAW,EACX,SAAyC,EAAE;IAE3C,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,OAAO,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;QAC9C,MAAM,IAAI,GAAU,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;QACzD,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,CAAC,YAAY,EAAE,CAAC;IACrD,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,IAAI,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC;YAClB,yEAAyE;YACzE,6DAA6D;YAC7D,yEAAyE;YACzE,MAAM,IAAI,SAAS,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC;QAC5D,CAAC;QACD,MAAM,CAAC,CAAC;IACV,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,OAAO,CAC3B,GAAQ,EACR,GAAW,EACX,SAAyC,EAAE;IAE3C,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC;IAC9C,OAAO,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;AACzB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,GAAQ,EACR,GAAW,EACX,SAAyC,EAAE;IAE3C,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,GAAG,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC;IAC5C,IAAI,CAAC,GAAG;QAAE,OAAO,IAAI,CAAC;IACtB,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC9B,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,CAAE,GAAG,CAAC,IAAI,CAAC,CAAC,CAAE,CAAO,CAAC,CAAC,CAAC,IAAI,CAAC;AACnD,CAAC"}
@@ -0,0 +1,104 @@
1
+ export function encode(type, input) {
2
+ if (input === null || input === undefined) {
3
+ throw new Error(`cannot encode null/undefined for ${type}`);
4
+ }
5
+ switch (type) {
6
+ case "text":
7
+ case "url":
8
+ return { value: String(input).trim() };
9
+ case "personal-name": {
10
+ if (typeof input === "object")
11
+ return input;
12
+ const full = String(input).trim();
13
+ const parts = full.split(/\s+/);
14
+ const first_name = parts[0] ?? "";
15
+ const last_name = parts.length > 1 ? parts.slice(1).join(" ") : "";
16
+ return { full_name: full, first_name, last_name };
17
+ }
18
+ case "email-address": {
19
+ const raw = String(input).trim();
20
+ const lower = raw.toLowerCase();
21
+ const at = lower.indexOf("@");
22
+ if (at < 0)
23
+ throw new Error(`invalid email: ${raw}`);
24
+ const local = lower.slice(0, at);
25
+ const domain = lower.slice(at + 1);
26
+ return {
27
+ email_address: lower,
28
+ original_email_address: raw,
29
+ email_domain: domain,
30
+ email_root_domain: rootDomain(domain),
31
+ email_local_specifier: local,
32
+ };
33
+ }
34
+ case "domain": {
35
+ const d = normalizeDomain(String(input));
36
+ return { domain: d, root_domain: rootDomain(d) };
37
+ }
38
+ case "number":
39
+ return { value: Number(input) };
40
+ case "currency": {
41
+ if (typeof input === "object")
42
+ return input;
43
+ return { currency_value: Number(input), currency_code: "USD" };
44
+ }
45
+ case "date":
46
+ return { date: String(input).trim() };
47
+ case "timestamp":
48
+ return { timestamp: String(input).trim() };
49
+ case "select":
50
+ case "status": {
51
+ if (typeof input === "object")
52
+ return input;
53
+ return { title: String(input).trim() };
54
+ }
55
+ case "record-reference": {
56
+ const v = input;
57
+ if (!v?.target_object || !v?.target_record_id) {
58
+ throw new Error("record-reference requires target_object + target_record_id");
59
+ }
60
+ return { target_object: v.target_object, target_record_id: v.target_record_id };
61
+ }
62
+ }
63
+ }
64
+ export function normalizeUniqueKey(type, value) {
65
+ switch (type) {
66
+ case "email-address":
67
+ return value.email_address?.toLowerCase() ?? null;
68
+ case "domain":
69
+ return value.domain?.toLowerCase() ?? null;
70
+ case "url":
71
+ return value.value?.toLowerCase() ?? null;
72
+ case "text":
73
+ return value.value ?? null;
74
+ default:
75
+ return null;
76
+ }
77
+ }
78
+ export function recordReferenceTarget(value) {
79
+ const t = value.target_object;
80
+ const r = value.target_record_id;
81
+ if (!t || !r)
82
+ return null;
83
+ return { object: t, record_id: r };
84
+ }
85
+ export function normalizeDomain(input) {
86
+ let d = input.trim().toLowerCase();
87
+ d = d.replace(/^https?:\/\//, "");
88
+ d = d.replace(/^www\./, "");
89
+ d = d.split("/")[0];
90
+ return d;
91
+ }
92
+ export function rootDomain(domain) {
93
+ const parts = domain.split(".");
94
+ if (parts.length <= 2)
95
+ return domain;
96
+ return parts.slice(-2).join(".");
97
+ }
98
+ export function domainFromEmail(email) {
99
+ const at = email.indexOf("@");
100
+ if (at < 0)
101
+ return null;
102
+ return email.slice(at + 1).toLowerCase();
103
+ }
104
+ //# sourceMappingURL=values.js.map