ad2app-lib 1.49.0 → 1.59.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/dist/analytics/index.d.ts +85 -2
- package/dist/analytics/index.js +26 -0
- package/dist/types/I_AccessDenial.d.ts +7 -0
- package/dist/types/I_AccessDenial.js +7 -0
- package/dist/types/agency-campaigns.d.ts +108 -5
- package/dist/types/agency-campaigns.js +111 -5
- package/dist/types/agency-pots.d.ts +518 -0
- package/dist/types/agency-pots.js +393 -0
- package/dist/types/agency-threads.d.ts +22 -1
- package/dist/types/agency.d.ts +93 -6
- package/dist/types/agency.js +70 -3
- package/dist/types/dealroom.d.ts +651 -0
- package/dist/types/dealroom.js +387 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.js +3 -0
- package/package.json +1 -1
- package/src/analytics/index.test.ts +23 -1
- package/src/analytics/index.ts +69 -2
- package/src/types/I_AccessDenial.ts +7 -0
- package/src/types/access-denial.test.ts +2 -1
- package/src/types/agency-campaigns.ts +187 -5
- package/src/types/agency-pots.test.ts +255 -0
- package/src/types/agency-pots.ts +751 -0
- package/src/types/agency-threads.ts +14 -3
- package/src/types/agency.ts +120 -7
- package/src/types/consumer-compat.test.ts +90 -0
- package/src/types/dealroom-audit1.test.ts +56 -0
- package/src/types/dealroom-wave2.test.ts +61 -0
- package/src/types/dealroom-wave3.test.ts +68 -0
- package/src/types/dealroom-wave4.test.ts +103 -0
- package/src/types/dealroom.test.ts +231 -0
- package/src/types/dealroom.ts +868 -0
- package/src/types/index.ts +4 -0
|
@@ -0,0 +1,393 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.PotFields = exports.PrepareCampaignFileUploadDto = exports.UpdateMaterialCaptionDto = exports.PotRemovalDecisionDto = exports.PotHoldActDto = exports.PotPublishAtDto = exports.MovePotDeadlineDto = exports.RefillPotDto = exports.ApplyToPotDto = exports.CAMPAIGN_FILE_MAX_BYTES = exports.CAMPAIGN_FILE_CONTENT_TYPE = exports.AGENCY_POT_CODES = exports.POT_REMOVAL_DECISIONS = exports.POT_HOLD_ACTIONS = exports.POT_HOLD_REASONS = exports.POT_AVAILABILITY = exports.POT_STEPS = exports.POT_ENTRY_STATES = exports.creatorPotForbiddenKeys = exports.CREATOR_POT_FORBIDDEN_KEY = exports.POT_CURRENCIES = exports.potCostPer1000Minor = exports.potViewsAtMax = exports.potEarnings = exports.potBonusMinor = exports.checkDisclosure = exports.DISCLOSURE_RESULTS = exports.DISCLOSURE_VISIBLE_CHARS = void 0;
|
|
13
|
+
const class_validator_1 = require("class-validator");
|
|
14
|
+
const agency_1 = require("./agency");
|
|
15
|
+
/**
|
|
16
|
+
* Pot campaigns (spec 175 US9): the second way to pay creators on a campaign,
|
|
17
|
+
* beside the negotiated offer of US7.
|
|
18
|
+
*
|
|
19
|
+
* The agency funds ONE pot and sets a maximum per creator; each creator applies
|
|
20
|
+
* with their own guarantee and rate per 1,000 views; the agency accepts or
|
|
21
|
+
* declines, never counters (SC-018). Earnings are the guarantee plus the rate
|
|
22
|
+
* times the counted views, never above the maximum, and accrue only while the
|
|
23
|
+
* pot has unreserved money (FR-030, FR-032).
|
|
24
|
+
*
|
|
25
|
+
* Money is integer minor units plus an ISO-4217 code, everywhere. A creator
|
|
26
|
+
* never receives a pot-level figure: the only pot-level signal they get is the
|
|
27
|
+
* two-valued availability (SC-016), fenced by `creatorPotForbiddenKeys`.
|
|
28
|
+
*
|
|
29
|
+
* See specs/speckit/175-agency-roster/plan.md → US9 addendum.
|
|
30
|
+
*/
|
|
31
|
+
// ── The disclosure check (FR-040) ───────────────────────────────────────────
|
|
32
|
+
/** A caption shows this many characters before "more"; the disclosure must sit inside them. */
|
|
33
|
+
exports.DISCLOSURE_VISIBLE_CHARS = 125;
|
|
34
|
+
/**
|
|
35
|
+
* UOKiK's recommended wordings, with or without "#", with or without Polish
|
|
36
|
+
* diacritics. The list is a counsel decision (spec 175 T030) and lives here
|
|
37
|
+
* only: the upload form, the approval, the publish gate and the report all
|
|
38
|
+
* call `checkDisclosure`.
|
|
39
|
+
*/
|
|
40
|
+
const STRONG_WORDINGS = [
|
|
41
|
+
'reklama',
|
|
42
|
+
'materia[łl]\\s*reklamowy',
|
|
43
|
+
'wsp[óo][łl]praca\\s*reklamowa',
|
|
44
|
+
'p[łl]atna\\s*wsp[óo][łl]praca',
|
|
45
|
+
'post\\s*sponsorowany',
|
|
46
|
+
];
|
|
47
|
+
/** Tags that say something but may not be enough: flagged, never accepted silently. */
|
|
48
|
+
const WEAK_TAGS = ['wsp[óo][łl]praca', 'ad', 'spons', 'promo'];
|
|
49
|
+
/**
|
|
50
|
+
* A wording is a whole word: nothing glued after it, and nothing glued before it
|
|
51
|
+
* unless it opens with `#` (a tag glued to the word before it still starts at its `#`).
|
|
52
|
+
*/
|
|
53
|
+
const word = (body) => new RegExp(`(?:#(?:${body})|(?<![\\p{L}\\p{N}_#])(?:${body}))(?![\\p{L}\\p{N}_])`, 'giu');
|
|
54
|
+
const tag = (body) => new RegExp(`#(?:${body})(?![\\p{L}\\p{N}_])`, 'giu');
|
|
55
|
+
const STRONG = word(STRONG_WORDINGS.join('|'));
|
|
56
|
+
const WEAK = tag(WEAK_TAGS.join('|'));
|
|
57
|
+
exports.DISCLOSURE_RESULTS = ['pass', 'weak', 'missing'];
|
|
58
|
+
const checkDisclosure = (raw) => {
|
|
59
|
+
// Composed form, so a decomposed "ł"/"ó" (pasted from some keyboards) reads as one letter.
|
|
60
|
+
const caption = raw.normalize('NFC');
|
|
61
|
+
const strong = [...caption.matchAll(STRONG)][0];
|
|
62
|
+
if (strong && strong.index !== undefined) {
|
|
63
|
+
return {
|
|
64
|
+
result: strong.index < exports.DISCLOSURE_VISIBLE_CHARS ? 'pass' : 'weak',
|
|
65
|
+
found: strong[0],
|
|
66
|
+
at: strong.index,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
const weak = [...caption.matchAll(WEAK)][0];
|
|
70
|
+
if (weak && weak.index !== undefined)
|
|
71
|
+
return { result: 'weak', found: weak[0], at: weak.index };
|
|
72
|
+
return { result: 'missing', found: null, at: null };
|
|
73
|
+
};
|
|
74
|
+
exports.checkDisclosure = checkDisclosure;
|
|
75
|
+
// ── Earnings (FR-030, FR-032, FR-035) ───────────────────────────────────────
|
|
76
|
+
/** The per-view part for `views`: rate × views / 1000, rounded DOWN to the minor unit. Exact for any size. */
|
|
77
|
+
const potBonusMinor = (ratePer1000Minor, views) => Number((BigInt(wholeOrZero(ratePer1000Minor)) * BigInt(wholeOrZero(views))) / 1000n);
|
|
78
|
+
exports.potBonusMinor = potBonusMinor;
|
|
79
|
+
/** A non-negative whole number; anything else (NaN, Infinity, negative) is 0. */
|
|
80
|
+
function wholeOrZero(n) {
|
|
81
|
+
return Number.isFinite(n) && n > 0 ? Math.trunc(n) : 0;
|
|
82
|
+
}
|
|
83
|
+
/** What a creator's terms earn at `views` with an unlimited pot: never above the maximum. */
|
|
84
|
+
const potEarnings = ({ guaranteeMinor, ratePer1000Minor, views, maxMinor }) => Math.min(maxMinor, guaranteeMinor + (0, exports.potBonusMinor)(ratePer1000Minor, views));
|
|
85
|
+
exports.potEarnings = potEarnings;
|
|
86
|
+
/** The exact view count at which the terms reach the maximum (rounded up), or null when they never do. */
|
|
87
|
+
const potViewsAtMax = ({ guaranteeMinor, ratePer1000Minor, maxMinor }) => {
|
|
88
|
+
const left = maxMinor - guaranteeMinor;
|
|
89
|
+
if (left <= 0)
|
|
90
|
+
return 0;
|
|
91
|
+
const rate = BigInt(wholeOrZero(ratePer1000Minor));
|
|
92
|
+
if (rate === 0n)
|
|
93
|
+
return null;
|
|
94
|
+
const numerator = BigInt(Math.trunc(left)) * 1000n;
|
|
95
|
+
return Number((numerator + rate - 1n) / rate);
|
|
96
|
+
};
|
|
97
|
+
exports.potViewsAtMax = potViewsAtMax;
|
|
98
|
+
/** Cost per 1,000 views in minor units, rounded half up; null without views. */
|
|
99
|
+
const potCostPer1000Minor = (costMinor, views) => {
|
|
100
|
+
const v = wholeOrZero(views);
|
|
101
|
+
return v > 0 ? Number((BigInt(wholeOrZero(costMinor)) * 2000n + BigInt(v)) / (2n * BigInt(v))) : null;
|
|
102
|
+
};
|
|
103
|
+
exports.potCostPer1000Minor = potCostPer1000Minor;
|
|
104
|
+
/**
|
|
105
|
+
* The currencies a pot may be kept in: every amount is in minor units of two
|
|
106
|
+
* decimals (grosz, cents), so a zero- or three-decimal currency (JPY, KWD) is
|
|
107
|
+
* refused rather than shown a hundred times off (review 2026-10-06 L14).
|
|
108
|
+
*/
|
|
109
|
+
exports.POT_CURRENCIES = ['PLN', 'EUR', 'USD', 'GBP', 'CHF', 'CZK', 'SEK', 'NOK', 'DKK'];
|
|
110
|
+
// ── The creator's fence (SC-016) ────────────────────────────────────────────
|
|
111
|
+
/** Any key carrying a pot-level figure. A creator-facing response must have none, at any depth. */
|
|
112
|
+
exports.CREATOR_POT_FORBIDDEN_KEY = /budget|remainder|reserved|funded|goal|covered|commitment|acceptedCreators|earned|blended|resultViews|heldViews|countedViews/i;
|
|
113
|
+
/** The paths of every forbidden key in `value`; empty when the response is clean. */
|
|
114
|
+
const creatorPotForbiddenKeys = (value, path = '') => {
|
|
115
|
+
if (value === null || typeof value !== 'object')
|
|
116
|
+
return [];
|
|
117
|
+
return Object.entries(value).flatMap(([key, child]) => {
|
|
118
|
+
const at = path ? `${path}.${key}` : key;
|
|
119
|
+
return [...(exports.CREATOR_POT_FORBIDDEN_KEY.test(key) ? [at] : []), ...(0, exports.creatorPotForbiddenKeys)(child, at)];
|
|
120
|
+
});
|
|
121
|
+
};
|
|
122
|
+
exports.creatorPotForbiddenKeys = creatorPotForbiddenKeys;
|
|
123
|
+
// ── States ───────────────────────────────────────────────────────────────────
|
|
124
|
+
/**
|
|
125
|
+
* An entry is one creator's application on one pot.
|
|
126
|
+
* applied → accepted | declined | withdrawn; accepted → released (left or
|
|
127
|
+
* removed before publication).
|
|
128
|
+
*/
|
|
129
|
+
exports.POT_ENTRY_STATES = ['applied', 'accepted', 'declined', 'withdrawn', 'released'];
|
|
130
|
+
/**
|
|
131
|
+
* The pot board's columns, in order (design A2): invitation sent, application,
|
|
132
|
+
* in the campaign, material in, scheduled, bonus counting, bonus final, done
|
|
133
|
+
* (the keep-up period ended with the post still up).
|
|
134
|
+
*/
|
|
135
|
+
exports.POT_STEPS = ['invited', 'applied', 'accepted', 'material_in', 'scheduled', 'counting', 'final', 'done'];
|
|
136
|
+
exports.POT_AVAILABILITY = ['full_max_available', 'filling_up'];
|
|
137
|
+
/** Why a bonus is held (FR-037): the jump against the creator's own history, or paid delivery ad2app did not start. */
|
|
138
|
+
exports.POT_HOLD_REASONS = ['jump', 'paid_delivery'];
|
|
139
|
+
/** The agency's three acts on a held bonus. `message` records the act; the thread opens on the client. */
|
|
140
|
+
exports.POT_HOLD_ACTIONS = ['approve', 'cap', 'message'];
|
|
141
|
+
/**
|
|
142
|
+
* A post taken down after the bonus window but before the keep-up end: the
|
|
143
|
+
* agency is informed and decides whether the guarantee stays earned (FR-032).
|
|
144
|
+
* Before the window ends the guarantee is not earned, with no decision.
|
|
145
|
+
*/
|
|
146
|
+
exports.POT_REMOVAL_DECISIONS = ['keep_base', 'withhold_base'];
|
|
147
|
+
/** Refusal codes the frontend owes its own copy for. */
|
|
148
|
+
exports.AGENCY_POT_CODES = {
|
|
149
|
+
/** Accepting would reserve more than the pot has unreserved. */
|
|
150
|
+
POT_CANNOT_COVER: 'agency-pot-cannot-cover',
|
|
151
|
+
/** The guarantee must be below the maximum per creator. */
|
|
152
|
+
GUARANTEE_TOO_HIGH: 'agency-pot-guarantee-too-high',
|
|
153
|
+
/** Applications closed at the application deadline, or the pot was moved. */
|
|
154
|
+
APPLICATIONS_CLOSED: 'agency-pot-applications-closed',
|
|
155
|
+
/** The kind is fixed once a creator is invited; the terms once an entry is accepted. */
|
|
156
|
+
POT_LOCKED: 'agency-pot-locked',
|
|
157
|
+
/** A refill above the maximum budget. */
|
|
158
|
+
ABOVE_MAX_BUDGET: 'agency-pot-above-max-budget',
|
|
159
|
+
/** The caption fails the disclosure check (FR-040). */
|
|
160
|
+
DISCLOSURE_REQUIRED: 'agency-pot-disclosure-required',
|
|
161
|
+
/** The creator has not connected the platform the post goes to. */
|
|
162
|
+
NO_ACCOUNT: 'agency-pot-no-account',
|
|
163
|
+
/** The confirmed time is not the one on the row now (the agency moved it meanwhile). */
|
|
164
|
+
PUBLISH_TIME_CHANGED: 'agency-pot-publish-time-changed',
|
|
165
|
+
};
|
|
166
|
+
/** PDF, images, video, office documents and archives; no HTML or SVG (opened in the browser). */
|
|
167
|
+
exports.CAMPAIGN_FILE_CONTENT_TYPE = /^(application\/pdf|image\/(png|jpeg|gif|webp|heic|heif|avif)|video\/[A-Za-z0-9.+-]+|application\/(msword|vnd\.openxmlformats-officedocument\.[a-z.]+|vnd\.ms-(excel|powerpoint)|vnd\.oasis\.opendocument\.[a-z.]+|rtf|zip|x-zip-compressed|x-7z-compressed|x-rar-compressed|vnd\.rar|gzip|x-tar)|text\/(plain|csv))$/;
|
|
168
|
+
exports.CAMPAIGN_FILE_MAX_BYTES = 2 * 1024 * 1024 * 1024;
|
|
169
|
+
// ── Bodies ───────────────────────────────────────────────────────────────────
|
|
170
|
+
const MONEY_MAX = 100000000000;
|
|
171
|
+
/**
|
|
172
|
+
* `POST /agency/campaign-invitations/:memberId/application` — the creator's own
|
|
173
|
+
* terms. Applying from an invitation also joins the campaign, answering any
|
|
174
|
+
* access request folded into it with `scopes` (absent = everything asked).
|
|
175
|
+
*/
|
|
176
|
+
class ApplyToPotDto {
|
|
177
|
+
constructor(data) {
|
|
178
|
+
this.guaranteeMinor = data?.guaranteeMinor ?? 0;
|
|
179
|
+
this.ratePer1000Minor = data?.ratePer1000Minor ?? 0;
|
|
180
|
+
this.scopes = data?.scopes;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
exports.ApplyToPotDto = ApplyToPotDto;
|
|
184
|
+
__decorate([
|
|
185
|
+
(0, class_validator_1.IsInt)(),
|
|
186
|
+
(0, class_validator_1.Min)(0),
|
|
187
|
+
(0, class_validator_1.Max)(MONEY_MAX),
|
|
188
|
+
__metadata("design:type", Number)
|
|
189
|
+
], ApplyToPotDto.prototype, "guaranteeMinor", void 0);
|
|
190
|
+
__decorate([
|
|
191
|
+
(0, class_validator_1.IsInt)(),
|
|
192
|
+
(0, class_validator_1.Min)(0),
|
|
193
|
+
(0, class_validator_1.Max)(MONEY_MAX),
|
|
194
|
+
__metadata("design:type", Number)
|
|
195
|
+
], ApplyToPotDto.prototype, "ratePer1000Minor", void 0);
|
|
196
|
+
__decorate([
|
|
197
|
+
(0, class_validator_1.IsOptional)(),
|
|
198
|
+
(0, class_validator_1.IsArray)(),
|
|
199
|
+
(0, class_validator_1.IsIn)(agency_1.AGENCY_GRANT_SCOPES, { each: true }),
|
|
200
|
+
__metadata("design:type", Array)
|
|
201
|
+
], ApplyToPotDto.prototype, "scopes", void 0);
|
|
202
|
+
/** `POST /agency/campaigns/:id/pot/refill` — up to the maximum budget. */
|
|
203
|
+
class RefillPotDto {
|
|
204
|
+
constructor(data) {
|
|
205
|
+
this.amountMinor = data?.amountMinor ?? 0;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
exports.RefillPotDto = RefillPotDto;
|
|
209
|
+
__decorate([
|
|
210
|
+
(0, class_validator_1.IsInt)(),
|
|
211
|
+
(0, class_validator_1.Min)(1),
|
|
212
|
+
(0, class_validator_1.Max)(MONEY_MAX),
|
|
213
|
+
__metadata("design:type", Number)
|
|
214
|
+
], RefillPotDto.prototype, "amountMinor", void 0);
|
|
215
|
+
/** `PATCH /agency/campaigns/:id/pot/application-deadline`. */
|
|
216
|
+
class MovePotDeadlineDto {
|
|
217
|
+
constructor(data) {
|
|
218
|
+
this.applicationDeadlineAt = data?.applicationDeadlineAt ?? '';
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
exports.MovePotDeadlineDto = MovePotDeadlineDto;
|
|
222
|
+
__decorate([
|
|
223
|
+
(0, class_validator_1.IsDateString)(),
|
|
224
|
+
__metadata("design:type", String)
|
|
225
|
+
], MovePotDeadlineDto.prototype, "applicationDeadlineAt", void 0);
|
|
226
|
+
/** The agency sets the time agreed with the brand; the creator confirms that same value. */
|
|
227
|
+
class PotPublishAtDto {
|
|
228
|
+
constructor(data) {
|
|
229
|
+
this.publishAt = data?.publishAt ?? '';
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
exports.PotPublishAtDto = PotPublishAtDto;
|
|
233
|
+
__decorate([
|
|
234
|
+
(0, class_validator_1.IsDateString)(),
|
|
235
|
+
__metadata("design:type", String)
|
|
236
|
+
], PotPublishAtDto.prototype, "publishAt", void 0);
|
|
237
|
+
class PotHoldActDto {
|
|
238
|
+
constructor(data) {
|
|
239
|
+
this.action = data?.action ?? 'approve';
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
exports.PotHoldActDto = PotHoldActDto;
|
|
243
|
+
__decorate([
|
|
244
|
+
(0, class_validator_1.IsIn)(exports.POT_HOLD_ACTIONS),
|
|
245
|
+
__metadata("design:type", String)
|
|
246
|
+
], PotHoldActDto.prototype, "action", void 0);
|
|
247
|
+
/** `POST /agency/campaigns/:id/pot/entries/:entryId/removal` — the agency's decision on a late takedown (FR-032). */
|
|
248
|
+
class PotRemovalDecisionDto {
|
|
249
|
+
constructor(data) {
|
|
250
|
+
this.decision = data?.decision ?? 'keep_base';
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
exports.PotRemovalDecisionDto = PotRemovalDecisionDto;
|
|
254
|
+
__decorate([
|
|
255
|
+
(0, class_validator_1.IsIn)(exports.POT_REMOVAL_DECISIONS),
|
|
256
|
+
__metadata("design:type", String)
|
|
257
|
+
], PotRemovalDecisionDto.prototype, "decision", void 0);
|
|
258
|
+
/** The caption is the creator's until publication (FR-032). */
|
|
259
|
+
class UpdateMaterialCaptionDto {
|
|
260
|
+
constructor(data) {
|
|
261
|
+
this.caption = data?.caption ?? '';
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
exports.UpdateMaterialCaptionDto = UpdateMaterialCaptionDto;
|
|
265
|
+
__decorate([
|
|
266
|
+
(0, class_validator_1.IsString)(),
|
|
267
|
+
(0, class_validator_1.MaxLength)(2200),
|
|
268
|
+
__metadata("design:type", String)
|
|
269
|
+
], UpdateMaterialCaptionDto.prototype, "caption", void 0);
|
|
270
|
+
class PrepareCampaignFileUploadDto {
|
|
271
|
+
constructor(data) {
|
|
272
|
+
this.fileName = data?.fileName ?? '';
|
|
273
|
+
this.contentType = data?.contentType ?? '';
|
|
274
|
+
this.sizeBytes = data?.sizeBytes ?? 0;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
exports.PrepareCampaignFileUploadDto = PrepareCampaignFileUploadDto;
|
|
278
|
+
__decorate([
|
|
279
|
+
(0, class_validator_1.IsString)(),
|
|
280
|
+
(0, class_validator_1.IsNotEmpty)(),
|
|
281
|
+
(0, class_validator_1.MaxLength)(255),
|
|
282
|
+
__metadata("design:type", String)
|
|
283
|
+
], PrepareCampaignFileUploadDto.prototype, "fileName", void 0);
|
|
284
|
+
__decorate([
|
|
285
|
+
(0, class_validator_1.IsString)(),
|
|
286
|
+
(0, class_validator_1.Matches)(exports.CAMPAIGN_FILE_CONTENT_TYPE),
|
|
287
|
+
__metadata("design:type", String)
|
|
288
|
+
], PrepareCampaignFileUploadDto.prototype, "contentType", void 0);
|
|
289
|
+
__decorate([
|
|
290
|
+
(0, class_validator_1.IsInt)(),
|
|
291
|
+
(0, class_validator_1.Min)(1),
|
|
292
|
+
(0, class_validator_1.Max)(exports.CAMPAIGN_FILE_MAX_BYTES),
|
|
293
|
+
__metadata("design:type", Number)
|
|
294
|
+
], PrepareCampaignFileUploadDto.prototype, "sizeBytes", void 0);
|
|
295
|
+
/** The pot's fields on campaign create (and on a move); flat for the reason given in agency-campaigns.ts. */
|
|
296
|
+
class PotFields {
|
|
297
|
+
assignPot(data) {
|
|
298
|
+
this.potBudgetMinor = data?.potBudgetMinor;
|
|
299
|
+
this.potMaxBudgetMinor = data?.potMaxBudgetMinor;
|
|
300
|
+
this.potCapMinor = data?.potCapMinor;
|
|
301
|
+
this.potBonusWindowDays = data?.potBonusWindowDays;
|
|
302
|
+
this.potKeepUpMonths = data?.potKeepUpMonths;
|
|
303
|
+
this.potGoalViews = data?.potGoalViews;
|
|
304
|
+
this.potCurrency = data?.potCurrency;
|
|
305
|
+
this.potApplicationDeadlineAt = data?.potApplicationDeadlineAt;
|
|
306
|
+
this.potPaidPartnershipLabel = data?.potPaidPartnershipLabel;
|
|
307
|
+
this.potSponsorHandle = data?.potSponsorHandle;
|
|
308
|
+
this.potCollabHandle = data?.potCollabHandle;
|
|
309
|
+
this.potFirstComment = data?.potFirstComment;
|
|
310
|
+
this.potCommentsEnabled = data?.potCommentsEnabled;
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
exports.PotFields = PotFields;
|
|
314
|
+
__decorate([
|
|
315
|
+
(0, class_validator_1.IsOptional)(),
|
|
316
|
+
(0, class_validator_1.IsInt)(),
|
|
317
|
+
(0, class_validator_1.Min)(1),
|
|
318
|
+
(0, class_validator_1.Max)(MONEY_MAX),
|
|
319
|
+
__metadata("design:type", Number)
|
|
320
|
+
], PotFields.prototype, "potBudgetMinor", void 0);
|
|
321
|
+
__decorate([
|
|
322
|
+
(0, class_validator_1.IsOptional)(),
|
|
323
|
+
(0, class_validator_1.IsInt)(),
|
|
324
|
+
(0, class_validator_1.Min)(1),
|
|
325
|
+
(0, class_validator_1.Max)(MONEY_MAX),
|
|
326
|
+
__metadata("design:type", Number)
|
|
327
|
+
], PotFields.prototype, "potMaxBudgetMinor", void 0);
|
|
328
|
+
__decorate([
|
|
329
|
+
(0, class_validator_1.IsOptional)(),
|
|
330
|
+
(0, class_validator_1.IsInt)(),
|
|
331
|
+
(0, class_validator_1.Min)(1),
|
|
332
|
+
(0, class_validator_1.Max)(MONEY_MAX),
|
|
333
|
+
__metadata("design:type", Number)
|
|
334
|
+
], PotFields.prototype, "potCapMinor", void 0);
|
|
335
|
+
__decorate([
|
|
336
|
+
(0, class_validator_1.IsOptional)(),
|
|
337
|
+
(0, class_validator_1.IsInt)(),
|
|
338
|
+
(0, class_validator_1.Min)(1),
|
|
339
|
+
(0, class_validator_1.Max)(365),
|
|
340
|
+
__metadata("design:type", Number)
|
|
341
|
+
], PotFields.prototype, "potBonusWindowDays", void 0);
|
|
342
|
+
__decorate([
|
|
343
|
+
(0, class_validator_1.IsOptional)(),
|
|
344
|
+
(0, class_validator_1.IsInt)(),
|
|
345
|
+
(0, class_validator_1.Min)(1),
|
|
346
|
+
(0, class_validator_1.Max)(60),
|
|
347
|
+
__metadata("design:type", Number)
|
|
348
|
+
], PotFields.prototype, "potKeepUpMonths", void 0);
|
|
349
|
+
__decorate([
|
|
350
|
+
(0, class_validator_1.IsOptional)(),
|
|
351
|
+
(0, class_validator_1.IsInt)(),
|
|
352
|
+
(0, class_validator_1.Min)(1),
|
|
353
|
+
(0, class_validator_1.Max)(100000000000),
|
|
354
|
+
__metadata("design:type", Number)
|
|
355
|
+
], PotFields.prototype, "potGoalViews", void 0);
|
|
356
|
+
__decorate([
|
|
357
|
+
(0, class_validator_1.IsOptional)(),
|
|
358
|
+
(0, class_validator_1.IsIn)(exports.POT_CURRENCIES),
|
|
359
|
+
__metadata("design:type", String)
|
|
360
|
+
], PotFields.prototype, "potCurrency", void 0);
|
|
361
|
+
__decorate([
|
|
362
|
+
(0, class_validator_1.IsOptional)(),
|
|
363
|
+
(0, class_validator_1.IsDateString)(),
|
|
364
|
+
__metadata("design:type", String)
|
|
365
|
+
], PotFields.prototype, "potApplicationDeadlineAt", void 0);
|
|
366
|
+
__decorate([
|
|
367
|
+
(0, class_validator_1.IsOptional)(),
|
|
368
|
+
(0, class_validator_1.IsBoolean)(),
|
|
369
|
+
__metadata("design:type", Boolean)
|
|
370
|
+
], PotFields.prototype, "potPaidPartnershipLabel", void 0);
|
|
371
|
+
__decorate([
|
|
372
|
+
(0, class_validator_1.IsOptional)(),
|
|
373
|
+
(0, class_validator_1.IsString)(),
|
|
374
|
+
(0, class_validator_1.Matches)(/^@?[A-Za-z0-9._]{1,64}$/),
|
|
375
|
+
__metadata("design:type", String)
|
|
376
|
+
], PotFields.prototype, "potSponsorHandle", void 0);
|
|
377
|
+
__decorate([
|
|
378
|
+
(0, class_validator_1.IsOptional)(),
|
|
379
|
+
(0, class_validator_1.IsString)(),
|
|
380
|
+
(0, class_validator_1.Matches)(/^@?[A-Za-z0-9._]{1,64}$/),
|
|
381
|
+
__metadata("design:type", String)
|
|
382
|
+
], PotFields.prototype, "potCollabHandle", void 0);
|
|
383
|
+
__decorate([
|
|
384
|
+
(0, class_validator_1.IsOptional)(),
|
|
385
|
+
(0, class_validator_1.IsString)(),
|
|
386
|
+
(0, class_validator_1.MaxLength)(2200),
|
|
387
|
+
__metadata("design:type", String)
|
|
388
|
+
], PotFields.prototype, "potFirstComment", void 0);
|
|
389
|
+
__decorate([
|
|
390
|
+
(0, class_validator_1.IsOptional)(),
|
|
391
|
+
(0, class_validator_1.IsBoolean)(),
|
|
392
|
+
__metadata("design:type", Boolean)
|
|
393
|
+
], PotFields.prototype, "potCommentsEnabled", void 0);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { CampaignSide, I_CampaignCreatorIdentity } from './agency-campaigns';
|
|
2
|
+
import type { AgencyOrganizationType } from './agency';
|
|
2
3
|
/**
|
|
3
4
|
* Agency ↔ creator threads (spec 175 US8, FR-023): one conversation per
|
|
4
5
|
* organization and creator, inside ad2app.
|
|
@@ -31,21 +32,41 @@ export interface I_AgencyThreadMessage {
|
|
|
31
32
|
side: CampaignSide;
|
|
32
33
|
body: string;
|
|
33
34
|
at: string;
|
|
35
|
+
/** A delegate wrote this for the creator through a `deals` grant (spec 148): which grant, and the member's name. */
|
|
36
|
+
actingFor?: {
|
|
37
|
+
grantId: string;
|
|
38
|
+
memberName: string;
|
|
39
|
+
};
|
|
34
40
|
}
|
|
35
41
|
export interface I_AgencyThreadSummary {
|
|
36
42
|
id: string;
|
|
37
43
|
/** Agency side: who the thread is with. */
|
|
38
44
|
creator: I_CampaignCreatorIdentity;
|
|
39
|
-
/** Creator side: which organization. */
|
|
45
|
+
/** Creator side: which organization, and whether it is an agency or a brand (spec 148). */
|
|
40
46
|
organization: {
|
|
41
47
|
id: string;
|
|
42
48
|
name: string;
|
|
49
|
+
type?: AgencyOrganizationType;
|
|
43
50
|
};
|
|
51
|
+
/** `actingFor`: a delegate wrote the last message for the creator (spec 148 US8), under this member's name. */
|
|
44
52
|
lastMessage: {
|
|
45
53
|
side: CampaignSide;
|
|
46
54
|
body: string;
|
|
47
55
|
at: string;
|
|
56
|
+
actingFor?: {
|
|
57
|
+
memberName: string;
|
|
58
|
+
};
|
|
48
59
|
} | null;
|
|
60
|
+
/**
|
|
61
|
+
* Spec 148 US8 (audit #2): the other organizations whose members read this
|
|
62
|
+
* conversation acting for the creator: a manager holding the creator's
|
|
63
|
+
* `deals` grant while this is a deal's thread, or one whose member already
|
|
64
|
+
* wrote in it. Empty when only the two parties see it.
|
|
65
|
+
*/
|
|
66
|
+
delegates?: Array<{
|
|
67
|
+
id: string;
|
|
68
|
+
name: string;
|
|
69
|
+
}>;
|
|
49
70
|
/** The other side wrote last, seen from the caller's side. */
|
|
50
71
|
unanswered: boolean;
|
|
51
72
|
/** No live relationship: read-only for whoever still exists. */
|
package/dist/types/agency.d.ts
CHANGED
|
@@ -54,8 +54,29 @@ export type I_AgencyGrantScope = (typeof AGENCY_GRANT_SCOPES)[number];
|
|
|
54
54
|
* answer), so this is a trust boundary, not a convenience.
|
|
55
55
|
*/
|
|
56
56
|
export declare const isAgencyGrantScope: (value: string) => value is I_AgencyGrantScope;
|
|
57
|
-
/**
|
|
58
|
-
|
|
57
|
+
/**
|
|
58
|
+
* Delegation (spec 148 FR-017a): the one scope that reaches WRITES, and only
|
|
59
|
+
* the creator-side deal acts (apply, offer acts, materials, the deal thread).
|
|
60
|
+
*
|
|
61
|
+
* Kept OUT of AGENCY_GRANT_SCOPES on purpose: that list is what an
|
|
62
|
+
* organization may ASK for, and no organization ever asks for this. Only the
|
|
63
|
+
* creator adds it to `grantedScopes`, which makes it the one exception to
|
|
64
|
+
* "granted is a subset of requested". Publishing, contract signature,
|
|
65
|
+
* payouts, the settlement form and platforms stay unreachable through it.
|
|
66
|
+
*/
|
|
67
|
+
export declare const DELEGATION_SCOPES: readonly ["deals"];
|
|
68
|
+
export type I_DelegationScope = (typeof DELEGATION_SCOPES)[number];
|
|
69
|
+
/** Everything a grant may carry once the creator has answered. */
|
|
70
|
+
export type I_GrantScope = I_AgencyGrantScope | I_DelegationScope;
|
|
71
|
+
/** Narrowing guard over both sets; an unrecognised scope fails closed. */
|
|
72
|
+
export declare const isGrantScope: (value: string) => value is I_GrantScope;
|
|
73
|
+
/**
|
|
74
|
+
* `'brand'` arrived with spec 148 (US2): one column, no enum table. A brand
|
|
75
|
+
* authors campaigns like an agency but has no roster; it is created only
|
|
76
|
+
* while the backend's brand door is open.
|
|
77
|
+
*/
|
|
78
|
+
export declare const AGENCY_ORGANIZATION_TYPES: readonly ["agency", "brand"];
|
|
79
|
+
export type AgencyOrganizationType = (typeof AGENCY_ORGANIZATION_TYPES)[number];
|
|
59
80
|
/**
|
|
60
81
|
* `closed` was added by the 2026-09-21 requirements review (FR-004b).
|
|
61
82
|
*
|
|
@@ -81,6 +102,11 @@ export interface I_AgencyOrganization {
|
|
|
81
102
|
/** ISO-3166 alpha-2 of the register the identifier belongs to. */
|
|
82
103
|
registryCountry: string;
|
|
83
104
|
contactEmail: string;
|
|
105
|
+
/**
|
|
106
|
+
* The organization's logo, a storage path read through a signed URL (spec
|
|
107
|
+
* 148). Required before a campaign is listed open. Absent on older backends.
|
|
108
|
+
*/
|
|
109
|
+
logoUrl?: string;
|
|
84
110
|
status: AgencyOrganizationStatus;
|
|
85
111
|
/** The reason an admin gave; shown to a rejected applicant (FR-002). */
|
|
86
112
|
statusReason?: string;
|
|
@@ -117,7 +143,13 @@ export interface I_AgencyMember {
|
|
|
117
143
|
*/
|
|
118
144
|
export declare const CREATOR_ACCESS_GRANT_STATES: readonly ["requested", "active", "declined", "expired", "revoked"];
|
|
119
145
|
export type CreatorAccessGrantState = (typeof CREATOR_ACCESS_GRANT_STATES)[number];
|
|
120
|
-
|
|
146
|
+
/**
|
|
147
|
+
* `dealroom_application` (spec 148): created or widened when the creator
|
|
148
|
+
* applies to an open listing. The system revokes a grant of this origin, and
|
|
149
|
+
* only of this origin, when that deal ends.
|
|
150
|
+
*/
|
|
151
|
+
export declare const CREATOR_ACCESS_GRANT_ORIGINS: readonly ["invite_link", "agency_request", "dealroom_application"];
|
|
152
|
+
export type CreatorAccessGrantOrigin = (typeof CREATOR_ACCESS_GRANT_ORIGINS)[number];
|
|
121
153
|
/** Who ended it. Shown in the agency's past-creators history (FR-013b). */
|
|
122
154
|
export type CreatorAccessGrantRevokedBy = 'creator' | 'agency' | 'organization' | 'account-deleted' | 'purge' | 'system';
|
|
123
155
|
export interface I_CreatorAccessGrant {
|
|
@@ -130,10 +162,19 @@ export interface I_CreatorAccessGrant {
|
|
|
130
162
|
creatorUserId?: string;
|
|
131
163
|
organizationId: string;
|
|
132
164
|
organizationName: string;
|
|
165
|
+
/** Spec 148: `brand` cannot hold `deals` (it is the creator's counterparty), so the switch is not offered. Absent on older backends. */
|
|
166
|
+
organizationType?: AgencyOrganizationType;
|
|
133
167
|
/** What the agency asked for. */
|
|
134
168
|
requestedScopes: I_AgencyGrantScope[];
|
|
135
|
-
/** What the creator actually granted — a subset, possibly smaller, never larger. */
|
|
169
|
+
/** What the creator actually granted — a subset, possibly smaller, never larger. Reads only. */
|
|
136
170
|
grantedScopes: I_AgencyGrantScope[];
|
|
171
|
+
/**
|
|
172
|
+
* Spec 148 FR-017a: the creator lets this organization run their Dealroom
|
|
173
|
+
* deals (the `deals` delegation scope, which no organization can ask for and
|
|
174
|
+
* only the creator adds). Kept out of `grantedScopes` so that list stays the
|
|
175
|
+
* reads 175 code is typed on. Absent on older backends: read absent as no.
|
|
176
|
+
*/
|
|
177
|
+
deals?: boolean;
|
|
137
178
|
/** Frozen at grant time; what the history shows after a purge. */
|
|
138
179
|
creatorIdentity: {
|
|
139
180
|
handle: string;
|
|
@@ -256,6 +297,12 @@ export interface I_AgencyRosterRow {
|
|
|
256
297
|
*/
|
|
257
298
|
reaskedAt?: string;
|
|
258
299
|
reaskAvailableAt?: string;
|
|
300
|
+
/**
|
|
301
|
+
* Spec 148 US8: the organization may act for this creator in the Dealroom
|
|
302
|
+
* (the active grant holds `deals`, the org is not a brand). Only
|
|
303
|
+
* sent while the Dealroom is on; absent while it is off (read absent as no).
|
|
304
|
+
*/
|
|
305
|
+
canActForCreator?: boolean;
|
|
259
306
|
}
|
|
260
307
|
/**
|
|
261
308
|
* The platforms a creator has connected, as the agency side sees them
|
|
@@ -428,6 +475,14 @@ export declare class CreateAgencyOrganizationDto {
|
|
|
428
475
|
/** ISO-3166 alpha-2: which register a reviewer should look in. */
|
|
429
476
|
registryCountry: string;
|
|
430
477
|
contactEmail: string;
|
|
478
|
+
/** Spec 148 US2: absent = `agency`. `brand` is refused while the backend's brand door is closed. */
|
|
479
|
+
type?: AgencyOrganizationType;
|
|
480
|
+
/**
|
|
481
|
+
* Spec 148 US2, money release only (DORMANT): the card a brand pays its
|
|
482
|
+
* first subscription charge with, taken BEFORE the organization exists.
|
|
483
|
+
* Ignored while the backend's money switch is off (brands apply free).
|
|
484
|
+
*/
|
|
485
|
+
paymentMethodId?: string;
|
|
431
486
|
constructor(data?: Partial<CreateAgencyOrganizationDto>);
|
|
432
487
|
}
|
|
433
488
|
export declare class InviteAgencyMemberDto {
|
|
@@ -453,11 +508,29 @@ export declare class AcceptGrantDto {
|
|
|
453
508
|
scopes?: I_AgencyGrantScope[];
|
|
454
509
|
constructor(data?: Partial<AcceptGrantDto>);
|
|
455
510
|
}
|
|
456
|
-
/**
|
|
511
|
+
/**
|
|
512
|
+
* The creator narrowing or widening a live grant — the only other write path.
|
|
513
|
+
*
|
|
514
|
+
* `scopes` are the READS only; `deals` is never one of them (it stays out of
|
|
515
|
+
* AGENCY_GRANT_SCOPES). Delegation (spec 148 FR-017a) is its own field, so the
|
|
516
|
+
* data-access screen, which saves reads, can never drop it by omission:
|
|
517
|
+
*
|
|
518
|
+
* - `deals` absent ⇒ delegation unchanged (a reads-only save keeps `deals`);
|
|
519
|
+
* - `deals: true` ⇒ added, `deals: false` ⇒ removed;
|
|
520
|
+
* - `scopes` may be left out when `deals` is sent ⇒ the reads stay as they are.
|
|
521
|
+
*/
|
|
457
522
|
export declare class UpdateGrantScopesDto {
|
|
458
|
-
scopes
|
|
523
|
+
scopes?: I_AgencyGrantScope[];
|
|
524
|
+
/** Let this organization run my deals (spec 148 US8). Creator-only; absent = unchanged. */
|
|
525
|
+
deals?: boolean;
|
|
459
526
|
constructor(data?: Partial<UpdateGrantScopesDto>);
|
|
460
527
|
}
|
|
528
|
+
/**
|
|
529
|
+
* Spec 148 US8: the header a delegate names the creator with on the
|
|
530
|
+
* creator-side deal routes (`X-Acting-For: <creatorUserId>`). Every other
|
|
531
|
+
* route refuses a request that carries it (`dealroom-delegate-forbidden`).
|
|
532
|
+
*/
|
|
533
|
+
export declare const ACTING_FOR_HEADER = "x-acting-for";
|
|
461
534
|
export declare class SponsorCreatorDto {
|
|
462
535
|
tier: SponsoredTier;
|
|
463
536
|
constructor(data?: Partial<SponsorCreatorDto>);
|
|
@@ -512,6 +585,20 @@ export interface I_AgencyDiscoverHit {
|
|
|
512
585
|
export interface I_AgencyDiscoverResult {
|
|
513
586
|
results: I_AgencyDiscoverHit[];
|
|
514
587
|
}
|
|
588
|
+
/** `GET /admin/agency-organizations[?type=]`: one pending organization on the admin queue. */
|
|
589
|
+
export interface I_AdminOrganizationRow {
|
|
590
|
+
id: string;
|
|
591
|
+
/** Spec 148: `agency` or `brand`; filter with `?type=`. */
|
|
592
|
+
type: AgencyOrganizationType;
|
|
593
|
+
name: string;
|
|
594
|
+
website: string | null;
|
|
595
|
+
registryId: string;
|
|
596
|
+
registryCountry: string;
|
|
597
|
+
contactEmail: string;
|
|
598
|
+
/** Derived, a SIGNAL only (FR-003). */
|
|
599
|
+
contactEmailDomain: string;
|
|
600
|
+
appliedAt: string;
|
|
601
|
+
}
|
|
515
602
|
export declare class AdminSetOrganizationStatusDto {
|
|
516
603
|
status: Extract<AgencyOrganizationStatus, 'approved' | 'rejected'>;
|
|
517
604
|
/** Required on reject — a rejected applicant is shown this (FR-002). The
|