@proteos/sdk 0.28.0 → 0.29.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@proteos/sdk",
3
- "version": "0.28.0",
3
+ "version": "0.29.0",
4
4
  "license": "Apache-2.0",
5
5
  "description": "TypeScript SDK for the Proteos platform",
6
6
  "repository": {
@@ -30,6 +30,12 @@ import type {
30
30
  BlockContactRequest,
31
31
  Contact,
32
32
  ContactAddress,
33
+ ConversationFilter,
34
+ ConversationFilterEvent,
35
+ CreateConversationFilterRequest,
36
+ ListConversationFilterEventsQuery,
37
+ ListConversationFiltersQuery,
38
+ UpdateConversationFilterRequest,
33
39
  ContactErasureRequest,
34
40
  ContactMergeProposal,
35
41
  MergeContactsRequest,
@@ -64,6 +70,8 @@ export class ConversationClient {
64
70
  readonly contacts: ContactService
65
71
  readonly messages: MessageService
66
72
  readonly agentListeners: AgentListenerService
73
+ /** Ingest-time filter rules (drop-with-audit) + their event trail. */
74
+ readonly conversationFilters: ConversationFilterService
67
75
  /** Per-org glossary: custom vocabulary that boosts transcription accuracy. */
68
76
  readonly glossaryTerms: GlossaryTermService
69
77
  readonly transcriptions: TranscriptionService
@@ -78,6 +86,7 @@ export class ConversationClient {
78
86
  this.contacts = new ContactServiceImpl(client)
79
87
  this.messages = new MessageServiceImpl(client)
80
88
  this.agentListeners = new AgentListenerServiceImpl(client)
89
+ this.conversationFilters = new ConversationFilterServiceImpl(client)
81
90
  this.glossaryTerms = new GlossaryTermServiceImpl(client)
82
91
  this.transcriptions = new TranscriptionServiceImpl(client)
83
92
  this.meetings = new MeetingServiceImpl(client)
@@ -429,6 +438,52 @@ class AgentListenerServiceImpl implements AgentListenerService {
429
438
  }
430
439
  }
431
440
 
441
+ /**
442
+ * Ingest-time conversation filters: block/allow rules that drop matching
443
+ * inbound messages before persistence, scoped globally or per connection.
444
+ * listEvents pages a rule's drop-audit trail (who got dropped, when, why).
445
+ */
446
+ export interface ConversationFilterService {
447
+ list(query?: ListConversationFiltersQuery): Promise<ListResponse<ConversationFilter>>
448
+ get(id: string): Promise<ConversationFilter>
449
+ create(request: CreateConversationFilterRequest): Promise<ConversationFilter>
450
+ update(id: string, request: UpdateConversationFilterRequest): Promise<ConversationFilter>
451
+ delete(id: string): Promise<void>
452
+ listEvents(id: string, query?: ListConversationFilterEventsQuery): Promise<ListResponse<ConversationFilterEvent>>
453
+ }
454
+
455
+ class ConversationFilterServiceImpl implements ConversationFilterService {
456
+ constructor(private readonly client: ProteosClient) {}
457
+
458
+ list(query: ListConversationFiltersQuery = {}): Promise<ListResponse<ConversationFilter>> {
459
+ return this.client.requestWithQuery('GET', `${CONVERSATION_BASE_PATH}/conversation-filters`, query)
460
+ }
461
+
462
+ get(id: string): Promise<ConversationFilter> {
463
+ return this.client.request('GET', `${CONVERSATION_BASE_PATH}/conversation-filters/${encodeURIComponent(id)}`)
464
+ }
465
+
466
+ create(request: CreateConversationFilterRequest): Promise<ConversationFilter> {
467
+ return this.client.request('POST', `${CONVERSATION_BASE_PATH}/conversation-filters`, request)
468
+ }
469
+
470
+ update(id: string, request: UpdateConversationFilterRequest): Promise<ConversationFilter> {
471
+ return this.client.request('PATCH', `${CONVERSATION_BASE_PATH}/conversation-filters/${encodeURIComponent(id)}`, request)
472
+ }
473
+
474
+ async delete(id: string): Promise<void> {
475
+ await this.client.request('DELETE', `${CONVERSATION_BASE_PATH}/conversation-filters/${encodeURIComponent(id)}`)
476
+ }
477
+
478
+ listEvents(id: string, query: ListConversationFilterEventsQuery = {}): Promise<ListResponse<ConversationFilterEvent>> {
479
+ return this.client.requestWithQuery(
480
+ 'GET',
481
+ `${CONVERSATION_BASE_PATH}/conversation-filters/${encodeURIComponent(id)}/events`,
482
+ query,
483
+ )
484
+ }
485
+ }
486
+
432
487
  /**
433
488
  * Per-org glossary: custom-vocabulary terms that boost transcription accuracy.
434
489
  * A term feeds the transcription provider's keyterm prompting; `priority` ranks
@@ -566,6 +566,126 @@ export interface ListAgentListenersQuery extends PaginationQuery {
566
566
  is_enabled?: boolean
567
567
  }
568
568
 
569
+ /**
570
+ * Conversation filters: ingest-time rules that drop matching inbound messages
571
+ * BEFORE persistence (no message, no contact — only a content-free audit
572
+ * event). Scope-first evaluation: connection-scoped rules are final when one
573
+ * matches; global rules apply otherwise. Specificity within a scope:
574
+ * address > domain > role_based > automated > internal_conversations > all,
575
+ * allow beats block within a class.
576
+ */
577
+ export type ConversationFilterType =
578
+ | 'address'
579
+ | 'domain'
580
+ | 'role_based'
581
+ | 'automated'
582
+ | 'internal_conversations'
583
+ | 'all'
584
+ export type ConversationFilterAction = 'block' | 'allow'
585
+ /** Which side of the message address/domain rules test (default: sender). */
586
+ export type FilterMatchOn = 'sender' | 'any_participant'
587
+ /** Deterministic machine-mail header signals the automated filter matches. */
588
+ export type AutomatedSignal =
589
+ | 'auto_submitted'
590
+ | 'bulk'
591
+ | 'mailing_list'
592
+ | 'bounce'
593
+ | 'auto_response_suppress'
594
+
595
+ /** Exact canonical address (lowercased email / E.164 phone / provider id), any channel kind. */
596
+ export interface AddressFilterConfig {
597
+ kind: ContactAddressKind
598
+ value: string
599
+ match_on?: FilterMatchOn
600
+ }
601
+ /** Equals on the parsed email domain (lowercase, no leading '@'). */
602
+ export interface DomainFilterConfig {
603
+ domain: string
604
+ match_on?: FilterMatchOn
605
+ }
606
+ /** Sender local-part is a role mailbox; empty prefixes = the built-in set. Email-only. */
607
+ export interface RoleBasedFilterConfig {
608
+ prefixes?: string[]
609
+ }
610
+ /** Header-signal machine-mail detection; empty signals = all. Email-only. */
611
+ export interface AutomatedFilterConfig {
612
+ signals?: AutomatedSignal[]
613
+ }
614
+ /** Drops only when sender AND every recipient are on these domains. Always block. */
615
+ export interface InternalConversationsFilterConfig {
616
+ domains: string[]
617
+ }
618
+ /** Matches every message (empty config) — the scope-control primitive. */
619
+ export type AllFilterConfig = Record<string, never>
620
+
621
+ export type ConversationFilterConfig =
622
+ | AddressFilterConfig
623
+ | DomainFilterConfig
624
+ | RoleBasedFilterConfig
625
+ | AutomatedFilterConfig
626
+ | InternalConversationsFilterConfig
627
+ | AllFilterConfig
628
+
629
+ export interface ConversationFilter {
630
+ id: string
631
+ org_id: string
632
+ /** Empty = global (org-wide); set = scoped to that connection. */
633
+ connection_id: string
634
+ filter_type: ConversationFilterType
635
+ action: ConversationFilterAction
636
+ filter_config?: ConversationFilterConfig
637
+ is_enabled: boolean
638
+ /** Read-only rollup: messages this rule dropped in the last 30 days. */
639
+ recent_event_count?: number
640
+ created_at: string
641
+ created_by: UserRef
642
+ updated_at: string
643
+ updated_by: UserRef
644
+ }
645
+
646
+ /** One drop-audit entry (content-free: routing/identity facts only). */
647
+ export interface ConversationFilterEvent {
648
+ id: string
649
+ org_id: string
650
+ connection_id: string
651
+ conversation_filter_id: string
652
+ filter_type: ConversationFilterType
653
+ reason: string
654
+ sender_kind?: ContactAddressKind
655
+ sender_value?: string
656
+ external_message_id?: string
657
+ occurred_at: string
658
+ }
659
+
660
+ export interface CreateConversationFilterRequest {
661
+ connection_id?: string
662
+ filter_type: ConversationFilterType
663
+ action: ConversationFilterAction
664
+ filter_config?: Record<string, unknown>
665
+ is_enabled?: boolean
666
+ /** Opts past the own-domain guard (self_domain_block). */
667
+ is_self_domain_acknowledged?: boolean
668
+ }
669
+
670
+ export interface UpdateConversationFilterRequest {
671
+ /** filter_type and filter_config must be sent together. */
672
+ filter_type?: ConversationFilterType
673
+ action?: ConversationFilterAction
674
+ filter_config?: Record<string, unknown>
675
+ is_enabled?: boolean
676
+ is_self_domain_acknowledged?: boolean
677
+ }
678
+
679
+ export interface ListConversationFiltersQuery extends PaginationQuery {
680
+ /** Omit = all; '' = global-only; an id = that connection's rules. */
681
+ connection_id?: string
682
+ filter_type?: ConversationFilterType
683
+ action?: ConversationFilterAction
684
+ is_enabled?: boolean
685
+ }
686
+
687
+ export type ListConversationFilterEventsQuery = PaginationQuery
688
+
569
689
  /**
570
690
  * Discriminates a send target: a person's contact address or a venue. The
571
691
  * server also accepts the legacy 'participant' value as an alias for
package/src/index.ts CHANGED
@@ -237,6 +237,24 @@ export type {
237
237
  ContactRef,
238
238
  ContactSource,
239
239
  ContactStatus,
240
+ AddressFilterConfig,
241
+ AllFilterConfig,
242
+ AutomatedFilterConfig,
243
+ AutomatedSignal,
244
+ ConversationFilter,
245
+ ConversationFilterAction,
246
+ ConversationFilterConfig,
247
+ ConversationFilterEvent,
248
+ ConversationFilterService,
249
+ ConversationFilterType,
250
+ CreateConversationFilterRequest,
251
+ DomainFilterConfig,
252
+ FilterMatchOn,
253
+ InternalConversationsFilterConfig,
254
+ ListConversationFilterEventsQuery,
255
+ ListConversationFiltersQuery,
256
+ RoleBasedFilterConfig,
257
+ UpdateConversationFilterRequest,
240
258
  ErasureRequestStatus,
241
259
  MergeContactsRequest,
242
260
  MergeProposalStatus,