@happyvertical/smrt-sales 0.57.37 → 0.57.39

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.
Files changed (68) hide show
  1. package/dist/agreements/models/Agreement.d.ts +2 -2
  2. package/dist/agreements/models/Agreement.d.ts.map +1 -1
  3. package/dist/agreements/models/AgreementExecution.d.ts +2 -2
  4. package/dist/agreements/models/AgreementExecution.d.ts.map +1 -1
  5. package/dist/agreements/models/AgreementExecutionEvent.d.ts +2 -2
  6. package/dist/agreements/models/AgreementExecutionEvent.d.ts.map +1 -1
  7. package/dist/agreements/models/ExecutedAgreement.d.ts +2 -2
  8. package/dist/agreements/models/ExecutedAgreement.d.ts.map +1 -1
  9. package/dist/agreements.js +2 -2
  10. package/dist/chunks/__smrt-register__-B1Rg_X-v.js +6 -0
  11. package/dist/chunks/__smrt-register__-B1Rg_X-v.js.map +1 -0
  12. package/dist/chunks/{agreements-RsyRLeDn.js → agreements-C8rxIVGB.js} +9 -9
  13. package/dist/chunks/agreements-C8rxIVGB.js.map +1 -0
  14. package/dist/chunks/{commissions-DSVGf1ZX.js → commissions-B1WnBKsn.js} +15 -15
  15. package/dist/chunks/commissions-B1WnBKsn.js.map +1 -0
  16. package/dist/chunks/{crm-BENK-hHd.js → crm-Bzk65hv_.js} +13 -13
  17. package/dist/chunks/crm-Bzk65hv_.js.map +1 -0
  18. package/dist/chunks/{referrals-o8qZG5fw.js → referrals-DE0tKm5G.js} +12 -12
  19. package/dist/chunks/referrals-DE0tKm5G.js.map +1 -0
  20. package/dist/commissions/models/Commission.d.ts +2 -2
  21. package/dist/commissions/models/Commission.d.ts.map +1 -1
  22. package/dist/commissions/models/CommissionAdjustment.d.ts +2 -2
  23. package/dist/commissions/models/CommissionAdjustment.d.ts.map +1 -1
  24. package/dist/commissions/models/CommissionPayout.d.ts +2 -2
  25. package/dist/commissions/models/CommissionPayout.d.ts.map +1 -1
  26. package/dist/commissions/models/CommissionPlan.d.ts +2 -2
  27. package/dist/commissions/models/CommissionPlan.d.ts.map +1 -1
  28. package/dist/commissions/models/Earner.d.ts +2 -2
  29. package/dist/commissions/models/Earner.d.ts.map +1 -1
  30. package/dist/commissions/models/EarnerSourceAttribution.d.ts +2 -2
  31. package/dist/commissions/models/EarnerSourceAttribution.d.ts.map +1 -1
  32. package/dist/commissions/models/EarningEvent.d.ts +2 -2
  33. package/dist/commissions/models/EarningEvent.d.ts.map +1 -1
  34. package/dist/commissions.js +2 -2
  35. package/dist/crm/models/Lead.d.ts +2 -2
  36. package/dist/crm/models/Lead.d.ts.map +1 -1
  37. package/dist/crm/models/Opportunity.d.ts +2 -2
  38. package/dist/crm/models/Opportunity.d.ts.map +1 -1
  39. package/dist/crm/models/OpportunityConversion.d.ts +2 -2
  40. package/dist/crm/models/OpportunityConversion.d.ts.map +1 -1
  41. package/dist/crm/models/SalesActivity.d.ts +2 -2
  42. package/dist/crm/models/SalesActivity.d.ts.map +1 -1
  43. package/dist/crm/models/SalesGovernanceEvent.d.ts +2 -2
  44. package/dist/crm/models/SalesGovernanceEvent.d.ts.map +1 -1
  45. package/dist/crm/models/SalesGovernanceState.d.ts +2 -2
  46. package/dist/crm/models/SalesGovernanceState.d.ts.map +1 -1
  47. package/dist/crm.js +2 -2
  48. package/dist/index.js +5 -5
  49. package/dist/manifest.json +155 -23
  50. package/dist/referrals/models/AttributionPolicy.d.ts +2 -2
  51. package/dist/referrals/models/AttributionPolicy.d.ts.map +1 -1
  52. package/dist/referrals/models/Referral.d.ts +2 -2
  53. package/dist/referrals/models/Referral.d.ts.map +1 -1
  54. package/dist/referrals/models/ReferralAgreement.d.ts +2 -2
  55. package/dist/referrals/models/ReferralAgreement.d.ts.map +1 -1
  56. package/dist/referrals/models/ReferralLink.d.ts +2 -2
  57. package/dist/referrals/models/ReferralLink.d.ts.map +1 -1
  58. package/dist/referrals/models/ReferralTermSnapshot.d.ts +2 -2
  59. package/dist/referrals/models/ReferralTermSnapshot.d.ts.map +1 -1
  60. package/dist/referrals.js +2 -2
  61. package/dist/smrt-knowledge.json +69 -3
  62. package/package.json +8 -8
  63. package/dist/chunks/__smrt-register__-o8Dm_Ogl.js +0 -6
  64. package/dist/chunks/__smrt-register__-o8Dm_Ogl.js.map +0 -1
  65. package/dist/chunks/agreements-RsyRLeDn.js.map +0 -1
  66. package/dist/chunks/commissions-DSVGf1ZX.js.map +0 -1
  67. package/dist/chunks/crm-BENK-hHd.js.map +0 -1
  68. package/dist/chunks/referrals-o8qZG5fw.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"crm-Bzk65hv_.js","names":["leadId","lead","opportunity","task","stage","db"],"sources":["../../src/crm/models/Lead.ts","../../src/crm/types.ts","../../src/crm/services/lead-inbox.ts","../../src/crm/models/Opportunity.ts","../../src/crm/models/PipelineStage.ts","../../src/crm/collections/PipelineStageCollection.ts","../../src/crm/models/SalesActivity.ts","../../src/crm/collections/SalesActivityCollection.ts","../../src/crm/collections/OpportunityCollection.ts","../../src/crm/models/PipelineDefinition.ts","../../src/crm/collections/PipelineDefinitionCollection.ts","../../src/crm/models/SalesRepresentative.ts","../../src/crm/collections/SalesRepresentativeCollection.ts","../../src/crm/collections/LeadCollection.ts","../../src/crm/models/OpportunityConversion.ts","../../src/crm/collections/OpportunityConversionCollection.ts","../../src/crm/services/governance-write.ts","../../src/crm/models/SalesGovernanceEvent.ts","../../src/crm/collections/SalesGovernanceEventCollection.ts","../../src/crm/models/SalesGovernanceState.ts","../../src/crm/collections/SalesGovernanceStateCollection.ts","../../src/crm/recipes.ts","../../src/crm/services/LeadConversionService.ts","../../src/crm/services/LeadWorkflowService.ts","../../src/crm/services/SalesGovernanceService.ts"],"sourcesContent":["/**\n * Lead — identified prospect with guarded lifecycle and audited merge support.\n * @packageDocumentation\n */\n\nimport {\n crossPackageRef,\n field,\n foreignKey,\n SmrtObject,\n type SmrtSaveOptions,\n smrt,\n} from '@happyvertical/smrt-core';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\nimport type { LeadOptions, LeadStatus } from '../types.js';\n\n/**\n * Legal status transitions for a Lead, keyed by the prior persisted status.\n * A status re-saved unchanged (no-op) and a brand-new row are always\n * permitted; this map governs *changes* only.\n *\n * Flow: `new → working|qualified|disqualified|merged`;\n * `working → qualified|disqualified|merged`; `qualified → merged`;\n * `disqualified → working|merged` (re-open); `merged` is terminal.\n *\n * Guards against raw mass-assignment forcing, e.g., a merged lead back to\n * `working` or a qualified lead back to `new` (commerce Contract pattern).\n */\nconst LEAD_STATUS_TRANSITIONS: Record<LeadStatus, LeadStatus[]> = {\n new: ['working', 'qualified', 'disqualified', 'merged'],\n working: ['qualified', 'disqualified', 'merged'],\n qualified: ['merged'],\n disqualified: ['working', 'merged'],\n merged: [],\n};\n\n/**\n * Module-scoped record of the status each Lead instance was loaded with, for\n * the save-time transition guard. WeakMap keeps it out of the schema and GCs\n * with the instance — same pattern as commerce Contract.\n */\nconst loadedLeadStatus = new WeakMap<Lead, LeadStatus>();\n\n/**\n * Lead is an identified prospect: a person/organization that showed intent\n * but has not yet been qualified into an Opportunity.\n *\n * Acquisition provenance is generic — `sourceKind`/`sourceId` name where the\n * lead came from (a campaign, an import, a referral, a form, …) without this\n * module knowing referral semantics; `acquisitionContext` preserves the raw\n * acquisition payload as JSON, and audited merges append the loser's context\n * under a `mergedSources` array so no acquisition history is ever lost.\n *\n * Leads are never deleted (audit trail): duplicates are merged via\n * `LeadCollection.mergeLeads()` — the loser becomes terminal `merged` with\n * `mergedIntoId` pointing at the winner, and its activities stay attached.\n *\n * @example\n * ```typescript\n * const leads = await LeadCollection.create({ db });\n * const lead = await leads.create({\n * name: 'Acme rooftop retrofit',\n * email: 'facilities@acme.test',\n * sourceKind: 'campaign',\n * sourceId: 'spring-2026',\n * });\n * const opportunity = await leads.qualify({ leadId: lead.id ?? '' });\n * ```\n */\n@TenantScoped({ mode: 'optional' })\n@smrt({\n api: { include: ['list', 'get', 'create', 'update'] }, // no delete — audit trail\n mcp: { include: ['list', 'get', 'create'] },\n cli: { skipApiCheck: true },\n})\nexport class Lead extends SmrtObject { static __smrtPackage__ = \"@happyvertical/smrt-sales\";\n /**\n * Tenant ID for multi-tenant isolation.\n * Nullable to support both tenant-scoped and global leads.\n */\n @tenantId({ nullable: true })\n tenantId: string | null = null;\n\n /** Short descriptive name of the prospect/deal-to-be. Required. */\n @field({ required: true, description: 'What you call this lead.' })\n name: string = '';\n\n /** Primary human contact name. */\n @field({ description: 'The person to talk to.' })\n contactName: string = '';\n\n /** Primary contact email. */\n @field({ description: 'Their email address.' })\n email: string = '';\n\n /** Primary contact phone. */\n @field({ description: 'Their phone number.' })\n phone: string = '';\n\n /** Prospect organization/company name. */\n @field({ description: 'The company they are with.' })\n organizationName: string = '';\n\n /**\n * Optional identity link once the prospect is a known Profile —\n * cross-package string reference to smrt-profiles.\n */\n @crossPackageRef('@happyvertical/smrt-profiles:Profile')\n profileId: string = '';\n\n /** Owning sales rep (assignment). Empty while unassigned. */\n @field({ description: 'The sales representative who owns this lead.' })\n @foreignKey('SalesRepresentative')\n ownerRepId: string = '';\n\n /** Lifecycle status; transitions are save-guarded (see module map). */\n @field({\n description: 'Where the lead stands, for example new or qualified.',\n })\n status: LeadStatus = 'new';\n\n /**\n * Generic acquisition-source kind (open string): `'campaign'`,\n * `'referral'`, `'import'`, `'web_form'`, … CRM stores the pointer without\n * interpreting it — referral attribution lives in the referrals module.\n */\n sourceKind: string = '';\n\n /** Identifier within the `sourceKind` namespace. */\n sourceId: string = '';\n\n /**\n * Preserved acquisition history as a JSON object string. Use\n * {@link getAcquisitionContext}/{@link setAcquisitionContext}. Merges append\n * the losing lead's context under a `mergedSources` array — both sides'\n * histories survive.\n */\n acquisitionContext: string = '{}';\n\n /**\n * Generic external intake-draft reference (open string) — e.g. the id of a\n * form submission, imported CSV row, or referral intake draft that this\n * lead was materialized from.\n */\n intakeRef: string = '';\n\n /**\n * Winner lead this row was merged into. Set (with status `merged`) by\n * `LeadCollection.mergeLeads()`; empty for live leads. Self-referencing FK.\n */\n @foreignKey('Lead')\n mergedIntoId: string = '';\n\n /** When the lead was qualified into an opportunity. */\n qualifiedAt: Date | null = null;\n\n /**\n * Free-form JSON object stored as a string. Use\n * {@link getMetadata}/{@link setMetadata} instead of parsing manually.\n */\n metadata: string = '{}';\n\n constructor(options: LeadOptions = {}) {\n super(options);\n if (options.tenantId !== undefined) this.tenantId = options.tenantId;\n if (options.name !== undefined) this.name = options.name;\n if (options.contactName !== undefined)\n this.contactName = options.contactName;\n if (options.email !== undefined) this.email = options.email;\n if (options.phone !== undefined) this.phone = options.phone;\n if (options.organizationName !== undefined)\n this.organizationName = options.organizationName;\n if (options.profileId !== undefined) this.profileId = options.profileId;\n if (options.ownerRepId !== undefined) this.ownerRepId = options.ownerRepId;\n if (options.status !== undefined) this.status = options.status;\n if (options.sourceKind !== undefined) this.sourceKind = options.sourceKind;\n if (options.sourceId !== undefined) this.sourceId = options.sourceId;\n if (options.acquisitionContext !== undefined)\n this.acquisitionContext = options.acquisitionContext;\n if (options.intakeRef !== undefined) this.intakeRef = options.intakeRef;\n if (options.mergedIntoId !== undefined)\n this.mergedIntoId = options.mergedIntoId;\n if (options.qualifiedAt !== undefined)\n this.qualifiedAt = options.qualifiedAt;\n if (options.metadata !== undefined) this.metadata = options.metadata;\n }\n\n /** Whether the lead has been folded into another lead (terminal). */\n isMerged(): boolean {\n return this.status === 'merged';\n }\n\n /** Whether the lead has been qualified into an opportunity. */\n isQualified(): boolean {\n return this.status === 'qualified';\n }\n\n /** Parse the acquisition-context JSON string; `{}` on malformed content. */\n getAcquisitionContext(): Record<string, unknown> {\n try {\n const parsed: unknown = JSON.parse(this.acquisitionContext);\n if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {\n return parsed as Record<string, unknown>;\n }\n return {};\n } catch {\n return {};\n }\n }\n\n /** Serialize and store the acquisition-context object. */\n setAcquisitionContext(context: Record<string, unknown>): void {\n this.acquisitionContext = JSON.stringify(context);\n }\n\n /** Parse the metadata JSON string; returns `{}` on malformed content. */\n getMetadata(): Record<string, unknown> {\n try {\n const parsed: unknown = JSON.parse(this.metadata);\n if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {\n return parsed as Record<string, unknown>;\n }\n return {};\n } catch {\n return {};\n }\n }\n\n /** Serialize and store the metadata object. */\n setMetadata(metadata: Record<string, unknown>): void {\n this.metadata = JSON.stringify(metadata);\n }\n\n /**\n * Capture the status the row was loaded with so the save-time transition\n * guard can reject illegal status flips made via raw field assignment\n * (mass-assignment on the generated update route, a stale caller, etc.).\n * Only persisted rows carry a prior status.\n */\n override async initialize(): Promise<this> {\n await super.initialize();\n if (await this.isSaved()) {\n loadedLeadStatus.set(this, this.status);\n }\n return this;\n }\n\n /**\n * Validate the status transition before persisting, then save. A forged\n * `status` (e.g. un-merging a merged lead) is rejected here regardless of\n * how the instance was constructed.\n */\n override async save(options?: SmrtSaveOptions): Promise<this> {\n const prior = await this.resolvePriorStatus();\n this.assertLeadStatusTransition(prior);\n const result = (await super.save(options)) as this;\n loadedLeadStatus.set(this, this.status);\n return result;\n }\n\n /**\n * Reject an illegal status flip done via raw assignment. No-op transitions\n * and brand-new rows are always allowed.\n */\n protected assertLeadStatusTransition(prior: LeadStatus | undefined): void {\n if (prior === undefined) return; // new row — any starting status is fine\n if (prior === this.status) return; // no-op re-save\n const allowed = LEAD_STATUS_TRANSITIONS[prior] ?? [];\n if (!allowed.includes(this.status)) {\n throw new Error(\n `Lead ${this.name || this.id}: illegal status transition ` +\n `'${prior}' → '${this.status}'.`,\n );\n }\n }\n\n /**\n * Resolve the AUTHORITATIVE prior status (commerce Contract pattern). The\n * WeakMap is only populated when {@link initialize} loaded the row from the\n * DB; it is empty for an instance built via\n * `collection.create({ id: <existing>, _skipLoad: true })` — the upsert\n * path that writes onto an existing row without hydrating it. Trusting an\n * empty WeakMap there would treat the write as a brand-new row and skip the\n * guard entirely (a poisonable prior-state).\n *\n * So when this instance carries an `id`, read the persisted row straight\n * from the database and treat its `status` as the prior. Only when no row\n * exists (truly new) do we fall back to the WeakMap. The raw row's `status`\n * column is single-word (no snake_case transform).\n */\n protected async resolvePriorStatus(): Promise<LeadStatus | undefined> {\n if (this.id) {\n try {\n const row = await this.db.get(this.tableName, { id: this.id });\n if (row && row.status != null) {\n return row.status as LeadStatus;\n }\n } catch {\n // DB not ready / table absent — fall through to the in-memory record.\n }\n }\n return loadedLeadStatus.get(this);\n }\n}\n\nexport default Lead;\n","/**\n * Shared types, status unions, and operation contracts for the CRM module.\n *\n * Statuses are string-literal unions derived from `as const` arrays so both\n * the runtime list (for validation/UI pickers) and the compile-time union stay\n * in lockstep. All monetary fields across the module are integer cents\n * (`*Cents`, INTEGER columns); rates/probabilities are decimals in `0`–`1`\n * (DECIMAL columns). See `packages/sales/AGENTS.md`.\n *\n * @packageDocumentation\n */\n\nimport type { SmrtObjectOptions } from '@happyvertical/smrt-core';\nimport type { Lead } from './models/Lead.js';\nimport type { OpportunityConversion } from './models/OpportunityConversion.js';\nimport type { PipelineDefinition } from './models/PipelineDefinition.js';\nimport type { PipelineStage } from './models/PipelineStage.js';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Status unions\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** Lifecycle statuses for a {@link SalesRepresentativeOptions | SalesRepresentative} role. */\nexport const SALES_REPRESENTATIVE_STATUSES = [\n 'active',\n 'inactive',\n 'suspended',\n] as const;\nexport type SalesRepresentativeStatus =\n (typeof SALES_REPRESENTATIVE_STATUSES)[number];\n\n/**\n * Lead lifecycle statuses. Transitions are guarded at save time (see the\n * `LEAD_STATUS_TRANSITIONS` map in `models/Lead.ts`):\n * `new → working|qualified|disqualified|merged`,\n * `working → qualified|disqualified|merged`, `qualified → merged`,\n * `disqualified → working|merged`; `merged` is terminal.\n */\nexport const LEAD_STATUSES = [\n 'new',\n 'working',\n 'qualified',\n 'disqualified',\n 'merged',\n] as const;\nexport type LeadStatus = (typeof LEAD_STATUSES)[number];\n\n/** Pipeline definition statuses — archived pipelines stay readable for history. */\nexport const PIPELINE_STATUSES = ['active', 'archived'] as const;\nexport type PipelineStatus = (typeof PIPELINE_STATUSES)[number];\n\n/**\n * Opportunity lifecycle statuses. `open → won|lost` is enforced at save time;\n * `won` and `lost` are terminal (post-terminal stage moves are rejected).\n */\nexport const OPPORTUNITY_STATUSES = ['open', 'won', 'lost'] as const;\nexport type OpportunityStatus = (typeof OPPORTUNITY_STATUSES)[number];\n\n/** The two subject types a SalesActivity row can attach to. */\nexport const SALES_ACTIVITY_SUBJECT_KINDS = ['lead', 'opportunity'] as const;\nexport type SalesActivitySubjectKind =\n (typeof SALES_ACTIVITY_SUBJECT_KINDS)[number];\n\n/**\n * Recommended activity kinds for the SalesActivity audit/next-action trail.\n *\n * The `activityKind` field itself is an OPEN string — consumers may record\n * their own kinds (e.g. `'demo'`, `'site_visit'`) without a schema change.\n * Framework-written kinds (`qualification`, `stage_change`, `merge`) come\n * from this list.\n */\nexport const SALES_ACTIVITY_KINDS = [\n 'note',\n 'call',\n 'email',\n 'meeting',\n 'task',\n 'assignment',\n 'qualification',\n 'stage_change',\n 'merge',\n 'status_change',\n] as const;\nexport type RecommendedSalesActivityKind =\n (typeof SALES_ACTIVITY_KINDS)[number];\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Default pipeline seed\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Natural `key` of the seeded default pipeline\n * (`PipelineDefinitionCollection.ensureDefaultPipeline()`).\n */\nexport const DEFAULT_PIPELINE_KEY = 'default';\n\n/** Seed shape for one default pipeline stage. */\nexport interface DefaultPipelineStageSeed {\n key: string;\n name: string;\n /** Default win probability adopted by opportunities entering the stage. */\n probability: number;\n /** Terminal-won flag — entering this stage closes the opportunity as won. */\n isWon?: boolean;\n /** Terminal-lost flag — entering this stage closes the opportunity as lost. */\n isLost?: boolean;\n}\n\n/**\n * The 7 default stages seeded by `ensureDefaultPipeline()`, in order.\n *\n * Seeded stages are ordinary rows: consumers may rename, reorder, re-weight,\n * or add stages via normal PipelineStage collection operations without any\n * Lead/Opportunity model change. Sort order is seeded in steps of 10 to leave\n * headroom for inserting custom stages between defaults.\n */\nexport const DEFAULT_PIPELINE_STAGES: readonly DefaultPipelineStageSeed[] = [\n { key: 'new', name: 'New', probability: 0.1 },\n { key: 'qualified', name: 'Qualified', probability: 0.25 },\n { key: 'discovery', name: 'Discovery', probability: 0.4 },\n { key: 'proposal', name: 'Proposal', probability: 0.6 },\n { key: 'negotiation', name: 'Negotiation', probability: 0.8 },\n { key: 'closed_won', name: 'Closed Won', probability: 1.0, isWon: true },\n { key: 'closed_lost', name: 'Closed Lost', probability: 0.0, isLost: true },\n] as const;\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Model constructor options\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface SalesRepresentativeOptions extends SmrtObjectOptions {\n tenantId?: string | null;\n profileId?: string;\n earnerId?: string;\n status?: SalesRepresentativeStatus;\n title?: string;\n metadata?: string;\n}\n\nexport interface LeadOptions extends SmrtObjectOptions {\n tenantId?: string | null;\n name?: string;\n contactName?: string;\n email?: string;\n phone?: string;\n organizationName?: string;\n profileId?: string;\n ownerRepId?: string;\n status?: LeadStatus;\n sourceKind?: string;\n sourceId?: string;\n acquisitionContext?: string;\n intakeRef?: string;\n mergedIntoId?: string;\n qualifiedAt?: Date | null;\n metadata?: string;\n}\n\nexport interface PipelineDefinitionOptions extends SmrtObjectOptions {\n tenantId?: string | null;\n key?: string;\n name?: string;\n isDefault?: boolean;\n status?: PipelineStatus;\n metadata?: string;\n}\n\nexport interface PipelineStageOptions extends SmrtObjectOptions {\n tenantId?: string | null;\n pipelineId?: string;\n key?: string;\n name?: string;\n sortOrder?: number;\n probability?: number;\n isWon?: boolean;\n isLost?: boolean;\n metadata?: string;\n}\n\nexport interface OpportunityOptions extends SmrtObjectOptions {\n tenantId?: string | null;\n name?: string;\n leadId?: string;\n ownerRepId?: string;\n pipelineId?: string;\n stageId?: string;\n expectedValueCents?: number;\n currency?: string;\n probability?: number;\n expectedCloseAt?: Date | null;\n status?: OpportunityStatus;\n outcomeReason?: string;\n wonAt?: Date | null;\n lostAt?: Date | null;\n sourceKind?: string;\n sourceId?: string;\n metadata?: string;\n}\n\nexport interface SalesActivityOptions extends SmrtObjectOptions {\n tenantId?: string | null;\n subjectKind?: SalesActivitySubjectKind;\n subjectId?: string;\n activityKind?: string;\n summary?: string;\n dueAt?: Date | null;\n completedAt?: Date | null;\n actorProfileId?: string;\n metadata?: string;\n}\n\nexport interface OpportunityConversionOptions extends SmrtObjectOptions {\n tenantId?: string | null;\n opportunityId?: string;\n targetKind?: string;\n targetId?: string;\n note?: string;\n metadata?: string;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Collection operation contracts\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** Params for `PipelineDefinitionCollection.ensureDefaultPipeline()`. */\nexport interface EnsureDefaultPipelineParams {\n /**\n * Explicit tenant scope for the seeded pipeline/stages. Usually omitted —\n * an ambient `withTenant()` context auto-populates tenancy; pass it when\n * seeding outside a tenant context on behalf of a specific tenant.\n */\n tenantId?: string | null;\n}\n\n/** Result of `PipelineDefinitionCollection.ensureDefaultPipeline()`. */\nexport interface EnsureDefaultPipelineResult {\n pipeline: PipelineDefinition;\n /** All stages of the pipeline ordered by `sortOrder`. */\n stages: PipelineStage[];\n}\n\n/** Params for `LeadCollection.qualify()`. */\nexport interface QualifyLeadParams {\n leadId: string;\n /** Profile of the actor qualifying the lead, for both audit rows. */\n actorProfileId?: string;\n /** Opportunity name; defaults to the lead's name. */\n opportunityName?: string;\n /** Target pipeline; defaults to the seeded default pipeline. */\n pipelineId?: string;\n /** Owning rep for the opportunity; defaults to the lead's `ownerRepId`. */\n ownerRepId?: string;\n /** Expected deal value in integer cents. */\n expectedValueCents?: number;\n /** ISO 4217 currency code; defaults to `'USD'`. */\n currency?: string;\n expectedCloseAt?: Date | null;\n /** Clock for the `qualifiedAt` stamp; defaults to now. */\n now?: Date;\n}\n\n/** Params for `LeadCollection.mergeLeads()`. */\nexport interface MergeLeadsParams {\n /** The surviving (canonical) lead. */\n winnerId: string;\n /** The duplicate lead to fold into the winner; becomes terminal `merged`. */\n loserId: string;\n /** Profile of the operator performing the merge, for the audit trail. */\n actorProfileId?: string;\n /** Human-readable merge reason, recorded in both audit rows. */\n reason?: string;\n}\n\n/** Result of `LeadCollection.mergeLeads()`. */\nexport interface MergeLeadsResult {\n winner: Lead;\n loser: Lead;\n}\n\n/** Params for `OpportunityCollection.moveToStage()`. */\nexport interface MoveToStageParams {\n opportunityId: string;\n /** Target stage — must belong to the opportunity's pipeline. */\n stageId: string;\n /** Profile of the actor moving the stage, for the audit trail. */\n actorProfileId?: string;\n /**\n * Outcome note recorded on the opportunity (conventionally set when moving\n * into a terminal-lost stage, e.g. `'budget cut'`).\n */\n outcomeReason?: string;\n /** Override the stage's default probability for this opportunity. */\n probabilityOverride?: number;\n /** Clock for the `wonAt`/`lostAt` stamps; defaults to now. */\n now?: Date;\n}\n\n/** Params for `OpportunityConversionCollection.recordConversion()`. */\nexport interface RecordConversionParams {\n opportunityId: string;\n /** Downstream record kind — open string: `'client'`, `'project'`, `'contract'`, `'subscription'`, … */\n targetKind: string;\n /** Identifier of the downstream record (created by the caller, never by CRM). */\n targetId: string;\n note?: string;\n}\n\n/** Result of `OpportunityConversionCollection.recordConversion()`. */\nexport interface RecordConversionResult {\n conversion: OpportunityConversion;\n /** `false` when the natural-key link already existed (idempotent repeat). */\n created: boolean;\n}\n","/**\n * Public contracts and SQL-safe option normalization for the Lead inbox.\n * @packageDocumentation\n */\n\nimport type { Lead } from '../models/Lead.js';\nimport type { SalesActivity } from '../models/SalesActivity.js';\nimport type { SalesRepresentative } from '../models/SalesRepresentative.js';\nimport { LEAD_STATUSES, type LeadStatus } from '../types.js';\n\n/** Stable inbox orderings supported on every SQL adapter. */\nexport type LeadInboxSort = 'created' | 'next_action' | 'name';\n\n/** Filters and page bounds for `LeadCollection.listInbox()`. */\nexport interface LeadInboxOptions {\n status?: LeadStatus;\n ownerRepId?: string;\n unassigned?: boolean;\n overdue?: boolean;\n search?: string;\n sort?: LeadInboxSort;\n limit: number;\n offset: number;\n /** Evaluation instant for the overdue filter/count; defaults to now. */\n now?: Date;\n}\n\n/** Batched owner and next-action projection for one hydrated Lead. */\nexport interface LeadInboxItem {\n lead: Lead;\n owner: SalesRepresentative | null;\n nextAction: SalesActivity | null;\n}\n\n/** Counts used by the lifecycle and derived inbox tabs. */\nexport type LeadInboxStatusCounts = Record<\n LeadStatus | 'all' | 'unassigned' | 'overdue',\n number\n>;\n\n/** A page of hydrated Leads plus its batched relationship projection. */\nexport interface LeadInboxResult {\n leads: Lead[];\n items: LeadInboxItem[];\n total: number;\n statusCounts: LeadInboxStatusCounts;\n}\n\nexport interface NormalizedLeadInboxOptions {\n status?: LeadStatus;\n ownerRepId?: string;\n unassigned: boolean;\n overdue: boolean;\n search?: string;\n sort: LeadInboxSort;\n limit: number;\n offset: number;\n now: Date;\n}\n\nconst INBOX_SORTS = new Set<LeadInboxSort>(['created', 'next_action', 'name']);\n\n/** Validate caller-controlled options before they reach SQL. */\nexport function normalizeLeadInboxOptions(\n options: LeadInboxOptions,\n): NormalizedLeadInboxOptions {\n if (!options || typeof options !== 'object') {\n throw new Error('LeadCollection.listInbox: options are required');\n }\n if (\n !Number.isSafeInteger(options.limit) ||\n options.limit < 1 ||\n options.limit > 100\n ) {\n throw new Error(\n 'LeadCollection.listInbox: limit must be an integer between 1 and 100',\n );\n }\n if (!Number.isSafeInteger(options.offset) || options.offset < 0) {\n throw new Error(\n 'LeadCollection.listInbox: offset must be a non-negative integer',\n );\n }\n if (options.status !== undefined && !LEAD_STATUSES.includes(options.status)) {\n throw new Error(\n `LeadCollection.listInbox: unsupported status '${String(options.status)}'`,\n );\n }\n const sort = options.sort ?? 'created';\n if (!INBOX_SORTS.has(sort)) {\n throw new Error(\n `LeadCollection.listInbox: unsupported sort '${String(sort)}'`,\n );\n }\n if (\n options.ownerRepId !== undefined &&\n (typeof options.ownerRepId !== 'string' || !options.ownerRepId.trim())\n ) {\n throw new Error(\n 'LeadCollection.listInbox: ownerRepId must be a non-empty string',\n );\n }\n if (options.search !== undefined && typeof options.search !== 'string') {\n throw new Error('LeadCollection.listInbox: search must be a string');\n }\n if (\n options.now !== undefined &&\n (!(options.now instanceof Date) || !Number.isFinite(options.now.getTime()))\n ) {\n throw new Error('LeadCollection.listInbox: now must be a valid Date');\n }\n\n const search = options.search?.trim();\n return {\n ...(options.status ? { status: options.status } : {}),\n ...(options.ownerRepId?.trim()\n ? { ownerRepId: options.ownerRepId.trim() }\n : {}),\n ...(search ? { search } : {}),\n unassigned: options.unassigned === true,\n overdue: options.overdue === true,\n sort,\n limit: options.limit,\n offset: options.offset,\n now: options.now ?? new Date(),\n };\n}\n\n/** Empty explicit count shape, including zero-count lifecycle tabs. */\nexport function emptyLeadInboxStatusCounts(): LeadInboxStatusCounts {\n return {\n all: 0,\n new: 0,\n working: 0,\n qualified: 0,\n disqualified: 0,\n merged: 0,\n unassigned: 0,\n overdue: 0,\n };\n}\n","/**\n * Opportunity — a qualified engagement moving through a pipeline.\n * @packageDocumentation\n */\n\nimport {\n field,\n foreignKey,\n SmrtObject,\n type SmrtSaveOptions,\n smrt,\n} from '@happyvertical/smrt-core';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\nimport type { OpportunityOptions, OpportunityStatus } from '../types.js';\n\n/**\n * Legal status transitions for an Opportunity, keyed by the prior persisted\n * status. A status re-saved unchanged (no-op) and a brand-new row are always\n * permitted; this map governs *changes* only.\n *\n * Flow: `open → won|lost`; `won` and `lost` are terminal. Guards against raw\n * mass-assignment re-opening a closed deal (commerce Contract pattern).\n */\nconst OPPORTUNITY_STATUS_TRANSITIONS: Record<\n OpportunityStatus,\n OpportunityStatus[]\n> = {\n open: ['won', 'lost'],\n won: [],\n lost: [],\n};\n\n/**\n * Module-scoped record of the status each Opportunity instance was loaded\n * with, for the save-time transition guard. WeakMap keeps it out of the\n * schema and GCs with the instance.\n */\nconst loadedOpportunityStatus = new WeakMap<Opportunity, OpportunityStatus>();\n\n/**\n * Opportunity is a qualified engagement: a deal with an expected value moving\n * through the stages of a PipelineDefinition.\n *\n * Money is integer cents (`expectedValueCents`, INTEGER) with an ISO 4217\n * `currency`; `probability` is a decimal in `0`–`1` (DECIMAL). Stage\n * movement goes through `OpportunityCollection.moveToStage()`, which\n * validates the stage belongs to the opportunity's pipeline, adopts the\n * stage's probability, closes the deal on terminal stages, and writes a\n * `stage_change` SalesActivity. `sourceKind`/`sourceId` are copied from the\n * originating Lead at qualification time so reporting can attribute won\n * revenue without joining back through leads.\n *\n * @example\n * ```typescript\n * const opportunities = await OpportunityCollection.create({ db });\n * const moved = await opportunities.moveToStage({\n * opportunityId: opportunity.id ?? '',\n * stageId: proposalStage.id ?? '',\n * });\n * ```\n */\n@TenantScoped({ mode: 'optional' })\n@smrt({\n api: { include: ['list', 'get', 'create', 'update'] },\n mcp: { include: ['list', 'get'] },\n cli: { skipApiCheck: true },\n})\nexport class Opportunity extends SmrtObject { static __smrtPackage__ = \"@happyvertical/smrt-sales\";\n /**\n * Tenant ID for multi-tenant isolation.\n * Nullable to support both tenant-scoped and global opportunities.\n */\n @tenantId({ nullable: true })\n tenantId: string | null = null;\n\n /** Deal name shown on boards and lists. Required. */\n @field({ required: true, description: 'What you call this deal.' })\n name: string = '';\n\n /** Originating lead (empty for opportunities created directly). */\n @field({ description: 'The lead it came from.' })\n @foreignKey('Lead')\n leadId: string = '';\n\n /** Owning sales rep. */\n @field({ description: 'The sales representative who owns this deal.' })\n @foreignKey('SalesRepresentative')\n ownerRepId: string = '';\n\n /** Pipeline the deal moves through. */\n @field({ description: 'The pipeline it moves through.' })\n @foreignKey('PipelineDefinition')\n pipelineId: string = '';\n\n /** Current stage within the pipeline. */\n @field({ description: 'The stage it is at now.' })\n @foreignKey('PipelineStage')\n stageId: string = '';\n\n /** Expected deal value in integer cents (INTEGER column). */\n @field({ description: 'What you expect the deal to be worth, in cents.' })\n expectedValueCents: number = 0;\n\n /** ISO 4217 currency code for `expectedValueCents`. */\n @field({ description: 'The currency of that value.' })\n currency: string = 'USD';\n\n /**\n * Win probability (`0`–`1`, DECIMAL). Adopted from the current stage's\n * default on stage moves unless explicitly overridden.\n */\n @field({\n description: 'How likely it is to close, as a decimal (0.5 is 50%).',\n })\n probability: number = 0.0;\n\n /** Forecasted close date. */\n @field({ description: 'When you expect it to close.' })\n expectedCloseAt: Date | null = null;\n\n /** Lifecycle status; `open → won|lost` is save-guarded, terminal after. */\n @field({ description: 'open, won or lost.' })\n status: OpportunityStatus = 'open';\n\n /**\n * Human-readable outcome note — conventionally the loss reason\n * (`'budget cut'`) or a win annotation.\n */\n outcomeReason: string = '';\n\n /** When the deal closed as won. */\n wonAt: Date | null = null;\n\n /** When the deal closed as lost. */\n lostAt: Date | null = null;\n\n /**\n * Acquisition source copied from the originating lead at qualification\n * time (open string), kept denormalized for reporting.\n */\n sourceKind: string = '';\n\n /** Identifier within the `sourceKind` namespace (copied from the lead). */\n sourceId: string = '';\n\n /**\n * Free-form JSON object stored as a string. Use\n * {@link getMetadata}/{@link setMetadata} instead of parsing manually.\n */\n metadata: string = '{}';\n\n constructor(options: OpportunityOptions = {}) {\n super(options);\n if (options.tenantId !== undefined) this.tenantId = options.tenantId;\n if (options.name !== undefined) this.name = options.name;\n if (options.leadId !== undefined) this.leadId = options.leadId;\n if (options.ownerRepId !== undefined) this.ownerRepId = options.ownerRepId;\n if (options.pipelineId !== undefined) this.pipelineId = options.pipelineId;\n if (options.stageId !== undefined) this.stageId = options.stageId;\n if (options.expectedValueCents !== undefined)\n this.expectedValueCents = options.expectedValueCents;\n if (options.currency !== undefined) this.currency = options.currency;\n if (options.probability !== undefined)\n this.probability = options.probability;\n if (options.expectedCloseAt !== undefined)\n this.expectedCloseAt = options.expectedCloseAt;\n if (options.status !== undefined) this.status = options.status;\n if (options.outcomeReason !== undefined)\n this.outcomeReason = options.outcomeReason;\n if (options.wonAt !== undefined) this.wonAt = options.wonAt;\n if (options.lostAt !== undefined) this.lostAt = options.lostAt;\n if (options.sourceKind !== undefined) this.sourceKind = options.sourceKind;\n if (options.sourceId !== undefined) this.sourceId = options.sourceId;\n if (options.metadata !== undefined) this.metadata = options.metadata;\n }\n\n /** Whether the deal is still in play. */\n isOpen(): boolean {\n return this.status === 'open';\n }\n\n /** Whether the deal closed (won or lost). */\n isClosed(): boolean {\n return this.status !== 'open';\n }\n\n /** Parse the metadata JSON string; returns `{}` on malformed content. */\n getMetadata(): Record<string, unknown> {\n try {\n const parsed: unknown = JSON.parse(this.metadata);\n if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {\n return parsed as Record<string, unknown>;\n }\n return {};\n } catch {\n return {};\n }\n }\n\n /** Serialize and store the metadata object. */\n setMetadata(metadata: Record<string, unknown>): void {\n this.metadata = JSON.stringify(metadata);\n }\n\n /**\n * Capture the status the row was loaded with so the save-time transition\n * guard can reject illegal status flips made via raw field assignment.\n * Only persisted rows carry a prior status.\n */\n override async initialize(): Promise<this> {\n await super.initialize();\n if (await this.isSaved()) {\n loadedOpportunityStatus.set(this, this.status);\n }\n return this;\n }\n\n /**\n * Validate the status transition before persisting, then save. A forged\n * `status` (e.g. re-opening a lost deal) is rejected here regardless of\n * how the instance was constructed.\n */\n override async save(options?: SmrtSaveOptions): Promise<this> {\n const prior = await this.resolvePriorStatus();\n this.assertOpportunityStatusTransition(prior);\n const result = (await super.save(options)) as this;\n loadedOpportunityStatus.set(this, this.status);\n return result;\n }\n\n /**\n * Reject an illegal status flip done via raw assignment. No-op transitions\n * and brand-new rows are always allowed.\n */\n protected assertOpportunityStatusTransition(\n prior: OpportunityStatus | undefined,\n ): void {\n if (prior === undefined) return; // new row — any starting status is fine\n if (prior === this.status) return; // no-op re-save\n const allowed = OPPORTUNITY_STATUS_TRANSITIONS[prior] ?? [];\n if (!allowed.includes(this.status)) {\n throw new Error(\n `Opportunity ${this.name || this.id}: illegal status transition ` +\n `'${prior}' → '${this.status}'.`,\n );\n }\n }\n\n /**\n * Resolve the AUTHORITATIVE prior status (commerce Contract pattern): when\n * this instance carries an `id`, re-read the persisted row and use its\n * `status` as the prior — a create-onto-existing is an update, and an\n * un-hydrated instance must not bypass the guard. Falls back to the\n * load-time WeakMap (empty for truly new rows → `undefined` = new).\n */\n protected async resolvePriorStatus(): Promise<OpportunityStatus | undefined> {\n if (this.id) {\n try {\n const row = await this.db.get(this.tableName, { id: this.id });\n if (row && row.status != null) {\n return row.status as OpportunityStatus;\n }\n } catch {\n // DB not ready / table absent — fall through to the in-memory record.\n }\n }\n return loadedOpportunityStatus.get(this);\n }\n}\n\nexport default Opportunity;\n","/**\n * PipelineStage — one ordered step of a PipelineDefinition.\n * @packageDocumentation\n */\n\nimport { field, foreignKey, SmrtObject, smrt } from '@happyvertical/smrt-core';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\nimport type { PipelineStageOptions } from '../types.js';\n\n/**\n * PipelineStage is a configurable step within a pipeline. Stages carry the\n * default win `probability` an opportunity adopts on entry and the terminal\n * flags (`isWon`/`isLost`) that close an opportunity when it moves in\n * (see `OpportunityCollection.moveToStage()`).\n *\n * Natural key `(pipeline_id, key)` (`conflictColumns`) — re-seeding a stage\n * key within a pipeline upserts. Stages are plain rows: rename, re-weight,\n * insert, or reorder (via `sortOrder`) with normal collection operations —\n * no Lead/Opportunity model change is ever needed.\n *\n * @example\n * ```typescript\n * const stages = await PipelineStageCollection.create({ db });\n * await stages.create({\n * pipelineId: pipeline.id,\n * key: 'legal_review',\n * name: 'Legal Review',\n * sortOrder: 45, // between seeded proposal (40) and negotiation (50)\n * probability: 0.7,\n * });\n * ```\n */\n@TenantScoped({ mode: 'optional' })\n@smrt({\n api: { include: ['list', 'get', 'create', 'update'] },\n mcp: { include: ['list', 'get'] },\n cli: false,\n conflictColumns: ['pipeline_id', 'key'],\n})\nexport class PipelineStage extends SmrtObject { static __smrtPackage__ = \"@happyvertical/smrt-sales\";\n /**\n * Tenant ID for multi-tenant isolation.\n * Nullable to support both tenant-scoped and global stages.\n */\n @tenantId({ nullable: true })\n tenantId: string | null = null;\n\n /** Owning pipeline. Required. */\n @field({ description: 'The pipeline this stage belongs to.' })\n @foreignKey('PipelineDefinition', { required: true })\n pipelineId: string = '';\n\n /**\n * Stable machine key, unique within the pipeline (natural key with\n * `pipelineId`). Required — e.g. `'proposal'`, `'closed_won'`.\n */\n @field({ required: true, description: 'A short code for the stage.' })\n key: string = '';\n\n /** Human-readable stage name shown on board columns. */\n @field({ description: 'What the stage is called.' })\n name: string = '';\n\n /** Ordering within the pipeline (ascending). Seeded in steps of 10. */\n @field({ description: 'Where it comes in the pipeline.' })\n sortOrder: number = 0;\n\n /**\n * Default win probability (`0`–`1`, DECIMAL) adopted by an opportunity\n * entering this stage unless the move overrides it.\n */\n @field({\n description: 'How likely a deal at this stage is to close, as a decimal.',\n })\n probability: number = 0.0;\n\n /** Terminal flag: moving an opportunity here closes it as `won`. */\n @field({\n description: 'Whether reaching this stage closes the deal as won.',\n })\n isWon: boolean = false;\n\n /** Terminal flag: moving an opportunity here closes it as `lost`. */\n @field({\n description: 'Whether reaching this stage closes the deal as lost.',\n })\n isLost: boolean = false;\n\n /**\n * Free-form JSON object stored as a string. Use\n * {@link getMetadata}/{@link setMetadata} instead of parsing manually.\n */\n metadata: string = '{}';\n\n constructor(options: PipelineStageOptions = {}) {\n super(options);\n if (options.tenantId !== undefined) this.tenantId = options.tenantId;\n if (options.pipelineId !== undefined) this.pipelineId = options.pipelineId;\n if (options.key !== undefined) this.key = options.key;\n if (options.name !== undefined) this.name = options.name;\n if (options.sortOrder !== undefined) this.sortOrder = options.sortOrder;\n if (options.probability !== undefined)\n this.probability = options.probability;\n if (options.isWon !== undefined) this.isWon = options.isWon;\n if (options.isLost !== undefined) this.isLost = options.isLost;\n if (options.metadata !== undefined) this.metadata = options.metadata;\n }\n\n /** Whether entering this stage closes the opportunity (won or lost). */\n isTerminal(): boolean {\n return this.isWon || this.isLost;\n }\n\n /** Parse the metadata JSON string; returns `{}` on malformed content. */\n getMetadata(): Record<string, unknown> {\n try {\n const parsed: unknown = JSON.parse(this.metadata);\n if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {\n return parsed as Record<string, unknown>;\n }\n return {};\n } catch {\n return {};\n }\n }\n\n /** Serialize and store the metadata object. */\n setMetadata(metadata: Record<string, unknown>): void {\n this.metadata = JSON.stringify(metadata);\n }\n}\n\nexport default PipelineStage;\n","/**\n * PipelineStageCollection — collection manager for PipelineStage.\n * @packageDocumentation\n */\n\nimport { SmrtCollection } from '@happyvertical/smrt-core';\nimport { PipelineStage } from '../models/PipelineStage.js';\n\nexport class PipelineStageCollection extends SmrtCollection<PipelineStage> {\n static readonly _itemClass = PipelineStage;\n\n /**\n * List a pipeline's stages in board order.\n *\n * @param pipelineId - Owning PipelineDefinition id\n * @returns Stages ordered by `sortOrder` ascending\n */\n async findByPipeline(pipelineId: string): Promise<PipelineStage[]> {\n return await this.list({\n where: { pipelineId },\n orderBy: 'sort_order ASC',\n });\n }\n\n /**\n * Find one stage by its natural key within a pipeline.\n *\n * @param pipelineId - Owning PipelineDefinition id\n * @param key - Stage machine key (e.g. `'proposal'`)\n * @returns The stage, or null when the key does not exist in the pipeline\n */\n async findByKey(\n pipelineId: string,\n key: string,\n ): Promise<PipelineStage | null> {\n const results = await this.list({\n where: { pipelineId, key },\n limit: 1,\n });\n return results[0] ?? null;\n }\n}\n\nexport default PipelineStageCollection;\n","/**\n * SalesActivity — the activity, next-action, and audit trail for CRM subjects.\n * @packageDocumentation\n */\n\nimport {\n crossPackageRef,\n field,\n SmrtObject,\n type SmrtSaveOptions,\n smrt,\n} from '@happyvertical/smrt-core';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\nimport type {\n SalesActivityOptions,\n SalesActivitySubjectKind,\n} from '../types.js';\n\n/** Internal one-save permit consumed by the Lead workflow completion path. */\nconst workflowCompletionPermits = new WeakSet<SalesActivity>();\n\n/**\n * Permit one monotonic `completedAt` stamp on a hydrated task.\n *\n * This intentionally stays out of the CRM barrel: generated CRUD exposes no\n * activity update route, and the public `LeadWorkflowService` is the only\n * supported completion surface that may acquire this internal capability.\n */\nexport function permitSalesActivityWorkflowCompletion(\n activity: SalesActivity,\n): void {\n workflowCompletionPermits.add(activity);\n}\n\n/**\n * SalesActivity is the shared trail for Leads and Opportunities: human\n * touchpoints (`note`, `call`, `email`, `meeting`), next actions (`task`\n * with `dueAt`/`completedAt`), and framework-written audit rows\n * (`assignment`, `qualification`, `stage_change`, `merge`, `status_change`).\n *\n * The subject is polymorphic by string pair — `subjectKind`\n * (`'lead' | 'opportunity'`) plus `subjectId` — deliberately NOT a typed FK\n * so one table serves both subjects. `activityKind` is an OPEN string;\n * `SALES_ACTIVITY_KINDS` exports the recommended vocabulary.\n *\n * Activities are an immutable trail: the generated surfaces expose only\n * `create`/`list`/`get` (no update/delete). Merges intentionally leave the\n * losing lead's activities attached to the loser —\n * `LeadCollection.activitiesIncludingMerged()` re-assembles the full history\n * across merge chains.\n *\n * @example\n * ```typescript\n * const activities = await SalesActivityCollection.create({ db });\n * await activities.create({\n * subjectKind: 'lead',\n * subjectId: lead.id,\n * activityKind: 'task',\n * summary: 'Send follow-up deck',\n * dueAt: new Date('2026-08-01'),\n * });\n * const open = await activities.findOpenTasks('lead', lead.id ?? '');\n * ```\n */\n@TenantScoped({ mode: 'optional' })\n@smrt({\n api: { include: ['create', 'list', 'get'] }, // immutable trail — no update/delete\n mcp: { include: ['list', 'create'] },\n cli: false,\n})\nexport class SalesActivity extends SmrtObject { static __smrtPackage__ = \"@happyvertical/smrt-sales\";\n /**\n * Tenant ID for multi-tenant isolation.\n * Nullable to support both tenant-scoped and global activities.\n */\n @tenantId({ nullable: true })\n tenantId: string | null = null;\n\n /** Which model the activity attaches to: `'lead'` or `'opportunity'`. */\n @field({\n description: 'What the activity is about: a lead or an opportunity.',\n })\n subjectKind: SalesActivitySubjectKind = 'lead';\n\n /** Id of the subject row. Required. */\n @field({\n required: true,\n description: 'The lead or opportunity it is about.',\n })\n subjectId: string = '';\n\n /**\n * Kind of activity — OPEN string so consumers can extend the vocabulary\n * without schema changes. See `SALES_ACTIVITY_KINDS` for the recommended\n * kinds (framework-written rows use `qualification`, `stage_change`,\n * `merge`).\n */\n @field({\n description: 'The kind of activity, for example call, note or email.',\n })\n activityKind: string = 'note';\n\n /** One-line human-readable description. */\n @field({ description: 'What happened or what needs doing.' })\n summary: string = '';\n\n /** Next-action due date — set for `task`-like activities. */\n @field({ description: 'When it is due.' })\n dueAt: Date | null = null;\n\n /** When the next action was completed; `null` while open. */\n @field({ description: 'When it was done.' })\n completedAt: Date | null = null;\n\n /**\n * Profile of the human/agent who performed or recorded the activity —\n * cross-package string reference to smrt-profiles.\n */\n @crossPackageRef('@happyvertical/smrt-profiles:Profile')\n actorProfileId: string = '';\n\n /**\n * Free-form JSON object stored as a string (framework audit rows carry\n * structured detail here, e.g. `stage_change` from/to ids or the full\n * loser snapshot on `merge`). Use {@link getMetadata}/{@link setMetadata}.\n */\n metadata: string = '{}';\n\n constructor(options: SalesActivityOptions = {}) {\n super(options);\n if (options.tenantId !== undefined) this.tenantId = options.tenantId;\n if (options.subjectKind !== undefined)\n this.subjectKind = options.subjectKind;\n if (options.subjectId !== undefined) this.subjectId = options.subjectId;\n if (options.activityKind !== undefined)\n this.activityKind = options.activityKind;\n if (options.summary !== undefined) this.summary = options.summary;\n if (options.dueAt !== undefined) this.dueAt = options.dueAt;\n if (options.completedAt !== undefined)\n this.completedAt = options.completedAt;\n if (options.actorProfileId !== undefined)\n this.actorProfileId = options.actorProfileId;\n if (options.metadata !== undefined) this.metadata = options.metadata;\n }\n\n /** Whether this is an open next action (due date set, not completed). */\n isOpenTask(): boolean {\n return this.dueAt !== null && this.completedAt === null;\n }\n\n /** Parse the metadata JSON string; returns `{}` on malformed content. */\n getMetadata(): Record<string, unknown> {\n try {\n const parsed: unknown = JSON.parse(this.metadata);\n if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {\n return parsed as Record<string, unknown>;\n }\n return {};\n } catch {\n return {};\n }\n }\n\n /** Serialize and store the metadata object. */\n setMetadata(metadata: Record<string, unknown>): void {\n this.metadata = JSON.stringify(metadata);\n }\n\n /**\n * Keep Lead-task completion monotonic and service-owned even for direct\n * model callers. The shared activity model continues to support existing\n * opportunity and imported-history completion flows; only the Lead\n * follow-up workflow owns its task completion transition.\n */\n override async save(options?: SmrtSaveOptions): Promise<this> {\n const persisted = await this.resolvePersistedState();\n const priorCompletedAt = persisted?.completedAt;\n const requestedCompletedAt = this.completedAt;\n const isNewCompletion =\n requestedCompletedAt !== null &&\n (priorCompletedAt === null || priorCompletedAt === undefined);\n\n if (\n priorCompletedAt &&\n !sameInstant(priorCompletedAt, requestedCompletedAt)\n ) {\n throw new Error(\n 'SalesActivity.completedAt is monotonic and cannot be changed once set.',\n );\n }\n if (persisted?.isLeadTask && !isLeadTask(this)) {\n throw new Error(\n 'SalesActivity Lead task identity cannot be changed once persisted.',\n );\n }\n if (\n (persisted?.isLeadTask === true || isLeadTask(this)) &&\n isNewCompletion &&\n !workflowCompletionPermits.has(this)\n ) {\n throw new Error(\n 'SalesActivity.completedAt may only be set through LeadWorkflowService.',\n );\n }\n\n const result = (await super.save(options)) as this;\n workflowCompletionPermits.delete(this);\n return result;\n }\n\n /** `undefined` means this id has not been persisted yet. */\n private async resolvePersistedState(): Promise<\n { completedAt: Date | null; isLeadTask: boolean } | undefined\n > {\n if (!this.id) return undefined;\n try {\n const row = await this.db.get(this.tableName, { id: this.id });\n if (!row) return undefined;\n const value = row.completed_at;\n const completedAt =\n value === null || value === undefined\n ? null\n : value instanceof Date\n ? value\n : new Date(String(value));\n return {\n completedAt:\n completedAt === null || Number.isFinite(completedAt.getTime())\n ? completedAt\n : null,\n isLeadTask: row.subject_kind === 'lead' && row.activity_kind === 'task',\n };\n } catch {\n // A fresh collection can construct its first object before the table is\n // verified. Let the normal save path create storage, then persist it.\n return undefined;\n }\n }\n}\n\nfunction sameInstant(expected: Date, actual: Date | null): actual is Date {\n return actual !== null && expected.getTime() === actual.getTime();\n}\n\nfunction isLeadTask(activity: SalesActivity): boolean {\n return activity.subjectKind === 'lead' && activity.activityKind === 'task';\n}\n\nexport default SalesActivity;\n","/**\n * SalesActivityCollection — collection manager for the SalesActivity trail.\n * @packageDocumentation\n */\n\nimport { SmrtCollection } from '@happyvertical/smrt-core';\nimport { SalesActivity } from '../models/SalesActivity.js';\nimport type { SalesActivitySubjectKind } from '../types.js';\n\nexport class SalesActivityCollection extends SmrtCollection<SalesActivity> {\n static readonly _itemClass = SalesActivity;\n\n /**\n * Full trail for one subject, oldest first (chronological reading order).\n *\n * @param subjectKind - `'lead'` or `'opportunity'`\n * @param subjectId - Subject row id\n */\n async findBySubject(\n subjectKind: SalesActivitySubjectKind,\n subjectId: string,\n ): Promise<SalesActivity[]> {\n return await this.list({\n where: { subjectKind, subjectId },\n orderBy: 'created_at ASC',\n });\n }\n\n /**\n * Open next actions for one subject: `task` activities with a due date\n * (`dueAt` set) that have not been completed (`completedAt` null),\n * soonest due first with a deterministic id tie-breaker.\n *\n * @param subjectKind - `'lead'` or `'opportunity'`\n * @param subjectId - Subject row id\n */\n async findOpenTasks(\n subjectKind: SalesActivitySubjectKind,\n subjectId: string,\n ): Promise<SalesActivity[]> {\n return await this.list({\n where: {\n subjectKind,\n subjectId,\n activityKind: 'task',\n 'dueAt !=': null,\n completedAt: null,\n },\n orderBy: ['dueAt ASC', 'id ASC'],\n });\n }\n}\n\nexport default SalesActivityCollection;\n","/**\n * OpportunityCollection — collection manager for Opportunity, including\n * validated, audited stage movement.\n * @packageDocumentation\n */\n\nimport { SmrtCollection } from '@happyvertical/smrt-core';\nimport { Opportunity } from '../models/Opportunity.js';\nimport type { MoveToStageParams } from '../types.js';\nimport { PipelineStageCollection } from './PipelineStageCollection.js';\nimport { SalesActivityCollection } from './SalesActivityCollection.js';\n\nexport class OpportunityCollection extends SmrtCollection<Opportunity> {\n static readonly _itemClass = Opportunity;\n\n private stageCollectionPromise: Promise<PipelineStageCollection> | null =\n null;\n private activityCollectionPromise: Promise<SalesActivityCollection> | null =\n null;\n\n /** Sibling stage collection sharing this collection's DB connection. */\n private async getStageCollection(): Promise<PipelineStageCollection> {\n if (!this.stageCollectionPromise) {\n this.stageCollectionPromise = PipelineStageCollection.create({\n db: this.db,\n _reuseInitializedDb: true,\n _deferRuntimeInitialization: true,\n });\n }\n return this.stageCollectionPromise;\n }\n\n /** Sibling activity collection sharing this collection's DB connection. */\n private async getActivityCollection(): Promise<SalesActivityCollection> {\n if (!this.activityCollectionPromise) {\n this.activityCollectionPromise = SalesActivityCollection.create({\n db: this.db,\n _reuseInitializedDb: true,\n _deferRuntimeInitialization: true,\n });\n }\n return this.activityCollectionPromise;\n }\n\n /**\n * Opportunities originating from a given lead, oldest first (the first row\n * is the one `LeadCollection.qualify()` treats as canonical).\n */\n async findByLead(leadId: string): Promise<Opportunity[]> {\n return await this.list({\n where: { leadId },\n orderBy: 'created_at ASC',\n });\n }\n\n /**\n * Open (still in play) opportunities, optionally narrowed to one pipeline.\n */\n async findOpen(pipelineId?: string): Promise<Opportunity[]> {\n return await this.list({\n where: { status: 'open', ...(pipelineId ? { pipelineId } : {}) },\n orderBy: 'created_at ASC',\n });\n }\n\n /**\n * Move an opportunity to another stage of ITS pipeline, with the full\n * consequence set:\n *\n * - validates the target stage belongs to the opportunity's pipeline\n * (an opportunity created without a pipeline adopts the stage's);\n * - adopts the stage's default `probability` unless\n * `probabilityOverride` is given;\n * - terminal stages close the deal: `isWon` sets `status: 'won'` +\n * `wonAt`; `isLost` sets `status: 'lost'` + `lostAt` (record the loss\n * reason via `outcomeReason`);\n * - writes a `stage_change` SalesActivity carrying from/to detail.\n *\n * Moves after a terminal status are rejected — a closed deal's history is\n * settled; reopening is not supported (create a new opportunity instead).\n *\n * @returns The updated opportunity\n */\n async moveToStage(params: MoveToStageParams): Promise<Opportunity> {\n const opportunity = await this.get({ id: params.opportunityId });\n if (!opportunity) {\n throw new Error(\n `OpportunityCollection.moveToStage: opportunity '${params.opportunityId}' not found`,\n );\n }\n if (opportunity.status !== 'open') {\n throw new Error(\n `OpportunityCollection.moveToStage: opportunity '${params.opportunityId}' ` +\n `is '${opportunity.status}' — stage moves after a terminal status are not allowed`,\n );\n }\n\n const stagesCollection = await this.getStageCollection();\n const stage = await stagesCollection.get({ id: params.stageId });\n if (!stage) {\n throw new Error(\n `OpportunityCollection.moveToStage: stage '${params.stageId}' not found`,\n );\n }\n if (opportunity.pipelineId && stage.pipelineId !== opportunity.pipelineId) {\n throw new Error(\n `OpportunityCollection.moveToStage: stage '${stage.key || stage.id}' belongs to ` +\n `pipeline '${stage.pipelineId}', not the opportunity's pipeline '${opportunity.pipelineId}'`,\n );\n }\n\n const fromStageId = opportunity.stageId;\n const fromStatus = opportunity.status;\n\n // An opportunity created without a pipeline adopts the stage's pipeline\n // on its first move.\n if (!opportunity.pipelineId) {\n opportunity.pipelineId = stage.pipelineId;\n }\n opportunity.stageId = stage.id ?? '';\n opportunity.probability = params.probabilityOverride ?? stage.probability;\n if (params.outcomeReason !== undefined) {\n opportunity.outcomeReason = params.outcomeReason;\n }\n if (stage.isWon) {\n opportunity.status = 'won';\n opportunity.wonAt = params.now ?? new Date();\n } else if (stage.isLost) {\n opportunity.status = 'lost';\n opportunity.lostAt = params.now ?? new Date();\n }\n await opportunity.save();\n\n const activities = await this.getActivityCollection();\n await activities.create({\n ...(opportunity.tenantId !== null\n ? { tenantId: opportunity.tenantId }\n : {}),\n subjectKind: 'opportunity',\n subjectId: opportunity.id ?? '',\n activityKind: 'stage_change',\n summary: `Moved to stage '${stage.key}'`,\n actorProfileId: params.actorProfileId ?? '',\n metadata: JSON.stringify({\n fromStageId,\n toStageId: stage.id ?? '',\n toStageKey: stage.key,\n fromStatus,\n toStatus: opportunity.status,\n probability: opportunity.probability,\n ...(params.outcomeReason !== undefined\n ? { outcomeReason: params.outcomeReason }\n : {}),\n }),\n });\n\n return opportunity;\n }\n}\n\nexport default OpportunityCollection;\n","/**\n * PipelineDefinition — a named, tenant-scoped sales pipeline.\n * @packageDocumentation\n */\n\nimport { field, SmrtObject, smrt } from '@happyvertical/smrt-core';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\nimport type { PipelineDefinitionOptions, PipelineStatus } from '../types.js';\n\n/**\n * PipelineDefinition names an ordered set of {@link PipelineStage | stages}\n * that opportunities move through. Pipelines are configuration rows, not\n * code: tenants can run several (e.g. `default`, `enterprise`, `renewals`)\n * and reshape stages freely without any Lead/Opportunity model change.\n *\n * The natural key is `(tenant_id, key)` (`conflictColumns`), so re-seeding a\n * pipeline with the same key upserts instead of duplicating. The seeded\n * default pipeline (key `'default'`, 7 stages) comes from\n * `PipelineDefinitionCollection.ensureDefaultPipeline()`.\n *\n * @example\n * ```typescript\n * const pipelines = await PipelineDefinitionCollection.create({ db });\n * const { pipeline, stages } = await pipelines.ensureDefaultPipeline();\n * const enterprise = await pipelines.create({\n * key: 'enterprise',\n * name: 'Enterprise motion',\n * });\n * ```\n */\n@TenantScoped({ mode: 'optional' })\n@smrt({\n api: { include: ['list', 'get', 'create', 'update'] },\n mcp: { include: ['list', 'get'] },\n cli: { skipApiCheck: true },\n conflictColumns: ['tenant_id', 'key'],\n})\nexport class PipelineDefinition extends SmrtObject { static __smrtPackage__ = \"@happyvertical/smrt-sales\";\n /**\n * Tenant ID for multi-tenant isolation.\n * Nullable to support both tenant-scoped and global pipelines.\n */\n @tenantId({ nullable: true })\n tenantId: string | null = null;\n\n /**\n * Stable machine key, unique per tenant (natural key with `tenantId`).\n * Required — e.g. `'default'`, `'enterprise'`.\n */\n @field({ required: true, description: 'A short code for the pipeline.' })\n key: string = '';\n\n /** Human-readable pipeline name shown on CRM surfaces. */\n @field({ description: 'What the pipeline is called.' })\n name: string = '';\n\n /**\n * Marks the tenant's default pipeline. Informational for pickers/UI; the\n * seeded default pipeline sets it `true`.\n */\n @field({ description: 'Whether this is the default pipeline for new deals.' })\n isDefault: boolean = false;\n\n /** `active` pipelines accept new opportunities; `archived` are read-only history. */\n @field({\n description:\n 'Whether the pipeline is active (accepts new deals) or archived.',\n })\n status: PipelineStatus = 'active';\n\n /**\n * Free-form JSON object stored as a string. Use\n * {@link getMetadata}/{@link setMetadata} instead of parsing manually.\n */\n @field({ description: 'Extra details kept with the pipeline.' })\n metadata: string = '{}';\n\n constructor(options: PipelineDefinitionOptions = {}) {\n super(options);\n if (options.tenantId !== undefined) this.tenantId = options.tenantId;\n if (options.key !== undefined) this.key = options.key;\n if (options.name !== undefined) this.name = options.name;\n if (options.isDefault !== undefined) this.isDefault = options.isDefault;\n if (options.status !== undefined) this.status = options.status;\n if (options.metadata !== undefined) this.metadata = options.metadata;\n }\n\n /** Whether the pipeline accepts new opportunities. */\n isActive(): boolean {\n return this.status === 'active';\n }\n\n /** Parse the metadata JSON string; returns `{}` on malformed content. */\n getMetadata(): Record<string, unknown> {\n try {\n const parsed: unknown = JSON.parse(this.metadata);\n if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {\n return parsed as Record<string, unknown>;\n }\n return {};\n } catch {\n return {};\n }\n }\n\n /** Serialize and store the metadata object. */\n setMetadata(metadata: Record<string, unknown>): void {\n this.metadata = JSON.stringify(metadata);\n }\n}\n\nexport default PipelineDefinition;\n","/**\n * PipelineDefinitionCollection — collection manager for PipelineDefinition,\n * including the idempotent default-pipeline seeder.\n * @packageDocumentation\n */\n\nimport { SmrtCollection } from '@happyvertical/smrt-core';\nimport { PipelineDefinition } from '../models/PipelineDefinition.js';\nimport type { PipelineStage } from '../models/PipelineStage.js';\nimport {\n DEFAULT_PIPELINE_KEY,\n DEFAULT_PIPELINE_STAGES,\n type EnsureDefaultPipelineParams,\n type EnsureDefaultPipelineResult,\n} from '../types.js';\nimport { PipelineStageCollection } from './PipelineStageCollection.js';\n\n/** Narrow a possibly-unset SmrtObject id into a usable string. */\nfunction requireId(value: string | null | undefined, what: string): string {\n if (!value) {\n throw new Error(`PipelineDefinitionCollection: ${what} has no id`);\n }\n return value;\n}\n\nexport class PipelineDefinitionCollection extends SmrtCollection<PipelineDefinition> {\n static readonly _itemClass = PipelineDefinition;\n\n private stageCollectionPromise: Promise<PipelineStageCollection> | null =\n null;\n\n /** Sibling stage collection sharing this collection's DB connection. */\n private async getStageCollection(): Promise<PipelineStageCollection> {\n if (!this.stageCollectionPromise) {\n this.stageCollectionPromise = PipelineStageCollection.create({\n db: this.db,\n });\n }\n return this.stageCollectionPromise;\n }\n\n /**\n * Find one pipeline by its machine key (natural key within the tenant\n * scope — ambient tenancy auto-filters the lookup).\n */\n async findByKey(key: string): Promise<PipelineDefinition | null> {\n const results = await this.list({ where: { key }, limit: 1 });\n return results[0] ?? null;\n }\n\n /**\n * Find the pipeline flagged `isDefault` (informational designation).\n */\n async findDefault(): Promise<PipelineDefinition | null> {\n const results = await this.list({\n where: { isDefault: true },\n orderBy: 'created_at ASC',\n limit: 1,\n });\n return results[0] ?? null;\n }\n\n /**\n * A pipeline's stages in board order (`sortOrder` ascending).\n */\n async getStages(pipelineId: string): Promise<PipelineStage[]> {\n const stages = await this.getStageCollection();\n return await stages.findByPipeline(pipelineId);\n }\n\n /**\n * Idempotently find-or-create the seeded default pipeline (key\n * `'default'`, `isDefault: true`) and its 7 default stages:\n * `new(0.1) → qualified(0.25) → discovery(0.4) → proposal(0.6) →\n * negotiation(0.8) → closed_won(1.0, isWon) → closed_lost(0.0, isLost)`.\n *\n * Idempotency is per stage KEY: a second call creates nothing, and a\n * partially-seeded pipeline (e.g. an interrupted first run) is healed by\n * creating only the missing keys. Existing stages are never overwritten —\n * renames, re-weights, reorders, and custom stages added via normal\n * PipelineStage operations all survive re-runs.\n *\n * Tenancy: under an ambient `withTenant()` context the pipeline/stages\n * auto-scope to that tenant; pass `tenantId` to seed for a specific tenant\n * from a system/global context. Lookup is by natural key, so each tenant\n * gets exactly one seeded default pipeline.\n *\n * @returns The pipeline plus ALL of its stages ordered by `sortOrder`\n * (including any custom stages added since seeding)\n */\n async ensureDefaultPipeline(\n params: EnsureDefaultPipelineParams = {},\n ): Promise<EnsureDefaultPipelineResult> {\n const tenantScope =\n params.tenantId !== undefined ? { tenantId: params.tenantId } : {};\n\n let pipeline = (\n await this.list({\n where: { key: DEFAULT_PIPELINE_KEY, ...tenantScope },\n limit: 1,\n })\n )[0];\n\n if (!pipeline) {\n pipeline = await this.create({\n ...tenantScope,\n key: DEFAULT_PIPELINE_KEY,\n name: 'Default Sales Pipeline',\n isDefault: true,\n status: 'active',\n });\n }\n\n const pipelineId = requireId(pipeline.id, 'default pipeline');\n const stagesCollection = await this.getStageCollection();\n const existing = await stagesCollection.findByPipeline(pipelineId);\n const existingKeys = new Set(existing.map((stage) => stage.key));\n\n // Stage tenancy follows the pipeline row (auto-populated under ambient\n // tenancy; explicit when the pipeline was seeded with a tenantId param).\n const stageTenantScope =\n pipeline.tenantId !== null\n ? { tenantId: pipeline.tenantId }\n : tenantScope;\n\n for (const [index, seed] of DEFAULT_PIPELINE_STAGES.entries()) {\n if (existingKeys.has(seed.key)) continue;\n await stagesCollection.create({\n ...stageTenantScope,\n pipelineId,\n key: seed.key,\n name: seed.name,\n // Steps of 10 leave headroom to slot custom stages between defaults.\n sortOrder: (index + 1) * 10,\n probability: seed.probability,\n isWon: seed.isWon ?? false,\n isLost: seed.isLost ?? false,\n });\n }\n\n const stages = await stagesCollection.findByPipeline(pipelineId);\n return { pipeline, stages };\n }\n}\n\nexport default PipelineDefinitionCollection;\n","/**\n * SalesRepresentative — the sales-rep role model.\n * @packageDocumentation\n */\n\nimport {\n crossPackageRef,\n foreignKey,\n SmrtObject,\n smrt,\n} from '@happyvertical/smrt-core';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\nimport type {\n SalesRepresentativeOptions,\n SalesRepresentativeStatus,\n} from '../types.js';\n\n/**\n * SalesRepresentative is a ROLE model: it links an identity (smrt-profiles\n * Profile) to sales ownership (Leads/Opportunities reference `ownerRepId`).\n *\n * Roles and money stay separate (see `packages/sales/AGENTS.md` \"Roles vs.\n * money\"): a rep connects to payouts only through the optional `earnerId`\n * pointing at the commissions module's neutral `Earner`. No referral or\n * commission semantics live on this model.\n *\n * @example\n * ```typescript\n * const reps = await SalesRepresentativeCollection.create({ db });\n * const rep = await reps.create({\n * profileId: 'profile-uuid',\n * title: 'Account Executive',\n * });\n * const active = await reps.findActive();\n * ```\n */\n@TenantScoped({ mode: 'optional' })\n@smrt({\n api: { include: ['list', 'get', 'create', 'update'] },\n mcp: { include: ['list', 'get'] },\n cli: { skipApiCheck: true },\n})\nexport class SalesRepresentative extends SmrtObject { static __smrtPackage__ = \"@happyvertical/smrt-sales\";\n /**\n * Tenant ID for multi-tenant isolation.\n * Nullable to support both tenant-scoped and global (operator-level) reps.\n */\n @tenantId({ nullable: true })\n tenantId: string | null = null;\n\n /**\n * Identity of the person acting as a rep — cross-package string reference\n * to a smrt-profiles Profile.\n */\n @crossPackageRef('@happyvertical/smrt-profiles:Profile')\n profileId: string = '';\n\n /**\n * Optional link to the commissions module's `Earner` (the neutral payout\n * identity). String-form same-package FK: the Earner class lives in\n * `src/commissions` and is intentionally NOT imported here — the string\n * form registers the relationship without a module dependency, keeping the\n * `crm → commissions` boundary reference-only. Empty when the rep is not\n * commission-compensated.\n */\n @foreignKey('Earner')\n earnerId: string = '';\n\n /** Role status — only `active` reps should receive new assignments. */\n status: SalesRepresentativeStatus = 'active';\n\n /** Job title shown on CRM surfaces (e.g. `'Account Executive'`). */\n title: string = '';\n\n /**\n * Free-form JSON object stored as a string. Use\n * {@link getMetadata}/{@link setMetadata} instead of parsing manually.\n */\n metadata: string = '{}';\n\n constructor(options: SalesRepresentativeOptions = {}) {\n super(options);\n if (options.tenantId !== undefined) this.tenantId = options.tenantId;\n if (options.profileId !== undefined) this.profileId = options.profileId;\n if (options.earnerId !== undefined) this.earnerId = options.earnerId;\n if (options.status !== undefined) this.status = options.status;\n if (options.title !== undefined) this.title = options.title;\n if (options.metadata !== undefined) this.metadata = options.metadata;\n }\n\n /** Whether the rep may receive new lead/opportunity assignments. */\n isActive(): boolean {\n return this.status === 'active';\n }\n\n /** Parse the metadata JSON string; returns `{}` on malformed content. */\n getMetadata(): Record<string, unknown> {\n try {\n const parsed: unknown = JSON.parse(this.metadata);\n if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {\n return parsed as Record<string, unknown>;\n }\n return {};\n } catch {\n return {};\n }\n }\n\n /** Serialize and store the metadata object. */\n setMetadata(metadata: Record<string, unknown>): void {\n this.metadata = JSON.stringify(metadata);\n }\n}\n\nexport default SalesRepresentative;\n","/**\n * SalesRepresentativeCollection — collection manager for SalesRepresentative.\n * @packageDocumentation\n */\n\nimport { SmrtCollection } from '@happyvertical/smrt-core';\nimport { SalesRepresentative } from '../models/SalesRepresentative.js';\n\nexport class SalesRepresentativeCollection extends SmrtCollection<SalesRepresentative> {\n static readonly _itemClass = SalesRepresentative;\n\n /**\n * Find rep roles held by a given profile (a profile may hold the role in\n * several tenants/contexts).\n *\n * @param profileId - smrt-profiles Profile id\n * @returns Reps for that profile, newest first\n */\n async findByProfile(profileId: string): Promise<SalesRepresentative[]> {\n return await this.list({\n where: { profileId },\n orderBy: 'created_at DESC',\n });\n }\n\n /**\n * Find all active reps (eligible for new lead/opportunity assignment).\n */\n async findActive(): Promise<SalesRepresentative[]> {\n return await this.list({\n where: { status: 'active' },\n orderBy: 'created_at DESC',\n });\n }\n}\n\nexport default SalesRepresentativeCollection;\n","/**\n * LeadCollection — collection manager for Lead, including qualification into\n * opportunities, audited duplicate merges, and merge-aware history reads.\n * @packageDocumentation\n */\n\nimport { SmrtCollection } from '@happyvertical/smrt-core';\nimport { getTenantId, TenantContextError } from '@happyvertical/smrt-tenancy';\nimport { Lead } from '../models/Lead.js';\nimport type { Opportunity } from '../models/Opportunity.js';\nimport type { PipelineDefinition } from '../models/PipelineDefinition.js';\nimport type { PipelineStage } from '../models/PipelineStage.js';\nimport type { SalesActivity } from '../models/SalesActivity.js';\nimport type { SalesRepresentative } from '../models/SalesRepresentative.js';\nimport {\n emptyLeadInboxStatusCounts,\n type LeadInboxOptions,\n type LeadInboxResult,\n type NormalizedLeadInboxOptions,\n normalizeLeadInboxOptions,\n} from '../services/lead-inbox.js';\nimport type {\n LeadStatus,\n MergeLeadsParams,\n MergeLeadsResult,\n QualifyLeadParams,\n} from '../types.js';\nimport { OpportunityCollection } from './OpportunityCollection.js';\nimport { PipelineDefinitionCollection } from './PipelineDefinitionCollection.js';\nimport { SalesActivityCollection } from './SalesActivityCollection.js';\nimport { SalesRepresentativeCollection } from './SalesRepresentativeCollection.js';\n\n/**\n * Winner contact fields that {@link LeadCollection.mergeLeads} fills from the\n * loser when (and only when) the winner's value is empty. Non-empty winner\n * data is never overwritten.\n */\nconst MERGE_FILL_CONTACT_FIELDS = [\n 'contactName',\n 'email',\n 'phone',\n 'organizationName',\n] as const;\n\n/** Narrow a possibly-unset SmrtObject id into a usable string. */\nfunction requireId(value: string | null | undefined, what: string): string {\n if (!value) {\n throw new Error(`LeadCollection: ${what} has no id`);\n }\n return value;\n}\n\nexport class LeadCollection extends SmrtCollection<Lead> {\n static readonly _itemClass = Lead;\n\n private opportunityCollectionPromise: Promise<OpportunityCollection> | null =\n null;\n private pipelineCollectionPromise: Promise<PipelineDefinitionCollection> | null =\n null;\n private activityCollectionPromise: Promise<SalesActivityCollection> | null =\n null;\n private representativeCollectionPromise: Promise<SalesRepresentativeCollection> | null =\n null;\n\n /** Sibling opportunity collection sharing this collection's DB connection. */\n private async getOpportunityCollection(): Promise<OpportunityCollection> {\n if (!this.opportunityCollectionPromise) {\n this.opportunityCollectionPromise = OpportunityCollection.create({\n db: this.db,\n _reuseInitializedDb: true,\n _deferRuntimeInitialization: true,\n });\n }\n return this.opportunityCollectionPromise;\n }\n\n /** Sibling pipeline collection sharing this collection's DB connection. */\n private async getPipelineCollection(): Promise<PipelineDefinitionCollection> {\n if (!this.pipelineCollectionPromise) {\n this.pipelineCollectionPromise = PipelineDefinitionCollection.create({\n db: this.db,\n _reuseInitializedDb: true,\n _deferRuntimeInitialization: true,\n });\n }\n return this.pipelineCollectionPromise;\n }\n\n /** Sibling activity collection sharing this collection's DB connection. */\n private async getActivityCollection(): Promise<SalesActivityCollection> {\n if (!this.activityCollectionPromise) {\n this.activityCollectionPromise = SalesActivityCollection.create({\n db: this.db,\n _reuseInitializedDb: true,\n _deferRuntimeInitialization: true,\n });\n }\n return this.activityCollectionPromise;\n }\n\n /** Sibling representative collection sharing this collection's DB connection. */\n private async getRepresentativeCollection(): Promise<SalesRepresentativeCollection> {\n if (!this.representativeCollectionPromise) {\n this.representativeCollectionPromise =\n SalesRepresentativeCollection.create({\n db: this.db,\n _reuseInitializedDb: true,\n _deferRuntimeInitialization: true,\n });\n }\n return this.representativeCollectionPromise;\n }\n\n /** Leads in a given lifecycle status, newest first. */\n async findByStatus(status: LeadStatus): Promise<Lead[]> {\n return await this.list({\n where: { status },\n orderBy: 'created_at DESC',\n });\n }\n\n /** Leads owned by a given sales rep, newest first. */\n async findByOwner(ownerRepId: string): Promise<Lead[]> {\n return await this.list({\n where: { ownerRepId },\n orderBy: 'created_at DESC',\n });\n }\n\n /**\n * Return one tenant's Lead inbox with exact pagination and tab counts.\n *\n * `total` applies every requested filter. `statusCounts` applies the same\n * owner and search scope, but deliberately ignores status/unassigned/overdue\n * so a host can switch tabs without issuing a second request. Search is a\n * trimmed, case-insensitive literal substring across name, contact name,\n * email, phone, and organization. `next_action` sorts the earliest open task\n * first and places Leads without an open task last. Every order has an id\n * tie-breaker, so offset pages remain stable while the underlying data does.\n *\n * The read performs a constant number of queries: page, counts, earliest\n * open tasks, and owners. It requires ambient tenancy and applies an explicit\n * tenant predicate to both Lead and activity SQL.\n */\n async listInbox(options: LeadInboxOptions): Promise<LeadInboxResult> {\n const tenantId = getTenantId();\n if (!tenantId) {\n throw new TenantContextError(\n 'LeadCollection.listInbox: an ambient tenant context is required',\n );\n }\n const normalized = normalizeLeadInboxOptions(options);\n const now = normalized.now.toISOString();\n const readScope = await this.resolveListReadPredicate();\n const base = buildInboxBasePredicate(normalized, tenantId, readScope);\n const tab = buildInboxTabPredicate(normalized, now);\n const nextActionsCte = inboxNextActionsCte();\n const orderBy = inboxOrderBy(normalized.sort);\n\n const leads = await this.query(\n `${nextActionsCte.sql}\n SELECT l.*\n FROM ${this.tableName} l\n LEFT JOIN inbox_next_actions na ON na.subject_id = CAST(l.id AS TEXT)\n WHERE (${base.sql}) AND (${tab.sql})\n ORDER BY ${orderBy}\n LIMIT ? OFFSET ?`,\n [\n tenantId,\n ...base.values,\n ...tab.values,\n normalized.limit,\n normalized.offset,\n ],\n { allowRawOnTenantScoped: true },\n );\n const visibleLeads = await readScope.finish(leads);\n\n const countResult = await this.db.query(\n `${nextActionsCte.sql}\n SELECT l.status,\n COUNT(*) AS status_count,\n SUM(CASE WHEN l.owner_rep_id IS NULL OR CAST(l.owner_rep_id AS TEXT) = '' THEN 1 ELSE 0 END) AS unassigned_count,\n SUM(CASE WHEN na.due_at < ? THEN 1 ELSE 0 END) AS overdue_count,\n SUM(CASE WHEN ${tab.sql} THEN 1 ELSE 0 END) AS filtered_count\n FROM ${this.tableName} l\n LEFT JOIN inbox_next_actions na ON na.subject_id = CAST(l.id AS TEXT)\n WHERE ${base.sql}\n GROUP BY l.status`,\n tenantId,\n now,\n ...tab.values,\n ...base.values,\n );\n const statusCounts = emptyLeadInboxStatusCounts();\n let total = 0;\n for (const row of countResult.rows) {\n const status = String(row.status);\n if (status in statusCounts && status !== 'all') {\n statusCounts[status as keyof typeof statusCounts] = toInboxCount(\n row.status_count,\n );\n }\n statusCounts.all += toInboxCount(row.status_count);\n statusCounts.unassigned += toInboxCount(row.unassigned_count);\n statusCounts.overdue += toInboxCount(row.overdue_count);\n total += toInboxCount(row.filtered_count);\n }\n\n if (visibleLeads.length === 0) {\n return { leads: visibleLeads, items: [], total, statusCounts };\n }\n\n const leadIds = visibleLeads.map((lead) =>\n requireId(lead.id, 'inbox lead'),\n );\n const activities = await this.getActivityCollection();\n const idPlaceholders = leadIds.map(() => '?').join(', ');\n const nextActions = await activities.query(\n `SELECT a.*\n FROM sales_activities a\n WHERE a.tenant_id = ?\n AND a.subject_kind = 'lead'\n AND a.activity_kind = 'task'\n AND a.completed_at IS NULL\n AND a.due_at IS NOT NULL\n AND a.subject_id IN (${idPlaceholders})\n AND NOT EXISTS (\n SELECT 1 FROM sales_activities earlier\n WHERE earlier.tenant_id = a.tenant_id\n AND earlier.subject_kind = a.subject_kind\n AND earlier.subject_id = a.subject_id\n AND earlier.activity_kind = 'task'\n AND earlier.completed_at IS NULL\n AND earlier.due_at IS NOT NULL\n AND (earlier.due_at < a.due_at OR (earlier.due_at = a.due_at AND earlier.id < a.id))\n )`,\n [tenantId, ...leadIds],\n { allowRawOnTenantScoped: true },\n );\n const nextActionByLead = new Map<string, SalesActivity>(\n nextActions.map((activity) => [activity.subjectId, activity]),\n );\n\n const ownerIds = [\n ...new Set(\n visibleLeads.map((lead) => lead.ownerRepId).filter((id) => id !== ''),\n ),\n ];\n const owners = ownerIds.length\n ? await (await this.getRepresentativeCollection()).listByIds(ownerIds)\n : [];\n const ownerById = new Map<string, SalesRepresentative>(\n owners.map((owner) => [requireId(owner.id, 'inbox owner'), owner]),\n );\n const items = visibleLeads.map((lead) => ({\n lead,\n owner: ownerById.get(lead.ownerRepId) ?? null,\n nextAction:\n nextActionByLead.get(requireId(lead.id, 'inbox lead')) ?? null,\n }));\n\n return { leads: visibleLeads, items, total, statusCounts };\n }\n\n /**\n * Qualify a lead into an Opportunity.\n *\n * Transitions the lead to `qualified` (stamping `qualifiedAt` once) and\n * creates an Opportunity at the FIRST stage of the target pipeline —\n * `pipelineId` when given, otherwise the seeded default pipeline\n * (`ensureDefaultPipeline()`). The opportunity adopts the first stage's\n * probability, copies the lead's `sourceKind`/`sourceId` for reporting,\n * and defaults its name/owner from the lead. A `qualification`\n * SalesActivity is written on BOTH the lead and the opportunity.\n *\n * IDEMPOTENT: when the lead is already `qualified` and an opportunity\n * exists for it, that opportunity is returned unchanged (no new rows, no\n * new activities). A qualified lead with no opportunity (interrupted\n * earlier run) is healed by creating the missing opportunity.\n *\n * Illegal source statuses are rejected by the lead's save-time transition\n * guard (`disqualified`/`merged` leads cannot be qualified).\n *\n * @returns The (existing or newly created) opportunity\n */\n async qualify(params: QualifyLeadParams): Promise<Opportunity> {\n const lead = await this.get({ id: params.leadId });\n if (!lead) {\n throw new Error(\n `LeadCollection.qualify: lead '${params.leadId}' not found`,\n );\n }\n const leadId = requireId(lead.id, `lead '${params.leadId}'`);\n\n const opportunities = await this.getOpportunityCollection();\n if (lead.status === 'qualified') {\n const existing = await opportunities.findByLead(leadId);\n if (existing[0]) {\n return existing[0];\n }\n }\n\n // Resolve the target pipeline and its entry stage BEFORE mutating the\n // lead, so a bad pipelineId leaves the lead untouched.\n const pipelines = await this.getPipelineCollection();\n let pipeline: PipelineDefinition;\n let stages: PipelineStage[];\n if (params.pipelineId) {\n const found = await pipelines.get({ id: params.pipelineId });\n if (!found) {\n throw new Error(\n `LeadCollection.qualify: pipeline '${params.pipelineId}' not found`,\n );\n }\n pipeline = found;\n stages = await pipelines.getStages(requireId(pipeline.id, 'pipeline'));\n } else {\n ({ pipeline, stages } = await pipelines.ensureDefaultPipeline({\n ...(lead.tenantId !== null ? { tenantId: lead.tenantId } : {}),\n }));\n }\n const firstStage = stages[0];\n if (!firstStage) {\n throw new Error(\n `LeadCollection.qualify: pipeline '${pipeline.key || pipeline.id}' has no stages`,\n );\n }\n\n if (lead.status !== 'qualified') {\n lead.status = 'qualified'; // save-guard rejects illegal transitions\n if (!lead.qualifiedAt) {\n lead.qualifiedAt = params.now ?? new Date();\n }\n await lead.save();\n }\n\n const opportunity = await opportunities.create({\n ...(lead.tenantId !== null ? { tenantId: lead.tenantId } : {}),\n name: params.opportunityName ?? lead.name,\n leadId,\n ownerRepId: params.ownerRepId ?? lead.ownerRepId,\n pipelineId: pipeline.id ?? '',\n stageId: firstStage.id ?? '',\n probability: firstStage.probability,\n expectedValueCents: params.expectedValueCents ?? 0,\n currency: params.currency ?? 'USD',\n expectedCloseAt: params.expectedCloseAt ?? null,\n status: 'open',\n sourceKind: lead.sourceKind,\n sourceId: lead.sourceId,\n });\n const opportunityId = requireId(opportunity.id, 'created opportunity');\n\n const activities = await this.getActivityCollection();\n const tenantScope =\n lead.tenantId !== null ? { tenantId: lead.tenantId } : {};\n await activities.create({\n ...tenantScope,\n subjectKind: 'lead',\n subjectId: leadId,\n activityKind: 'qualification',\n summary: `Qualified into opportunity '${opportunity.name}'`,\n actorProfileId: params.actorProfileId ?? '',\n metadata: JSON.stringify({\n opportunityId,\n pipelineId: pipeline.id ?? '',\n stageId: firstStage.id ?? '',\n stageKey: firstStage.key,\n }),\n });\n await activities.create({\n ...tenantScope,\n subjectKind: 'opportunity',\n subjectId: opportunityId,\n activityKind: 'qualification',\n summary: `Created from qualified lead '${lead.name}'`,\n actorProfileId: params.actorProfileId ?? '',\n metadata: JSON.stringify({\n leadId,\n pipelineId: pipeline.id ?? '',\n stageId: firstStage.id ?? '',\n stageKey: firstStage.key,\n }),\n });\n\n return opportunity;\n }\n\n /**\n * Audited duplicate merge: fold the `loserId` lead into the `winnerId`\n * lead.\n *\n * Validations: the ids must differ, both leads must exist, the loser must\n * not already be merged, the winner must not itself be merged (merge into\n * the chain head instead), and the merge must not create a\n * `mergedIntoId` cycle.\n *\n * Effects:\n * - EMPTY winner contact fields (`contactName`/`email`/`phone`/\n * `organizationName`) are filled from the loser; non-empty winner data\n * is never overwritten;\n * - the loser's acquisition context is appended into the winner's under a\n * `mergedSources` array (both histories preserved verbatim);\n * - the loser becomes terminal: `status: 'merged'` +\n * `mergedIntoId: winnerId`;\n * - a `merge` SalesActivity is written on BOTH leads, each carrying a full\n * pre-merge loser snapshot in metadata;\n * - the loser's existing activities STAY attached to the loser (history\n * preserved in place) — read the combined trail via\n * {@link activitiesIncludingMerged}.\n */\n async mergeLeads(params: MergeLeadsParams): Promise<MergeLeadsResult> {\n const { winnerId, loserId } = params;\n if (winnerId === loserId) {\n throw new Error(\n `LeadCollection.mergeLeads: winner and loser must be distinct leads (got '${winnerId}' twice)`,\n );\n }\n const winner = await this.get({ id: winnerId });\n if (!winner) {\n throw new Error(\n `LeadCollection.mergeLeads: winner lead '${winnerId}' not found`,\n );\n }\n const loser = await this.get({ id: loserId });\n if (!loser) {\n throw new Error(\n `LeadCollection.mergeLeads: loser lead '${loserId}' not found`,\n );\n }\n if (loser.status === 'merged') {\n throw new Error(\n `LeadCollection.mergeLeads: lead '${loserId}' is already merged into '${loser.mergedIntoId}'`,\n );\n }\n if (winner.status === 'merged') {\n throw new Error(\n `LeadCollection.mergeLeads: winner lead '${winnerId}' has itself been merged into ` +\n `'${winner.mergedIntoId}' — merge into the chain head instead`,\n );\n }\n\n // Cycle guard (defense in depth for raw-set mergedIntoId data): walking\n // the winner's merge ancestry must never reach the loser.\n const visited = new Set<string>([winnerId]);\n let cursor = winner.mergedIntoId;\n while (cursor) {\n if (cursor === loserId) {\n throw new Error(\n `LeadCollection.mergeLeads: merging '${loserId}' into '${winnerId}' would create a merge cycle`,\n );\n }\n if (visited.has(cursor)) break; // pre-existing cycle in data — stop walking\n visited.add(cursor);\n const ancestor = await this.get({ id: cursor });\n cursor = ancestor?.mergedIntoId ?? '';\n }\n\n // Full pre-merge snapshot of the loser for both audit rows.\n const loserSnapshot = loser.toJSON() as Record<string, unknown>;\n\n // Fill EMPTY winner contact fields from the loser — never overwrite.\n const filledFields: string[] = [];\n for (const fieldName of MERGE_FILL_CONTACT_FIELDS) {\n if (winner[fieldName] === '' && loser[fieldName] !== '') {\n winner[fieldName] = loser[fieldName];\n filledFields.push(fieldName);\n }\n }\n\n // Preserve BOTH acquisition histories: append the loser's context (plus\n // its source pointer) under the winner's `mergedSources` array.\n const winnerContext = winner.getAcquisitionContext();\n const priorSources = winnerContext.mergedSources;\n const mergedSources = Array.isArray(priorSources) ? [...priorSources] : [];\n mergedSources.push({\n leadId: loserId,\n mergedAt: new Date().toISOString(),\n sourceKind: loser.sourceKind,\n sourceId: loser.sourceId,\n acquisitionContext: loser.getAcquisitionContext(),\n });\n winner.setAcquisitionContext({ ...winnerContext, mergedSources });\n\n await winner.save();\n\n loser.status = 'merged';\n loser.mergedIntoId = winnerId;\n await loser.save();\n\n const activities = await this.getActivityCollection();\n const actorProfileId = params.actorProfileId ?? '';\n const reason = params.reason ?? '';\n const auditDetail = {\n winnerId,\n loserId,\n reason,\n filledFields,\n loserSnapshot,\n };\n await activities.create({\n ...(winner.tenantId !== null ? { tenantId: winner.tenantId } : {}),\n subjectKind: 'lead',\n subjectId: winnerId,\n activityKind: 'merge',\n summary: `Merged duplicate lead '${loser.name}' into this lead`,\n actorProfileId,\n metadata: JSON.stringify({ ...auditDetail, direction: 'absorbed' }),\n });\n await activities.create({\n ...(loser.tenantId !== null ? { tenantId: loser.tenantId } : {}),\n subjectKind: 'lead',\n subjectId: loserId,\n activityKind: 'merge',\n summary: `Merged into lead '${winner.name}'`,\n actorProfileId,\n metadata: JSON.stringify({ ...auditDetail, direction: 'merged_away' }),\n });\n\n return { winner, loser };\n }\n\n /**\n * The lead's activity trail INCLUDING the trails of every lead merged into\n * it, transitively (losers keep their own activities; this read\n * re-assembles the full history across `mergedIntoId` chains).\n *\n * Traversal is breadth-first over merge children with a visited-set guard,\n * so malformed cyclic data cannot loop. Results are in chronological\n * order.\n */\n async activitiesIncludingMerged(leadId: string): Promise<SalesActivity[]> {\n const visited = new Set<string>();\n let frontier = [leadId];\n while (frontier.length > 0) {\n const batch = frontier.filter((id) => id && !visited.has(id));\n if (batch.length === 0) break;\n for (const id of batch) {\n visited.add(id);\n }\n const children = await this.list({\n where: { 'mergedIntoId in': batch },\n });\n frontier = children\n .map((child) => child.id ?? '')\n .filter((id) => id !== '');\n }\n\n const activities = await this.getActivityCollection();\n return await activities.list({\n where: { subjectKind: 'lead', 'subjectId in': Array.from(visited) },\n orderBy: ['createdAt ASC', 'id ASC'],\n });\n }\n}\n\ninterface InboxSqlPredicate {\n sql: string;\n values: unknown[];\n}\n\nfunction inboxNextActionsCte(): InboxSqlPredicate {\n return {\n sql: `WITH inbox_next_actions AS (\n SELECT subject_id, MIN(due_at) AS due_at\n FROM sales_activities\n WHERE tenant_id = ?\n AND subject_kind = 'lead'\n AND activity_kind = 'task'\n AND completed_at IS NULL\n AND due_at IS NOT NULL\n GROUP BY subject_id\n )`,\n values: [],\n };\n}\n\nfunction buildInboxBasePredicate(\n options: NormalizedLeadInboxOptions,\n tenantId: string,\n readScope: { sql: string; values: unknown[] },\n): InboxSqlPredicate {\n const clauses = ['l.tenant_id = ?', `(${readScope.sql})`];\n const values: unknown[] = [tenantId, ...readScope.values];\n if (options.ownerRepId) {\n clauses.push('l.owner_rep_id = ?');\n values.push(options.ownerRepId);\n }\n if (options.search) {\n const literal = options.search.toLowerCase().replace(/[!%_]/g, '!$&');\n const match = `%${literal}%`;\n clauses.push(`(\n LOWER(COALESCE(l.name, '')) LIKE ? ESCAPE '!'\n OR LOWER(COALESCE(l.contact_name, '')) LIKE ? ESCAPE '!'\n OR LOWER(COALESCE(l.email, '')) LIKE ? ESCAPE '!'\n OR LOWER(COALESCE(l.phone, '')) LIKE ? ESCAPE '!'\n OR LOWER(COALESCE(l.organization_name, '')) LIKE ? ESCAPE '!'\n )`);\n values.push(match, match, match, match, match);\n }\n return { sql: clauses.join(' AND '), values };\n}\n\nfunction buildInboxTabPredicate(\n options: NormalizedLeadInboxOptions,\n now: string,\n): InboxSqlPredicate {\n const clauses: string[] = [];\n const values: unknown[] = [];\n if (options.status) {\n clauses.push('l.status = ?');\n values.push(options.status);\n }\n if (options.unassigned) {\n clauses.push(\n \"(l.owner_rep_id IS NULL OR CAST(l.owner_rep_id AS TEXT) = '')\",\n );\n }\n if (options.overdue) {\n clauses.push('na.due_at < ?');\n values.push(now);\n }\n return { sql: clauses.join(' AND ') || '1 = 1', values };\n}\n\nfunction inboxOrderBy(sort: NormalizedLeadInboxOptions['sort']): string {\n switch (sort) {\n case 'name':\n return 'LOWER(l.name) ASC, l.id ASC';\n case 'next_action':\n return 'CASE WHEN na.due_at IS NULL THEN 1 ELSE 0 END ASC, na.due_at ASC, l.id ASC';\n default:\n return 'l.created_at DESC, l.id ASC';\n }\n}\n\nfunction toInboxCount(value: unknown): number {\n const count = Number(value ?? 0);\n if (!Number.isSafeInteger(count) || count < 0) {\n throw new Error(\n `LeadCollection.listInbox: database returned invalid count '${String(value)}'`,\n );\n }\n return count;\n}\n\nexport default LeadCollection;\n","/**\n * OpportunityConversion — idempotent link from a won deal to a downstream record.\n * @packageDocumentation\n */\n\nimport {\n field,\n foreignKey,\n SmrtObject,\n type SmrtSaveOptions,\n smrt,\n} from '@happyvertical/smrt-core';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\nimport type { OpportunityConversionOptions } from '../types.js';\n\n/**\n * OpportunityConversion records that a WON opportunity materialized into a\n * downstream record — a client, project, contract, subscription, or any\n * caller-defined kind. The target is a generic `(targetKind, targetId)`\n * string pair: CRM never creates (or mutates) the downstream records\n * themselves and never touches referral or commission state.\n *\n * The natural key `(opportunity_id, target_kind, target_id)`\n * (`conflictColumns`) makes recording idempotent — use\n * `OpportunityConversionCollection.recordConversion()`, which enforces the\n * won-status precondition and reports whether the link already existed.\n * Links are append-only: the generated surfaces expose `list`/`get`/`create`\n * only (no update/delete).\n *\n * @example\n * ```typescript\n * const conversions = await OpportunityConversionCollection.create({ db });\n * const { conversion, created } = await conversions.recordConversion({\n * opportunityId: opportunity.id ?? '',\n * targetKind: 'contract',\n * targetId: contractId,\n * });\n * ```\n */\n@TenantScoped({ mode: 'optional' })\n@smrt({\n api: { include: ['list', 'get', 'create'] }, // append-only — no update/delete\n mcp: { include: ['list', 'get'] },\n cli: false,\n conflictColumns: ['opportunity_id', 'target_kind', 'target_id'],\n})\nexport class OpportunityConversion extends SmrtObject { static __smrtPackage__ = \"@happyvertical/smrt-sales\";\n /**\n * Tenant ID for multi-tenant isolation.\n * Nullable to support both tenant-scoped and global conversions.\n */\n @tenantId({ nullable: true })\n tenantId: string | null = null;\n\n /** The won opportunity that converted. Required. */\n @foreignKey('Opportunity', { required: true })\n opportunityId: string = '';\n\n /**\n * Downstream record kind — OPEN string: `'client'`, `'project'`,\n * `'contract'`, `'subscription'`, … Required.\n */\n @field({ required: true })\n targetKind: string = '';\n\n /** Identifier of the downstream record within `targetKind`. Required. */\n @field({ required: true })\n targetId: string = '';\n\n /** Optional human-readable note about the conversion. */\n note: string = '';\n\n /**\n * Free-form JSON object stored as a string. Use\n * {@link getMetadata}/{@link setMetadata} instead of parsing manually.\n */\n metadata: string = '{}';\n\n constructor(options: OpportunityConversionOptions = {}) {\n super(options);\n if (options.tenantId !== undefined) this.tenantId = options.tenantId;\n if (options.opportunityId !== undefined)\n this.opportunityId = options.opportunityId;\n if (options.targetKind !== undefined) this.targetKind = options.targetKind;\n if (options.targetId !== undefined) this.targetId = options.targetId;\n if (options.note !== undefined) this.note = options.note;\n if (options.metadata !== undefined) this.metadata = options.metadata;\n }\n\n /** Parse the metadata JSON string; returns `{}` on malformed content. */\n getMetadata(): Record<string, unknown> {\n try {\n const parsed: unknown = JSON.parse(this.metadata);\n if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {\n return parsed as Record<string, unknown>;\n }\n return {};\n } catch {\n return {};\n }\n }\n\n /** Serialize and store the metadata object. */\n setMetadata(metadata: Record<string, unknown>): void {\n this.metadata = JSON.stringify(metadata);\n }\n\n /**\n * Save with the append-only guard: a fresh instance whose\n * `(opportunityId, targetKind, targetId)` natural key already belongs to\n * a DIFFERENT row is refused — the conflict-column upsert would replace\n * the existing conversion link (note and id) without the won-opportunity\n * validation. Idempotent linking goes through\n * `OpportunityConversionCollection.recordConversion()`, which finds\n * first and reports `{ created: false }`.\n */\n override async save(options?: SmrtSaveOptions): Promise<this> {\n if (this.opportunityId && this.targetKind && this.targetId) {\n try {\n const res = await this.db.query(\n `SELECT id FROM ${this.tableName} WHERE opportunity_id = $1 AND target_kind = $2 AND target_id = $3`,\n this.opportunityId,\n this.targetKind,\n this.targetId,\n );\n const rows = Array.isArray(res)\n ? (res as Record<string, unknown>[])\n : ((res as { rows?: Record<string, unknown>[] }).rows ?? []);\n const taken = rows.find((row) => row.id !== this.id);\n if (taken) {\n throw new Error(\n `OpportunityConversion ${this.opportunityId}/${this.targetKind}/${this.targetId}: ` +\n 'this conversion link already exists — conversion links are ' +\n 'append-only. Use ' +\n 'OpportunityConversionCollection.recordConversion() for ' +\n 'idempotent linking.',\n );\n }\n } catch (error) {\n if (error instanceof Error && error.message.includes('append-only')) {\n throw error;\n }\n // DB not ready / table absent — nothing persisted to collide with.\n }\n }\n return (await super.save(options)) as this;\n }\n}\n\nexport default OpportunityConversion;\n","/**\n * OpportunityConversionCollection — collection manager for\n * OpportunityConversion, including the idempotent recorder.\n * @packageDocumentation\n */\n\nimport { SmrtCollection } from '@happyvertical/smrt-core';\nimport { OpportunityConversion } from '../models/OpportunityConversion.js';\nimport type {\n RecordConversionParams,\n RecordConversionResult,\n} from '../types.js';\nimport { OpportunityCollection } from './OpportunityCollection.js';\n\nexport class OpportunityConversionCollection extends SmrtCollection<OpportunityConversion> {\n static readonly _itemClass = OpportunityConversion;\n\n private opportunityCollectionPromise: Promise<OpportunityCollection> | null =\n null;\n\n /** Sibling opportunity collection sharing this collection's DB connection. */\n private async getOpportunityCollection(): Promise<OpportunityCollection> {\n if (!this.opportunityCollectionPromise) {\n this.opportunityCollectionPromise = OpportunityCollection.create({\n db: this.db,\n _reuseInitializedDb: true,\n _deferRuntimeInitialization: true,\n });\n }\n return this.opportunityCollectionPromise;\n }\n\n /** All conversion links recorded for one opportunity, oldest first. */\n async findByOpportunity(\n opportunityId: string,\n ): Promise<OpportunityConversion[]> {\n return await this.list({\n where: { opportunityId },\n orderBy: 'created_at ASC',\n });\n }\n\n /**\n * Record that a WON opportunity materialized into a downstream record,\n * idempotently on the natural key `(opportunityId, targetKind, targetId)`.\n *\n * Preconditions: the opportunity must exist and its status must be `'won'`\n * — conversions from open or lost deals are rejected with a clear error.\n * CRM only records the link; creating the downstream record itself\n * (client, project, contract, subscription, …) is the caller's job.\n *\n * @returns `{ conversion, created }` — `created: false` when the link\n * already existed (the existing row is returned untouched)\n */\n async recordConversion(\n params: RecordConversionParams,\n ): Promise<RecordConversionResult> {\n const opportunities = await this.getOpportunityCollection();\n const opportunity = await opportunities.get({ id: params.opportunityId });\n if (!opportunity) {\n throw new Error(\n `OpportunityConversionCollection.recordConversion: opportunity '${params.opportunityId}' not found`,\n );\n }\n if (opportunity.status !== 'won') {\n throw new Error(\n `OpportunityConversionCollection.recordConversion: opportunity '${params.opportunityId}' ` +\n `has status '${opportunity.status}' — conversions can only be recorded for won opportunities`,\n );\n }\n\n const existing = await this.list({\n where: {\n opportunityId: params.opportunityId,\n targetKind: params.targetKind,\n targetId: params.targetId,\n },\n limit: 1,\n });\n if (existing[0]) {\n return { conversion: existing[0], created: false };\n }\n\n const conversion = await this.create({\n ...(opportunity.tenantId !== null\n ? { tenantId: opportunity.tenantId }\n : {}),\n opportunityId: params.opportunityId,\n targetKind: params.targetKind,\n targetId: params.targetId,\n note: params.note ?? '',\n });\n return { conversion, created: true };\n }\n}\n\nexport default OpportunityConversionCollection;\n","/** Package-private write capability; absent from every public barrel. */\nimport { AsyncLocalStorage } from 'node:async_hooks';\nimport type { DatabaseInterface } from '@happyvertical/sql';\n\nconst writes = new AsyncLocalStorage<DatabaseInterface>();\nexport function withGovernanceWrite<T>(\n db: DatabaseInterface,\n fn: () => Promise<T>,\n): Promise<T> {\n return writes.run(db, fn);\n}\nexport function assertGovernanceWrite(db: DatabaseInterface): void {\n if (writes.getStore() !== db)\n throw new Error('Sales governance state is service-owned');\n}\n","/** Immutable intent/result audit for seller governance operations. */\nimport {\n SmrtObject,\n type SmrtObjectOptions,\n type SmrtSaveOptions,\n smrt,\n} from '@happyvertical/smrt-core';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\n\nimport { assertGovernanceWrite } from '../services/governance-write.js';\n\nexport interface SalesGovernanceEventOptions extends SmrtObjectOptions {\n tenantId?: string;\n intent?: string;\n result?: string;\n}\nconst snapshots = new WeakMap<SalesGovernanceEvent, string>();\n\n/** UUID replay fence and immutable audit; no generated mutation surface. */\n@TenantScoped({ mode: 'required' })\n@smrt({ api: false, mcp: false, cli: false })\nexport class SalesGovernanceEvent extends SmrtObject { static __smrtPackage__ = \"@happyvertical/smrt-sales\";\n @tenantId()\n tenantId: string = '';\n intent: string = '';\n result: string = '';\n\n constructor(options: SalesGovernanceEventOptions = {}) {\n super(options);\n if (options.tenantId !== undefined) this.tenantId = options.tenantId;\n if (options.intent !== undefined) this.intent = options.intent;\n if (options.result !== undefined) this.result = options.result;\n }\n\n override async initialize(): Promise<this> {\n await super.initialize();\n if (await this.isSaved()) snapshots.set(this, this.snapshot());\n return this;\n }\n\n override async save(options?: SmrtSaveOptions): Promise<this> {\n const previous = snapshots.get(this);\n if (previous !== undefined && previous !== this.snapshot()) {\n throw new Error('Sales governance events are immutable');\n }\n assertGovernanceWrite(this.db);\n await super.save(options);\n snapshots.set(this, this.snapshot());\n return this;\n }\n\n override async delete(): Promise<void> {\n throw new Error('Sales governance events cannot be deleted');\n }\n\n private snapshot(): string {\n return JSON.stringify([this.tenantId, this.intent, this.result]);\n }\n}\n","/** Read immutable operation outcomes and history in the current tenant. */\nimport { SmrtCollection } from '@happyvertical/smrt-core';\nimport { SalesGovernanceEvent } from '../models/SalesGovernanceEvent.js';\n\nexport class SalesGovernanceEventCollection extends SmrtCollection<SalesGovernanceEvent> {\n static readonly _itemClass = SalesGovernanceEvent;\n}\n","/** Private transactional state for advertiser leases and governed quotes. */\nimport {\n SmrtObject,\n type SmrtObjectOptions,\n type SmrtSaveOptions,\n smrt,\n} from '@happyvertical/smrt-core';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\n\nimport { assertGovernanceWrite } from '../services/governance-write.js';\n\nexport interface SalesGovernanceStateOptions extends SmrtObjectOptions {\n tenantId?: string;\n revision?: number;\n payload?: string;\n}\n\n/** Service-owned compare-and-swap fence. Migrate through the SMRT manifest. */\n@TenantScoped({ mode: 'required' })\n@smrt({ api: false, mcp: false, cli: false })\nexport class SalesGovernanceState extends SmrtObject { static __smrtPackage__ = \"@happyvertical/smrt-sales\";\n @tenantId()\n tenantId: string = '';\n revision: number = 0;\n payload: string = '{}';\n\n constructor(options: SalesGovernanceStateOptions = {}) {\n super(options);\n if (options.tenantId !== undefined) this.tenantId = options.tenantId;\n if (options.revision !== undefined) this.revision = options.revision;\n if (options.payload !== undefined) this.payload = options.payload;\n }\n override async save(options?: SmrtSaveOptions): Promise<this> {\n assertGovernanceWrite(this.db);\n return super.save(options);\n }\n override async delete(): Promise<void> {\n throw new Error('Sales governance state is service-owned');\n }\n}\n","/** Tenant-filtered database serialization primitives for seller governance. */\nimport { SmrtCollection } from '@happyvertical/smrt-core';\nimport { requireTenantId } from '@happyvertical/smrt-tenancy';\nimport { SalesGovernanceState } from '../models/SalesGovernanceState.js';\n\nimport { assertGovernanceWrite } from '../services/governance-write.js';\n\nexport class SalesGovernanceStateCollection extends SmrtCollection<SalesGovernanceState> {\n static readonly _itemClass = SalesGovernanceState;\n\n /** Insert the shared resource fence without changing its current owner. */\n async ensure(id: string): Promise<void> {\n assertGovernanceWrite(this.db);\n await this.query(\n `INSERT INTO ${this.tableName} (id, slug, context, tenant_id, revision, payload)\n VALUES (?, ?, '', ?, 0, '{}') ON CONFLICT DO NOTHING`,\n [id, id, requireTenantId()],\n { allowRawOnTenantScoped: true },\n );\n }\n\n /** Serialize a resource on pooled adapters and reload its committed state. */\n async lock(id: string): Promise<SalesGovernanceState> {\n await this.ensure(id);\n assertGovernanceWrite(this.db);\n const rows = await this.query(\n `UPDATE ${this.tableName} SET revision = revision WHERE id = ? AND tenant_id = ? RETURNING id`,\n [id, requireTenantId()],\n { allowRawOnTenantScoped: true },\n );\n if (rows.length !== 1)\n throw new Error('Sales governance resource unavailable');\n const state = await this.get({ id }, { cache: false });\n if (!state) throw new Error('Sales governance resource unavailable');\n return state;\n }\n\n /** CAS is the cross-process serialization point; losers must retry the operation. */\n async compareAndSwap(\n id: string,\n revision: number,\n payload: string,\n ): Promise<boolean> {\n assertGovernanceWrite(this.db);\n const rows = await this.query(\n `UPDATE ${this.tableName} SET revision = revision + 1, payload = ?\n WHERE id = ? AND tenant_id = ? AND revision = ? RETURNING id`,\n [payload, id, requireTenantId(), revision],\n { allowRawOnTenantScoped: true },\n );\n return rows.length === 1;\n }\n}\n","/**\n * Declared recipes for smrt-sales (#3590, #3604): user-facing units of\n * functionality an app or agent can pick instead of the whole package.\n * The scanner reads these statics into the `recipes` array of `manifest.json`\n * and `smrt-knowledge.json`; nothing here runs at that point.\n *\n * @packageDocumentation\n */\n\nimport { SmrtRecipe } from '@happyvertical/smrt-core';\nimport { Lead } from './models/Lead.js';\nimport { Opportunity } from './models/Opportunity.js';\nimport { PipelineDefinition } from './models/PipelineDefinition.js';\nimport { PipelineStage } from './models/PipelineStage.js';\nimport { SalesActivity } from './models/SalesActivity.js';\n\n/** Leads & pipeline: Capture leads and move them through your sales stages. */\nexport class SalesPipelineRecipe extends SmrtRecipe {\n static id = 'sales.pipeline';\n static help = './pipeline.recipe.md';\n static label = 'Leads & pipeline';\n static summary = 'Capture leads and move them through your sales stages.';\n static synonyms = ['crm', 'prospects', 'opportunities', 'deals', 'funnel'];\n static section = {\n id: 'sales',\n label: 'Sales',\n icon: 'shoppingBag',\n description: 'Customers, orders and quotes: everything you sell.',\n };\n static models = [\n Lead,\n Opportunity,\n PipelineDefinition,\n PipelineStage,\n SalesActivity,\n ];\n static nav = [\n {\n label: 'Leads',\n model: Lead,\n icon: 'users',\n description:\n 'People who might become customers, and where each one stands.',\n },\n {\n label: 'Opportunities',\n model: Opportunity,\n icon: 'briefcase',\n description: 'Deals in progress, with their value and next step.',\n },\n {\n label: 'Pipelines',\n model: PipelineDefinition,\n icon: 'layers',\n description: 'The stages a deal moves through on its way to a sale.',\n },\n ];\n static options = {\n Lead: {\n fields: {\n profileId: { visibility: 'hidden' },\n mergedIntoId: { visibility: 'hidden' },\n sourceKind: { visibility: 'hidden' },\n sourceId: { visibility: 'hidden' },\n acquisitionContext: { visibility: 'hidden' },\n intakeRef: { visibility: 'hidden' },\n metadata: { visibility: 'hidden' },\n qualifiedAt: { visibility: 'hidden' },\n },\n },\n Opportunity: {\n fields: {\n sourceKind: { visibility: 'hidden' },\n sourceId: { visibility: 'hidden' },\n metadata: { visibility: 'hidden' },\n outcomeReason: { visibility: 'hidden' },\n wonAt: { visibility: 'hidden' },\n lostAt: { visibility: 'hidden' },\n },\n },\n PipelineStage: { fields: { metadata: { visibility: 'hidden' } } },\n SalesActivity: {\n fields: {\n metadata: { visibility: 'hidden' },\n actorProfileId: { visibility: 'hidden' },\n },\n },\n } as const;\n}\n","/** Policy-free, caller-transaction Lead conversion receipts. @packageDocumentation */\nimport { createHash } from 'node:crypto';\nimport type { SmrtClassOptions } from '@happyvertical/smrt-core';\nimport { requireTenantId } from '@happyvertical/smrt-tenancy';\nimport { LeadCollection } from '../collections/LeadCollection.js';\nimport { SalesActivityCollection } from '../collections/SalesActivityCollection.js';\n\n/** Scope of one downstream conversion. Target kinds are host-defined. */\nexport interface GetLeadConversionInput {\n tenantId: string;\n leadId: string;\n targetKind: string;\n}\n/** Immutable host-created downstream target and its provenance. */\nexport interface LeadConversionReceipt extends GetLeadConversionInput {\n id: string;\n targetId: string;\n actorProfileId: string;\n metadata: Record<string, unknown>;\n}\n/** Record a target the host created within the same transaction. */\nexport interface RecordLeadConversionInput extends GetLeadConversionInput {\n targetId: string;\n actorProfileId: string;\n metadata?: Record<string, unknown>;\n}\n\n/**\n * Records an early Lead conversion without qualifying or closing a deal.\n * The host must authorize inputs, own the transaction, and serialize writes\n * for the tenant/lead/targetKind scope before creating a target. This service\n * participates in that executor and never opens a nested transaction. Returned\n * receipts are plain data; use them only after the caller commits.\n */\nexport class LeadConversionService {\n private constructor(\n private readonly leads: LeadCollection,\n private readonly activities: SalesActivityCollection,\n private readonly callerTransaction: boolean,\n ) {}\n\n /** Bind read access to any initialized executor; mutations require caller mode. */\n static async create(\n options: SmrtClassOptions & { transaction?: 'caller' },\n ): Promise<LeadConversionService> {\n if (!options.db)\n throw new Error('Lead conversion requires an initialized database');\n const collectionOptions = {\n db: options.db,\n _reuseInitializedDb: true,\n _deferRuntimeInitialization: true,\n };\n return new LeadConversionService(\n await LeadCollection.create(collectionOptions),\n await SalesActivityCollection.create(collectionOptions),\n options.transaction === 'caller',\n );\n }\n\n /** Read the tenant-local receipt, failing closed for inaccessible Leads. */\n async getForLead(\n input: GetLeadConversionInput,\n ): Promise<LeadConversionReceipt | null> {\n const scope = await this.scope(input);\n const id = receiptId(scope);\n const activity = await this.activities.get({ id }, { cache: false });\n if (!activity) return null;\n const envelope = activity.getMetadata();\n if (\n activity.tenantId !== scope.tenantId ||\n activity.subjectKind !== 'lead' ||\n activity.subjectId !== scope.leadId ||\n activity.activityKind !== 'lead_conversion' ||\n envelope.targetKind !== scope.targetKind ||\n typeof envelope.targetId !== 'string' ||\n !envelope.targetId ||\n !isObject(envelope.metadata)\n ) {\n throw new Error('Lead conversion receipt is inconsistent');\n }\n return {\n ...scope,\n id,\n targetId: envelope.targetId,\n actorProfileId: activity.actorProfileId,\n metadata: envelope.metadata,\n };\n }\n\n /** Resolve originating Leads for a host target without exposing receipt storage. */\n async findForTarget(input: {\n tenantId: string;\n targetKind: string;\n targetId: string;\n }): Promise<LeadConversionReceipt[]> {\n const tenantId = requireTenantId();\n if (input.tenantId !== tenantId)\n throw new Error('Lead is unavailable in the active tenant');\n const targetKind = text(input.targetKind, 'targetKind');\n const targetId = text(input.targetId, 'targetId');\n const candidates = await this.activities.list({\n where: { tenantId, subjectKind: 'lead', activityKind: 'lead_conversion' },\n orderBy: 'created_at ASC',\n });\n const receipts: LeadConversionReceipt[] = [];\n for (const candidate of candidates) {\n const metadata = candidate.getMetadata();\n if (metadata.targetKind !== targetKind || metadata.targetId !== targetId)\n continue;\n const receipt = await this.getForLead({\n tenantId,\n leadId: candidate.subjectId,\n targetKind,\n });\n if (\n receipt &&\n receipt.id === candidate.id &&\n receipt.targetId === targetId\n )\n receipts.push(receipt);\n }\n return receipts;\n }\n\n /** Exact retries preserve the original actor and receipt; changed intent fails. */\n async recordForLead(\n input: RecordLeadConversionInput,\n ): Promise<LeadConversionReceipt> {\n if (!this.callerTransaction)\n throw new Error('Lead conversion requires a caller-owned transaction');\n const targetId = text(input.targetId, 'targetId');\n const actorProfileId = text(input.actorProfileId, 'actorProfileId');\n const metadata = jsonObject(input.metadata ?? {});\n const existing = await this.getForLead(input);\n if (existing) {\n if (\n existing.targetId !== targetId ||\n stableJson(existing.metadata) !== stableJson(metadata)\n ) {\n throw new Error(\n 'Lead conversion already recorded with different intent',\n );\n }\n return existing;\n }\n const scope = await this.scope(input);\n const id = receiptId(scope);\n await this.activities.create({\n id,\n tenantId: scope.tenantId,\n subjectKind: 'lead',\n subjectId: scope.leadId,\n activityKind: 'lead_conversion',\n summary: `Lead converted to ${scope.targetKind}`,\n actorProfileId,\n metadata: JSON.stringify({\n targetKind: scope.targetKind,\n targetId,\n metadata,\n }),\n });\n return { ...scope, id, targetId, actorProfileId, metadata };\n }\n\n private async scope(\n input: GetLeadConversionInput,\n ): Promise<GetLeadConversionInput> {\n const tenantId = requireTenantId();\n if (input.tenantId !== tenantId)\n throw new Error('Lead is unavailable in the active tenant');\n const leadId = text(input.leadId, 'leadId');\n const targetKind = text(input.targetKind, 'targetKind');\n const lead = await this.leads.get({ id: leadId }, { cache: false });\n if (!lead || lead.tenantId !== tenantId)\n throw new Error('Lead is unavailable in the active tenant');\n return { tenantId, leadId, targetKind };\n }\n}\n\nfunction text(value: string, name: string): string {\n if (typeof value !== 'string' || !value.trim() || value !== value.trim()) {\n throw new Error(\n `Lead conversion ${name} must be a nonempty trimmed string`,\n );\n }\n return value;\n}\nfunction isObject(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === 'object' && !Array.isArray(value);\n}\nfunction jsonObject(value: unknown): Record<string, unknown> {\n if (!isObject(value))\n throw new Error('Lead conversion metadata must be a JSON object');\n let encoded: string;\n try {\n encoded = JSON.stringify(value, (_key, item) => {\n if (\n typeof item === 'function' ||\n typeof item === 'symbol' ||\n typeof item === 'undefined' ||\n (typeof item === 'number' && !Number.isFinite(item))\n ) {\n throw new Error('Non-JSON metadata');\n }\n return item;\n });\n } catch {\n throw new Error('Lead conversion metadata must contain only JSON data');\n }\n return JSON.parse(encoded) as Record<string, unknown>;\n}\nfunction stableJson(value: unknown): string {\n if (Array.isArray(value)) return `[${value.map(stableJson).join(',')}]`;\n if (isObject(value))\n return `{${Object.keys(value)\n .sort()\n .map((key) => `${JSON.stringify(key)}:${stableJson(value[key])}`)\n .join(',')}}`;\n return JSON.stringify(value);\n}\nfunction receiptId(scope: GetLeadConversionInput): string {\n const hash = createHash('sha256')\n .update(\n JSON.stringify([\n 'lead-conversion-v1',\n scope.tenantId,\n scope.leadId,\n scope.targetKind,\n ]),\n )\n .digest('hex');\n return `${hash.slice(0, 8)}-${hash.slice(8, 12)}-5${hash.slice(13, 16)}-a${hash.slice(17, 20)}-${hash.slice(20, 32)}`;\n}\n","/**\n * Tenant-safe, audited follow-up workflow for CRM Leads.\n *\n * The service is the narrow mutation seam for generic Lead intake, follow-up,\n * qualification, and Opportunity closure. It delegates persistence lifecycles\n * to their owning collections and never creates downstream records.\n *\n * @packageDocumentation\n */\n\nimport { createHash } from 'node:crypto';\nimport type { SmrtClassOptions } from '@happyvertical/smrt-core';\nimport {\n requireTenantId,\n TenantContextError,\n} from '@happyvertical/smrt-tenancy';\nimport type { DatabaseInterface } from '@happyvertical/sql';\nimport { LeadCollection } from '../collections/LeadCollection.js';\nimport { OpportunityCollection } from '../collections/OpportunityCollection.js';\nimport { OpportunityConversionCollection } from '../collections/OpportunityConversionCollection.js';\nimport { PipelineDefinitionCollection } from '../collections/PipelineDefinitionCollection.js';\nimport { PipelineStageCollection } from '../collections/PipelineStageCollection.js';\nimport { SalesActivityCollection } from '../collections/SalesActivityCollection.js';\nimport { SalesRepresentativeCollection } from '../collections/SalesRepresentativeCollection.js';\nimport type { Lead } from '../models/Lead.js';\nimport type { Opportunity } from '../models/Opportunity.js';\nimport type { OpportunityConversion } from '../models/OpportunityConversion.js';\nimport type { PipelineStage } from '../models/PipelineStage.js';\nimport {\n permitSalesActivityWorkflowCompletion,\n type SalesActivity,\n} from '../models/SalesActivity.js';\nimport type { SalesRepresentative } from '../models/SalesRepresentative.js';\nimport type { LeadStatus } from '../types.js';\n\n/** Human follow-up kinds accepted by {@link LeadWorkflowService.recordActivity}. */\nexport const LEAD_HUMAN_ACTIVITY_KINDS = [\n 'note',\n 'call',\n 'email',\n 'meeting',\n] as const;\nexport type LeadHumanActivityKind = (typeof LEAD_HUMAN_ACTIVITY_KINDS)[number];\n\n/** Maximum persisted text length for generic workflow summaries and reasons. */\nexport const MAX_LEAD_WORKFLOW_TEXT_LENGTH = 1_000;\n\nconst UUID_RE =\n /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/iu;\n\n/** Queue state for a lead's next actionable follow-up step. */\nexport type LeadWorkQueueState =\n | 'terminal'\n | 'reopenable'\n | 'unassigned'\n | 'no_next_action'\n | 'overdue'\n | 'due_today'\n | 'upcoming';\n\n/** Plain input consumed by {@link projectLeadWorkQueue}; safe for host view mappers. */\nexport interface LeadWorkQueueInput {\n status: LeadStatus;\n ownerRepId?: string | null;\n nextAction?: { dueAt?: Date | null } | null;\n /** Inject a clock to make queue classification deterministic. */\n now?: Date;\n /**\n * Optional IANA timezone used only for the calendar-day boundary. Omitting\n * it leaves the host/runtime timezone in control; CRM never imposes one.\n */\n timeZone?: string;\n}\n\n/** Reusable, policy-free work-queue projection. */\nexport interface LeadWorkQueueProjection {\n state: LeadWorkQueueState;\n isActionable: boolean;\n isUnassigned: boolean;\n hasNoNextAction: boolean;\n isOverdue: boolean;\n isDueToday: boolean;\n isUpcoming: boolean;\n isTerminal: boolean;\n isReopenable: boolean;\n}\n\n/**\n * Classify a lead without assuming an SLA, automatic owner, or timezone.\n * Terminal qualified/merged rows are never queued; disqualified leads remain\n * explicitly reopenable rather than being conflated with immutable terminals.\n */\nexport function projectLeadWorkQueue(\n input: LeadWorkQueueInput,\n): LeadWorkQueueProjection {\n const terminal = input.status === 'qualified' || input.status === 'merged';\n const reopenable = input.status === 'disqualified';\n const ownerRepId = input.ownerRepId?.trim() ?? '';\n const dueAt = input.nextAction?.dueAt ?? null;\n const dueTime = dueAt instanceof Date ? dueAt.getTime() : Number.NaN;\n const now = input.now ?? new Date();\n const nowTime = now.getTime();\n\n if (terminal) return queueProjection('terminal');\n if (reopenable) return queueProjection('reopenable');\n if (!ownerRepId) return queueProjection('unassigned');\n if (!Number.isFinite(dueTime)) return queueProjection('no_next_action');\n if (dueTime < nowTime) return queueProjection('overdue');\n\n const dueDay = calendarDayKey(new Date(dueTime), input.timeZone);\n const nowDay = calendarDayKey(now, input.timeZone);\n return queueProjection(dueDay === nowDay ? 'due_today' : 'upcoming');\n}\n\n/** Details returned to reusable UI after one tenant-safe work-state read. */\nexport interface LeadWorkState {\n lead: Lead;\n owner: SalesRepresentative | null;\n earliestOpenTask: SalesActivity | null;\n /** Canonical opportunity created from this lead, when one is visible. */\n opportunity: Opportunity | null;\n queue: LeadWorkQueueProjection;\n}\n\nexport type LeadDedupePolicy = 'none' | 'email' | 'email_or_org';\n\nexport interface CreateLeadInput {\n name: string;\n email?: string;\n contactName?: string;\n phone?: string;\n organizationName?: string;\n /** Optional host-authorized Profile identity for the prospect/requester. */\n profileId?: string;\n sourceKind: string;\n sourceId?: string;\n acquisitionContext?: Record<string, unknown>;\n ownerRepId?: string;\n actorProfileId?: string;\n dedupe?: LeadDedupePolicy;\n idempotencyKey?: string;\n now?: Date;\n}\n\nexport interface CreateLeadResult {\n lead: Lead;\n created: boolean;\n /** A terminal possible duplicate that requires an explicit caller decision. */\n duplicateOf?: Lead;\n}\n\nexport interface QualifyLeadInput {\n leadId: string;\n pipelineId?: string;\n actorProfileId: string;\n opportunityName?: string;\n expectedValueCents?: number;\n currency?: string;\n expectedCloseAt?: Date | null;\n now?: Date;\n}\n\nexport interface QualifyLeadResult {\n lead: Lead;\n opportunity: Opportunity;\n created: boolean;\n}\n\nexport interface MoveOpportunityToStageInput {\n opportunityId: string;\n stageId: string;\n actorProfileId: string;\n probabilityOverride?: number;\n now?: Date;\n}\n\nexport interface MoveOpportunityToStageResult {\n opportunity: Opportunity;\n /** `false` for an exact retry of the current stage and probability. */\n changed: boolean;\n}\n\nexport interface OpportunityConversionInput {\n targetKind: string;\n targetId: string;\n note?: string;\n}\n\nexport interface CloseOpportunityInput {\n opportunityId: string;\n outcome: 'won' | 'lost';\n actorProfileId: string;\n reason?: string;\n conversion?: OpportunityConversionInput;\n now?: Date;\n}\n\nexport interface CloseOpportunityResult {\n opportunity: Opportunity;\n conversion?: OpportunityConversion;\n changed: boolean;\n conversionCreated?: boolean;\n}\n\nexport interface AssignLeadInput {\n leadId: string;\n ownerRepId: string;\n actorProfileId: string;\n now?: Date;\n}\n\nexport interface AssignLeadResult {\n lead: Lead;\n /** `false` when the active representative already owned the Lead. */\n changed: boolean;\n}\n\n/** Operator-authorized correction; identity and acquisition provenance stay intact. */\nexport interface UpdateLeadContactInput {\n leadId: string;\n actorProfileId: string;\n name: string;\n contactName: string;\n email: string;\n now?: Date;\n}\n\nexport interface StartWorkingInput {\n leadId: string;\n actorProfileId: string;\n now?: Date;\n}\n\nexport interface DisqualifyLeadInput {\n leadId: string;\n actorProfileId: string;\n reason: string;\n now?: Date;\n}\n\nexport interface RecordLeadActivityInput {\n leadId: string;\n actorProfileId: string;\n activityKind: LeadHumanActivityKind;\n summary: string;\n metadata?: Record<string, unknown>;\n now?: Date;\n}\n\nexport interface ScheduleLeadNextActionInput {\n leadId: string;\n actorProfileId: string;\n summary: string;\n dueAt: Date;\n metadata?: Record<string, unknown>;\n now?: Date;\n}\n\nexport interface CompleteLeadNextActionInput {\n leadId: string;\n taskId: string;\n actorProfileId: string;\n now?: Date;\n}\n\nexport interface CompleteLeadNextActionResult {\n task: SalesActivity;\n /** `false` for a compatible exact replay after the task was completed. */\n completed: boolean;\n}\n\nexport interface GetLeadWorkStateInput {\n leadId: string;\n now?: Date;\n timeZone?: string;\n}\n\n/** Stable machine-readable refusal reasons for workflow callers. */\nexport type LeadWorkflowValidationReason =\n | 'tenant_context_required'\n | 'transaction_unavailable'\n | 'lead_unavailable'\n | 'representative_unavailable'\n | 'representative_inactive'\n | 'lead_not_actionable'\n | 'invalid_transition'\n | 'reason_required'\n | 'reason_too_long'\n | 'summary_required'\n | 'summary_too_long'\n | 'invalid_activity_kind'\n | 'invalid_metadata'\n | 'invalid_due_at'\n | 'task_unavailable'\n | 'task_not_open'\n | 'completion_replay_conflict'\n | 'name_required'\n | 'contact_required'\n | 'invalid_email'\n | 'source_kind_required'\n | 'invalid_dedupe_policy'\n | 'invalid_idempotency_key'\n | 'idempotency_conflict'\n | 'pipeline_unavailable'\n | 'pipeline_has_no_terminal_stage'\n | 'stage_unavailable'\n | 'opportunity_unavailable'\n | 'invalid_value'\n | 'invalid_conversion'\n | 'opportunity_replay_conflict';\n\n/** Workflow validation error that never reveals cross-tenant row existence. */\nexport class LeadWorkflowValidationError extends Error {\n readonly code = 'LEAD_WORKFLOW_VALIDATION_ERROR' as const;\n\n constructor(\n readonly reason: LeadWorkflowValidationReason,\n message: string,\n ) {\n super(message);\n this.name = 'LeadWorkflowValidationError';\n }\n}\n\ninterface LeadWorkflowServiceDeps {\n leads: LeadCollection;\n activities: SalesActivityCollection;\n representatives: SalesRepresentativeCollection;\n opportunities: OpportunityCollection;\n conversions: OpportunityConversionCollection;\n pipelines: PipelineDefinitionCollection;\n stages: PipelineStageCollection;\n}\n\n/** Transaction-scoped collections inherit the outer adapter's lock capability. */\ninterface LeadWorkflowTransactionDeps extends LeadWorkflowServiceDeps {\n supportsRowLocks: boolean;\n}\n\ninterface TransactionCapableDatabase extends DatabaseInterface {\n transaction?<T>(fn: (tx: DatabaseInterface) => Promise<T>): Promise<T>;\n}\n\ninterface NormalizedCreateLeadInput {\n name: string;\n email: string;\n contactName: string;\n phone: string;\n organizationName: string;\n profileId: string;\n sourceKind: string;\n sourceId: string;\n acquisitionContext: Record<string, unknown>;\n ownerRepId: string;\n actorProfileId: string;\n dedupe: LeadDedupePolicy;\n idempotencyKey: string;\n now: Date;\n intent: Record<string, unknown>;\n}\n\n/** Serialize mutations for adapters without independent row-locking sessions. */\nconst singleConnectionMutationTails = new WeakMap<\n DatabaseInterface,\n Promise<void>\n>();\n\n/**\n * Reusable Lead follow-up service. Every mutation is one transaction that\n * locks the target lead (and task when completing), applies the guarded model\n * transition, and appends its immutable audit record before commit.\n */\nexport class LeadWorkflowService {\n private constructor(private readonly deps: LeadWorkflowServiceDeps) {}\n\n static async create(\n options: SmrtClassOptions = {},\n ): Promise<LeadWorkflowService> {\n return new LeadWorkflowService({\n leads: await LeadCollection.create(options),\n activities: await SalesActivityCollection.create(options),\n representatives: await SalesRepresentativeCollection.create(options),\n opportunities: await OpportunityCollection.create(options),\n conversions: await OpportunityConversionCollection.create(options),\n pipelines: await PipelineDefinitionCollection.create(options),\n stages: await PipelineStageCollection.create(options),\n });\n }\n\n /** Create or explicitly report a tenant-local duplicate Lead. */\n async createLead(input: CreateLeadInput): Promise<CreateLeadResult> {\n const normalized = this.normalizeCreateLeadInput(input);\n const tenantId = this.requireActiveTenant();\n const intent = stableStringify(normalized.intent);\n const intentHash = sha256(intent);\n const operationId =\n normalized.idempotencyKey || normalized.dedupe !== 'none'\n ? uuidFromHash(\n sha256(\n `lead-intake:${tenantId}:${\n normalized.idempotencyKey\n ? `key:${normalized.idempotencyKey}`\n : `intent:${intentHash}`\n }`,\n ),\n )\n : undefined;\n\n const result = await this.runMutation(async (deps, activeTenantId) => {\n if (operationId) {\n await this.lockOperationFence(deps, `lead-intake:${operationId}`);\n const replay = await deps.activities.get(\n { id: operationId },\n { cache: false },\n );\n if (replay) {\n const metadata = replay.getMetadata();\n if (\n replay.activityKind !== 'lead_intake' &&\n replay.activityKind !== 'inbound'\n ) {\n throw this.refusal(\n 'idempotency_conflict',\n 'Lead intake operation key is already used by another activity',\n );\n }\n if (metadata.intentHash !== intentHash) {\n throw this.refusal(\n 'idempotency_conflict',\n 'Lead intake idempotency key was already used with different input',\n );\n }\n return {\n leadId: replay.subjectId,\n created: false,\n };\n }\n }\n\n if (normalized.ownerRepId) {\n const representative = await deps.representatives.get(\n { id: normalized.ownerRepId },\n { cache: false },\n );\n if (!representative) {\n throw this.refusal(\n 'representative_unavailable',\n 'Representative is unavailable in the active tenant',\n );\n }\n if (!representative.isActive()) {\n throw this.refusal(\n 'representative_inactive',\n 'Representative is not active',\n );\n }\n }\n\n const matches = await this.findDedupeMatches(\n deps,\n activeTenantId,\n normalized,\n );\n const active = matches.find(\n (candidate) =>\n candidate.status === 'new' || candidate.status === 'working',\n );\n if (active) {\n const leadId = this.requireLeadId(active);\n await deps.activities.create({\n ...(operationId ? { id: operationId } : {}),\n tenantId: activeTenantId,\n subjectKind: 'lead',\n subjectId: leadId,\n activityKind: 'inbound',\n summary: 'Received duplicate lead intake',\n actorProfileId: normalized.actorProfileId,\n metadata: JSON.stringify({\n intentHash,\n created: false,\n dedupe: normalized.dedupe,\n receivedAt: normalized.now.toISOString(),\n sourceKind: normalized.sourceKind,\n sourceId: normalized.sourceId,\n }),\n });\n return { leadId, created: false };\n }\n\n const terminal = matches[0];\n if (terminal) {\n const duplicateOfId = this.requireLeadId(terminal);\n return {\n leadId: duplicateOfId,\n created: false,\n duplicateOfId,\n };\n }\n\n const lead = await deps.leads.create({\n tenantId: activeTenantId,\n name: normalized.name,\n email: normalized.email,\n contactName: normalized.contactName,\n phone: normalized.phone,\n organizationName: normalized.organizationName,\n ...(normalized.profileId ? { profileId: normalized.profileId } : {}),\n sourceKind: normalized.sourceKind,\n sourceId: normalized.sourceId,\n acquisitionContext: stableStringify(normalized.acquisitionContext),\n ownerRepId: normalized.ownerRepId,\n status: 'new',\n });\n const leadId = this.requireLeadId(lead);\n await deps.activities.create({\n ...(operationId ? { id: operationId } : {}),\n tenantId: activeTenantId,\n subjectKind: 'lead',\n subjectId: leadId,\n activityKind: 'lead_intake',\n summary: 'Created lead from intake',\n actorProfileId: normalized.actorProfileId,\n metadata: JSON.stringify({\n intentHash,\n created: true,\n dedupe: normalized.dedupe,\n receivedAt: normalized.now.toISOString(),\n sourceKind: normalized.sourceKind,\n sourceId: normalized.sourceId,\n }),\n });\n return { leadId, created: true };\n });\n\n const lead = await this.readLead(this.deps.leads, result.leadId, tenantId);\n return {\n lead,\n created: result.created,\n ...(result.duplicateOfId ? { duplicateOf: lead } : {}),\n };\n }\n\n /** Qualify a Lead through the collection lifecycle in one transaction. */\n async qualifyLead(input: QualifyLeadInput): Promise<QualifyLeadResult> {\n const actorProfileId = this.requireIdentifier(\n input.actorProfileId,\n 'actorProfileId',\n );\n if (input.pipelineId && !UUID_RE.test(input.pipelineId)) {\n throw this.refusal(\n 'pipeline_unavailable',\n 'Pipeline is unavailable in the active tenant',\n );\n }\n if (\n input.expectedValueCents !== undefined &&\n (!Number.isSafeInteger(input.expectedValueCents) ||\n input.expectedValueCents < 0)\n ) {\n throw this.refusal(\n 'invalid_value',\n 'Expected value must be a non-negative safe integer number of cents',\n );\n }\n const tenantId = this.requireActiveTenant();\n const result = await this.runMutation(async (deps, activeTenantId) => {\n const lead = await this.lockLead(deps, input.leadId, activeTenantId);\n if (lead.status === 'disqualified' || lead.status === 'merged') {\n throw this.refusal(\n 'invalid_transition',\n `Lead cannot be qualified from '${lead.status}'`,\n );\n }\n if (input.pipelineId) {\n const pipeline = await deps.pipelines.get(\n { id: input.pipelineId },\n { cache: false },\n );\n if (!pipeline || pipeline.tenantId !== activeTenantId) {\n throw this.refusal(\n 'pipeline_unavailable',\n 'Pipeline is unavailable in the active tenant',\n );\n }\n }\n const leadId = this.requireLeadId(lead);\n const prior = await deps.opportunities.findByLead(leadId);\n let opportunity: Opportunity;\n try {\n opportunity = await deps.leads.qualify({\n leadId,\n actorProfileId,\n pipelineId: input.pipelineId,\n opportunityName: input.opportunityName,\n expectedValueCents: input.expectedValueCents,\n currency: input.currency,\n expectedCloseAt: input.expectedCloseAt,\n now: input.now,\n });\n } catch (error) {\n if (\n error instanceof Error &&\n (error.message.includes('pipeline') ||\n error.message.includes('stages'))\n ) {\n throw this.refusal('pipeline_unavailable', error.message);\n }\n throw error;\n }\n return {\n leadId,\n opportunityId: this.requireOpportunityId(opportunity),\n created: prior.length === 0,\n };\n });\n // SQLite and DuckDB root handles multiplex one native connection. Keep\n // post-commit result reads sequential so their prepared statements cannot\n // overlap on that connection.\n const lead = await this.readLead(this.deps.leads, result.leadId, tenantId);\n const opportunity = await this.readOpportunity(\n result.opportunityId,\n tenantId,\n );\n return { lead, opportunity, created: result.created };\n }\n\n /** Move an open Opportunity between nonterminal stages in one transaction. */\n async moveOpportunityToStage(\n input: MoveOpportunityToStageInput,\n ): Promise<MoveOpportunityToStageResult> {\n const actorProfileId = this.requireIdentifier(\n input.actorProfileId,\n 'actorProfileId',\n );\n if (!UUID_RE.test(input.opportunityId)) {\n throw this.refusal(\n 'opportunity_unavailable',\n 'Opportunity is unavailable in the active tenant',\n );\n }\n if (!UUID_RE.test(input.stageId)) {\n throw this.refusal(\n 'stage_unavailable',\n 'Opportunity stage is unavailable in the active tenant',\n );\n }\n if (\n input.probabilityOverride !== undefined &&\n (!Number.isFinite(input.probabilityOverride) ||\n input.probabilityOverride < 0 ||\n input.probabilityOverride > 1)\n ) {\n throw this.refusal(\n 'invalid_value',\n 'Opportunity probability must be between 0 and 1',\n );\n }\n const tenantId = this.requireActiveTenant();\n const result = await this.runMutation(async (deps, activeTenantId) => {\n const opportunity = await this.lockOpportunity(\n deps,\n input.opportunityId,\n activeTenantId,\n );\n if (opportunity.status !== 'open') {\n throw this.refusal(\n 'invalid_transition',\n `Opportunity cannot move stages while '${opportunity.status}'`,\n );\n }\n const stage = await this.lockPipelineStage(\n deps,\n input.stageId,\n activeTenantId,\n );\n if (\n !stage ||\n stage.tenantId !== activeTenantId ||\n stage.pipelineId !== opportunity.pipelineId\n ) {\n throw this.refusal(\n 'stage_unavailable',\n 'Opportunity stage is unavailable in the active tenant and pipeline',\n );\n }\n if (stage.isWon || stage.isLost) {\n throw this.refusal(\n 'invalid_transition',\n 'Terminal Opportunity stages must use closeOpportunity()',\n );\n }\n const probability = input.probabilityOverride ?? stage.probability;\n if (opportunity.stageId === input.stageId) {\n if (opportunity.probability !== probability) {\n throw this.refusal(\n 'opportunity_replay_conflict',\n 'Opportunity is already at this stage with a different probability',\n );\n }\n return { opportunityId: input.opportunityId, changed: false };\n }\n await deps.opportunities.moveToStage({\n opportunityId: input.opportunityId,\n stageId: input.stageId,\n actorProfileId,\n probabilityOverride: input.probabilityOverride,\n now: input.now,\n });\n return { opportunityId: input.opportunityId, changed: true };\n });\n return {\n opportunity: await this.readOpportunity(result.opportunityId, tenantId),\n changed: result.changed,\n };\n }\n\n /** Close an opportunity at its configured terminal stage and optionally link conversion. */\n async closeOpportunity(\n input: CloseOpportunityInput,\n ): Promise<CloseOpportunityResult> {\n const actorProfileId = this.requireIdentifier(\n input.actorProfileId,\n 'actorProfileId',\n );\n if (!UUID_RE.test(input.opportunityId)) {\n throw this.refusal(\n 'opportunity_unavailable',\n 'Opportunity is unavailable in the active tenant',\n );\n }\n if (input.outcome !== 'won' && input.outcome !== 'lost') {\n throw this.refusal(\n 'invalid_transition',\n \"Opportunity outcome must be 'won' or 'lost'\",\n );\n }\n if (input.conversion && input.outcome !== 'won') {\n throw this.refusal(\n 'invalid_conversion',\n 'A conversion can only be recorded for a won opportunity',\n );\n }\n const conversion = input.conversion\n ? {\n targetKind: this.requireOpenIdentifier(\n input.conversion.targetKind,\n 'conversion targetKind',\n ),\n targetId: this.requireOpenIdentifier(\n input.conversion.targetId,\n 'conversion targetId',\n ),\n note: input.conversion.note?.trim() ?? '',\n }\n : undefined;\n const reason = input.reason?.trim();\n if (reason && reason.length > MAX_LEAD_WORKFLOW_TEXT_LENGTH) {\n throw this.refusal(\n 'reason_too_long',\n `Lead workflow reason must be at most ${MAX_LEAD_WORKFLOW_TEXT_LENGTH} characters`,\n );\n }\n const tenantId = this.requireActiveTenant();\n const result = await this.runMutation(async (deps, activeTenantId) => {\n const opportunity = await this.lockOpportunity(\n deps,\n input.opportunityId,\n activeTenantId,\n );\n let changed = false;\n if (opportunity.status !== 'open') {\n if (opportunity.status !== input.outcome) {\n throw this.refusal(\n 'opportunity_replay_conflict',\n `Opportunity is already closed as '${opportunity.status}'`,\n );\n }\n if (reason && opportunity.outcomeReason !== reason) {\n throw this.refusal(\n 'opportunity_replay_conflict',\n 'Opportunity was already closed with a different reason',\n );\n }\n } else {\n const stages = await deps.stages.list({\n where: { pipelineId: opportunity.pipelineId },\n orderBy: 'sort_order ASC',\n });\n const terminal = stages.find((stage) =>\n input.outcome === 'won' ? stage.isWon : stage.isLost,\n );\n if (!terminal?.id) {\n throw this.refusal(\n 'pipeline_has_no_terminal_stage',\n `Opportunity pipeline has no '${input.outcome}' terminal stage`,\n );\n }\n await deps.opportunities.moveToStage({\n opportunityId: input.opportunityId,\n stageId: terminal.id,\n actorProfileId,\n outcomeReason: reason,\n now: input.now,\n });\n changed = true;\n }\n\n let conversionId: string | undefined;\n let conversionCreated: boolean | undefined;\n if (conversion) {\n const recorded = await deps.conversions.recordConversion({\n opportunityId: input.opportunityId,\n ...conversion,\n });\n conversionId = this.requireConversionId(recorded.conversion);\n conversionCreated = recorded.created;\n }\n return {\n opportunityId: input.opportunityId,\n changed,\n conversionId,\n conversionCreated,\n };\n });\n const opportunity = await this.readOpportunity(\n result.opportunityId,\n tenantId,\n );\n const persistedConversion = result.conversionId\n ? await this.deps.conversions.get(\n { id: result.conversionId },\n { cache: false },\n )\n : undefined;\n return {\n opportunity,\n changed: result.changed,\n ...(persistedConversion ? { conversion: persistedConversion } : {}),\n ...(result.conversionCreated !== undefined\n ? { conversionCreated: result.conversionCreated }\n : {}),\n };\n }\n\n /** Assign or reassign an active representative, with one audit row per change. */\n async assignLead(input: AssignLeadInput): Promise<AssignLeadResult> {\n const actorProfileId = this.requireIdentifier(\n input.actorProfileId,\n 'actorProfileId',\n );\n const ownerRepId = this.requireIdentifier(input.ownerRepId, 'ownerRepId');\n return await this.runMutation(async (deps, tenantId) => {\n const lead = await this.lockLead(deps, input.leadId, tenantId);\n this.assertActiveFollowUpLead(lead);\n const representative = await deps.representatives.get(\n { id: ownerRepId },\n { cache: false },\n );\n // The tenant-scoped collection lookup is the membership boundary. Do\n // not infer tenancy from a nullable hydrated field: a missing foreign\n // row and a cross-tenant row deliberately have the same refusal.\n if (!representative) {\n throw this.refusal(\n 'representative_unavailable',\n 'Representative is unavailable in the active tenant',\n );\n }\n if (!representative.isActive()) {\n throw this.refusal(\n 'representative_inactive',\n 'Representative is not active',\n );\n }\n if (lead.ownerRepId === ownerRepId) return { lead, changed: false };\n\n const priorOwnerRepId = lead.ownerRepId;\n lead.ownerRepId = ownerRepId;\n await lead.save();\n await this.appendAudit(deps.activities, lead, {\n actorProfileId,\n activityKind: 'assignment',\n summary: priorOwnerRepId\n ? 'Reassigned lead owner'\n : 'Assigned lead owner',\n metadata: {\n fromOwnerRepId: priorOwnerRepId || null,\n toOwnerRepId: ownerRepId,\n occurredAt: this.now(input.now).toISOString(),\n },\n });\n return { lead, changed: true };\n });\n }\n\n /** Correct editable contact fields with one actor-attributed audit and row lock. */\n async updateLeadContact(input: UpdateLeadContactInput): Promise<Lead> {\n const actorProfileId = this.requireIdentifier(\n input.actorProfileId,\n 'actorProfileId',\n );\n const name = typeof input.name === 'string' ? input.name.trim() : '';\n const contactName =\n typeof input.contactName === 'string' ? input.contactName.trim() : '';\n const email =\n typeof input.email === 'string' ? input.email.trim().toLowerCase() : '';\n if (!name) throw this.refusal('name_required', 'Lead name is required');\n if (\n [name, contactName, email].some(\n (value) => value.length > MAX_LEAD_WORKFLOW_TEXT_LENGTH,\n )\n )\n throw this.refusal('invalid_metadata', 'Lead contact text is too long');\n if (email && !/^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/u.test(email))\n throw this.refusal('invalid_email', 'Lead email is invalid');\n return await this.runMutation(async (deps, tenantId) => {\n const lead = await this.lockLead(deps, input.leadId, tenantId);\n if (lead.status === 'merged')\n throw this.refusal(\n 'lead_not_actionable',\n 'Merged Lead contact cannot be corrected',\n );\n if (!email && !lead.phone.trim())\n throw this.refusal(\n 'contact_required',\n 'Lead requires at least one of email or phone',\n );\n const before = {\n name: lead.name,\n contactName: lead.contactName,\n email: lead.email,\n };\n const after = { name, contactName, email };\n if (\n before.name === name &&\n before.contactName === contactName &&\n before.email === email\n )\n return lead;\n Object.assign(lead, after);\n await lead.save();\n await this.appendAudit(deps.activities, lead, {\n actorProfileId,\n activityKind: 'contact_update',\n summary: 'Corrected lead contact',\n metadata: {\n before,\n after,\n occurredAt: this.now(input.now).toISOString(),\n },\n });\n return lead;\n });\n }\n\n /** Start a new Lead or reopen a disqualified Lead for active follow-up. */\n async startWorking(input: StartWorkingInput): Promise<Lead> {\n const actorProfileId = this.requireIdentifier(\n input.actorProfileId,\n 'actorProfileId',\n );\n return await this.runMutation(async (deps, tenantId) => {\n const lead = await this.lockLead(deps, input.leadId, tenantId);\n if (lead.status !== 'new' && lead.status !== 'disqualified') {\n throw this.refusal(\n 'invalid_transition',\n `Lead cannot start working from '${lead.status}'`,\n );\n }\n const from = lead.status;\n lead.status = 'working';\n await lead.save();\n await this.appendAudit(deps.activities, lead, {\n actorProfileId,\n activityKind: 'status_change',\n summary:\n from === 'disqualified'\n ? 'Reopened lead follow-up'\n : 'Started lead follow-up',\n metadata: {\n from,\n to: 'working',\n occurredAt: this.now(input.now).toISOString(),\n },\n });\n return lead;\n });\n }\n\n /** Disqualify a new or working Lead with a required bounded rationale. */\n async disqualifyLead(input: DisqualifyLeadInput): Promise<Lead> {\n const actorProfileId = this.requireIdentifier(\n input.actorProfileId,\n 'actorProfileId',\n );\n const reason = this.requireBoundedText(input.reason, 'reason');\n return await this.runMutation(async (deps, tenantId) => {\n const lead = await this.lockLead(deps, input.leadId, tenantId);\n if (lead.status !== 'new' && lead.status !== 'working') {\n throw this.refusal(\n 'invalid_transition',\n `Lead cannot be disqualified from '${lead.status}'`,\n );\n }\n const from = lead.status;\n lead.status = 'disqualified';\n await lead.save();\n await this.appendAudit(deps.activities, lead, {\n actorProfileId,\n activityKind: 'status_change',\n summary: 'Disqualified lead',\n metadata: {\n from,\n to: 'disqualified',\n reason,\n occurredAt: this.now(input.now).toISOString(),\n },\n });\n return lead;\n });\n }\n\n /** Append one immutable human note, call, email, or meeting to an active Lead. */\n async recordActivity(input: RecordLeadActivityInput): Promise<SalesActivity> {\n const actorProfileId = this.requireIdentifier(\n input.actorProfileId,\n 'actorProfileId',\n );\n const summary = this.requireBoundedText(input.summary, 'summary');\n if (!LEAD_HUMAN_ACTIVITY_KINDS.includes(input.activityKind)) {\n throw this.refusal(\n 'invalid_activity_kind',\n 'Activity kind is not a human follow-up activity',\n );\n }\n const metadata = this.canonicalMetadata(input.metadata);\n return await this.runMutation(async (deps, tenantId) => {\n const lead = await this.lockLead(deps, input.leadId, tenantId);\n this.assertActiveFollowUpLead(lead);\n return await deps.activities.create({\n tenantId,\n subjectKind: 'lead',\n subjectId: this.requireLeadId(lead),\n activityKind: input.activityKind,\n summary,\n actorProfileId,\n metadata,\n });\n });\n }\n\n /** Schedule one open `task` activity for an active Lead. */\n async scheduleNextAction(\n input: ScheduleLeadNextActionInput,\n ): Promise<SalesActivity> {\n const actorProfileId = this.requireIdentifier(\n input.actorProfileId,\n 'actorProfileId',\n );\n const summary = this.requireBoundedText(input.summary, 'summary');\n const dueAt = this.requireValidDate(input.dueAt, 'dueAt');\n const metadata = this.canonicalMetadata(input.metadata);\n return await this.runMutation(async (deps, tenantId) => {\n const lead = await this.lockLead(deps, input.leadId, tenantId);\n this.assertActiveFollowUpLead(lead);\n return await deps.activities.create({\n tenantId,\n subjectKind: 'lead',\n subjectId: this.requireLeadId(lead),\n activityKind: 'task',\n summary,\n dueAt,\n actorProfileId,\n metadata,\n });\n });\n }\n\n /**\n * Complete one open lead task exactly once. The task is locked with its Lead\n * so concurrent callers serialize; a compatible retry returns the completed\n * task without adding a second immutable completion event.\n */\n async completeNextAction(\n input: CompleteLeadNextActionInput,\n ): Promise<CompleteLeadNextActionResult> {\n const actorProfileId = this.requireIdentifier(\n input.actorProfileId,\n 'actorProfileId',\n );\n return await this.runMutation(async (deps, tenantId) => {\n const lead = await this.lockLead(deps, input.leadId, tenantId);\n this.assertActiveFollowUpLead(lead);\n const task = await this.lockLeadTask(\n deps,\n input.taskId,\n this.requireLeadId(lead),\n tenantId,\n );\n if (task.activityKind !== 'task' || !task.dueAt) {\n throw this.refusal(\n 'task_unavailable',\n 'Task is unavailable for this lead',\n );\n }\n\n if (task.completedAt) {\n const completion = await this.findTaskCompletionAudit(\n deps.activities,\n this.requireLeadId(lead),\n this.requireActivityId(task),\n );\n if (completion?.actorProfileId === actorProfileId) {\n return { task, completed: false };\n }\n throw this.refusal(\n 'completion_replay_conflict',\n 'Task was already completed by another actor or without compatible audit evidence',\n );\n }\n\n const completedAt = this.now(input.now);\n task.completedAt = completedAt;\n permitSalesActivityWorkflowCompletion(task);\n await task.save();\n await this.appendAudit(deps.activities, lead, {\n actorProfileId,\n activityKind: 'task_completion',\n summary: `Completed next action: ${task.summary}`,\n metadata: {\n taskId: this.requireActivityId(task),\n completedAt: completedAt.toISOString(),\n },\n });\n return { task, completed: true };\n });\n }\n\n /** Return a deterministic chronological activity trail across merged Lead history. */\n async getLeadTimeline(leadId: string): Promise<SalesActivity[]> {\n const tenantId = this.requireActiveTenant();\n const lead = await this.readLead(this.deps.leads, leadId, tenantId);\n return await this.deps.leads.activitiesIncludingMerged(\n this.requireLeadId(lead),\n );\n }\n\n /** Return the Lead, its visible owner, earliest open task, and queue projection. */\n async getLeadWorkState(input: GetLeadWorkStateInput): Promise<LeadWorkState> {\n const tenantId = this.requireActiveTenant();\n const lead = await this.readLead(this.deps.leads, input.leadId, tenantId);\n const leadId = this.requireLeadId(lead);\n const [owner, openTasks, linkedOpportunities] = await Promise.all([\n lead.ownerRepId\n ? this.deps.representatives.get(\n { id: lead.ownerRepId },\n { cache: false },\n )\n : Promise.resolve(null),\n this.deps.activities.findOpenTasks('lead', leadId),\n this.deps.opportunities.findByLead(leadId),\n ]);\n const earliestOpenTask = openTasks[0] ?? null;\n return {\n lead,\n // The tenant-scoped lookup determines visibility; do not make the\n // reusable projection depend on nullable field hydration details.\n owner,\n earliestOpenTask,\n opportunity: linkedOpportunities[0] ?? null,\n queue: projectLeadWorkQueue({\n status: lead.status,\n ownerRepId: lead.ownerRepId,\n nextAction: earliestOpenTask,\n now: input.now,\n timeZone: input.timeZone,\n }),\n };\n }\n\n private async runMutation<T>(\n fn: (deps: LeadWorkflowTransactionDeps, tenantId: string) => Promise<T>,\n ): Promise<T> {\n const tenantId = this.requireActiveTenant();\n const db = this.deps.leads.db as TransactionCapableDatabase;\n if (typeof db.transaction !== 'function') {\n throw this.refusal(\n 'transaction_unavailable',\n 'Lead workflow mutations require a transaction-capable database adapter',\n );\n }\n // `transaction()` is an adapter method, not a detached callback: bind the\n // database receiver before the serial queue invokes it later.\n const transaction = db.transaction.bind(db);\n // Transaction callback views intentionally omit pool-only lifecycle\n // methods such as `acquireSession`. Capture the pool capability before\n // entering the callback so PostgreSQL still takes its row-lock path.\n const supportsRowLocks = this.supportsRowLocks(db);\n const runTransaction = async () =>\n await transaction(async (tx) =>\n fn(\n {\n leads: await LeadCollection.create({\n db: tx,\n _reuseInitializedDb: true,\n _deferRuntimeInitialization: true,\n }),\n activities: await SalesActivityCollection.create({\n db: tx,\n _reuseInitializedDb: true,\n _deferRuntimeInitialization: true,\n }),\n representatives: await SalesRepresentativeCollection.create({\n db: tx,\n _reuseInitializedDb: true,\n _deferRuntimeInitialization: true,\n }),\n opportunities: await OpportunityCollection.create({\n db: tx,\n _reuseInitializedDb: true,\n _deferRuntimeInitialization: true,\n }),\n conversions: await OpportunityConversionCollection.create({\n db: tx,\n _reuseInitializedDb: true,\n _deferRuntimeInitialization: true,\n }),\n pipelines: await PipelineDefinitionCollection.create({\n db: tx,\n _reuseInitializedDb: true,\n _deferRuntimeInitialization: true,\n }),\n stages: await PipelineStageCollection.create({\n db: tx,\n _reuseInitializedDb: true,\n _deferRuntimeInitialization: true,\n }),\n supportsRowLocks,\n },\n tenantId,\n ),\n );\n\n // PostgreSQL transactions have independent pooled sessions and acquire a\n // row lock below. SQLite/DuckDB/JSON multiplex one connection instead;\n // chain their whole mutation so two readers cannot both complete one task.\n if (supportsRowLocks) return await runTransaction();\n const previous = singleConnectionMutationTails.get(db) ?? Promise.resolve();\n const turn = previous.then(runTransaction, runTransaction);\n singleConnectionMutationTails.set(\n db,\n turn.then(\n () => undefined,\n () => undefined,\n ),\n );\n return await turn;\n }\n\n /** PostgreSQL gets a row lock; other adapters are serialized by runMutation. */\n private async lockLead(\n deps: LeadWorkflowTransactionDeps,\n leadId: string,\n tenantId: string,\n ): Promise<Lead> {\n if (!UUID_RE.test(leadId)) {\n throw this.refusal(\n 'lead_unavailable',\n 'Lead is unavailable in the active tenant',\n );\n }\n if (deps.supportsRowLocks) {\n const rows = await deps.leads.query(\n `SELECT * FROM ${deps.leads.tableName}\n WHERE id = $1 AND tenant_id = $2\n FOR UPDATE`,\n [leadId, tenantId],\n { allowRawOnTenantScoped: true },\n );\n const lead = rows[0];\n if (lead && lead.tenantId === tenantId) return lead;\n throw this.refusal(\n 'lead_unavailable',\n 'Lead is unavailable in the active tenant',\n );\n }\n return await this.readLead(deps.leads, leadId, tenantId);\n }\n\n private async lockLeadTask(\n deps: LeadWorkflowTransactionDeps,\n taskId: string,\n leadId: string,\n tenantId: string,\n ): Promise<SalesActivity> {\n if (!UUID_RE.test(taskId)) {\n throw this.refusal(\n 'task_unavailable',\n 'Task is unavailable for this lead',\n );\n }\n if (deps.supportsRowLocks) {\n const rows = await deps.activities.query(\n `SELECT * FROM ${deps.activities.tableName}\n WHERE id = $1\n AND subject_kind = 'lead'\n AND subject_id = $2\n AND tenant_id = $3\n FOR UPDATE`,\n [taskId, leadId, tenantId],\n { allowRawOnTenantScoped: true },\n );\n const task = rows[0];\n if (task && task.tenantId === tenantId) return task;\n throw this.refusal(\n 'task_unavailable',\n 'Task is unavailable for this lead',\n );\n }\n const task = await deps.activities.get({ id: taskId }, { cache: false });\n if (\n !task ||\n task.tenantId !== tenantId ||\n task.subjectKind !== 'lead' ||\n task.subjectId !== leadId\n ) {\n throw this.refusal(\n 'task_unavailable',\n 'Task is unavailable for this lead',\n );\n }\n return task;\n }\n\n private async lockOpportunity(\n deps: LeadWorkflowTransactionDeps,\n opportunityId: string,\n tenantId: string,\n ): Promise<Opportunity> {\n if (deps.supportsRowLocks) {\n const rows = await deps.opportunities.query(\n `SELECT * FROM ${deps.opportunities.tableName}\n WHERE id = $1 AND tenant_id = $2\n FOR UPDATE`,\n [opportunityId, tenantId],\n { allowRawOnTenantScoped: true },\n );\n const opportunity = rows[0];\n if (opportunity && opportunity.tenantId === tenantId) return opportunity;\n throw this.refusal(\n 'opportunity_unavailable',\n 'Opportunity is unavailable in the active tenant',\n );\n }\n return await this.readOpportunityFrom(\n deps.opportunities,\n opportunityId,\n tenantId,\n );\n }\n\n private async lockPipelineStage(\n deps: LeadWorkflowTransactionDeps,\n stageId: string,\n tenantId: string,\n ): Promise<PipelineStage> {\n if (deps.supportsRowLocks) {\n const rows = await deps.stages.query(\n `SELECT * FROM ${deps.stages.tableName}\n WHERE id = $1 AND tenant_id = $2\n FOR UPDATE`,\n [stageId, tenantId],\n { allowRawOnTenantScoped: true },\n );\n const stage = rows[0];\n if (stage && stage.tenantId === tenantId) return stage;\n throw this.refusal(\n 'stage_unavailable',\n 'Opportunity stage is unavailable in the active tenant and pipeline',\n );\n }\n const stage = await deps.stages.get({ id: stageId }, { cache: false });\n if (stage && stage.tenantId === tenantId) return stage;\n throw this.refusal(\n 'stage_unavailable',\n 'Opportunity stage is unavailable in the active tenant and pipeline',\n );\n }\n\n private async lockOperationFence(\n deps: LeadWorkflowTransactionDeps,\n key: string,\n ): Promise<void> {\n if (!deps.supportsRowLocks) return;\n await deps.leads.db.query(\n 'SELECT pg_advisory_xact_lock(hashtext($1))',\n key,\n );\n }\n\n private async findDedupeMatches(\n deps: LeadWorkflowTransactionDeps,\n tenantId: string,\n input: NormalizedCreateLeadInput,\n ): Promise<Lead[]> {\n if (input.dedupe === 'none') return [];\n const clauses: string[] = [];\n const identityLocks: string[] = [];\n const params: string[] = [tenantId];\n if (input.email) {\n params.push(input.email);\n clauses.push(`LOWER(TRIM(email)) = $${params.length}`);\n identityLocks.push(`lead-dedupe:${tenantId}:email:${input.email}`);\n }\n if (input.dedupe === 'email_or_org' && input.organizationName) {\n const organizationName = input.organizationName.toLowerCase();\n params.push(organizationName);\n clauses.push(`LOWER(TRIM(organization_name)) = $${params.length}`);\n identityLocks.push(\n `lead-dedupe:${tenantId}:organization:${organizationName}`,\n );\n }\n if (clauses.length === 0) return [];\n if (deps.supportsRowLocks) {\n for (const identityLock of identityLocks.sort()) {\n await this.lockOperationFence(deps, identityLock);\n }\n }\n return await deps.leads.query(\n `SELECT * FROM ${deps.leads.tableName}\n WHERE tenant_id = $1 AND (${clauses.join(' OR ')})\n ORDER BY created_at DESC${deps.supportsRowLocks ? ' FOR UPDATE' : ''}`,\n params,\n { allowRawOnTenantScoped: true },\n );\n }\n\n private async readLead(\n leads: LeadCollection,\n leadId: string,\n tenantId: string,\n ): Promise<Lead> {\n if (!UUID_RE.test(leadId)) {\n throw this.refusal(\n 'lead_unavailable',\n 'Lead is unavailable in the active tenant',\n );\n }\n const lead = await leads.get({ id: leadId }, { cache: false });\n if (!lead || lead.tenantId !== tenantId) {\n throw this.refusal(\n 'lead_unavailable',\n 'Lead is unavailable in the active tenant',\n );\n }\n return lead;\n }\n\n private async readOpportunity(\n opportunityId: string,\n tenantId: string,\n ): Promise<Opportunity> {\n return await this.readOpportunityFrom(\n this.deps.opportunities,\n opportunityId,\n tenantId,\n );\n }\n\n private async readOpportunityFrom(\n opportunities: OpportunityCollection,\n opportunityId: string,\n tenantId: string,\n ): Promise<Opportunity> {\n const opportunity = await opportunities.get(\n { id: opportunityId },\n { cache: false },\n );\n if (!opportunity || opportunity.tenantId !== tenantId) {\n throw this.refusal(\n 'opportunity_unavailable',\n 'Opportunity is unavailable in the active tenant',\n );\n }\n return opportunity;\n }\n\n private normalizeCreateLeadInput(\n input: CreateLeadInput,\n ): NormalizedCreateLeadInput {\n const name = typeof input.name === 'string' ? input.name.trim() : '';\n if (!name) {\n throw this.refusal('name_required', 'Lead name is required');\n }\n const email =\n typeof input.email === 'string' ? input.email.trim().toLowerCase() : '';\n const phone = typeof input.phone === 'string' ? input.phone.trim() : '';\n if (!email && !phone) {\n throw this.refusal(\n 'contact_required',\n 'Lead intake requires at least one of email or phone',\n );\n }\n if (email && !/^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/u.test(email)) {\n throw this.refusal('invalid_email', 'Lead email is invalid');\n }\n const sourceKind =\n typeof input.sourceKind === 'string' ? input.sourceKind.trim() : '';\n if (!sourceKind) {\n throw this.refusal('source_kind_required', 'Lead sourceKind is required');\n }\n const dedupe = input.dedupe ?? 'email';\n if (!['none', 'email', 'email_or_org'].includes(dedupe)) {\n throw this.refusal(\n 'invalid_dedupe_policy',\n 'Lead dedupe policy is invalid',\n );\n }\n const idempotencyKey = input.idempotencyKey?.trim() ?? '';\n if (idempotencyKey.length > 255) {\n throw this.refusal(\n 'invalid_idempotency_key',\n 'Lead idempotency key must be at most 255 characters',\n );\n }\n const acquisitionContext = input.acquisitionContext ?? {};\n if (\n !isPlainJsonObject(acquisitionContext) ||\n !isJsonValue(acquisitionContext, new Set<object>())\n ) {\n throw this.refusal(\n 'invalid_metadata',\n 'Lead acquisitionContext must be a plain JSON object with JSON values',\n );\n }\n const ownerRepId = input.ownerRepId\n ? this.requireIdentifier(input.ownerRepId, 'ownerRepId')\n : '';\n const profileId =\n input.profileId !== undefined\n ? this.requireIdentifier(input.profileId, 'profileId')\n : '';\n const actorProfileId = input.actorProfileId\n ? this.requireIdentifier(input.actorProfileId, 'actorProfileId')\n : '';\n const now = input.now ?? new Date();\n if (!Number.isFinite(now.getTime())) {\n throw this.refusal('invalid_due_at', 'Lead intake now must be valid');\n }\n const normalized = {\n name,\n email,\n contactName: input.contactName?.trim() ?? '',\n phone,\n organizationName: input.organizationName?.trim() ?? '',\n profileId,\n sourceKind,\n sourceId: input.sourceId?.trim() ?? '',\n acquisitionContext,\n ownerRepId,\n actorProfileId,\n dedupe,\n idempotencyKey,\n now,\n };\n return {\n ...normalized,\n intent: {\n name: normalized.name,\n email: normalized.email,\n contactName: normalized.contactName,\n phone: normalized.phone,\n organizationName: normalized.organizationName,\n ...(normalized.profileId ? { profileId: normalized.profileId } : {}),\n sourceKind: normalized.sourceKind,\n sourceId: normalized.sourceId,\n acquisitionContext: normalized.acquisitionContext,\n ownerRepId: normalized.ownerRepId,\n dedupe: normalized.dedupe,\n },\n };\n }\n\n private assertActiveFollowUpLead(lead: Lead): void {\n if (lead.status !== 'new' && lead.status !== 'working') {\n throw this.refusal(\n 'lead_not_actionable',\n `Lead is not actionable for ordinary follow-up while '${lead.status}'`,\n );\n }\n }\n\n private async appendAudit(\n activities: SalesActivityCollection,\n lead: Lead,\n input: {\n actorProfileId: string;\n activityKind: string;\n summary: string;\n metadata: Record<string, unknown>;\n },\n ): Promise<SalesActivity> {\n return await activities.create({\n tenantId: lead.tenantId,\n subjectKind: 'lead',\n subjectId: this.requireLeadId(lead),\n activityKind: input.activityKind,\n summary: input.summary,\n actorProfileId: input.actorProfileId,\n metadata: JSON.stringify(input.metadata),\n });\n }\n\n private async findTaskCompletionAudit(\n activities: SalesActivityCollection,\n leadId: string,\n taskId: string,\n ): Promise<SalesActivity | null> {\n const activity = (await activities.findBySubject('lead', leadId)).find(\n (candidate) =>\n candidate.activityKind === 'task_completion' &&\n candidate.getMetadata().taskId === taskId,\n );\n return activity ?? null;\n }\n\n private requireActiveTenant(): string {\n try {\n return requireTenantId();\n } catch (error) {\n if (!(error instanceof TenantContextError)) throw error;\n throw this.refusal(\n 'tenant_context_required',\n 'Lead workflow operations require an active tenant context',\n );\n }\n }\n\n private canonicalMetadata(\n metadata: Record<string, unknown> | undefined,\n ): string {\n const value = metadata ?? {};\n if (!isPlainJsonObject(value) || !isJsonValue(value, new Set<object>())) {\n throw this.refusal(\n 'invalid_metadata',\n 'Activity metadata must be a plain JSON object with JSON values',\n );\n }\n return JSON.stringify(value);\n }\n\n private requireBoundedText(\n value: string,\n field: 'summary' | 'reason',\n ): string {\n const normalized = typeof value === 'string' ? value.trim() : '';\n if (!normalized) {\n throw this.refusal(\n field === 'summary' ? 'summary_required' : 'reason_required',\n `Lead workflow ${field} is required`,\n );\n }\n if (normalized.length > MAX_LEAD_WORKFLOW_TEXT_LENGTH) {\n throw this.refusal(\n field === 'summary' ? 'summary_too_long' : 'reason_too_long',\n `Lead workflow ${field} must be at most ${MAX_LEAD_WORKFLOW_TEXT_LENGTH} characters`,\n );\n }\n return normalized;\n }\n\n private requireIdentifier(value: string, field: string): string {\n const normalized = typeof value === 'string' ? value.trim() : '';\n const requiresUuid = field === 'ownerRepId' || field === 'actorProfileId';\n if (!normalized || (requiresUuid && !UUID_RE.test(normalized))) {\n throw this.refusal(\n field === 'ownerRepId'\n ? 'representative_unavailable'\n : 'invalid_metadata',\n `Lead workflow ${field} must be a UUID`,\n );\n }\n return normalized;\n }\n\n private requireValidDate(value: Date, field: string): Date {\n if (!(value instanceof Date) || !Number.isFinite(value.getTime())) {\n throw this.refusal(\n 'invalid_due_at',\n `Lead workflow ${field} must be a valid date`,\n );\n }\n return value;\n }\n\n private requireLeadId(lead: Lead): string {\n if (!lead.id)\n throw this.refusal(\n 'lead_unavailable',\n 'Lead is unavailable in the active tenant',\n );\n return lead.id;\n }\n\n private requireActivityId(activity: SalesActivity): string {\n if (!activity.id)\n throw this.refusal(\n 'task_unavailable',\n 'Task is unavailable for this lead',\n );\n return activity.id;\n }\n\n private requireOpportunityId(opportunity: Opportunity): string {\n if (!opportunity.id) {\n throw this.refusal(\n 'opportunity_unavailable',\n 'Opportunity is unavailable in the active tenant',\n );\n }\n return opportunity.id;\n }\n\n private requireConversionId(conversion: OpportunityConversion): string {\n if (!conversion.id) {\n throw this.refusal(\n 'invalid_conversion',\n 'Opportunity conversion could not be persisted',\n );\n }\n return conversion.id;\n }\n\n private requireOpenIdentifier(value: string, field: string): string {\n const normalized = typeof value === 'string' ? value.trim() : '';\n if (!normalized) {\n throw this.refusal('invalid_conversion', `${field} is required`);\n }\n return normalized;\n }\n\n private now(value: Date | undefined): Date {\n return value ?? new Date();\n }\n\n private supportsRowLocks(db: DatabaseInterface): boolean {\n return (\n typeof (db as TransactionCapableDatabase).acquireSession === 'function'\n );\n }\n\n private refusal(\n reason: LeadWorkflowValidationReason,\n message: string,\n ): LeadWorkflowValidationError {\n return new LeadWorkflowValidationError(reason, message);\n }\n}\n\nfunction queueProjection(state: LeadWorkQueueState): LeadWorkQueueProjection {\n return {\n state,\n isActionable:\n state === 'unassigned' ||\n state === 'no_next_action' ||\n state === 'overdue' ||\n state === 'due_today' ||\n state === 'upcoming',\n isUnassigned: state === 'unassigned',\n hasNoNextAction: state === 'no_next_action',\n isOverdue: state === 'overdue',\n isDueToday: state === 'due_today',\n isUpcoming: state === 'upcoming',\n isTerminal: state === 'terminal',\n isReopenable: state === 'reopenable',\n };\n}\n\nfunction calendarDayKey(date: Date, timeZone: string | undefined): string {\n const options: Intl.DateTimeFormatOptions = {\n year: 'numeric',\n month: '2-digit',\n day: '2-digit',\n };\n let formatter: Intl.DateTimeFormat;\n try {\n formatter = new Intl.DateTimeFormat('en-US', { ...options, timeZone });\n } catch {\n // A host-provided timezone is advisory queue-display input, not a reason\n // for a work-state projection to fail. Invalid IANA values use the\n // runtime timezone just as an omitted value does.\n formatter = new Intl.DateTimeFormat('en-US', options);\n }\n const parts = formatter.formatToParts(date);\n const get = (type: Intl.DateTimeFormatPartTypes): string =>\n parts.find((part) => part.type === type)?.value ?? '';\n return `${get('year')}-${get('month')}-${get('day')}`;\n}\n\nfunction isPlainJsonObject(value: unknown): value is Record<string, unknown> {\n if (value === null || typeof value !== 'object' || Array.isArray(value))\n return false;\n const prototype = Object.getPrototypeOf(value);\n return prototype === Object.prototype || prototype === null;\n}\n\nfunction isJsonValue(value: unknown, ancestors: Set<object>): boolean {\n if (\n value === null ||\n typeof value === 'string' ||\n typeof value === 'boolean' ||\n (typeof value === 'number' && Number.isFinite(value))\n ) {\n return true;\n }\n if (Array.isArray(value)) {\n if (ancestors.has(value)) return false;\n ancestors.add(value);\n try {\n return value.every((item) => isJsonValue(item, ancestors));\n } finally {\n ancestors.delete(value);\n }\n }\n if (isPlainJsonObject(value)) {\n if (ancestors.has(value)) return false;\n ancestors.add(value);\n try {\n return Object.values(value).every((item) => isJsonValue(item, ancestors));\n } finally {\n ancestors.delete(value);\n }\n }\n return false;\n}\n\n/** Canonical JSON representation used only for stable intake intent hashes. */\nfunction stableStringify(value: unknown): string {\n if (Array.isArray(value)) {\n return `[${value.map((item) => stableStringify(item)).join(',')}]`;\n }\n if (isPlainJsonObject(value)) {\n return `{${Object.keys(value)\n .sort()\n .map((key) => `${JSON.stringify(key)}:${stableStringify(value[key])}`)\n .join(',')}}`;\n }\n return JSON.stringify(value);\n}\n\nfunction sha256(value: string): string {\n return createHash('sha256').update(value).digest('hex');\n}\n\n/** Format 128 hash bits as an RFC 4122 version-5-shaped UUID. */\nfunction uuidFromHash(hash: string): string {\n const chars = hash.slice(0, 32).split('');\n chars[12] = '5';\n chars[16] = ((Number.parseInt(chars[16] ?? '0', 16) & 0x3) | 0x8).toString(\n 16,\n );\n const value = chars.join('');\n return `${value.slice(0, 8)}-${value.slice(8, 12)}-${value.slice(12, 16)}-${value.slice(16, 20)}-${value.slice(20)}`;\n}\n\nexport default LeadWorkflowService;\n","/** Authorized seller, canonical advertiser leases and exact maker/checker terms. */\nimport { createHash } from 'node:crypto';\nimport {\n requireTenant,\n requireTenantId,\n withTenant,\n} from '@happyvertical/smrt-tenancy';\nimport { type DatabaseInterface, getDatabase } from '@happyvertical/sql';\nimport { SalesGovernanceEventCollection } from '../collections/SalesGovernanceEventCollection.js';\nimport { SalesGovernanceStateCollection } from '../collections/SalesGovernanceStateCollection.js';\nimport { SalesRepresentativeCollection } from '../collections/SalesRepresentativeCollection.js';\nimport type { SalesGovernanceState } from '../models/SalesGovernanceState.js';\nimport { withGovernanceWrite } from './governance-write.js';\nimport type {\n SalesAdvertiserLease,\n SalesApprovalDecision,\n SalesCreateQuoteInput,\n SalesGovernanceDatabaseConfig,\n SalesGovernanceHost,\n SalesLeaseChangeInput,\n SalesLeaseInput,\n SalesQuoteOperation,\n SalesQuoteSnapshot,\n SalesQuoteTerms,\n SellerContext,\n SellerOperation,\n SellerPolicy,\n} from './sales-governance-types.js';\n\nexport class SalesGovernanceError extends Error {\n readonly code = 'SALES_GOVERNANCE_DENIED';\n constructor(readonly reason: string) {\n super(`Sales governance refused: ${reason}`);\n this.name = 'SalesGovernanceError';\n }\n}\nconst ownedTransactions = new WeakSet<DatabaseInterface>();\n\ninterface TransactionDatabase extends DatabaseInterface {\n transaction?<T>(fn: (tx: DatabaseInterface) => Promise<T>): Promise<T>;\n}\ninterface Deps {\n states: SalesGovernanceStateCollection;\n events: SalesGovernanceEventCollection;\n reps: SalesRepresentativeCollection;\n}\n\n/** All writes run in one transaction, or participate in the explicitly supplied executor. */\nexport class SalesGovernanceService {\n readonly #database: DatabaseInterface;\n readonly #backend: SalesGovernanceDatabaseConfig['type'];\n\n private constructor(\n database: DatabaseInterface,\n backend: SalesGovernanceDatabaseConfig['type'],\n private readonly host: SalesGovernanceHost,\n private readonly now: () => Date,\n ) {\n this.#database = database;\n this.#backend = backend;\n }\n\n /** Owned adapter for migrations and host reads; transaction writes use withTransaction. */\n get database(): DatabaseInterface {\n return this.#database;\n }\n\n static async create(options: {\n database: SalesGovernanceDatabaseConfig;\n host: SalesGovernanceHost;\n now?: () => Date;\n }): Promise<SalesGovernanceService> {\n // SQL has no public engine identity on arbitrary DatabaseInterface values.\n // Own connection creation so unsupported adapters cannot masquerade as a\n // transactional authority store. DuckDB support is blocked on SDK #1452:\n // https://github.com/happyvertical/sdk/issues/1452\n // SQLite is also excluded: a Sales same-process BUSY/close/recreate\n // recovery has not been established on the published SQL adapter.\n const configuration = { ...options?.database };\n const backend = configuration.type;\n if (backend !== 'postgres') deny('unsupported_backend');\n const allowed = new Set([\n 'type',\n 'url',\n 'cache',\n 'dbid',\n 'max',\n 'connectionTimeoutMillis',\n 'idleTimeoutMillis',\n ]);\n if (\n typeof configuration.url !== 'string' ||\n !configuration.url.trim() ||\n Object.keys(configuration).some((field) => !allowed.has(field)) ||\n (configuration.cache !== undefined && configuration.cache !== false)\n )\n deny('invalid_database_configuration');\n if (!options.host) deny('host_required');\n const db = await getDatabase({ ...configuration, cache: false });\n return new SalesGovernanceService(\n db,\n backend,\n options.host,\n options.now ?? (() => new Date()),\n );\n }\n\n /**\n * Run host writes and any governance mutations on one positively identified\n * executor. A thrown callback rolls back all changes. Do not retain tx.\n */\n async withTransaction<T>(\n fn: (tx: DatabaseInterface) => Promise<T>,\n ): Promise<T> {\n this.assertBackend();\n const db = this.database as TransactionDatabase;\n if (typeof db.transaction !== 'function') deny('transaction_unavailable');\n return db.transaction(async (tx) => {\n ownedTransactions.add(tx);\n try {\n return await fn(tx);\n } finally {\n ownedTransactions.delete(tx);\n }\n });\n }\n\n /** First successful registration wins until expiresAtMs <= now, or release. */\n async acquireLease(\n input: SalesLeaseInput,\n transaction?: DatabaseInterface,\n ): Promise<SalesAdvertiserLease> {\n input = {\n ...operationIdentity(input),\n sellerId: uuid(input.sellerId),\n advertiserId: uuid(input.advertiserId),\n };\n return this.operation('acquire', input, transaction, async (deps, db) => {\n const policy = await this.seller(input, input.sellerId, deps, db);\n await this.advertiser(input, input.advertiserId, db);\n const state = await deps.states.lock(\n key('lease', input.tenantId, input.advertiserId),\n );\n const previous = leaseSnapshot(\n parse<SalesAdvertiserLease>(state.payload),\n );\n const now = this.time();\n if (previous && !previous.released && previous.expiresAtMs > now)\n deny('advertiser_already_registered');\n const lease: SalesAdvertiserLease = {\n tenantId: input.tenantId,\n advertiserId: input.advertiserId,\n sellerId: input.sellerId,\n leaseId: input.operationId,\n expiresAtMs: expiry(now, policy.leaseDurationMs),\n released: false,\n };\n await this.store(deps, state, lease);\n return lease;\n });\n }\n\n /** Renewal requires a live matching owner token; it starts a fresh policy duration. */\n async renewLease(\n input: SalesLeaseChangeInput,\n transaction?: DatabaseInterface,\n ): Promise<SalesAdvertiserLease> {\n return this.changeLease('renew', input, transaction);\n }\n\n /** Release never transfers ownership and is audited even at the expiry boundary. */\n async releaseLease(\n input: SalesLeaseChangeInput,\n transaction?: DatabaseInterface,\n ): Promise<SalesAdvertiserLease> {\n return this.changeLease('release', input, transaction);\n }\n\n private async changeLease(\n kind: 'renew' | 'release',\n input: SalesLeaseChangeInput,\n tx?: DatabaseInterface,\n ): Promise<SalesAdvertiserLease> {\n input = {\n ...operationIdentity(input),\n sellerId: uuid(input.sellerId),\n advertiserId: uuid(input.advertiserId),\n leaseId: uuid(input.leaseId),\n };\n return this.operation(kind, input, tx, async (deps, db) => {\n const policy = await this.seller(input, input.sellerId, deps, db);\n await this.advertiser(input, input.advertiserId, db);\n const state = await deps.states.lock(\n key('lease', input.tenantId, input.advertiserId),\n );\n const lease = leaseSnapshot(parse<SalesAdvertiserLease>(state.payload));\n if (\n !lease ||\n lease.leaseId !== input.leaseId ||\n lease.sellerId !== input.sellerId ||\n lease.released\n )\n deny('lease_owner_mismatch');\n if (kind === 'renew') {\n if (lease.expiresAtMs <= this.time()) deny('lease_expired');\n lease.expiresAtMs = expiry(this.time(), policy.leaseDurationMs);\n } else lease.released = true;\n await this.store(deps, state, lease);\n return lease;\n });\n }\n\n /** Freeze one immutable commercial revision. Amendments use a greater revision. */\n async createQuote(\n input: SalesCreateQuoteInput,\n transaction?: DatabaseInterface,\n ): Promise<SalesQuoteSnapshot> {\n input = {\n ...operationIdentity(input),\n terms: quoteTermsIdentity(input.terms),\n };\n validateTerms(input.terms);\n return this.operation('quote', input, transaction, async (deps, db) => {\n const policy = await this.seller(input, input.terms.sellerId, deps, db);\n await this.advertiser(input, input.terms.advertiserId, db);\n await this.assertLiveLease(\n input.tenantId,\n input.terms.sellerId,\n input.terms.advertiserId,\n deps,\n );\n if (\n (await this.host.validateQuote(\n { ...input.terms, tenantId: input.tenantId },\n db,\n )) !== true\n )\n deny('quote_unavailable');\n const head = await deps.states.lock(\n key('quote-head', input.tenantId, input.terms.quoteId),\n );\n const previous = parse<{ revision: number }>(head.payload);\n if (previous && previous.revision >= input.terms.revision)\n deny('quote_revision_not_new');\n const state = await deps.states.lock(\n quoteKey(input.tenantId, input.terms.quoteId, input.terms.revision),\n );\n if (parse(state.payload)) deny('quote_revision_exists');\n const quote: SalesQuoteSnapshot = {\n ...input.terms,\n tenantId: input.tenantId,\n makerProfileId: input.actorProfileId,\n policy,\n status: 'draft',\n approval: null,\n };\n await this.store(deps, state, quote);\n await this.store(deps, head, { revision: quote.revision });\n return quote;\n });\n }\n\n async requestApproval(\n input: SalesQuoteOperation,\n transaction?: DatabaseInterface,\n ): Promise<SalesQuoteSnapshot> {\n input = quoteOperationIdentity(input);\n return this.operation(\n 'request-approval',\n input,\n transaction,\n async (deps, db) => {\n const [state, quote] = await this.quote(input, deps);\n await this.validateSellerQuote(input, quote, deps, db);\n if (quote.status !== 'draft' || quote.approval)\n deny('approval_already_requested');\n quote.approval = {\n requestId: input.operationId,\n status: 'pending',\n termsHash: termsHash(quote),\n checkerProfileId: null,\n expiresAtMs: expiry(this.time(), quote.policy.approvalDurationMs),\n reason: '',\n };\n await this.store(deps, state, quote);\n return quote;\n },\n );\n }\n\n async decideApproval(\n input: SalesApprovalDecision,\n transaction?: DatabaseInterface,\n ): Promise<SalesQuoteSnapshot> {\n input = {\n ...quoteOperationIdentity(input),\n requestId: uuid(input.requestId),\n };\n if (\n !['approved', 'rejected', 'revoked'].includes(input.decision) ||\n !input.reason?.trim()\n )\n deny('invalid_decision');\n return this.operation(\n 'decide-approval',\n input,\n transaction,\n async (deps, db) => {\n const [state, quote] = await this.quote(input, deps);\n await this.context(input, db);\n await this.assertLiveLease(\n input.tenantId,\n quote.sellerId,\n quote.advertiserId,\n deps,\n );\n if (uuid(input.actorProfileId) === uuid(quote.makerProfileId))\n deny('self_approval');\n if ((await this.host.canApprove(input, db)) !== true)\n deny('finance_unauthorized');\n const approval = quote.approval;\n if (\n !approval ||\n approval.requestId !== input.requestId ||\n approval.termsHash !== termsHash(quote)\n )\n deny('approval_mismatch');\n if (input.decision === 'revoked') {\n if (approval.status !== 'approved') deny('approval_not_approved');\n } else {\n if (approval.status !== 'pending' || quote.status !== 'draft')\n deny('approval_not_pending');\n if (approval.expiresAtMs <= this.time()) deny('approval_expired');\n }\n approval.status = input.decision;\n approval.checkerProfileId = input.actorProfileId;\n approval.reason = input.reason.trim();\n await this.store(deps, state, quote);\n return quote;\n },\n );\n }\n\n async issueQuote(\n input: SalesQuoteOperation,\n transaction?: DatabaseInterface,\n ): Promise<SalesQuoteSnapshot> {\n return this.transition('issue', input, transaction);\n }\n\n /** Commit local sign authority before provider I/O; never send directly from a stale quote. */\n async signQuote(\n input: SalesQuoteOperation,\n transaction?: DatabaseInterface,\n ): Promise<SalesQuoteSnapshot> {\n return this.transition('sign', input, transaction);\n }\n\n private async transition(\n kind: 'issue' | 'sign',\n input: SalesQuoteOperation,\n tx?: DatabaseInterface,\n ): Promise<SalesQuoteSnapshot> {\n input = quoteOperationIdentity(input);\n return this.operation(kind, input, tx, async (deps, db) => {\n const [state, quote] = await this.quote(input, deps);\n await this.validateSellerQuote(input, quote, deps, db);\n if (\n kind === 'issue' ? quote.status !== 'draft' : quote.status !== 'issued'\n )\n deny('invalid_quote_transition');\n this.approved(quote);\n quote.status = kind === 'issue' ? 'issued' : 'signed';\n await this.store(deps, state, quote);\n return quote;\n });\n }\n\n /** Provider preflight, including retries of already-signed local records. */\n async assertCanSign(\n input: Omit<SalesQuoteOperation, 'operationId'>,\n transaction?: DatabaseInterface,\n ): Promise<void> {\n input = { ...contextIdentity(input), quoteId: uuid(input.quoteId) };\n this.assertContext(input);\n await this.run(transaction, async (deps, db) => {\n const [, quote] = await this.quote(input, deps);\n await this.validateSellerQuote(input, quote, deps, db);\n if (quote.status !== 'signed') deny('quote_not_signed');\n this.approved(quote);\n });\n }\n\n /** Read canonical registration for an authorized current tenant member. */\n async getLease(\n input: SellerContext & { advertiserId: string },\n ): Promise<SalesAdvertiserLease | null> {\n input = {\n ...contextIdentity(input),\n advertiserId: uuid(input.advertiserId),\n };\n this.assertContext(input);\n return this.run(undefined, async (deps, db) => {\n await this.context(input, db);\n await this.advertiser(input, input.advertiserId, db);\n const state = await deps.states.get(\n { id: key('lease', input.tenantId, input.advertiserId) },\n { cache: false },\n );\n return state\n ? leaseSnapshot(parse<SalesAdvertiserLease>(state.payload))\n : null;\n });\n }\n\n /** Tenant-scoped UI projection. Authority is always rechecked by mutation methods. */\n async getQuote(input: {\n tenantId: string;\n quoteId: string;\n revision: number;\n }): Promise<SalesQuoteSnapshot | null> {\n input = {\n ...input,\n tenantId: uuid(input.tenantId),\n quoteId: uuid(input.quoteId),\n };\n if (uuid(requireTenantId()) !== input.tenantId)\n deny('tenant_context_mismatch');\n return this.inCanonicalTenant(async () => {\n const states = await SalesGovernanceStateCollection.create({\n db: this.database,\n });\n const state = await states.get(\n { id: quoteKey(input.tenantId, input.quoteId, input.revision) },\n { cache: false },\n );\n return state\n ? quoteSnapshot(parse<SalesQuoteSnapshot>(state.payload))\n : null;\n });\n }\n\n private approved(quote: SalesQuoteSnapshot): void {\n const discount = BigInt(quote.subtotalCents - quote.totalCents) * 10000n;\n if (\n discount <=\n BigInt(quote.subtotalCents) * BigInt(quote.policy.maxDiscountBps)\n )\n return;\n const approval = quote.approval;\n if (\n !approval ||\n approval.status !== 'approved' ||\n approval.expiresAtMs <= this.time() ||\n approval.termsHash !== termsHash(quote) ||\n !approval.checkerProfileId ||\n uuid(approval.checkerProfileId) === uuid(quote.makerProfileId)\n )\n deny('discount_approval_required');\n }\n\n private async assertLiveLease(\n tenantId: string,\n sellerId: string,\n advertiserId: string,\n deps: Deps,\n ): Promise<void> {\n const state = await deps.states.lock(\n key('lease', uuid(tenantId), uuid(advertiserId)),\n );\n const lease = leaseSnapshot(parse<SalesAdvertiserLease>(state.payload));\n if (\n !lease ||\n lease.tenantId !== uuid(tenantId) ||\n lease.advertiserId !== uuid(advertiserId) ||\n lease.sellerId !== uuid(sellerId) ||\n lease.released ||\n lease.expiresAtMs <= this.time()\n )\n deny('advertiser_lease_required');\n }\n\n private async validateSellerQuote(\n input: SellerContext,\n quote: SalesQuoteSnapshot,\n deps: Deps,\n db: DatabaseInterface,\n ): Promise<void> {\n const policy = await this.seller(input, quote.sellerId, deps, db);\n if (JSON.stringify(policy) !== JSON.stringify(quote.policy))\n deny('policy_changed');\n await this.advertiser(input, quote.advertiserId, db);\n await this.assertLiveLease(\n input.tenantId,\n quote.sellerId,\n quote.advertiserId,\n deps,\n );\n if ((await this.host.validateQuote(quote, db)) !== true)\n deny('quote_unavailable');\n if (\n quote.approval?.status === 'approved' &&\n quote.approval.checkerProfileId\n ) {\n const checker = {\n tenantId: input.tenantId,\n actorProfileId: quote.approval.checkerProfileId,\n };\n await this.context(checker, db);\n if ((await this.host.canApprove(checker, db)) !== true)\n deny('finance_unauthorized');\n }\n }\n\n private async quote(\n input: Omit<SalesQuoteOperation, 'operationId'>,\n deps: Deps,\n ): Promise<[SalesGovernanceState, SalesQuoteSnapshot]> {\n text(input.quoteId);\n integer(input.revision, 1);\n const head = await deps.states.lock(\n key('quote-head', input.tenantId, input.quoteId),\n );\n if (parse<{ revision: number }>(head.payload)?.revision !== input.revision)\n deny('stale_quote_revision');\n const state = await deps.states.lock(\n quoteKey(input.tenantId, input.quoteId, input.revision),\n );\n const quote = quoteSnapshot(parse<SalesQuoteSnapshot>(state.payload));\n if (!quote || quote.tenantId !== input.tenantId) deny('quote_unavailable');\n return [state, quote];\n }\n\n private async seller(\n input: SellerContext,\n sellerId: string,\n deps: Deps,\n db: DatabaseInterface,\n ): Promise<SellerPolicy> {\n await this.context(input, db);\n text(sellerId);\n const rows = await deps.reps.query(\n `UPDATE ${deps.reps.tableName} SET status = status WHERE id = ? AND tenant_id = ? AND profile_id = ? AND status = 'active' RETURNING id`,\n [sellerId, input.tenantId, input.actorProfileId],\n { allowRawOnTenantScoped: true },\n );\n if (rows.length !== 1) deny('seller_unauthorized');\n const context = { ...input, sellerId };\n if ((await this.host.canSell(context, db)) !== true)\n deny('seller_policy_denied');\n const policy = await this.host.policy(context, db);\n if (!policy || typeof policy !== 'object') deny('invalid_policy');\n text(policy.version);\n integer(policy.maxDiscountBps, 0, 10000);\n integer(policy.leaseDurationMs, 1);\n integer(policy.approvalDurationMs, 1);\n return {\n version: policy.version,\n maxDiscountBps: policy.maxDiscountBps,\n leaseDurationMs: policy.leaseDurationMs,\n approvalDurationMs: policy.approvalDurationMs,\n };\n }\n\n private async context(\n input: SellerContext,\n db: DatabaseInterface,\n ): Promise<void> {\n this.assertBackend();\n this.assertContext(input);\n if ((await this.host.isMember(input, db)) !== true)\n deny('membership_required');\n if ((await this.host.isUnsuspended(input, db)) !== true) deny('suspended');\n }\n private async advertiser(\n input: SellerContext,\n advertiserId: string,\n db: DatabaseInterface,\n ): Promise<void> {\n text(advertiserId);\n if (\n (await this.host.advertiserExists({ ...input, advertiserId }, db)) !==\n true\n )\n deny('advertiser_unavailable');\n }\n private assertContext(input: SellerContext): void {\n text(input.tenantId);\n text(input.actorProfileId);\n if (uuid(requireTenantId()) !== input.tenantId)\n deny('tenant_context_mismatch');\n }\n private time(): number {\n const now = this.now().getTime();\n integer(now, 0);\n return now;\n }\n private async store(\n deps: Deps,\n state: SalesGovernanceState,\n value: unknown,\n ): Promise<void> {\n if (\n !(await deps.states.compareAndSwap(\n state.id!,\n state.revision,\n JSON.stringify(value),\n ))\n )\n deny('concurrent_change_retry');\n }\n private async operation<T>(\n kind: string,\n input: SellerOperation,\n tx: DatabaseInterface | undefined,\n fn: (deps: Deps, db: DatabaseInterface) => Promise<T>,\n ): Promise<T> {\n this.assertBackend();\n this.assertContext(input);\n if (\n !/^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/.test(\n input.operationId,\n )\n )\n deny('invalid_operation_id');\n const intent = canonical(normalizeIdentityEnvelope({ kind, input }));\n return this.run(tx, async (deps, db) => {\n await deps.states.lock(key('operation', input.operationId));\n const previous = await deps.events.get(\n { id: input.operationId },\n { cache: false },\n );\n if (previous) {\n if (\n canonical(normalizeIdentityEnvelope(JSON.parse(previous.intent))) !==\n intent\n )\n deny('replay_conflict');\n // Replays return historical evidence, never a fresh transition authority.\n return normalizeIdentityEnvelope(JSON.parse(previous.result)) as T;\n }\n const result = await fn(deps, db);\n await deps.events.create({\n id: input.operationId,\n slug: input.operationId,\n tenantId: input.tenantId,\n intent,\n result: JSON.stringify(result),\n });\n return result;\n });\n }\n private assertBackend(): void {\n if (this.#backend !== 'postgres') deny('unsupported_backend');\n }\n\n private async inCanonicalTenant<T>(fn: () => Promise<T>): Promise<T> {\n const current = requireTenant();\n return withTenant({ ...current, tenantId: uuid(current.tenantId) }, fn);\n }\n\n private async run<T>(\n tx: DatabaseInterface | undefined,\n fn: (deps: Deps, db: DatabaseInterface) => Promise<T>,\n ): Promise<T> {\n this.assertBackend();\n const execute = async (db: DatabaseInterface) =>\n this.inCanonicalTenant(() =>\n withGovernanceWrite(db, async () =>\n fn(\n {\n states: await SalesGovernanceStateCollection.create({ db }),\n events: await SalesGovernanceEventCollection.create({ db }),\n reps: await SalesRepresentativeCollection.create({ db }),\n },\n db,\n ),\n ),\n );\n if (tx) {\n if (!ownedTransactions.has(tx)) deny('transaction_executor_required');\n return execute(tx);\n }\n const db = this.database as TransactionDatabase;\n if (typeof db.transaction !== 'function') deny('transaction_unavailable');\n return db.transaction(execute);\n }\n}\n\nfunction deny(reason: string): never {\n throw new SalesGovernanceError(reason);\n}\nfunction text(value: string): void {\n if (typeof value !== 'string' || !value.trim() || value.length > 256)\n deny('invalid_identity');\n}\nfunction integer(\n value: number,\n min: number,\n max = Number.MAX_SAFE_INTEGER,\n): void {\n if (!Number.isSafeInteger(value) || value < min || value > max)\n deny('invalid_numeric_value');\n}\nfunction expiry(now: number, duration: number): number {\n const value = now + duration;\n integer(value, 0);\n return value;\n}\nfunction parse<T>(payload: string): T | null {\n return payload === '{}' ? null : (JSON.parse(payload) as T);\n}\nfunction key(...parts: Array<string | number>): string {\n const hash = createHash('sha256').update(JSON.stringify(parts)).digest('hex');\n return `${hash.slice(0, 8)}-${hash.slice(8, 12)}-5${hash.slice(13, 16)}-a${hash.slice(17, 20)}-${hash.slice(20, 32)}`;\n}\nfunction quoteKey(tenant: string, quote: string, revision: number): string {\n return key('quote', tenant, quote, revision);\n}\nfunction validateTerms(terms: SalesQuoteTerms): void {\n if (!terms) deny('invalid_quote');\n for (const value of [\n terms.quoteId,\n terms.sellerId,\n terms.advertiserId,\n terms.rateCardVersion,\n terms.inventoryVersion,\n ])\n text(value);\n integer(terms.revision, 1);\n integer(terms.subtotalCents, 0);\n integer(terms.totalCents, 0, terms.subtotalCents);\n if (!/^[A-Z]{3}$/.test(terms.currency)) deny('invalid_currency');\n}\nfunction termsHash(quote: SalesQuoteSnapshot): string {\n const { status: _status, approval: _approval, ...terms } = quote;\n return createHash('sha256').update(canonical(terms)).digest('hex');\n}\nfunction canonical(value: unknown): string {\n if (value === null || typeof value !== 'object') return JSON.stringify(value);\n if (Array.isArray(value)) return `[${value.map(canonical).join(',')}]`;\n return `{${Object.keys(value)\n .sort()\n .map(\n (k) =>\n `${JSON.stringify(k)}:${canonical((value as Record<string, unknown>)[k])}`,\n )\n .join(',')}}`;\n}\n\nconst UUID =\n /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;\nfunction uuid(value: string): string {\n if (typeof value !== 'string' || !UUID.test(value))\n deny('invalid_uuid_identity');\n return value.toLowerCase();\n}\nfunction contextIdentity<T extends SellerContext>(input: T): T {\n return {\n ...input,\n tenantId: uuid(input.tenantId),\n actorProfileId: uuid(input.actorProfileId),\n };\n}\nfunction operationIdentity<T extends SellerOperation>(input: T): T {\n return { ...contextIdentity(input), operationId: uuid(input.operationId) };\n}\nfunction quoteOperationIdentity<T extends SalesQuoteOperation>(input: T): T {\n return { ...operationIdentity(input), quoteId: uuid(input.quoteId) };\n}\nfunction quoteTermsIdentity(terms: SalesQuoteTerms): SalesQuoteTerms {\n if (!terms) deny('invalid_quote');\n return {\n ...terms,\n quoteId: uuid(terms.quoteId),\n sellerId: uuid(terms.sellerId),\n advertiserId: uuid(terms.advertiserId),\n };\n}\nfunction leaseSnapshot(\n lease: SalesAdvertiserLease | null,\n): SalesAdvertiserLease | null {\n return (\n lease && {\n ...lease,\n tenantId: uuid(lease.tenantId),\n advertiserId: uuid(lease.advertiserId),\n sellerId: uuid(lease.sellerId),\n leaseId: uuid(lease.leaseId),\n }\n );\n}\nfunction quoteSnapshot(\n quote: SalesQuoteSnapshot | null,\n): SalesQuoteSnapshot | null {\n return (\n quote && {\n ...quote,\n ...quoteTermsIdentity(quote),\n tenantId: uuid(quote.tenantId),\n makerProfileId: uuid(quote.makerProfileId),\n approval: quote.approval && {\n ...quote.approval,\n requestId: uuid(quote.approval.requestId),\n checkerProfileId:\n quote.approval.checkerProfileId === null\n ? null\n : uuid(quote.approval.checkerProfileId),\n },\n }\n );\n}\nconst IDENTITY_FIELDS = new Set([\n 'tenantId',\n 'actorProfileId',\n 'sellerId',\n 'advertiserId',\n 'quoteId',\n 'operationId',\n 'leaseId',\n 'requestId',\n 'makerProfileId',\n 'checkerProfileId',\n]);\nfunction normalizeIdentityEnvelope(value: unknown): unknown {\n if (!value || typeof value !== 'object') return value;\n if (Array.isArray(value)) return value.map(normalizeIdentityEnvelope);\n return Object.fromEntries(\n Object.entries(value).map(([field, item]) => [\n field,\n IDENTITY_FIELDS.has(field) && item !== null\n ? uuid(item)\n : normalizeIdentityEnvelope(item),\n ]),\n );\n}\n"],"mappings":"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"}