ad2app-lib 1.47.0 → 1.50.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.
@@ -0,0 +1,103 @@
1
+ import { IsNotEmpty, IsString, Matches, MaxLength } from 'class-validator';
2
+
3
+ import type { CampaignSide, I_CampaignCreatorIdentity } from './agency-campaigns';
4
+
5
+ /**
6
+ * Agency ↔ creator threads (spec 175 US8, FR-023): one conversation per
7
+ * organization and creator, inside ad2app.
8
+ *
9
+ * Deliberately NOT the creator's platform inbox: nothing here reaches a social
10
+ * platform, and no grant scope opens a thread (SC-015). A thread is the two
11
+ * parties' own; a grant is a read of the creator's numbers, and the two never
12
+ * meet.
13
+ *
14
+ * "Unanswered" is derived: the other side wrote last. There is no read state
15
+ * and no mark-read step.
16
+ */
17
+
18
+ export const AGENCY_THREAD_CODES = {
19
+ /** No live relationship any more: the history stays readable, nothing can be sent (FR-023). */
20
+ CLOSED: 'agency-thread-closed',
21
+ /** Too many messages from one person in the window (THREAD_POST_LIMIT). */
22
+ RATE_LIMITED: 'agency-thread-rate-limited',
23
+ } as const;
24
+
25
+ /** Messages one person may post across all their threads per window: a conversation pace, never a script's. */
26
+ export const THREAD_POST_LIMIT = { limit: 60, windowMinutes: 10 } as const;
27
+
28
+ /** Long enough for a real message, short enough to stay a message. */
29
+ export const THREAD_MESSAGE_MAX = 4000;
30
+
31
+ /** Messages per read: the newest page with the thread, earlier pages on request. */
32
+ export const THREAD_PAGE_SIZE = 100;
33
+
34
+ export interface I_AgencyThreadMessage {
35
+ id: string;
36
+ side: CampaignSide;
37
+ body: string;
38
+ at: string;
39
+ }
40
+
41
+ export interface I_AgencyThreadSummary {
42
+ id: string;
43
+ /** Agency side: who the thread is with. */
44
+ creator: I_CampaignCreatorIdentity;
45
+ /** Creator side: which organization. */
46
+ organization: { id: string; name: string };
47
+ lastMessage: { side: CampaignSide; body: string; at: string } | null;
48
+ /** The other side wrote last, seen from the caller's side. */
49
+ unanswered: boolean;
50
+ /** No live relationship: read-only for whoever still exists. */
51
+ closed: boolean;
52
+ }
53
+
54
+ export interface I_AgencyThread {
55
+ summary: I_AgencyThreadSummary;
56
+ /** The newest page, oldest first. */
57
+ messages: I_AgencyThreadMessage[];
58
+ /** Older messages exist: read them with `…/messages?before=<oldest id>`. */
59
+ hasEarlier: boolean;
60
+ }
61
+
62
+ /** `GET …/threads/:id/messages?before=<message id>` — the page before a message. */
63
+ export interface I_AgencyThreadPage {
64
+ /** Oldest first. */
65
+ messages: I_AgencyThreadMessage[];
66
+ hasEarlier: boolean;
67
+ }
68
+
69
+ /** `GET /agency/threads` — the agency's inbox. */
70
+ export interface I_AgencyThreads {
71
+ items: I_AgencyThreadSummary[];
72
+ /** Creators on the roster the agency has no open thread with yet. */
73
+ startable: I_CampaignCreatorIdentity[];
74
+ /** The Inbox rail count. */
75
+ unanswered: number;
76
+ }
77
+
78
+ /** `GET /agency/creator-threads/mine` — the creator's threads, in the Agency tab. */
79
+ export interface I_CreatorThreads {
80
+ items: I_AgencyThreadSummary[];
81
+ unanswered: number;
82
+ }
83
+
84
+ export class StartAgencyThreadDto {
85
+ @IsString()
86
+ @Matches(/^[A-Za-z0-9-]{1,128}$/)
87
+ creatorUserId: string;
88
+
89
+ constructor(data?: Partial<StartAgencyThreadDto>) {
90
+ this.creatorUserId = data?.creatorUserId ?? '';
91
+ }
92
+ }
93
+
94
+ export class PostThreadMessageDto {
95
+ @IsString()
96
+ @IsNotEmpty()
97
+ @MaxLength(THREAD_MESSAGE_MAX)
98
+ text: string;
99
+
100
+ constructor(data?: Partial<PostThreadMessageDto>) {
101
+ this.text = data?.text ?? '';
102
+ }
103
+ }
@@ -52,6 +52,8 @@ export const AGENCY_ROUTE_PATHS = {
52
52
  join: '/agency/join',
53
53
  /** A creator answering an access request (FR-016). */
54
54
  requests: '/agency/requests',
55
+ /** A creator's campaign invitations and campaigns: the Agency tab of their Inbox (FR-023, FR-026). */
56
+ creatorCampaigns: '/inbox/agency',
55
57
  } as const;
56
58
 
57
59
  // ── Scopes ───────────────────────────────────────────────────────────────────
@@ -43,6 +43,9 @@ export * from "./agent";
43
43
 
44
44
  // ── Agency domain (organizations, memberships, creator access grants, spec 175)
45
45
  export * from "./agency";
46
+ export * from "./agency-campaigns";
47
+ export * from "./agency-pots";
48
+ export * from "./agency-threads";
46
49
 
47
50
  // ── Access control ────────────────────────────────────────────────────────────
48
51
  export * from "./I_AccessDenial";