@hasna/contacts 0.6.34 → 0.6.35
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.
- package/dashboard/dist/assets/index-0l6aQb1t.css +1 -0
- package/dashboard/dist/assets/index-opnZdkVD.js +229 -0
- package/dashboard/dist/index.html +13 -0
- package/dist/cli/commands/advanced.d.ts +3 -0
- package/dist/cli/commands/advanced.d.ts.map +1 -0
- package/dist/cli/commands/audience.d.ts +18 -0
- package/dist/cli/commands/audience.d.ts.map +1 -0
- package/dist/cli/commands/core.d.ts +3 -0
- package/dist/cli/commands/core.d.ts.map +1 -0
- package/dist/cli/commands/crm.d.ts +3 -0
- package/dist/cli/commands/crm.d.ts.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +1060 -46
- package/dist/cli/storage.d.ts +3 -0
- package/dist/cli/storage.d.ts.map +1 -0
- package/dist/cli/utils.d.ts +10 -0
- package/dist/cli/utils.d.ts.map +1 -0
- package/dist/cloud/http-storage.d.ts +88 -0
- package/dist/cloud/http-storage.d.ts.map +1 -0
- package/dist/db/activity.d.ts +15 -0
- package/dist/db/activity.d.ts.map +1 -0
- package/dist/db/applications.d.ts +10 -0
- package/dist/db/applications.d.ts.map +1 -0
- package/dist/db/audiences.d.ts +51 -0
- package/dist/db/audiences.d.ts.map +1 -0
- package/dist/db/companies.d.ts +19 -0
- package/dist/db/companies.d.ts.map +1 -0
- package/dist/db/contact-tasks.d.ts +19 -0
- package/dist/db/contact-tasks.d.ts.map +1 -0
- package/dist/db/contacts.d.ts +30 -0
- package/dist/db/contacts.d.ts.map +1 -0
- package/dist/db/coordination.d.ts +30 -0
- package/dist/db/coordination.d.ts.map +1 -0
- package/dist/db/database.d.ts +8 -0
- package/dist/db/database.d.ts.map +1 -0
- package/dist/db/deals.d.ts +14 -0
- package/dist/db/deals.d.ts.map +1 -0
- package/dist/db/documents.d.ts +38 -0
- package/dist/db/documents.d.ts.map +1 -0
- package/dist/db/events.d.ts +14 -0
- package/dist/db/events.d.ts.map +1 -0
- package/dist/db/field-history.d.ts +17 -0
- package/dist/db/field-history.d.ts.map +1 -0
- package/dist/db/freshness.d.ts +24 -0
- package/dist/db/freshness.d.ts.map +1 -0
- package/dist/db/graph.d.ts +21 -0
- package/dist/db/graph.d.ts.map +1 -0
- package/dist/db/groups.d.ts +22 -0
- package/dist/db/groups.d.ts.map +1 -0
- package/dist/db/health.d.ts +40 -0
- package/dist/db/health.d.ts.map +1 -0
- package/dist/db/identity.d.ts +32 -0
- package/dist/db/identity.d.ts.map +1 -0
- package/dist/db/job-history.d.ts +29 -0
- package/dist/db/job-history.d.ts.map +1 -0
- package/dist/db/learnings.d.ts +43 -0
- package/dist/db/learnings.d.ts.map +1 -0
- package/dist/db/notes.d.ts +8 -0
- package/dist/db/notes.d.ts.map +1 -0
- package/dist/db/org-chart.d.ts +37 -0
- package/dist/db/org-chart.d.ts.map +1 -0
- package/dist/db/org-members.d.ts +9 -0
- package/dist/db/org-members.d.ts.map +1 -0
- package/dist/db/paths.d.ts +3 -0
- package/dist/db/paths.d.ts.map +1 -0
- package/dist/db/pg-migrations.d.ts +8 -0
- package/dist/db/pg-migrations.d.ts.map +1 -0
- package/dist/db/project-memberships.d.ts +8 -0
- package/dist/db/project-memberships.d.ts.map +1 -0
- package/dist/db/relationships.d.ts +30 -0
- package/dist/db/relationships.d.ts.map +1 -0
- package/dist/db/signals.d.ts +18 -0
- package/dist/db/signals.d.ts.map +1 -0
- package/dist/db/sqlite-adapter.d.ts +15 -0
- package/dist/db/sqlite-adapter.d.ts.map +1 -0
- package/dist/db/storage.d.ts +15 -0
- package/dist/db/storage.d.ts.map +1 -0
- package/dist/db/tags.d.ts +14 -0
- package/dist/db/tags.d.ts.map +1 -0
- package/dist/db/tombstones.d.ts +19 -0
- package/dist/db/tombstones.d.ts.map +1 -0
- package/dist/db/vendor-comms.d.ts +15 -0
- package/dist/db/vendor-comms.d.ts.map +1 -0
- package/dist/generated/storage-kit/health.d.ts +20 -0
- package/dist/generated/storage-kit/health.d.ts.map +1 -0
- package/dist/generated/storage-kit/index.d.ts +8 -0
- package/dist/generated/storage-kit/index.d.ts.map +1 -0
- package/dist/generated/storage-kit/migrations.d.ts +48 -0
- package/dist/generated/storage-kit/migrations.d.ts.map +1 -0
- package/dist/generated/storage-kit/mode.d.ts +48 -0
- package/dist/generated/storage-kit/mode.d.ts.map +1 -0
- package/dist/generated/storage-kit/pool.d.ts +34 -0
- package/dist/generated/storage-kit/pool.d.ts.map +1 -0
- package/dist/generated/storage-kit/query.d.ts +36 -0
- package/dist/generated/storage-kit/query.d.ts.map +1 -0
- package/dist/generated/storage-kit/tls.d.ts +26 -0
- package/dist/generated/storage-kit/tls.d.ts.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +613 -23
- package/dist/lib/apple-contacts.d.ts +3 -0
- package/dist/lib/apple-contacts.d.ts.map +1 -0
- package/dist/lib/audience-contract.d.ts +215 -0
- package/dist/lib/audience-contract.d.ts.map +1 -0
- package/dist/lib/audit.d.ts +12 -0
- package/dist/lib/audit.d.ts.map +1 -0
- package/dist/lib/brief.d.ts +3 -0
- package/dist/lib/brief.d.ts.map +1 -0
- package/dist/lib/config.d.ts +7 -0
- package/dist/lib/config.d.ts.map +1 -0
- package/dist/lib/connector.d.ts +44 -0
- package/dist/lib/connector.d.ts.map +1 -0
- package/dist/lib/context.d.ts +5 -0
- package/dist/lib/context.d.ts.map +1 -0
- package/dist/lib/dedup.d.ts +10 -0
- package/dist/lib/dedup.d.ts.map +1 -0
- package/dist/lib/document-scanner.d.ts +8 -0
- package/dist/lib/document-scanner.d.ts.map +1 -0
- package/dist/lib/embeddings.d.ts +9 -0
- package/dist/lib/embeddings.d.ts.map +1 -0
- package/dist/lib/export.d.ts +8 -0
- package/dist/lib/export.d.ts.map +1 -0
- package/dist/lib/freshness.d.ts +19 -0
- package/dist/lib/freshness.d.ts.map +1 -0
- package/dist/lib/gmail-import.d.ts +51 -0
- package/dist/lib/gmail-import.d.ts.map +1 -0
- package/dist/lib/google-contacts.d.ts +115 -0
- package/dist/lib/google-contacts.d.ts.map +1 -0
- package/dist/lib/images.d.ts +30 -0
- package/dist/lib/images.d.ts.map +1 -0
- package/dist/lib/import.d.ts +10 -0
- package/dist/lib/import.d.ts.map +1 -0
- package/dist/lib/learning-maintenance.d.ts +8 -0
- package/dist/lib/learning-maintenance.d.ts.map +1 -0
- package/dist/lib/mailery-sync.d.ts +46 -0
- package/dist/lib/mailery-sync.d.ts.map +1 -0
- package/dist/lib/meeting-capture.d.ts +15 -0
- package/dist/lib/meeting-capture.d.ts.map +1 -0
- package/dist/lib/package-version.d.ts +6 -0
- package/dist/lib/package-version.d.ts.map +1 -0
- package/dist/lib/signals.d.ts +9 -0
- package/dist/lib/signals.d.ts.map +1 -0
- package/dist/lib/signature-parser.d.ts +36 -0
- package/dist/lib/signature-parser.d.ts.map +1 -0
- package/dist/lib/stats.d.ts +24 -0
- package/dist/lib/stats.d.ts.map +1 -0
- package/dist/lib/timeline.d.ts +11 -0
- package/dist/lib/timeline.d.ts.map +1 -0
- package/dist/lib/upcoming.d.ts +14 -0
- package/dist/lib/upcoming.d.ts.map +1 -0
- package/dist/lib/vault.d.ts +24 -0
- package/dist/lib/vault.d.ts.map +1 -0
- package/dist/mcp/handlers/advanced.d.ts +14 -0
- package/dist/mcp/handlers/advanced.d.ts.map +1 -0
- package/dist/mcp/handlers/audience.d.ts +9 -0
- package/dist/mcp/handlers/audience.d.ts.map +1 -0
- package/dist/mcp/handlers/core.d.ts +10 -0
- package/dist/mcp/handlers/core.d.ts.map +1 -0
- package/dist/mcp/handlers/crm.d.ts +14 -0
- package/dist/mcp/handlers/crm.d.ts.map +1 -0
- package/dist/mcp/handlers/index.d.ts +4 -0
- package/dist/mcp/handlers/index.d.ts.map +1 -0
- package/dist/mcp/handlers/types.d.ts +10 -0
- package/dist/mcp/handlers/types.d.ts.map +1 -0
- package/dist/mcp/http.d.ts +17 -0
- package/dist/mcp/http.d.ts.map +1 -0
- package/dist/mcp/index.d.ts +5 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +339 -27
- package/dist/mcp/register-tools.d.ts +3 -0
- package/dist/mcp/register-tools.d.ts.map +1 -0
- package/dist/mcp/schema.d.ts +3 -0
- package/dist/mcp/schema.d.ts.map +1 -0
- package/dist/mcp/storage-tools.d.ts +3 -0
- package/dist/mcp/storage-tools.d.ts.map +1 -0
- package/dist/mcp/tools.d.ts +3799 -0
- package/dist/mcp/tools.d.ts.map +1 -0
- package/dist/sdk/index.d.ts +16 -0
- package/dist/sdk/index.d.ts.map +1 -0
- package/dist/sdk/index.js +63 -0
- package/dist/sdk/v1.generated.d.ts +270 -0
- package/dist/sdk/v1.generated.d.ts.map +1 -0
- package/dist/server/cloud-index.d.ts +3 -0
- package/dist/server/cloud-index.d.ts.map +1 -0
- package/dist/server/cloud-serve.d.ts +3 -0
- package/dist/server/cloud-serve.d.ts.map +1 -0
- package/dist/server/cloud.d.ts +53 -0
- package/dist/server/cloud.d.ts.map +1 -0
- package/dist/server/index.d.ts +3 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +1022 -46
- package/dist/server/openapi.d.ts +1134 -0
- package/dist/server/openapi.d.ts.map +1 -0
- package/dist/server/pg-store.d.ts +893 -0
- package/dist/server/pg-store.d.ts.map +1 -0
- package/dist/server/security.d.ts +24 -0
- package/dist/server/security.d.ts.map +1 -0
- package/dist/server/serve.d.ts +9 -0
- package/dist/server/serve.d.ts.map +1 -0
- package/dist/server/v1.d.ts +28 -0
- package/dist/server/v1.d.ts.map +1 -0
- package/dist/store/index.d.ts +387 -0
- package/dist/store/index.d.ts.map +1 -0
- package/dist/types/index.d.ts +856 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/project-memberships.d.ts +32 -0
- package/dist/types/project-memberships.d.ts.map +1 -0
- package/migrations/0015_contact_project_membership_authority.sql +88 -0
- package/package.json +1 -1
- package/vendor/fast-uri/README.md +12 -0
- package/dist/server/cloud-index.js +0 -9187
package/dist/mcp/index.js
CHANGED
|
@@ -6741,7 +6741,10 @@ function uuid2() {
|
|
|
6741
6741
|
return crypto.randomUUID();
|
|
6742
6742
|
}
|
|
6743
6743
|
function now() {
|
|
6744
|
-
|
|
6744
|
+
const currentMs = Date.now();
|
|
6745
|
+
const nextMs = currentMs > lastNowMs ? currentMs : lastNowMs + 1;
|
|
6746
|
+
lastNowMs = nextMs;
|
|
6747
|
+
return new Date(nextMs).toISOString();
|
|
6745
6748
|
}
|
|
6746
6749
|
function quoteIdentifier(identifier) {
|
|
6747
6750
|
return `"${identifier.replaceAll('"', '""')}"`;
|
|
@@ -6779,7 +6782,7 @@ function runMigrations(db) {
|
|
|
6779
6782
|
db.exec(`INSERT OR REPLACE INTO _migrations(version) VALUES(${i})`);
|
|
6780
6783
|
}
|
|
6781
6784
|
}
|
|
6782
|
-
var MIGRATIONS, _db = null;
|
|
6785
|
+
var MIGRATIONS, _db = null, lastNowMs = 0;
|
|
6783
6786
|
var init_database = __esm(() => {
|
|
6784
6787
|
init_sqlite_adapter();
|
|
6785
6788
|
init_paths();
|
|
@@ -7351,6 +7354,81 @@ var init_database = __esm(() => {
|
|
|
7351
7354
|
);
|
|
7352
7355
|
|
|
7353
7356
|
CREATE INDEX IF NOT EXISTS idx_contacts_tombstones_deleted_at ON _contacts_tombstones(deleted_at);
|
|
7357
|
+
`,
|
|
7358
|
+
`
|
|
7359
|
+
CREATE TABLE IF NOT EXISTS contact_project_membership_states (
|
|
7360
|
+
contact_id TEXT NOT NULL REFERENCES contacts(id) ON DELETE CASCADE,
|
|
7361
|
+
project_id TEXT NOT NULL,
|
|
7362
|
+
linked INTEGER NOT NULL CHECK(linked IN (0, 1)),
|
|
7363
|
+
revision INTEGER NOT NULL DEFAULT 0 CHECK(revision >= 0),
|
|
7364
|
+
updated_at TEXT NOT NULL,
|
|
7365
|
+
PRIMARY KEY (contact_id, project_id)
|
|
7366
|
+
);
|
|
7367
|
+
|
|
7368
|
+
INSERT OR IGNORE INTO contact_project_membership_states
|
|
7369
|
+
(contact_id, project_id, linked, revision, updated_at)
|
|
7370
|
+
SELECT contact_id, project_id, 1, 0, datetime('now')
|
|
7371
|
+
FROM contact_projects;
|
|
7372
|
+
|
|
7373
|
+
CREATE TABLE IF NOT EXISTS contact_project_membership_receipts (
|
|
7374
|
+
receipt_id TEXT PRIMARY KEY,
|
|
7375
|
+
direction TEXT NOT NULL CHECK(direction IN ('attach', 'detach')),
|
|
7376
|
+
contact_id TEXT NOT NULL REFERENCES contacts(id) ON DELETE CASCADE,
|
|
7377
|
+
project_id TEXT NOT NULL,
|
|
7378
|
+
operation_id TEXT NOT NULL,
|
|
7379
|
+
step_id TEXT NOT NULL,
|
|
7380
|
+
expected_version TEXT NOT NULL,
|
|
7381
|
+
before_json TEXT NOT NULL,
|
|
7382
|
+
after_json TEXT NOT NULL,
|
|
7383
|
+
created_at TEXT NOT NULL,
|
|
7384
|
+
UNIQUE(operation_id, step_id)
|
|
7385
|
+
);
|
|
7386
|
+
|
|
7387
|
+
CREATE INDEX IF NOT EXISTS idx_contact_project_membership_states_project
|
|
7388
|
+
ON contact_project_membership_states(project_id, linked, contact_id);
|
|
7389
|
+
CREATE INDEX IF NOT EXISTS idx_contact_project_membership_receipts_target
|
|
7390
|
+
ON contact_project_membership_receipts(contact_id, project_id, created_at);
|
|
7391
|
+
|
|
7392
|
+
CREATE TRIGGER IF NOT EXISTS sync_contact_project_membership_state_after_insert
|
|
7393
|
+
AFTER INSERT ON contact_projects
|
|
7394
|
+
BEGIN
|
|
7395
|
+
INSERT INTO contact_project_membership_states
|
|
7396
|
+
(contact_id, project_id, linked, revision, updated_at)
|
|
7397
|
+
VALUES (NEW.contact_id, NEW.project_id, 1, 1, datetime('now'))
|
|
7398
|
+
ON CONFLICT(contact_id, project_id) DO UPDATE SET
|
|
7399
|
+
linked = 1,
|
|
7400
|
+
revision = CASE
|
|
7401
|
+
WHEN contact_project_membership_states.linked = 1
|
|
7402
|
+
THEN contact_project_membership_states.revision
|
|
7403
|
+
ELSE contact_project_membership_states.revision + 1
|
|
7404
|
+
END,
|
|
7405
|
+
updated_at = CASE
|
|
7406
|
+
WHEN contact_project_membership_states.linked = 1
|
|
7407
|
+
THEN contact_project_membership_states.updated_at
|
|
7408
|
+
ELSE datetime('now')
|
|
7409
|
+
END;
|
|
7410
|
+
END;
|
|
7411
|
+
|
|
7412
|
+
CREATE TRIGGER IF NOT EXISTS sync_contact_project_membership_state_after_delete
|
|
7413
|
+
AFTER DELETE ON contact_projects
|
|
7414
|
+
WHEN EXISTS (SELECT 1 FROM contacts WHERE id = OLD.contact_id)
|
|
7415
|
+
BEGIN
|
|
7416
|
+
INSERT INTO contact_project_membership_states
|
|
7417
|
+
(contact_id, project_id, linked, revision, updated_at)
|
|
7418
|
+
VALUES (OLD.contact_id, OLD.project_id, 0, 1, datetime('now'))
|
|
7419
|
+
ON CONFLICT(contact_id, project_id) DO UPDATE SET
|
|
7420
|
+
linked = 0,
|
|
7421
|
+
revision = CASE
|
|
7422
|
+
WHEN contact_project_membership_states.linked = 0
|
|
7423
|
+
THEN contact_project_membership_states.revision
|
|
7424
|
+
ELSE contact_project_membership_states.revision + 1
|
|
7425
|
+
END,
|
|
7426
|
+
updated_at = CASE
|
|
7427
|
+
WHEN contact_project_membership_states.linked = 0
|
|
7428
|
+
THEN contact_project_membership_states.updated_at
|
|
7429
|
+
ELSE datetime('now')
|
|
7430
|
+
END;
|
|
7431
|
+
END;
|
|
7354
7432
|
`
|
|
7355
7433
|
];
|
|
7356
7434
|
});
|
|
@@ -7448,6 +7526,219 @@ var init_tombstones = __esm(() => {
|
|
|
7448
7526
|
init_database();
|
|
7449
7527
|
});
|
|
7450
7528
|
|
|
7529
|
+
// src/types/project-memberships.ts
|
|
7530
|
+
var ContactProjectMembershipConflictError;
|
|
7531
|
+
var init_project_memberships = __esm(() => {
|
|
7532
|
+
ContactProjectMembershipConflictError = class ContactProjectMembershipConflictError extends Error {
|
|
7533
|
+
constructor(message) {
|
|
7534
|
+
super(message);
|
|
7535
|
+
this.name = "ContactProjectMembershipConflictError";
|
|
7536
|
+
}
|
|
7537
|
+
};
|
|
7538
|
+
});
|
|
7539
|
+
|
|
7540
|
+
// src/db/project-memberships.ts
|
|
7541
|
+
import { createHash } from "crypto";
|
|
7542
|
+
function digest(value) {
|
|
7543
|
+
return createHash("sha256").update(value).digest("hex");
|
|
7544
|
+
}
|
|
7545
|
+
function membershipVersion(contactId, projectId, linked, revision) {
|
|
7546
|
+
return `cpmv_${digest(JSON.stringify([contactId, projectId, linked, revision])).slice(0, 32)}`;
|
|
7547
|
+
}
|
|
7548
|
+
function receiptId(input) {
|
|
7549
|
+
return `cpmr_${digest(JSON.stringify([
|
|
7550
|
+
input.operation_id,
|
|
7551
|
+
input.step_id,
|
|
7552
|
+
input.contact_id,
|
|
7553
|
+
input.project_id
|
|
7554
|
+
])).slice(0, 32)}`;
|
|
7555
|
+
}
|
|
7556
|
+
function stateRow(contactId, projectId, db) {
|
|
7557
|
+
const persisted = db.query(`SELECT contact_id, project_id, linked, revision
|
|
7558
|
+
FROM contact_project_membership_states
|
|
7559
|
+
WHERE contact_id = ? AND project_id = ?`).get(contactId, projectId);
|
|
7560
|
+
if (persisted)
|
|
7561
|
+
return persisted;
|
|
7562
|
+
const linked = Boolean(db.query(`SELECT 1 AS present FROM contact_projects WHERE contact_id = ? AND project_id = ?`).get(contactId, projectId));
|
|
7563
|
+
return { contact_id: contactId, project_id: projectId, linked: linked ? 1 : 0, revision: 0 };
|
|
7564
|
+
}
|
|
7565
|
+
function snapshot(row) {
|
|
7566
|
+
const linked = Boolean(row.linked);
|
|
7567
|
+
return {
|
|
7568
|
+
contact_id: row.contact_id,
|
|
7569
|
+
project_id: row.project_id,
|
|
7570
|
+
linked,
|
|
7571
|
+
version: membershipVersion(row.contact_id, row.project_id, linked, row.revision)
|
|
7572
|
+
};
|
|
7573
|
+
}
|
|
7574
|
+
function required2(value, name) {
|
|
7575
|
+
const normalized = value.trim();
|
|
7576
|
+
if (!normalized)
|
|
7577
|
+
throw new Error(`${name} is required`);
|
|
7578
|
+
return normalized;
|
|
7579
|
+
}
|
|
7580
|
+
function normalizeInput(input) {
|
|
7581
|
+
return {
|
|
7582
|
+
contact_id: required2(input.contact_id, "contact_id"),
|
|
7583
|
+
project_id: required2(input.project_id, "project_id"),
|
|
7584
|
+
operation_id: required2(input.operation_id, "operation_id"),
|
|
7585
|
+
step_id: required2(input.step_id, "step_id"),
|
|
7586
|
+
expected_version: required2(input.expected_version, "expected_version")
|
|
7587
|
+
};
|
|
7588
|
+
}
|
|
7589
|
+
function parseSnapshot(value) {
|
|
7590
|
+
return JSON.parse(value);
|
|
7591
|
+
}
|
|
7592
|
+
function replay(row, direction, input) {
|
|
7593
|
+
if (row.direction !== direction || row.contact_id !== input.contact_id || row.project_id !== input.project_id || row.expected_version !== input.expected_version) {
|
|
7594
|
+
throw new ContactProjectMembershipConflictError(`operation_id/step_id already accepted for a different contact-project membership mutation`);
|
|
7595
|
+
}
|
|
7596
|
+
return {
|
|
7597
|
+
outcome: "duplicate_of_accepted",
|
|
7598
|
+
operation_id: row.operation_id,
|
|
7599
|
+
step_id: row.step_id,
|
|
7600
|
+
before: parseSnapshot(row.before_json),
|
|
7601
|
+
after: parseSnapshot(row.after_json),
|
|
7602
|
+
receipt_id: row.receipt_id
|
|
7603
|
+
};
|
|
7604
|
+
}
|
|
7605
|
+
function transitionWithoutReceipt(contactId, projectId, linked, db) {
|
|
7606
|
+
const beforeRow = stateRow(contactId, projectId, db);
|
|
7607
|
+
const changed = Boolean(beforeRow.linked) !== linked;
|
|
7608
|
+
const afterRow = {
|
|
7609
|
+
...beforeRow,
|
|
7610
|
+
linked: linked ? 1 : 0,
|
|
7611
|
+
revision: changed ? beforeRow.revision + 1 : beforeRow.revision
|
|
7612
|
+
};
|
|
7613
|
+
const changedAt = now();
|
|
7614
|
+
db.run(`INSERT INTO contact_project_membership_states
|
|
7615
|
+
(contact_id, project_id, linked, revision, updated_at)
|
|
7616
|
+
VALUES (?, ?, ?, ?, ?)
|
|
7617
|
+
ON CONFLICT(contact_id, project_id) DO UPDATE SET
|
|
7618
|
+
linked = excluded.linked,
|
|
7619
|
+
revision = excluded.revision,
|
|
7620
|
+
updated_at = excluded.updated_at`, [contactId, projectId, afterRow.linked, afterRow.revision, changedAt]);
|
|
7621
|
+
if (linked) {
|
|
7622
|
+
db.run(`INSERT OR IGNORE INTO contact_projects (contact_id, project_id) VALUES (?, ?)`, [contactId, projectId]);
|
|
7623
|
+
} else {
|
|
7624
|
+
db.run(`DELETE FROM contact_projects WHERE contact_id = ? AND project_id = ?`, [contactId, projectId]);
|
|
7625
|
+
}
|
|
7626
|
+
return changed;
|
|
7627
|
+
}
|
|
7628
|
+
function setContactProjectMembershipWithoutReceipt(contactId, projectId, linked, db = getDatabase()) {
|
|
7629
|
+
const normalizedContactId = required2(contactId, "contact_id");
|
|
7630
|
+
const normalizedProjectId = required2(projectId, "project_id");
|
|
7631
|
+
return db.transaction(() => transitionWithoutReceipt(normalizedContactId, normalizedProjectId, linked, db));
|
|
7632
|
+
}
|
|
7633
|
+
function replaceContactProjectMembershipsWithoutReceipts(contactId, projectIds, db = getDatabase()) {
|
|
7634
|
+
const normalizedContactId = required2(contactId, "contact_id");
|
|
7635
|
+
const normalizedProjectIds = [...new Set(projectIds.map((projectId) => required2(projectId, "project_id")))];
|
|
7636
|
+
return db.transaction(() => {
|
|
7637
|
+
const currentRows = db.query(`SELECT project_id FROM contact_projects WHERE contact_id = ?`).all(normalizedContactId);
|
|
7638
|
+
const desired = new Set(normalizedProjectIds);
|
|
7639
|
+
const population = new Set([...currentRows.map((row) => row.project_id), ...normalizedProjectIds]);
|
|
7640
|
+
for (const projectId of population) {
|
|
7641
|
+
transitionWithoutReceipt(normalizedContactId, projectId, desired.has(projectId), db);
|
|
7642
|
+
}
|
|
7643
|
+
return normalizedProjectIds;
|
|
7644
|
+
});
|
|
7645
|
+
}
|
|
7646
|
+
function readContactProjectMembership(contactId, projectId, db = getDatabase()) {
|
|
7647
|
+
return snapshot(stateRow(required2(contactId, "contact_id"), required2(projectId, "project_id"), db));
|
|
7648
|
+
}
|
|
7649
|
+
function listContactProjectMemberships(projectId, maxItems, db = getDatabase()) {
|
|
7650
|
+
const normalizedProjectId = required2(projectId, "project_id");
|
|
7651
|
+
if (!Number.isInteger(maxItems) || maxItems < 1)
|
|
7652
|
+
throw new Error("max_items must be a positive integer");
|
|
7653
|
+
const rows = db.query(`SELECT cp.contact_id, cp.project_id,
|
|
7654
|
+
COALESCE(state.linked, 1) AS linked,
|
|
7655
|
+
COALESCE(state.revision, 0) AS revision
|
|
7656
|
+
FROM contact_projects cp
|
|
7657
|
+
LEFT JOIN contact_project_membership_states state
|
|
7658
|
+
ON state.contact_id = cp.contact_id AND state.project_id = cp.project_id
|
|
7659
|
+
WHERE cp.project_id = ?
|
|
7660
|
+
ORDER BY cp.contact_id ASC
|
|
7661
|
+
LIMIT ?`).all(normalizedProjectId, maxItems + 1);
|
|
7662
|
+
if (rows.length > maxItems) {
|
|
7663
|
+
throw new Error(`contact project membership collection exceeds max_items=${maxItems}`);
|
|
7664
|
+
}
|
|
7665
|
+
const contactIds = rows.map((row) => row.contact_id);
|
|
7666
|
+
return {
|
|
7667
|
+
project_id: normalizedProjectId,
|
|
7668
|
+
contact_ids: contactIds,
|
|
7669
|
+
complete: true,
|
|
7670
|
+
membership_revision: `cpml_${digest(JSON.stringify(rows.map((row) => snapshot(row)))).slice(0, 32)}`
|
|
7671
|
+
};
|
|
7672
|
+
}
|
|
7673
|
+
function mutateContactProjectMembership(direction, rawInput, db = getDatabase()) {
|
|
7674
|
+
const input = normalizeInput(rawInput);
|
|
7675
|
+
return db.transaction(() => {
|
|
7676
|
+
const existingReceipt = db.query(`SELECT direction, contact_id, project_id, operation_id, step_id, expected_version,
|
|
7677
|
+
before_json, after_json, receipt_id
|
|
7678
|
+
FROM contact_project_membership_receipts
|
|
7679
|
+
WHERE operation_id = ? AND step_id = ?`).get(input.operation_id, input.step_id);
|
|
7680
|
+
if (existingReceipt)
|
|
7681
|
+
return replay(existingReceipt, direction, input);
|
|
7682
|
+
const contact = db.query(`SELECT id FROM contacts WHERE id = ?`).get(input.contact_id);
|
|
7683
|
+
if (!contact)
|
|
7684
|
+
throw new Error(`contact not found: ${input.contact_id}`);
|
|
7685
|
+
const beforeRow = stateRow(input.contact_id, input.project_id, db);
|
|
7686
|
+
const before = snapshot(beforeRow);
|
|
7687
|
+
if (before.version !== input.expected_version) {
|
|
7688
|
+
throw new ContactProjectMembershipConflictError(`contact project membership expected_version conflict: expected ${input.expected_version}, current ${before.version}`);
|
|
7689
|
+
}
|
|
7690
|
+
const desiredLinked = direction === "attach";
|
|
7691
|
+
const changed = before.linked !== desiredLinked;
|
|
7692
|
+
const afterRow = {
|
|
7693
|
+
...beforeRow,
|
|
7694
|
+
linked: desiredLinked ? 1 : 0,
|
|
7695
|
+
revision: changed ? beforeRow.revision + 1 : beforeRow.revision
|
|
7696
|
+
};
|
|
7697
|
+
const changedAt = now();
|
|
7698
|
+
db.run(`INSERT INTO contact_project_membership_states
|
|
7699
|
+
(contact_id, project_id, linked, revision, updated_at)
|
|
7700
|
+
VALUES (?, ?, ?, ?, ?)
|
|
7701
|
+
ON CONFLICT(contact_id, project_id) DO UPDATE SET
|
|
7702
|
+
linked = excluded.linked,
|
|
7703
|
+
revision = excluded.revision,
|
|
7704
|
+
updated_at = excluded.updated_at`, [input.contact_id, input.project_id, afterRow.linked, afterRow.revision, changedAt]);
|
|
7705
|
+
if (desiredLinked) {
|
|
7706
|
+
db.run(`INSERT OR IGNORE INTO contact_projects (contact_id, project_id) VALUES (?, ?)`, [input.contact_id, input.project_id]);
|
|
7707
|
+
} else {
|
|
7708
|
+
db.run(`DELETE FROM contact_projects WHERE contact_id = ? AND project_id = ?`, [input.contact_id, input.project_id]);
|
|
7709
|
+
}
|
|
7710
|
+
const after = snapshot(afterRow);
|
|
7711
|
+
const id = receiptId(input);
|
|
7712
|
+
db.run(`INSERT INTO contact_project_membership_receipts (
|
|
7713
|
+
receipt_id, direction, contact_id, project_id, operation_id, step_id,
|
|
7714
|
+
expected_version, before_json, after_json, created_at
|
|
7715
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, [
|
|
7716
|
+
id,
|
|
7717
|
+
direction,
|
|
7718
|
+
input.contact_id,
|
|
7719
|
+
input.project_id,
|
|
7720
|
+
input.operation_id,
|
|
7721
|
+
input.step_id,
|
|
7722
|
+
input.expected_version,
|
|
7723
|
+
JSON.stringify(before),
|
|
7724
|
+
JSON.stringify(after),
|
|
7725
|
+
changedAt
|
|
7726
|
+
]);
|
|
7727
|
+
return {
|
|
7728
|
+
outcome: changed ? "accepted" : "duplicate_of_accepted",
|
|
7729
|
+
operation_id: input.operation_id,
|
|
7730
|
+
step_id: input.step_id,
|
|
7731
|
+
before,
|
|
7732
|
+
after,
|
|
7733
|
+
receipt_id: id
|
|
7734
|
+
};
|
|
7735
|
+
});
|
|
7736
|
+
}
|
|
7737
|
+
var init_project_memberships2 = __esm(() => {
|
|
7738
|
+
init_database();
|
|
7739
|
+
init_project_memberships();
|
|
7740
|
+
});
|
|
7741
|
+
|
|
7451
7742
|
// src/db/contacts.ts
|
|
7452
7743
|
var exports_contacts = {};
|
|
7453
7744
|
__export(exports_contacts, {
|
|
@@ -8046,34 +8337,32 @@ function autoLinkContactToCompany(contactId, db) {
|
|
|
8046
8337
|
}
|
|
8047
8338
|
function linkContactToProject(contactId, projectId, db) {
|
|
8048
8339
|
const d = db || getDatabase();
|
|
8049
|
-
|
|
8340
|
+
setContactProjectMembershipWithoutReceipt(contactId, projectId, true, d);
|
|
8050
8341
|
}
|
|
8051
8342
|
function unlinkContactFromProject(contactId, projectId, db) {
|
|
8052
8343
|
const d = db || getDatabase();
|
|
8053
|
-
|
|
8344
|
+
setContactProjectMembershipWithoutReceipt(contactId, projectId, false, d);
|
|
8054
8345
|
}
|
|
8055
8346
|
function getContactProjectIds(contactId, db) {
|
|
8056
8347
|
const d = db || getDatabase();
|
|
8057
|
-
const rows = d.query(`SELECT project_id FROM contact_projects WHERE contact_id =
|
|
8348
|
+
const rows = d.query(`SELECT project_id FROM contact_projects WHERE contact_id = ? ORDER BY project_id ASC`).all(contactId);
|
|
8058
8349
|
return rows.map((r) => r.project_id);
|
|
8059
8350
|
}
|
|
8060
8351
|
function listContactIdsByProject(projectId, db) {
|
|
8061
8352
|
const d = db || getDatabase();
|
|
8062
|
-
const rows = d.query(`SELECT contact_id FROM contact_projects WHERE project_id =
|
|
8353
|
+
const rows = d.query(`SELECT contact_id FROM contact_projects WHERE project_id = ? ORDER BY contact_id ASC`).all(projectId);
|
|
8063
8354
|
return rows.map((r) => r.contact_id);
|
|
8064
8355
|
}
|
|
8065
8356
|
function setContactProjects(contactId, projectIds, db) {
|
|
8066
8357
|
const d = db || getDatabase();
|
|
8067
|
-
|
|
8068
|
-
for (const pid of projectIds) {
|
|
8069
|
-
d.run(`INSERT OR IGNORE INTO contact_projects (contact_id, project_id) VALUES (?, ?)`, [contactId, pid]);
|
|
8070
|
-
}
|
|
8358
|
+
replaceContactProjectMembershipsWithoutReceipts(contactId, projectIds, d);
|
|
8071
8359
|
}
|
|
8072
8360
|
var init_contacts = __esm(() => {
|
|
8073
8361
|
init_types();
|
|
8074
8362
|
init_database();
|
|
8075
8363
|
init_activity();
|
|
8076
8364
|
init_tombstones();
|
|
8365
|
+
init_project_memberships2();
|
|
8077
8366
|
});
|
|
8078
8367
|
|
|
8079
8368
|
// src/db/events.ts
|
|
@@ -21293,6 +21582,7 @@ function getStorageStatus(db = getDatabase()) {
|
|
|
21293
21582
|
|
|
21294
21583
|
// src/store/index.ts
|
|
21295
21584
|
init_contacts();
|
|
21585
|
+
init_project_memberships2();
|
|
21296
21586
|
|
|
21297
21587
|
// src/db/companies.ts
|
|
21298
21588
|
init_types();
|
|
@@ -22822,7 +23112,7 @@ init_database();
|
|
|
22822
23112
|
init_database();
|
|
22823
23113
|
import { existsSync as existsSync4, readFileSync as readFileSync2, writeFileSync, mkdirSync as mkdirSync3, unlinkSync } from "fs";
|
|
22824
23114
|
import { join as join3 } from "path";
|
|
22825
|
-
import { createCipheriv, createDecipheriv, randomBytes, pbkdf2Sync, createHash } from "crypto";
|
|
23115
|
+
import { createCipheriv, createDecipheriv, randomBytes, pbkdf2Sync, createHash as createHash2 } from "crypto";
|
|
22826
23116
|
var VAULT_DIR = getDataDir();
|
|
22827
23117
|
var VAULT_CONFIG = join3(VAULT_DIR, "vault.json");
|
|
22828
23118
|
var VAULT_SESSION = join3(VAULT_DIR, ".vault-session");
|
|
@@ -22868,7 +23158,7 @@ function initVault(passphrase) {
|
|
|
22868
23158
|
mkdirSync3(DOCUMENTS_DIR, { recursive: true });
|
|
22869
23159
|
const salt = randomBytes(32);
|
|
22870
23160
|
const key = deriveKey(passphrase, salt);
|
|
22871
|
-
const keyHash =
|
|
23161
|
+
const keyHash = createHash2("sha256").update(key).digest("hex");
|
|
22872
23162
|
const config2 = { salt: salt.toString("hex"), key_hash: keyHash, created_at: new Date().toISOString() };
|
|
22873
23163
|
writeFileSync(VAULT_CONFIG, JSON.stringify(config2, null, 2));
|
|
22874
23164
|
_derivedKey = key;
|
|
@@ -22883,7 +23173,7 @@ function unlockVault(passphrase) {
|
|
|
22883
23173
|
const config2 = JSON.parse(readFileSync2(VAULT_CONFIG, "utf-8"));
|
|
22884
23174
|
const salt = Buffer.from(config2.salt, "hex");
|
|
22885
23175
|
const key = deriveKey(passphrase, salt);
|
|
22886
|
-
const keyHash =
|
|
23176
|
+
const keyHash = createHash2("sha256").update(key).digest("hex");
|
|
22887
23177
|
if (keyHash !== config2.key_hash)
|
|
22888
23178
|
return false;
|
|
22889
23179
|
_derivedKey = key;
|
|
@@ -24419,6 +24709,15 @@ class LocalStore {
|
|
|
24419
24709
|
async listContactIdsByProject(projectId) {
|
|
24420
24710
|
return listContactIdsByProject(projectId, this.db);
|
|
24421
24711
|
}
|
|
24712
|
+
async readContactProjectMembership(contactId, projectId) {
|
|
24713
|
+
return readContactProjectMembership(contactId, projectId, this.db);
|
|
24714
|
+
}
|
|
24715
|
+
async listContactProjectMemberships(projectId, maxItems) {
|
|
24716
|
+
return listContactProjectMemberships(projectId, maxItems, this.db);
|
|
24717
|
+
}
|
|
24718
|
+
async mutateContactProjectMembership(direction, input) {
|
|
24719
|
+
return mutateContactProjectMembership(direction, input, this.db);
|
|
24720
|
+
}
|
|
24422
24721
|
async createCompany(input) {
|
|
24423
24722
|
return createCompany(input, this.db);
|
|
24424
24723
|
}
|
|
@@ -25041,20 +25340,33 @@ class ApiStore {
|
|
|
25041
25340
|
async findContactByEmailAddress(address) {
|
|
25042
25341
|
return this.getContactByEmail(address);
|
|
25043
25342
|
}
|
|
25044
|
-
async linkContactToProject() {
|
|
25045
|
-
|
|
25343
|
+
async linkContactToProject(contactId, projectId) {
|
|
25344
|
+
await this.client.transport.put(`/contacts/${this.enc(contactId)}/projects/${this.enc(projectId)}`);
|
|
25046
25345
|
}
|
|
25047
|
-
async unlinkContactFromProject() {
|
|
25048
|
-
|
|
25346
|
+
async unlinkContactFromProject(contactId, projectId) {
|
|
25347
|
+
await this.del(`/contacts/${this.enc(contactId)}/projects/${this.enc(projectId)}`);
|
|
25348
|
+
}
|
|
25349
|
+
async getContactProjectIds(contactId) {
|
|
25350
|
+
return pick2(await this.g(`/contacts/${this.enc(contactId)}/projects`), "project_ids") ?? [];
|
|
25351
|
+
}
|
|
25352
|
+
async setContactProjects(contactId, projectIds) {
|
|
25353
|
+
await this.client.transport.put(`/contacts/${this.enc(contactId)}/projects`, { project_ids: projectIds });
|
|
25354
|
+
}
|
|
25355
|
+
async listContactIdsByProject(projectId) {
|
|
25356
|
+
return pick2(await this.g(`/projects/${this.enc(projectId)}/contacts`), "contact_ids") ?? [];
|
|
25049
25357
|
}
|
|
25050
|
-
async
|
|
25051
|
-
return
|
|
25358
|
+
async readContactProjectMembership(contactId, projectId) {
|
|
25359
|
+
return this.client.transport.get(`/projects/${this.enc(projectId)}/contact-memberships/${this.enc(contactId)}`);
|
|
25052
25360
|
}
|
|
25053
|
-
async
|
|
25054
|
-
return
|
|
25361
|
+
async listContactProjectMemberships(projectId, maxItems) {
|
|
25362
|
+
return this.client.transport.get(`/projects/${this.enc(projectId)}/contact-memberships`, { query: { max_items: maxItems } });
|
|
25055
25363
|
}
|
|
25056
|
-
async
|
|
25057
|
-
return
|
|
25364
|
+
async mutateContactProjectMembership(direction, input) {
|
|
25365
|
+
return this.client.transport.post(`/projects/${this.enc(input.project_id)}/contact-memberships/${this.enc(input.contact_id)}/${direction}`, {
|
|
25366
|
+
operation_id: input.operation_id,
|
|
25367
|
+
step_id: input.step_id,
|
|
25368
|
+
expected_version: input.expected_version
|
|
25369
|
+
});
|
|
25058
25370
|
}
|
|
25059
25371
|
async createCompany(input) {
|
|
25060
25372
|
const res = await this.client.create("companies", stripUndefined(input));
|
|
@@ -27448,8 +27760,8 @@ var _contactsAgents = new Map;
|
|
|
27448
27760
|
var advancedHandlers = {
|
|
27449
27761
|
get_field_history: async (a) => json3({ history: await getStore().getFieldHistory(a.contact_id, a.field_name) }),
|
|
27450
27762
|
get_contact_at: async (a) => {
|
|
27451
|
-
const
|
|
27452
|
-
return json3({ contact_id: a.contact_id, timestamp: a.timestamp, snapshot });
|
|
27763
|
+
const snapshot2 = await getStore().getContactAt(a.contact_id, a.timestamp);
|
|
27764
|
+
return json3({ contact_id: a.contact_id, timestamp: a.timestamp, snapshot: snapshot2 });
|
|
27453
27765
|
},
|
|
27454
27766
|
get_job_history: async (a) => json3({ history: await getStore().getJobHistory(a.contact_id) }),
|
|
27455
27767
|
add_job_entry: async (a) => json3(await getStore().addJobEntry(a.contact_id, {
|
|
@@ -27925,11 +28237,11 @@ function jsonSchemaToZodType(schema) {
|
|
|
27925
28237
|
}
|
|
27926
28238
|
function jsonSchemaToZodObject(schema) {
|
|
27927
28239
|
const objectSchema = schema && typeof schema === "object" ? schema : {};
|
|
27928
|
-
const
|
|
28240
|
+
const required3 = new Set(objectSchema.required ?? []);
|
|
27929
28241
|
const shape = {};
|
|
27930
28242
|
for (const [key, value] of Object.entries(objectSchema.properties ?? {})) {
|
|
27931
28243
|
const propertySchema = jsonSchemaToZodType(value);
|
|
27932
|
-
shape[key] =
|
|
28244
|
+
shape[key] = required3.has(key) ? propertySchema : propertySchema.optional();
|
|
27933
28245
|
}
|
|
27934
28246
|
return describeSchema(exports_external.object(shape).passthrough(), objectSchema.description);
|
|
27935
28247
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"register-tools.d.ts","sourceRoot":"","sources":["../../src/mcp/register-tools.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAczE,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS,QAoBtD"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare function jsonSchemaToZodObject(schema: unknown): z.ZodObject<Record<string, z.ZodTypeAny>, "passthrough", z.ZodTypeAny, z.objectOutputType<Record<string, z.ZodTypeAny>, z.ZodTypeAny, "passthrough">, z.objectInputType<Record<string, z.ZodTypeAny>, z.ZodTypeAny, "passthrough">>;
|
|
3
|
+
//# sourceMappingURL=schema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/mcp/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAmB,MAAM,KAAK,CAAC;AAgEzC,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,OAAO,uOAWpD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage-tools.d.ts","sourceRoot":"","sources":["../../src/mcp/storage-tools.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AA0CzE,wBAAgB,4BAA4B,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA4CpE"}
|