@elevasis/core 0.12.0 → 0.14.0

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 (50) hide show
  1. package/dist/index.d.ts +1 -1
  2. package/dist/index.js +9 -2
  3. package/dist/organization-model/index.d.ts +1 -1
  4. package/dist/organization-model/index.js +9 -2
  5. package/dist/test-utils/index.d.ts +480 -389
  6. package/dist/test-utils/index.js +28 -2
  7. package/package.json +1 -1
  8. package/src/_gen/__tests__/__snapshots__/contracts.md.snap +2324 -0
  9. package/src/auth/multi-tenancy/credentials/__tests__/encryption.test.ts +217 -216
  10. package/src/auth/multi-tenancy/credentials/server/encryption.ts +5 -19
  11. package/src/auth/multi-tenancy/credentials/server/kek-loader.ts +3 -13
  12. package/src/auth/multi-tenancy/permissions.ts +12 -5
  13. package/src/business/acquisition/activity-events.test.ts +250 -0
  14. package/src/business/acquisition/activity-events.ts +84 -0
  15. package/src/business/acquisition/api-schemas.test.ts +1180 -0
  16. package/src/business/acquisition/api-schemas.ts +456 -235
  17. package/src/business/acquisition/crm-state-actions.test.ts +160 -0
  18. package/src/business/acquisition/derive-actions.test.ts +518 -0
  19. package/src/business/acquisition/derive-actions.ts +103 -0
  20. package/src/business/acquisition/index.ts +51 -11
  21. package/src/business/acquisition/stateful.ts +30 -0
  22. package/src/business/acquisition/types.ts +44 -77
  23. package/src/execution/engine/index.ts +4 -1
  24. package/src/execution/engine/tools/integration/server/adapters/apify/__tests__/apify-run-actor.integration.test.ts +1 -2
  25. package/src/execution/engine/tools/integration/server/adapters/attio/__tests__/attio-crud.integration.test.ts +363 -361
  26. package/src/execution/engine/tools/integration/server/adapters/attio/fetch/get-record/index.test.ts +162 -186
  27. package/src/execution/engine/tools/integration/server/adapters/attio/fetch/list-records/index.test.ts +316 -338
  28. package/src/execution/engine/tools/integration/server/adapters/gmail/gmail-adapter.ts +204 -210
  29. package/src/execution/engine/tools/integration/server/adapters/resend/fetch/send-email/index.test.ts +88 -0
  30. package/src/execution/engine/tools/integration/server/adapters/resend/fetch/send-email/index.ts +141 -134
  31. package/src/execution/engine/tools/integration/server/adapters/resend/fetch/utils/types.ts +76 -75
  32. package/src/execution/engine/tools/integration/service.test.ts +34 -9
  33. package/src/execution/engine/tools/integration/service.ts +6 -3
  34. package/src/execution/engine/tools/lead-service-types.ts +90 -30
  35. package/src/execution/engine/tools/platform/acquisition/types.ts +266 -260
  36. package/src/execution/engine/tools/registry.ts +5 -4
  37. package/src/execution/engine/tools/tool-maps.ts +43 -21
  38. package/src/execution/engine/workflow/types.ts +11 -0
  39. package/src/organization-model/contracts.ts +4 -4
  40. package/src/organization-model/domains/navigation.ts +62 -62
  41. package/src/organization-model/domains/sales.ts +272 -0
  42. package/src/organization-model/organization-graph.mdx +2 -2
  43. package/src/organization-model/published.ts +21 -21
  44. package/src/organization-model/resolve.ts +21 -8
  45. package/src/platform/constants/versions.ts +1 -1
  46. package/src/reference/_generated/contracts.md +2324 -0
  47. package/src/scaffold-registry/index.ts +10 -9
  48. package/src/scaffold-registry/schema.ts +68 -62
  49. package/src/supabase/database.types.ts +2958 -2884
  50. package/src/test-utils/rls/RLSTestContext.ts +585 -553
@@ -0,0 +1,103 @@
1
+ import { z } from 'zod'
2
+ import type { AcqDealRow } from './types'
3
+
4
+ export interface Action {
5
+ key: string
6
+ label: string
7
+ payloadSchema?: z.ZodTypeAny
8
+ }
9
+
10
+ export interface ActionDef {
11
+ key: string
12
+ label: string
13
+ isAvailableFor: (deal: AcqDealRow) => boolean
14
+ workflowId: string
15
+ payloadSchema?: z.ZodTypeAny
16
+ }
17
+
18
+ export const SendReplyActionPayloadSchema = z
19
+ .object({
20
+ replyBody: z.string().trim().min(1).max(10000)
21
+ })
22
+ .strict()
23
+
24
+ export const DEFAULT_CRM_ACTIONS: ActionDef[] = [
25
+ {
26
+ key: 'move_to_proposal',
27
+ label: 'Move to Proposal',
28
+ isAvailableFor: (deal) => deal.stage_key === 'interested',
29
+ workflowId: 'move_to_proposal-workflow'
30
+ },
31
+ {
32
+ key: 'move_to_closing',
33
+ label: 'Move to Closing',
34
+ isAvailableFor: (deal) => deal.stage_key === 'proposal',
35
+ workflowId: 'move_to_closing-workflow'
36
+ },
37
+ {
38
+ key: 'move_to_closed_won',
39
+ label: 'Close Won',
40
+ isAvailableFor: (deal) => deal.stage_key === 'closing',
41
+ workflowId: 'move_to_closed_won-workflow'
42
+ },
43
+ {
44
+ key: 'move_to_closed_lost',
45
+ label: 'Close Lost',
46
+ isAvailableFor: (deal) =>
47
+ deal.stage_key === 'interested' || deal.stage_key === 'proposal' || deal.stage_key === 'closing',
48
+ workflowId: 'move_to_closed_lost-workflow'
49
+ },
50
+ {
51
+ key: 'move_to_nurturing',
52
+ label: 'Move to Nurturing',
53
+ isAvailableFor: (deal) =>
54
+ deal.stage_key === 'interested' || deal.stage_key === 'proposal' || deal.stage_key === 'closing',
55
+ workflowId: 'move_to_nurturing-workflow'
56
+ },
57
+ {
58
+ key: 'send_reply',
59
+ label: 'Send Reply',
60
+ isAvailableFor: (deal) =>
61
+ deal.stage_key === 'interested' &&
62
+ (deal.state_key === 'discovery_replied' ||
63
+ deal.state_key === 'discovery_link_sent' ||
64
+ deal.state_key === 'discovery_nudging'),
65
+ workflowId: 'crm-send-reply-workflow',
66
+ payloadSchema: SendReplyActionPayloadSchema
67
+ },
68
+ {
69
+ key: 'send_link',
70
+ label: 'Send Booking Link',
71
+ isAvailableFor: (deal) => deal.stage_key === 'interested' && deal.state_key === 'discovery_replied',
72
+ workflowId: 'crm-send-booking-link-workflow'
73
+ },
74
+ {
75
+ key: 'send_nudge',
76
+ label: 'Send Nudge',
77
+ isAvailableFor: (deal) =>
78
+ deal.stage_key === 'interested' &&
79
+ (deal.state_key === 'discovery_link_sent' || deal.state_key === 'discovery_nudging'),
80
+ workflowId: 'crm-send-nudge-workflow'
81
+ },
82
+ {
83
+ key: 'mark_no_show',
84
+ label: 'Mark No-Show',
85
+ isAvailableFor: (deal) => deal.stage_key === 'interested' && deal.state_key === 'discovery_nudging',
86
+ // Mirrors the auto-timeout precedent in operations/sales/crm/pipeline/timeout-actions.ts:
87
+ // both manual-click and timeout move the deal to closed_lost. The action_taken activity
88
+ // event captures operator intent and distinguishes the manual variant from the timed one.
89
+ workflowId: 'mark_no_show-workflow'
90
+ },
91
+ {
92
+ key: 'rebook',
93
+ label: 'Rebook',
94
+ isAvailableFor: (deal) => deal.stage_key === 'interested' && deal.state_key === 'discovery_booking_cancelled',
95
+ workflowId: 'crm-rebook-workflow'
96
+ }
97
+ ]
98
+
99
+ export function deriveActions(deal: AcqDealRow, actions: ActionDef[] = DEFAULT_CRM_ACTIONS): Action[] {
100
+ return actions
101
+ .filter((a) => a.isAvailableFor(deal))
102
+ .map(({ key, label, payloadSchema }) => ({ key, label, payloadSchema }))
103
+ }
@@ -1,4 +1,7 @@
1
1
  export * from './types'
2
+ export * from './activity-events'
3
+ export * from './derive-actions'
4
+ export * from './stateful'
2
5
  // Export api-schemas selectively to avoid re-exporting names already defined in types.ts
3
6
  // (DealStage, AcqDealTaskKind are declared as union types there; api-schemas re-infers them from Zod)
4
7
  export {
@@ -27,7 +30,9 @@ export {
27
30
  ListDealTasksDueQuerySchema,
28
31
  CreateDealNoteRequestSchema,
29
32
  CreateDealTaskRequestSchema,
30
- SyncDealStageRequestSchema,
33
+ TransitionItemRequestSchema,
34
+ ExecuteActionParamsSchema,
35
+ ExecuteActionRequestSchema,
31
36
  DealContactSummarySchema,
32
37
  DealListItemSchema,
33
38
  DealListResponseSchema,
@@ -37,17 +42,17 @@ export {
37
42
  DealTaskResponseSchema,
38
43
  DealTaskListResponseSchema,
39
44
  DealSchemas,
40
- ListQualificationSchema,
41
- ListEnrichmentSchema,
42
- ListPersonalizationSchema,
43
- PipelineStepSchema,
44
- ListPipelineSchema,
45
- ListConfigSchema,
45
+ ListStatusSchema,
46
+ ScrapingConfigSchema,
47
+ IcpRubricSchema,
48
+ PipelineStageSchema,
49
+ PipelineConfigSchema,
46
50
  ListStageCountsSchema,
47
51
  ListTelemetrySchema,
48
52
  ListIdParamsSchema,
49
53
  CreateListRequestSchema,
50
54
  UpdateListRequestSchema,
55
+ UpdateListStatusRequestSchema,
51
56
  UpdateListConfigRequestSchema,
52
57
  AddCompaniesToListRequestSchema,
53
58
  RemoveCompaniesFromListRequestSchema,
@@ -59,7 +64,34 @@ export {
59
64
  ListTelemetryListResponseSchema,
60
65
  ListExecutionSummarySchema,
61
66
  ListExecutionsResponseSchema,
67
+ ListStageProgressSchema,
68
+ ListProgressResponseSchema,
62
69
  AcqListSchemas,
70
+ AcqSubstrateSchemas,
71
+ AcqArtifactOwnerKindSchema,
72
+ ListArtifactsQuerySchema,
73
+ CreateArtifactRequestSchema,
74
+ AcqArtifactResponseSchema,
75
+ AcqArtifactListResponseSchema,
76
+ ListMembersQuerySchema,
77
+ MemberIdParamsSchema,
78
+ AcqListMemberContactSummarySchema,
79
+ AcqListMemberResponseSchema,
80
+ AcqListMembersResponseSchema,
81
+ ListCompanyIdParamsSchema,
82
+ AcqListCompanyResponseSchema,
83
+ type AcqArtifactOwnerKind,
84
+ type ListArtifactsQuery,
85
+ type CreateArtifactRequest,
86
+ type AcqArtifactResponse,
87
+ type AcqArtifactListResponse,
88
+ type ListMembersQuery,
89
+ type MemberIdParams,
90
+ type AcqListMemberContactSummary,
91
+ type AcqListMemberResponse,
92
+ type AcqListMembersResponse,
93
+ type ListCompanyIdParams,
94
+ type AcqListCompanyResponse,
63
95
  type CompanyIdParams,
64
96
  type ContactIdParams,
65
97
  type ListCompaniesQuery,
@@ -81,20 +113,26 @@ export {
81
113
  type ListDealTasksDueQuery,
82
114
  type CreateDealNoteRequest,
83
115
  type CreateDealTaskRequest,
84
- type SyncDealStageRequest,
116
+ type TransitionItemRequest,
117
+ type ExecuteActionParams,
118
+ type ExecuteActionRequest,
85
119
  type DealListResponse,
86
120
  type DealDetailResponse,
87
121
  type DealNoteResponse,
88
122
  type DealNoteListResponse,
89
123
  type DealTaskResponse,
90
124
  type DealTaskListResponse,
91
- type ListConfigInput,
125
+ type ListStatus,
126
+ type ScrapingConfig,
127
+ type IcpRubric,
128
+ type PipelineStage,
129
+ type PipelineConfig,
92
130
  type ListStageCountsInput,
93
131
  type ListTelemetryInput,
94
- type PipelineStepInput,
95
132
  type ListIdParams,
96
133
  type CreateListRequest,
97
134
  type UpdateListRequest,
135
+ type UpdateListStatusRequest,
98
136
  type UpdateListConfigRequest,
99
137
  type AddCompaniesToListRequest,
100
138
  type RemoveCompaniesFromListRequest,
@@ -105,5 +143,7 @@ export {
105
143
  type ListTelemetryResponse,
106
144
  type ListTelemetryListResponse,
107
145
  type ListExecutionSummaryInput,
108
- type ListExecutionsResponse
146
+ type ListExecutionsResponse,
147
+ type ListStageProgress,
148
+ type ListProgress
109
149
  } from './api-schemas'
@@ -0,0 +1,30 @@
1
+ import { z } from 'zod'
2
+ import { ActivityEventSchema, type ActivityEvent } from './activity-events'
3
+
4
+ /**
5
+ * Stateful trait — the (pipeline_key, stage_key, state_key, activity_log) quartet
6
+ * applied to acq_deals (CRM HITL, shipped 2026-04-27) and being generalized to
7
+ * acq_lists / acq_list_members / acq_list_companies via Track B.
8
+ */
9
+ export interface Stateful {
10
+ pipeline_key: string
11
+ stage_key: string
12
+ state_key: string
13
+ activity_log: ActivityEvent[]
14
+ }
15
+
16
+ export const StatefulSchema = z.object({
17
+ pipeline_key: z.string(),
18
+ stage_key: z.string(),
19
+ state_key: z.string(),
20
+ activity_log: z.array(ActivityEventSchema)
21
+ })
22
+
23
+ /** Generic transition shape — concrete per-entity transitionItem implementations satisfy this. */
24
+ export type TransitionItem<T extends Stateful, TEvent extends ActivityEvent> = (
25
+ item: T,
26
+ transition: { stage_key?: string; state_key?: string; event: TEvent }
27
+ ) => T
28
+
29
+ /** Generic action-derivation shape — concrete per-entity deriveActions implementations satisfy this. */
30
+ export type DeriveActions<T extends Stateful, TAction> = (item: T) => TAction[]
@@ -153,24 +153,54 @@ export interface ContactEnrichmentData {
153
153
  // Domain Types (camelCase transformations of database rows)
154
154
  // =============================================================================
155
155
 
156
- /**
157
- * Acquisition list for organizing contacts and companies.
158
- * Transformed from AcqListRow with camelCase properties.
159
- */
156
+ export type ListStatus = 'draft' | 'enriching' | 'launched' | 'closing' | 'archived'
157
+
158
+ export interface ScrapingConfig {
159
+ source?: string
160
+ query?: string
161
+ filters?: Record<string, unknown>
162
+ [key: string]: unknown
163
+ }
164
+
165
+ export interface IcpRubric {
166
+ targetDescription?: string
167
+ minReviewCount?: number
168
+ minRating?: number
169
+ excludeFranchises?: boolean
170
+ customRules?: string
171
+ qualificationRubricKey?: string | null
172
+ [key: string]: unknown
173
+ }
174
+
175
+ export interface PipelineStage {
176
+ key: string
177
+ label?: string
178
+ description?: string
179
+ resourceId?: string
180
+ inputTemplate?: Record<string, unknown>
181
+ enabled?: boolean
182
+ order?: number
183
+ }
184
+
185
+ export interface PipelineConfig {
186
+ stages: PipelineStage[]
187
+ }
188
+
160
189
  export interface AcqList {
161
190
  id: string
162
191
  organizationId: string
163
192
  name: string
164
193
  description: string | null
165
- type: string
166
194
  batchIds: string[]
167
195
  instantlyCampaignId: string | null
168
- status: string
196
+ status: ListStatus
197
+ scrapingConfig: ScrapingConfig
198
+ icp: IcpRubric
199
+ pipelineConfig: PipelineConfig
169
200
  metadata: Record<string, unknown>
170
201
  launchedAt: Date | null
171
202
  completedAt: Date | null
172
203
  createdAt: Date
173
- config: ListConfig
174
204
  }
175
205
 
176
206
  /**
@@ -198,6 +228,12 @@ export interface AcqCompany {
198
228
  batchId: string | null
199
229
  status: 'active' | 'invalid'
200
230
  verticalResearch: string | null
231
+ /** Track A: flat qualification score (null until a scoring rubric is defined). Added by W1 migration. */
232
+ qualificationScore: number | null
233
+ /** Track A: flat qualification signals jsonb preserving the result payload shape. Added by W1 migration. */
234
+ qualificationSignals: Record<string, unknown> | null
235
+ /** Track A: key identifying the rubric used for qualification. Added by W1 migration. */
236
+ qualificationRubricKey: string | null
201
237
  createdAt: Date
202
238
  updatedAt: Date
203
239
  }
@@ -302,76 +338,7 @@ export interface AcqDealTask {
302
338
  createdByUserId: string | null
303
339
  }
304
340
 
305
- // ─── List Config / Progress / Telemetry Types ────────────────────────────────
306
-
307
- /**
308
- * One ordered step in a list's pipeline. Maps to a deployed workflow
309
- * (e.g. 'lgn-03-company-qualification-workflow'). The `inputTemplate`
310
- * is merged with `{ listId }` at run time to form the workflow input.
311
- */
312
- export interface PipelineStep {
313
- /** Stable key, e.g. 'scrape' | 'extract' | 'qualify' | 'discover' | 'verify' | 'personalize'. */
314
- key: string
315
- /** Human label rendered in the UI stepper. */
316
- label: string
317
- /** Deployed workflow resourceId (e.g. 'lgn-03-company-qualification-workflow'). */
318
- resourceId: string
319
- /** Input defaults merged with `{ listId }` at dispatch. */
320
- inputTemplate: Record<string, unknown>
321
- /** Whether the UI shows the Run button. */
322
- enabled: boolean
323
- /** Display order (ascending). */
324
- order: number
325
- }
326
-
327
- export type CompanyListStage = 'populated' | 'extracted' | 'qualified'
328
-
329
- export type ContactListStage = 'discovered' | 'verified' | 'personalized' | 'uploaded'
330
-
331
- /**
332
- * Per-list pipeline configuration stored as jsonb in `acq_lists.config`.
333
- *
334
- * `qualification` is the only required subtree. Every other subtree is optional
335
- * and inherits global defaults when omitted: workflows resolve values as
336
- * `list.config.foo ?? globalDefaults.foo`. Seeded rows from
337
- * `20260413000100_backfill_list_configs.sql` only populate `qualification`
338
- * and `scraping`; the rest was intentionally omitted.
339
- */
340
- export interface ListConfig {
341
- qualification: {
342
- /** One-line description of the target vertical/segment. */
343
- targetDescription: string
344
- /** Minimum Google review count to qualify. */
345
- minReviewCount: number
346
- /** Minimum Google star rating to qualify (e.g. 3.0). */
347
- minRating: number
348
- /** Whether to exclude franchises/chains during qualification. */
349
- excludeFranchises: boolean
350
- /** Free-form LLM rules layered on top of the structured criteria. */
351
- customRules: string
352
- }
353
- enrichment?: {
354
- emailDiscovery?: {
355
- primary: 'tomba' | 'anymailfinder'
356
- credentialName?: string
357
- }
358
- emailVerification?: {
359
- provider: 'millionverifier'
360
- threshold?: 'ok' | 'ok+catch_all'
361
- }
362
- }
363
- personalization?: {
364
- industryContext?: string
365
- /** Email body template with tags like {{opening_line}} / {{category_pain}}. */
366
- emailBody?: string
367
- creativeDirection?: string
368
- /** Contradiction-prevention rules layered into the personalization prompt. */
369
- exclusionRules?: string[]
370
- }
371
- pipeline?: {
372
- steps: PipelineStep[]
373
- }
374
- }
341
+ // ─── Progress / Telemetry Types ──────────────────────────────────────────────
375
342
 
376
343
  /**
377
344
  * Live-scan aggregate telemetry for a single list, computed on demand from
@@ -299,7 +299,7 @@ export {
299
299
  type MarkProposalReviewedParams,
300
300
  type UpdateCloseLostReasonParams,
301
301
  type UpdateFeesParams,
302
- type SyncDealStageParams,
302
+ type TransitionItemParams,
303
303
  type SetContactNurtureParams,
304
304
  type CancelSchedulesAndHitlByEmailParams,
305
305
  type CancelHitlByDealIdParams,
@@ -318,6 +318,9 @@ export {
318
318
  type GetDealByIdParams,
319
319
  type GetContactByIdParams,
320
320
  type GetCompanyByIdParams,
321
+ // CRM workflow helper param types
322
+ type TransitionDealParams,
323
+ type LoadDealParams,
321
324
  // List-oriented lead gen params (Step 3 of list-oriented migration)
322
325
  type UpdateListConfigParams,
323
326
  type UpdateCompanyStageParams,
@@ -21,13 +21,12 @@ import type { RunActorResult } from '../fetch/run-actor'
21
21
  * - Credential 'elevasis-apify' with valid Apify API token
22
22
  * - Organization ID: f9aa5a56-8c13-4cd1-9161-8827ae7b452b
23
23
  * - SUPABASE_URL and SUPABASE_SERVICE_KEY env vars set
24
- * - SECRETS_ENCRYPTION_KEY env var set
25
24
  * - Apify account accessible with provided credentials
26
25
  *
27
26
  * Run: pnpm test apify-run-actor.integration.test.ts
28
27
  */
29
28
 
30
- const SKIP_TESTS = !process.env.SUPABASE_URL || !process.env.SUPABASE_SERVICE_KEY || !process.env.SECRETS_ENCRYPTION_KEY
29
+ const SKIP_TESTS = !process.env.SUPABASE_URL || !process.env.SUPABASE_SERVICE_KEY
31
30
 
32
31
  describe.skipIf(SKIP_TESTS)('Apify Run Actor Integration Tests', () => {
33
32
  const adapter = new ApifyAdapter()