ad2app-lib 1.10.0 → 1.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.
@@ -0,0 +1,116 @@
1
+ "use strict";
2
+ /**
3
+ * Canonical publish-limits source of truth for ad2app (AD2-1140 Wave 1).
4
+ *
5
+ * Single source of truth for (a) the per-platform compose/publish limits
6
+ * (character count, image/video counts, max video duration) and (b) the
7
+ * universal media-upload byte cap ad2app itself enforces.
8
+ *
9
+ * Provenance:
10
+ * - Per-platform values are the CORRECTED figures from
11
+ * ad2app-frontend/src/components/social/compose/platformConstants.ts
12
+ * (PLATFORM_CONFIGS[*].charLimit / maxImages / maxVideos / acceptsVideo /
13
+ * acceptsImages / metadata.mediaConstraints.maxVideoDuration).
14
+ * - MAX_UPLOAD_BYTES matches ad2app-backend
15
+ * src/modules/late/late-media-upload.service.ts MAX_FILE_SIZE_BYTES + FR-105.
16
+ *
17
+ * Wave 2 (separate PRs) makes ad2app-frontend and ad2app-backend import from
18
+ * here instead of carrying their own copies, and deletes the stale
19
+ * per-platform maxImageSize/maxVideoSize byte values that this table
20
+ * deliberately does NOT carry forward (they were never the real enforced
21
+ * cap — MAX_UPLOAD_BYTES is).
22
+ */
23
+ Object.defineProperty(exports, "__esModule", { value: true });
24
+ exports.ALL_PUBLISH_PLATFORMS = exports.PUBLISH_LIMITS = exports.MAX_UPLOAD_BYTES = void 0;
25
+ /**
26
+ * The universal media-upload byte cap ad2app enforces on every publish,
27
+ * regardless of destination platform. This is ad2app's own operational
28
+ * choice (all media flows through the /late/uploadMedia path), NOT a
29
+ * per-platform maximum — do not read this as "what X/Instagram/etc. allow."
30
+ */
31
+ exports.MAX_UPLOAD_BYTES = 500 * 1024 * 1024;
32
+ /** Per-platform compose/publish limits for all 10 connectable platforms. */
33
+ exports.PUBLISH_LIMITS = {
34
+ twitter: {
35
+ charLimit: 280,
36
+ maxImages: 4,
37
+ maxVideos: 1,
38
+ maxVideoDurationSec: 3600,
39
+ acceptsVideo: true,
40
+ acceptsImages: true,
41
+ },
42
+ instagram: {
43
+ charLimit: 2200,
44
+ maxImages: 10,
45
+ maxVideos: 1,
46
+ maxVideoDurationSec: 3600,
47
+ acceptsVideo: true,
48
+ acceptsImages: true,
49
+ },
50
+ tiktok: {
51
+ charLimit: 2200,
52
+ maxImages: 35,
53
+ maxVideos: 1,
54
+ maxVideoDurationSec: 600,
55
+ acceptsVideo: true,
56
+ acceptsImages: true,
57
+ },
58
+ linkedin: {
59
+ charLimit: 3000,
60
+ maxImages: 9,
61
+ maxVideos: 1,
62
+ maxVideoDurationSec: 3600,
63
+ acceptsVideo: true,
64
+ acceptsImages: true,
65
+ },
66
+ facebook: {
67
+ charLimit: 63206,
68
+ maxImages: 10,
69
+ maxVideos: 1,
70
+ maxVideoDurationSec: 3600,
71
+ acceptsVideo: true,
72
+ acceptsImages: true,
73
+ },
74
+ youtube: {
75
+ charLimit: 5000,
76
+ maxImages: 0,
77
+ maxVideos: 1,
78
+ maxVideoDurationSec: 43200,
79
+ acceptsVideo: true,
80
+ acceptsImages: false,
81
+ },
82
+ threads: {
83
+ charLimit: 500,
84
+ maxImages: 10,
85
+ maxVideos: 1,
86
+ maxVideoDurationSec: 300,
87
+ acceptsVideo: true,
88
+ acceptsImages: true,
89
+ },
90
+ reddit: {
91
+ charLimit: 40000,
92
+ maxImages: 20,
93
+ maxVideos: 1,
94
+ maxVideoDurationSec: 3600,
95
+ acceptsVideo: true,
96
+ acceptsImages: true,
97
+ },
98
+ pinterest: {
99
+ charLimit: 500,
100
+ maxImages: 1,
101
+ maxVideos: 1,
102
+ maxVideoDurationSec: 900,
103
+ acceptsVideo: true,
104
+ acceptsImages: true,
105
+ },
106
+ bluesky: {
107
+ charLimit: 300,
108
+ maxImages: 4,
109
+ maxVideos: 1,
110
+ maxVideoDurationSec: 60,
111
+ acceptsVideo: true,
112
+ acceptsImages: true,
113
+ },
114
+ };
115
+ /** All publish platforms, canonical order (mirrors PUBLISH_LIMITS key order). */
116
+ exports.ALL_PUBLISH_PLATFORMS = Object.keys(exports.PUBLISH_LIMITS);
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Publish-limits domain — types.
3
+ *
4
+ * AD2-1140 Wave 1: canonicalizes the per-platform compose/publish limits that
5
+ * previously lived only as a hand-copied constant in ad2app-frontend
6
+ * (platformConstants.ts) plus the universal media-size cap enforced in
7
+ * ad2app-backend (late-media-upload.service.ts). Wave 2 makes both consumers
8
+ * import from here instead of carrying their own copies.
9
+ */
10
+ /** The 10 platforms ad2app can publish to. Matches the frontend's SocialPlatform union. */
11
+ export type PublishPlatform = 'twitter' | 'instagram' | 'tiktok' | 'linkedin' | 'facebook' | 'youtube' | 'threads' | 'reddit' | 'pinterest' | 'bluesky';
12
+ /** Per-platform compose/publish limits (content, not file-size — see MAX_UPLOAD_BYTES for that). */
13
+ export interface PlatformPublishLimits {
14
+ /** Max caption/body length in characters. */
15
+ charLimit: number;
16
+ /** Max still images per post (0 = platform does not accept images). */
17
+ maxImages: number;
18
+ /** Max videos per post (0 = platform does not accept video). */
19
+ maxVideos: number;
20
+ /** Max video duration in seconds. */
21
+ maxVideoDurationSec: number;
22
+ /** Whether the platform accepts video media at all. */
23
+ acceptsVideo: boolean;
24
+ /** Whether the platform accepts image media at all. */
25
+ acceptsImages: boolean;
26
+ }
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ /**
3
+ * Publish-limits domain — types.
4
+ *
5
+ * AD2-1140 Wave 1: canonicalizes the per-platform compose/publish limits that
6
+ * previously lived only as a hand-copied constant in ad2app-frontend
7
+ * (platformConstants.ts) plus the universal media-size cap enforced in
8
+ * ad2app-backend (late-media-upload.service.ts). Wave 2 makes both consumers
9
+ * import from here instead of carrying their own copies.
10
+ */
11
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -4,6 +4,12 @@
4
4
  * Covers KPI summaries, daily engagement entries, best-time-to-post slots,
5
5
  * per-post timeline snapshots, content decay windows, and follower stats.
6
6
  */
7
+ /**
8
+ * The upstream sources an analytics response aggregates. Used by
9
+ * `failedSources` to name which of them were unavailable.
10
+ */
11
+ export declare const ANALYTICS_SOURCES: readonly ["daily-metrics", "follower-stats", "content-decay", "top-posts"];
12
+ export type AnalyticsSource = (typeof ANALYTICS_SOURCES)[number];
7
13
  /**
8
14
  * Aggregated KPI figures for the selected date range.
9
15
  * Returned by GET /social/analytics.
@@ -11,8 +17,33 @@
11
17
  export declare class SchedulingAnalyticsKpiDTO {
12
18
  impressions: number;
13
19
  reach: number;
20
+ /** Total engagements (likes, comments, shares, saves) across all selected platforms. */
21
+ engagements: number;
22
+ /** Total video/media views across all selected platforms. */
23
+ views: number;
14
24
  engagementRate: number;
15
25
  followerGrowth: number;
26
+ /**
27
+ * Sources that were unavailable when this response was assembled
28
+ * (AD2-1045). Absent/empty = all sources healthy. When present, the
29
+ * numeric fields contain only data from the healthy sources — a partial
30
+ * outage must never read as real zeros.
31
+ */
32
+ failedSources?: AnalyticsSource[];
33
+ /**
34
+ * Structural availability of the impressions metric (AD2-1078) — distinct
35
+ * from `failedSources`, which is a transient per-fetch outage. False when
36
+ * the connected platform mix fundamentally does not expose impressions
37
+ * (e.g. Instagram Graph API v22+ dropped it): an honest "—" beats a fake
38
+ * 0, which reads as "zero people saw this". Absent/true = available.
39
+ */
40
+ impressionsAvailable?: boolean;
41
+ /**
42
+ * Structural availability of the reach metric (AD2-1078). False when the
43
+ * connected platform mix fundamentally never exposes reach (e.g. TikTok).
44
+ * Absent/true = available.
45
+ */
46
+ reachAvailable?: boolean;
16
47
  constructor(data: SchedulingAnalyticsKpiDTO);
17
48
  }
18
49
  /**
@@ -73,7 +104,11 @@ export declare class SchedulingPostTimelineEntryDTO {
73
104
  * Returned by GET /social/analytics/content-decay.
74
105
  */
75
106
  export declare class SchedulingContentDecayDTO {
76
- window: '1h' | '6h' | '24h' | '7d';
107
+ /**
108
+ * Zernio now returns aggregate bucket labels (e.g. "0-6h", "6-12h"), not
109
+ * the old fixed windows — widened accordingly (AD2-1061, 2026-07-03).
110
+ */
111
+ window: string;
77
112
  platform: string;
78
113
  /** Percentage of peak engagement remaining at this window */
79
114
  pct: number;
@@ -6,7 +6,18 @@
6
6
  * per-post timeline snapshots, content decay windows, and follower stats.
7
7
  */
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
- exports.SchedulingFollowerStatDTO = exports.SchedulingContentDecayDTO = exports.SchedulingPostTimelineEntryDTO = exports.SchedulingBestTimeSlotDTO = exports.SchedulingAnalyticsParamsDTO = exports.SchedulingAnalyticsEntryDTO = exports.SchedulingAnalyticsKpiDTO = void 0;
9
+ exports.SchedulingFollowerStatDTO = exports.SchedulingContentDecayDTO = exports.SchedulingPostTimelineEntryDTO = exports.SchedulingBestTimeSlotDTO = exports.SchedulingAnalyticsParamsDTO = exports.SchedulingAnalyticsEntryDTO = exports.SchedulingAnalyticsKpiDTO = exports.ANALYTICS_SOURCES = void 0;
10
+ // ── Analytics sources (AD2-1045) ──────────────────────────────────────────────
11
+ /**
12
+ * The upstream sources an analytics response aggregates. Used by
13
+ * `failedSources` to name which of them were unavailable.
14
+ */
15
+ exports.ANALYTICS_SOURCES = [
16
+ 'daily-metrics',
17
+ 'follower-stats',
18
+ 'content-decay',
19
+ 'top-posts',
20
+ ];
10
21
  // ── SchedulingAnalyticsKpiDTO ─────────────────────────────────────────────────
11
22
  /**
12
23
  * Aggregated KPI figures for the selected date range.
@@ -16,8 +27,19 @@ class SchedulingAnalyticsKpiDTO {
16
27
  constructor(data) {
17
28
  this.impressions = data.impressions;
18
29
  this.reach = data.reach;
30
+ this.engagements = data.engagements;
31
+ this.views = data.views;
19
32
  this.engagementRate = data.engagementRate;
20
33
  this.followerGrowth = data.followerGrowth;
34
+ if (data.failedSources !== undefined) {
35
+ this.failedSources = data.failedSources;
36
+ }
37
+ if (data.impressionsAvailable !== undefined) {
38
+ this.impressionsAvailable = data.impressionsAvailable;
39
+ }
40
+ if (data.reachAvailable !== undefined) {
41
+ this.reachAvailable = data.reachAvailable;
42
+ }
21
43
  }
22
44
  }
23
45
  exports.SchedulingAnalyticsKpiDTO = SchedulingAnalyticsKpiDTO;
@@ -44,6 +44,14 @@ export declare class SchedulingInboxCommentDTO {
44
44
  authorAvatarUrl?: string;
45
45
  text: string;
46
46
  createdAt: string;
47
+ /** Likes on the comment, verbatim from Zernio (AD2-1088). Absent, never backfilled to 0. */
48
+ likeCount?: number;
49
+ /** Replies count on the comment, verbatim from Zernio (AD2-1088). */
50
+ replyCount?: number;
51
+ /** True when OUR connected account authored it — the answered state (AD2-1088). */
52
+ isOwner?: boolean;
53
+ /** Parent comment id on nested replies (AD2-1088). Absent on top-level comments. */
54
+ parentId?: string;
47
55
  replies?: SchedulingInboxCommentDTO[];
48
56
  constructor(data: SchedulingInboxCommentDTO);
49
57
  }
@@ -55,6 +55,10 @@ class SchedulingInboxCommentDTO {
55
55
  this.authorAvatarUrl = data.authorAvatarUrl;
56
56
  this.text = data.text;
57
57
  this.createdAt = data.createdAt;
58
+ this.likeCount = data.likeCount;
59
+ this.replyCount = data.replyCount;
60
+ this.isOwner = data.isOwner;
61
+ this.parentId = data.parentId;
58
62
  this.replies = data.replies;
59
63
  }
60
64
  }
@@ -37,8 +37,45 @@ export declare class SchedulingCreatePostDTO {
37
37
  export declare class SchedulingUpdatePostDTO {
38
38
  content?: string;
39
39
  scheduledAt?: string;
40
+ /**
41
+ * Per-platform targets for the edit patch (C2, AD2-1026) — the backend's
42
+ * `UpdatePostDTO` intersects this on top locally today; promoted here so
43
+ * the type ships from the lib instead of a local clone.
44
+ */
45
+ platforms?: SchedulingPlatformTargetDTO[];
46
+ /** Full media array for the edit patch (C2, AD2-1026), same shape as create. */
47
+ mediaItems?: SchedulingMediaItemDTO[];
40
48
  constructor(data?: Partial<SchedulingUpdatePostDTO>);
41
49
  }
50
+ /**
51
+ * One media item on the edit-load response — verbatim from the live Zernio
52
+ * post's mediaItems (Post.mediaItems → MediaItem, OpenAPI v1.0.4:3223).
53
+ * Distinct from `SchedulingMediaItemDTO` (the create/update input shape):
54
+ * every field here is optional and `type` additionally allows `gif`/`document`
55
+ * to match what a fetched post can actually carry (T022b, AD2-1026).
56
+ */
57
+ export declare class SchedulingPostMediaItemDTO {
58
+ type?: 'image' | 'video' | 'gif' | 'document';
59
+ url?: string;
60
+ title?: string;
61
+ constructor(data?: Partial<SchedulingPostMediaItemDTO>);
62
+ }
63
+ /**
64
+ * One per-platform target on the edit-load response — the request-shape
65
+ * subset of Zernio's PlatformTarget (OpenAPI v1.0.4:3275): `platform`,
66
+ * `accountId` (always normalized to the plain string id — Zernio expands it
67
+ * to an account object on fetched posts, yaml:3282), and
68
+ * `platformSpecificData` VERBATIM (yaml:3297, additionalProperties: true).
69
+ * Response-only fields (status, platformPostUrl, errors) are never exposed
70
+ * here — they already live on platformStatuses/postUrls/platformErrors
71
+ * (T022b, AD2-1026).
72
+ */
73
+ export declare class SchedulingPostTargetDTO {
74
+ platform: string;
75
+ accountId?: string;
76
+ platformSpecificData?: Record<string, unknown>;
77
+ constructor(data?: Partial<SchedulingPostTargetDTO>);
78
+ }
42
79
  /** Response DTO representing a single post returned from the API. */
43
80
  export declare class SchedulingPostDTO {
44
81
  id: string;
@@ -55,6 +92,25 @@ export declare class SchedulingPostDTO {
55
92
  contentSnippet?: string;
56
93
  createdAt: string;
57
94
  updatedAt: string;
95
+ /**
96
+ * Media-miniature pass-through fields (C1, AD2-1083) — present only when
97
+ * the cache row has a stored thumbnail/media URL, absent otherwise (never
98
+ * an empty string).
99
+ */
100
+ thumbnailUrl?: string;
101
+ mediaUrl?: string;
102
+ /**
103
+ * Edit-load fields for compose edit mode (C2, AD2-1026 + T022b):
104
+ * `content` is the COMPLETE caption (the cache only stores the 280-char
105
+ * `contentSnippet`); `mediaItems`/`platformTargets` are the full per-post
106
+ * media array and per-platform accountIds + compose settings. All three
107
+ * ride the live Zernio fetch: present when it succeeds (arrays may be
108
+ * possibly-empty = known-empty), ALL absent when it fails, which blocks
109
+ * edit frontend-side.
110
+ */
111
+ content?: string;
112
+ mediaItems?: SchedulingPostMediaItemDTO[];
113
+ platformTargets?: SchedulingPostTargetDTO[];
58
114
  constructor(data: SchedulingPostDTO);
59
115
  }
60
116
  /** Query parameters for listing posts with optional filters. */
@@ -6,7 +6,7 @@
6
6
  * and the media items attached to a post.
7
7
  */
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
- exports.SchedulingContentCalendarDTO = exports.SchedulingPostListParamsDTO = exports.SchedulingPostDTO = exports.SchedulingUpdatePostDTO = exports.SchedulingCreatePostDTO = exports.SchedulingMediaItemDTO = exports.SchedulingPlatformTargetDTO = exports.SchedulingPostStatus = void 0;
9
+ exports.SchedulingContentCalendarDTO = exports.SchedulingPostListParamsDTO = exports.SchedulingPostDTO = exports.SchedulingPostTargetDTO = exports.SchedulingPostMediaItemDTO = exports.SchedulingUpdatePostDTO = exports.SchedulingCreatePostDTO = exports.SchedulingMediaItemDTO = exports.SchedulingPlatformTargetDTO = exports.SchedulingPostStatus = void 0;
10
10
  // ── Enums ─────────────────────────────────────────────────────────────────────
11
11
  var SchedulingPostStatus;
12
12
  (function (SchedulingPostStatus) {
@@ -60,9 +60,50 @@ class SchedulingUpdatePostDTO {
60
60
  return;
61
61
  this.content = data.content;
62
62
  this.scheduledAt = data.scheduledAt;
63
+ this.platforms = data.platforms;
64
+ this.mediaItems = data.mediaItems;
63
65
  }
64
66
  }
65
67
  exports.SchedulingUpdatePostDTO = SchedulingUpdatePostDTO;
68
+ // ── SchedulingPostMediaItemDTO ────────────────────────────────────────────────
69
+ /**
70
+ * One media item on the edit-load response — verbatim from the live Zernio
71
+ * post's mediaItems (Post.mediaItems → MediaItem, OpenAPI v1.0.4:3223).
72
+ * Distinct from `SchedulingMediaItemDTO` (the create/update input shape):
73
+ * every field here is optional and `type` additionally allows `gif`/`document`
74
+ * to match what a fetched post can actually carry (T022b, AD2-1026).
75
+ */
76
+ class SchedulingPostMediaItemDTO {
77
+ constructor(data) {
78
+ if (!data)
79
+ return;
80
+ this.type = data.type;
81
+ this.url = data.url;
82
+ this.title = data.title;
83
+ }
84
+ }
85
+ exports.SchedulingPostMediaItemDTO = SchedulingPostMediaItemDTO;
86
+ // ── SchedulingPostTargetDTO ───────────────────────────────────────────────────
87
+ /**
88
+ * One per-platform target on the edit-load response — the request-shape
89
+ * subset of Zernio's PlatformTarget (OpenAPI v1.0.4:3275): `platform`,
90
+ * `accountId` (always normalized to the plain string id — Zernio expands it
91
+ * to an account object on fetched posts, yaml:3282), and
92
+ * `platformSpecificData` VERBATIM (yaml:3297, additionalProperties: true).
93
+ * Response-only fields (status, platformPostUrl, errors) are never exposed
94
+ * here — they already live on platformStatuses/postUrls/platformErrors
95
+ * (T022b, AD2-1026).
96
+ */
97
+ class SchedulingPostTargetDTO {
98
+ constructor(data) {
99
+ if (!data)
100
+ return;
101
+ this.platform = data.platform;
102
+ this.accountId = data.accountId;
103
+ this.platformSpecificData = data.platformSpecificData;
104
+ }
105
+ }
106
+ exports.SchedulingPostTargetDTO = SchedulingPostTargetDTO;
66
107
  // ── SchedulingPostDTO ─────────────────────────────────────────────────────────
67
108
  /** Response DTO representing a single post returned from the API. */
68
109
  class SchedulingPostDTO {
@@ -79,6 +120,11 @@ class SchedulingPostDTO {
79
120
  this.contentSnippet = data.contentSnippet;
80
121
  this.createdAt = data.createdAt;
81
122
  this.updatedAt = data.updatedAt;
123
+ this.thumbnailUrl = data.thumbnailUrl;
124
+ this.mediaUrl = data.mediaUrl;
125
+ this.content = data.content;
126
+ this.mediaItems = data.mediaItems;
127
+ this.platformTargets = data.platformTargets;
82
128
  }
83
129
  }
84
130
  exports.SchedulingPostDTO = SchedulingPostDTO;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ad2app-lib",
3
- "version": "1.10.0",
3
+ "version": "1.14.0",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "type": "commonjs",
@@ -10,6 +10,7 @@
10
10
  "./api": "./dist/api/index.js",
11
11
  "./legal": "./dist/legal/index.js",
12
12
  "./analytics": "./dist/analytics/index.js",
13
+ "./publish-limits": "./dist/publish-limits/index.js",
13
14
  "./brand": "./brand/brand.mjs"
14
15
  },
15
16
  "typesVersions": {
@@ -29,6 +30,9 @@
29
30
  "analytics": [
30
31
  "dist/analytics/index.d.ts"
31
32
  ],
33
+ "publish-limits": [
34
+ "dist/publish-limits/index.d.ts"
35
+ ],
32
36
  "brand": [
33
37
  "brand/brand.d.ts"
34
38
  ],
package/src/legal/meta.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export const LEGAL_META = {
2
- lastUpdated: '10 June 2026',
2
+ lastUpdated: '6 July 2026',
3
3
  contactEmail: 'kontakt@ad2.app',
4
4
  controllerName: 'Ad2app sp. z o.o.',
5
5
  controllerAddress: 'ul. Juliana Smulikowskiego 4A/21, 00-389 Warszawa, Poland',