@dracoonghost/trndup-sdk 1.3.16 → 1.3.18
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/index.d.mts +857 -1
- package/dist/index.d.ts +857 -1
- package/dist/index.js +371 -0
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +371 -0
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -594,6 +594,566 @@ declare namespace Insights {
|
|
|
594
594
|
/** Max number of data points (default: 30, max: 90) */
|
|
595
595
|
limit?: number;
|
|
596
596
|
}
|
|
597
|
+
/**
|
|
598
|
+
* How we calculated this insight - shown to user for transparency
|
|
599
|
+
*/
|
|
600
|
+
interface CalculationExplanation {
|
|
601
|
+
/** Short description of the methodology */
|
|
602
|
+
method: string;
|
|
603
|
+
/** Time range analyzed */
|
|
604
|
+
timeRange: string;
|
|
605
|
+
/** Key factors that influenced the result */
|
|
606
|
+
factors: string[];
|
|
607
|
+
/** Data quality/reliability indicator */
|
|
608
|
+
dataQuality: 'high' | 'medium' | 'low';
|
|
609
|
+
/** Why data quality might be limited */
|
|
610
|
+
dataQualityNote?: string;
|
|
611
|
+
}
|
|
612
|
+
/**
|
|
613
|
+
* Common metadata for all insights
|
|
614
|
+
*/
|
|
615
|
+
interface InsightMeta {
|
|
616
|
+
/** When this insight was calculated */
|
|
617
|
+
calculatedAt: string;
|
|
618
|
+
/** When this insight expires (should be recalculated) */
|
|
619
|
+
validUntil: string;
|
|
620
|
+
/** Algorithm version for tracking changes */
|
|
621
|
+
algorithmVersion: string;
|
|
622
|
+
/** Whether result came from cache */
|
|
623
|
+
fromCache: boolean;
|
|
624
|
+
/** How this was calculated (for transparency) */
|
|
625
|
+
howWeCalculatedThis: CalculationExplanation;
|
|
626
|
+
}
|
|
627
|
+
/**
|
|
628
|
+
* Response when there's not enough data for an insight
|
|
629
|
+
*/
|
|
630
|
+
interface InsufficientDataResponse {
|
|
631
|
+
hasData: false;
|
|
632
|
+
reason: string;
|
|
633
|
+
minimumRequired: string;
|
|
634
|
+
currentAmount: string;
|
|
635
|
+
suggestion: string;
|
|
636
|
+
}
|
|
637
|
+
interface TopVideoData {
|
|
638
|
+
videoId: string;
|
|
639
|
+
title: string;
|
|
640
|
+
thumbnailUrl: string | null;
|
|
641
|
+
publishedAt: string;
|
|
642
|
+
/** Link to watch on YouTube */
|
|
643
|
+
watchUrl: string;
|
|
644
|
+
}
|
|
645
|
+
interface TopVideoMetrics {
|
|
646
|
+
views: number;
|
|
647
|
+
likes: number;
|
|
648
|
+
comments: number;
|
|
649
|
+
estimatedMinutesWatched: number;
|
|
650
|
+
engagementRate: number;
|
|
651
|
+
}
|
|
652
|
+
interface TopVideoComparison {
|
|
653
|
+
/** Performance vs user's average video */
|
|
654
|
+
vsChannelAverage: {
|
|
655
|
+
views: number;
|
|
656
|
+
engagement: number;
|
|
657
|
+
description: string;
|
|
658
|
+
};
|
|
659
|
+
/** Why this video performed well */
|
|
660
|
+
standoutReasons: string[];
|
|
661
|
+
}
|
|
662
|
+
interface BestPerformingVideoData {
|
|
663
|
+
/** Time range analyzed */
|
|
664
|
+
period: {
|
|
665
|
+
start: string;
|
|
666
|
+
end: string;
|
|
667
|
+
days: number;
|
|
668
|
+
};
|
|
669
|
+
/** The top performing video */
|
|
670
|
+
topVideo: TopVideoData;
|
|
671
|
+
/** Video's metrics for this period */
|
|
672
|
+
metrics: TopVideoMetrics;
|
|
673
|
+
/** How it compares to your other content */
|
|
674
|
+
comparison: TopVideoComparison;
|
|
675
|
+
/** Human-readable summary */
|
|
676
|
+
insight: string;
|
|
677
|
+
/** Runner-up videos (for context) */
|
|
678
|
+
runnersUp: Array<{
|
|
679
|
+
videoId: string;
|
|
680
|
+
title: string;
|
|
681
|
+
views: number;
|
|
682
|
+
thumbnailUrl: string | null;
|
|
683
|
+
}>;
|
|
684
|
+
}
|
|
685
|
+
type BestPerformingVideoResponse = (InsufficientDataResponse) | {
|
|
686
|
+
hasData: true;
|
|
687
|
+
data: BestPerformingVideoData;
|
|
688
|
+
_meta: InsightMeta;
|
|
689
|
+
};
|
|
690
|
+
interface DecayingVideo {
|
|
691
|
+
videoId: string;
|
|
692
|
+
title: string;
|
|
693
|
+
thumbnailUrl: string | null;
|
|
694
|
+
publishedAt: string;
|
|
695
|
+
watchUrl: string;
|
|
696
|
+
/** Age of video in days */
|
|
697
|
+
ageInDays: number;
|
|
698
|
+
/** Views in current period */
|
|
699
|
+
currentViews: number;
|
|
700
|
+
/** Views in previous period */
|
|
701
|
+
previousViews: number;
|
|
702
|
+
/** Decay rate as percentage (negative = declining) */
|
|
703
|
+
decayRate: number;
|
|
704
|
+
/** Severity of decay */
|
|
705
|
+
severity: 'severe' | 'moderate' | 'mild';
|
|
706
|
+
/** Actionable suggestion */
|
|
707
|
+
suggestion: string;
|
|
708
|
+
}
|
|
709
|
+
interface ContentDecayData {
|
|
710
|
+
/** Time range analyzed */
|
|
711
|
+
period: {
|
|
712
|
+
current: {
|
|
713
|
+
start: string;
|
|
714
|
+
end: string;
|
|
715
|
+
};
|
|
716
|
+
previous: {
|
|
717
|
+
start: string;
|
|
718
|
+
end: string;
|
|
719
|
+
};
|
|
720
|
+
days: number;
|
|
721
|
+
};
|
|
722
|
+
/** Number of videos analyzed */
|
|
723
|
+
videosAnalyzed: number;
|
|
724
|
+
/** Videos experiencing significant decay */
|
|
725
|
+
decayingVideos: DecayingVideo[];
|
|
726
|
+
/** Summary stats */
|
|
727
|
+
summary: {
|
|
728
|
+
totalDecaying: number;
|
|
729
|
+
severeCount: number;
|
|
730
|
+
moderateCount: number;
|
|
731
|
+
mildCount: number;
|
|
732
|
+
/** Combined view loss from all decaying videos */
|
|
733
|
+
totalViewsLost: number;
|
|
734
|
+
};
|
|
735
|
+
/** Human-readable summary */
|
|
736
|
+
insight: string;
|
|
737
|
+
/** What content decay means */
|
|
738
|
+
whatThisMeans: string;
|
|
739
|
+
}
|
|
740
|
+
type ContentDecayResponse = (InsufficientDataResponse) | {
|
|
741
|
+
hasData: true;
|
|
742
|
+
data: ContentDecayData;
|
|
743
|
+
_meta: InsightMeta;
|
|
744
|
+
};
|
|
745
|
+
interface DayPerformance {
|
|
746
|
+
day: string;
|
|
747
|
+
avgFirstDayViews: number;
|
|
748
|
+
avgEngagement: number;
|
|
749
|
+
videoCount: number;
|
|
750
|
+
/** Confidence in this data */
|
|
751
|
+
confidence: 'high' | 'medium' | 'low';
|
|
752
|
+
}
|
|
753
|
+
interface TimeSlotPerformance {
|
|
754
|
+
slot: string;
|
|
755
|
+
label: string;
|
|
756
|
+
avgFirstDayViews: number;
|
|
757
|
+
videoCount: number;
|
|
758
|
+
confidence: 'high' | 'medium' | 'low';
|
|
759
|
+
}
|
|
760
|
+
interface AudienceActivityData {
|
|
761
|
+
/** How many videos were analyzed */
|
|
762
|
+
videosAnalyzed: number;
|
|
763
|
+
/** Day when your audience is most active */
|
|
764
|
+
mostActiveDay: {
|
|
765
|
+
day: string;
|
|
766
|
+
confidence: 'high' | 'medium' | 'low';
|
|
767
|
+
/** Why this day shows highest activity */
|
|
768
|
+
reason: string;
|
|
769
|
+
};
|
|
770
|
+
/** Time slot when your audience is most active */
|
|
771
|
+
mostActiveTimeSlot: {
|
|
772
|
+
slot: string;
|
|
773
|
+
label: string;
|
|
774
|
+
confidence: 'high' | 'medium' | 'low';
|
|
775
|
+
reason: string;
|
|
776
|
+
};
|
|
777
|
+
/** Full breakdown by day */
|
|
778
|
+
dayBreakdown: DayPerformance[];
|
|
779
|
+
/** Full breakdown by time slot (if enough data) */
|
|
780
|
+
timeBreakdown: TimeSlotPerformance[] | null;
|
|
781
|
+
/** Human-readable summary */
|
|
782
|
+
insight: string;
|
|
783
|
+
/** Disclaimer about the data */
|
|
784
|
+
disclaimer: string;
|
|
785
|
+
}
|
|
786
|
+
type AudienceActivityResponse = (InsufficientDataResponse) | {
|
|
787
|
+
hasData: true;
|
|
788
|
+
data: AudienceActivityData;
|
|
789
|
+
_meta: InsightMeta;
|
|
790
|
+
};
|
|
791
|
+
/** @deprecated Use AudienceActivityData instead */
|
|
792
|
+
type BestUploadTimeData = AudienceActivityData;
|
|
793
|
+
/** @deprecated Use AudienceActivityResponse instead */
|
|
794
|
+
type BestUploadTimeResponse = AudienceActivityResponse;
|
|
795
|
+
interface FadingHitVideo {
|
|
796
|
+
videoId: string;
|
|
797
|
+
title: string;
|
|
798
|
+
thumbnailUrl: string | null;
|
|
799
|
+
publishedAt: string;
|
|
800
|
+
watchUrl: string;
|
|
801
|
+
/** How old the video is in days */
|
|
802
|
+
ageInDays: number;
|
|
803
|
+
/** Performance during peak period (actual peak, not just first 14 days) */
|
|
804
|
+
peakPerformance: {
|
|
805
|
+
/** Average daily views during peak window */
|
|
806
|
+
dailyViews: number;
|
|
807
|
+
/** Comparison to channel average (e.g., "45% above average") */
|
|
808
|
+
vsChannelAverage: string;
|
|
809
|
+
/** Was this a top performer (2x+ channel average)? */
|
|
810
|
+
wasTopPerformer: boolean;
|
|
811
|
+
/** When the actual peak occurred */
|
|
812
|
+
peakPeriod: {
|
|
813
|
+
start: string;
|
|
814
|
+
end: string;
|
|
815
|
+
/** How many days after upload the peak occurred */
|
|
816
|
+
daysAfterUpload: number;
|
|
817
|
+
/** True if video went viral later (not at launch) - delayed virality */
|
|
818
|
+
wasDelayedViral: boolean;
|
|
819
|
+
};
|
|
820
|
+
};
|
|
821
|
+
/** Performance in recent period (last 14 days) */
|
|
822
|
+
currentPerformance: {
|
|
823
|
+
/** Current average daily views */
|
|
824
|
+
dailyViews: number;
|
|
825
|
+
/** Percentage decline from peak (negative number) */
|
|
826
|
+
declineFromPeak: number;
|
|
827
|
+
};
|
|
828
|
+
/** How likely revival efforts would work */
|
|
829
|
+
revivalPotential: 'high' | 'medium' | 'low';
|
|
830
|
+
/** Why this video might be worth reviving */
|
|
831
|
+
whyRevive: string;
|
|
832
|
+
/** Specific suggestions to revive this video */
|
|
833
|
+
suggestions: string[];
|
|
834
|
+
}
|
|
835
|
+
interface FadingHitsData {
|
|
836
|
+
/** Time period for "current" performance check */
|
|
837
|
+
period: {
|
|
838
|
+
current: {
|
|
839
|
+
start: string;
|
|
840
|
+
end: string;
|
|
841
|
+
};
|
|
842
|
+
label: string;
|
|
843
|
+
};
|
|
844
|
+
/** Number of videos analyzed */
|
|
845
|
+
videosAnalyzed: number;
|
|
846
|
+
/** Videos that were performing above average but are now declining */
|
|
847
|
+
fadingHits: FadingHitVideo[];
|
|
848
|
+
/** Summary stats */
|
|
849
|
+
summary: {
|
|
850
|
+
totalFading: number;
|
|
851
|
+
highPotentialCount: number;
|
|
852
|
+
mediumPotentialCount: number;
|
|
853
|
+
lowPotentialCount: number;
|
|
854
|
+
/** Combined daily views being lost */
|
|
855
|
+
totalDailyViewsLost: number;
|
|
856
|
+
};
|
|
857
|
+
/** Human-readable summary */
|
|
858
|
+
insight: string;
|
|
859
|
+
/** What fading hits means */
|
|
860
|
+
whatThisMeans: string;
|
|
861
|
+
}
|
|
862
|
+
type FadingHitsResponse = (InsufficientDataResponse) | {
|
|
863
|
+
hasData: true;
|
|
864
|
+
data: FadingHitsData;
|
|
865
|
+
_meta: InsightMeta;
|
|
866
|
+
};
|
|
867
|
+
type SubscriberQualityLabel = 'excellent' | 'good' | 'fair' | 'needs_attention' | 'concerning';
|
|
868
|
+
interface SubscriberQualityData {
|
|
869
|
+
/** Time range analyzed */
|
|
870
|
+
period: {
|
|
871
|
+
start: string;
|
|
872
|
+
end: string;
|
|
873
|
+
days: number;
|
|
874
|
+
};
|
|
875
|
+
/** Overall quality score (0-100) */
|
|
876
|
+
qualityScore: number;
|
|
877
|
+
/** Score interpretation */
|
|
878
|
+
scoreLabel: SubscriberQualityLabel;
|
|
879
|
+
/** Core metrics */
|
|
880
|
+
metrics: {
|
|
881
|
+
/** Total subscribers gained */
|
|
882
|
+
subscribersGained: number;
|
|
883
|
+
/** Total subscribers lost */
|
|
884
|
+
subscribersLost: number;
|
|
885
|
+
/** Net subscriber change */
|
|
886
|
+
netSubscribers: number;
|
|
887
|
+
/** Retention rate (how many stay) */
|
|
888
|
+
retentionRate: number;
|
|
889
|
+
/** Average watch time per view */
|
|
890
|
+
avgWatchTimeMinutes: number;
|
|
891
|
+
/** Views per subscriber (engagement proxy) */
|
|
892
|
+
viewsPerSubscriber: number;
|
|
893
|
+
};
|
|
894
|
+
/** Comparison to previous period */
|
|
895
|
+
trend: {
|
|
896
|
+
scoreChange: number;
|
|
897
|
+
direction: 'improving' | 'stable' | 'declining';
|
|
898
|
+
description: string;
|
|
899
|
+
};
|
|
900
|
+
/** Human-readable summary */
|
|
901
|
+
insight: string;
|
|
902
|
+
/** Specific recommendations */
|
|
903
|
+
recommendations: string[];
|
|
904
|
+
}
|
|
905
|
+
type SubscriberQualityResponse = (InsufficientDataResponse) | {
|
|
906
|
+
hasData: true;
|
|
907
|
+
data: SubscriberQualityData;
|
|
908
|
+
_meta: InsightMeta;
|
|
909
|
+
};
|
|
910
|
+
type FatigueLevel = 'none' | 'low' | 'moderate' | 'high' | 'critical';
|
|
911
|
+
interface FatigueSignal {
|
|
912
|
+
/** Name of the signal */
|
|
913
|
+
name: string;
|
|
914
|
+
/** Current period value */
|
|
915
|
+
current: number;
|
|
916
|
+
/** Previous period value */
|
|
917
|
+
previous: number;
|
|
918
|
+
/** Change percentage (negative = declining) */
|
|
919
|
+
changePercent: number;
|
|
920
|
+
/** Whether this signal indicates fatigue */
|
|
921
|
+
indicatesFatigue: boolean;
|
|
922
|
+
/** Description of what this means */
|
|
923
|
+
interpretation: string;
|
|
924
|
+
}
|
|
925
|
+
interface AudienceFatigueData {
|
|
926
|
+
/** Time periods compared */
|
|
927
|
+
period: {
|
|
928
|
+
current: {
|
|
929
|
+
start: string;
|
|
930
|
+
end: string;
|
|
931
|
+
};
|
|
932
|
+
previous: {
|
|
933
|
+
start: string;
|
|
934
|
+
end: string;
|
|
935
|
+
};
|
|
936
|
+
daysPerPeriod: number;
|
|
937
|
+
};
|
|
938
|
+
/** Overall fatigue index (0-100, higher = more fatigue) */
|
|
939
|
+
fatigueIndex: number;
|
|
940
|
+
/** Human-readable fatigue level */
|
|
941
|
+
fatigueLevel: FatigueLevel;
|
|
942
|
+
/** Individual signals that contribute to the score */
|
|
943
|
+
signals: {
|
|
944
|
+
watchTimePerView: FatigueSignal;
|
|
945
|
+
engagementRate: FatigueSignal;
|
|
946
|
+
subscriberChurn: FatigueSignal;
|
|
947
|
+
viewsPerVideo: FatigueSignal;
|
|
948
|
+
};
|
|
949
|
+
/** Summary of signals */
|
|
950
|
+
summary: {
|
|
951
|
+
signalsIndicatingFatigue: number;
|
|
952
|
+
totalSignals: number;
|
|
953
|
+
primaryConcern: string | null;
|
|
954
|
+
};
|
|
955
|
+
/** Human-readable insight */
|
|
956
|
+
insight: string;
|
|
957
|
+
/** What to do about it */
|
|
958
|
+
recommendations: string[];
|
|
959
|
+
}
|
|
960
|
+
type AudienceFatigueResponse = (InsufficientDataResponse) | {
|
|
961
|
+
hasData: true;
|
|
962
|
+
data: AudienceFatigueData;
|
|
963
|
+
_meta: InsightMeta;
|
|
964
|
+
};
|
|
965
|
+
interface LengthBucketPerformance {
|
|
966
|
+
/** Bucket name (e.g., "5-10 minutes") */
|
|
967
|
+
bucket: string;
|
|
968
|
+
/** Bucket range in seconds */
|
|
969
|
+
range: {
|
|
970
|
+
min: number;
|
|
971
|
+
max: number | null;
|
|
972
|
+
};
|
|
973
|
+
/** Number of videos in this bucket */
|
|
974
|
+
videoCount: number;
|
|
975
|
+
/** Average retention as percentage */
|
|
976
|
+
avgRetention: number;
|
|
977
|
+
/** Average engagement rate */
|
|
978
|
+
avgEngagement: number;
|
|
979
|
+
/** Average views per video */
|
|
980
|
+
avgViews: number;
|
|
981
|
+
/** Combined performance score (0-100) */
|
|
982
|
+
performanceScore: number;
|
|
983
|
+
/** Is this the optimal bucket? */
|
|
984
|
+
isOptimal: boolean;
|
|
985
|
+
}
|
|
986
|
+
interface OptimalVideoLengthData {
|
|
987
|
+
/** How many videos were analyzed */
|
|
988
|
+
videosAnalyzed: number;
|
|
989
|
+
/** The recommended optimal length range */
|
|
990
|
+
optimalLength: {
|
|
991
|
+
bucket: string;
|
|
992
|
+
range: {
|
|
993
|
+
min: number;
|
|
994
|
+
max: number | null;
|
|
995
|
+
};
|
|
996
|
+
confidence: 'high' | 'medium' | 'low';
|
|
997
|
+
reason: string;
|
|
998
|
+
};
|
|
999
|
+
/** Performance breakdown by length bucket */
|
|
1000
|
+
breakdown: LengthBucketPerformance[];
|
|
1001
|
+
/** Key findings */
|
|
1002
|
+
findings: {
|
|
1003
|
+
bestRetention: {
|
|
1004
|
+
bucket: string;
|
|
1005
|
+
value: number;
|
|
1006
|
+
};
|
|
1007
|
+
bestEngagement: {
|
|
1008
|
+
bucket: string;
|
|
1009
|
+
value: number;
|
|
1010
|
+
};
|
|
1011
|
+
mostCommon: {
|
|
1012
|
+
bucket: string;
|
|
1013
|
+
count: number;
|
|
1014
|
+
};
|
|
1015
|
+
};
|
|
1016
|
+
/** Human-readable insight */
|
|
1017
|
+
insight: string;
|
|
1018
|
+
/** Specific recommendations */
|
|
1019
|
+
recommendations: string[];
|
|
1020
|
+
}
|
|
1021
|
+
type OptimalVideoLengthResponse = (InsufficientDataResponse) | {
|
|
1022
|
+
hasData: true;
|
|
1023
|
+
data: OptimalVideoLengthData;
|
|
1024
|
+
_meta: InsightMeta;
|
|
1025
|
+
};
|
|
1026
|
+
interface AllInsightsData {
|
|
1027
|
+
bestPerformingVideo: BestPerformingVideoResponse;
|
|
1028
|
+
contentDecay: ContentDecayResponse;
|
|
1029
|
+
audienceActivity: AudienceActivityResponse;
|
|
1030
|
+
subscriberQuality: SubscriberQualityResponse;
|
|
1031
|
+
fadingHits: FadingHitsResponse;
|
|
1032
|
+
audienceFatigue: AudienceFatigueResponse;
|
|
1033
|
+
optimalLength: OptimalVideoLengthResponse;
|
|
1034
|
+
}
|
|
1035
|
+
interface AllInsightsResponse {
|
|
1036
|
+
data: AllInsightsData;
|
|
1037
|
+
_meta: {
|
|
1038
|
+
calculatedAt: string;
|
|
1039
|
+
insightsAvailable: string[];
|
|
1040
|
+
};
|
|
1041
|
+
}
|
|
1042
|
+
interface GetBestVideoParams {
|
|
1043
|
+
/** Number of days to analyze (1-90, default: 30) */
|
|
1044
|
+
period?: number;
|
|
1045
|
+
}
|
|
1046
|
+
interface GetContentDecayParams {
|
|
1047
|
+
/** Days per comparison period (3-14, default: 7) */
|
|
1048
|
+
period?: number;
|
|
1049
|
+
}
|
|
1050
|
+
interface GetSubscriberQualityParams {
|
|
1051
|
+
/** Number of days to analyze (14-180, default: 90) */
|
|
1052
|
+
period?: number;
|
|
1053
|
+
}
|
|
1054
|
+
interface GetAudienceFatigueParams {
|
|
1055
|
+
/** Days per comparison period (14-90, default: 30) */
|
|
1056
|
+
period?: number;
|
|
1057
|
+
}
|
|
1058
|
+
}
|
|
1059
|
+
declare namespace Activity {
|
|
1060
|
+
/**
|
|
1061
|
+
* Job types for sync operations
|
|
1062
|
+
*/
|
|
1063
|
+
type JobType = 'videos_sync' | 'channel_analytics' | 'video_analytics';
|
|
1064
|
+
/**
|
|
1065
|
+
* Job status values
|
|
1066
|
+
*/
|
|
1067
|
+
type JobStatus = 'started' | 'completed' | 'failed';
|
|
1068
|
+
/**
|
|
1069
|
+
* Job trigger source
|
|
1070
|
+
*/
|
|
1071
|
+
type JobTrigger = 'scheduler' | 'api' | 'manual';
|
|
1072
|
+
/**
|
|
1073
|
+
* Job data details (varies by job type)
|
|
1074
|
+
*/
|
|
1075
|
+
interface JobData {
|
|
1076
|
+
videosFound?: number;
|
|
1077
|
+
newVideos?: number;
|
|
1078
|
+
updatedVideos?: number;
|
|
1079
|
+
totalVideos?: number;
|
|
1080
|
+
daysProcessed?: number;
|
|
1081
|
+
metricsUpdated?: number;
|
|
1082
|
+
syncedDays?: number;
|
|
1083
|
+
dateRange?: {
|
|
1084
|
+
start: string;
|
|
1085
|
+
end: string;
|
|
1086
|
+
};
|
|
1087
|
+
videoId?: string;
|
|
1088
|
+
videoTitle?: string;
|
|
1089
|
+
recordsCreated?: number;
|
|
1090
|
+
recordsUpdated?: number;
|
|
1091
|
+
queued?: number;
|
|
1092
|
+
skipped?: number;
|
|
1093
|
+
message?: string;
|
|
1094
|
+
[key: string]: unknown;
|
|
1095
|
+
}
|
|
1096
|
+
/**
|
|
1097
|
+
* A single activity log entry
|
|
1098
|
+
*/
|
|
1099
|
+
interface LogEntry {
|
|
1100
|
+
/** Unique log ID */
|
|
1101
|
+
id: string;
|
|
1102
|
+
/** BullMQ job ID */
|
|
1103
|
+
jobId: string;
|
|
1104
|
+
/** Type of sync job */
|
|
1105
|
+
type: JobType;
|
|
1106
|
+
/** Current status */
|
|
1107
|
+
status: JobStatus;
|
|
1108
|
+
/** When the job started */
|
|
1109
|
+
startedAt: string;
|
|
1110
|
+
/** When the job completed (if finished) */
|
|
1111
|
+
completedAt?: string;
|
|
1112
|
+
/** Duration in milliseconds */
|
|
1113
|
+
durationMs?: number;
|
|
1114
|
+
/** What triggered this job */
|
|
1115
|
+
triggeredBy: JobTrigger;
|
|
1116
|
+
/** Job result data */
|
|
1117
|
+
data?: JobData;
|
|
1118
|
+
/** Error message (if failed) */
|
|
1119
|
+
error?: string;
|
|
1120
|
+
}
|
|
1121
|
+
/**
|
|
1122
|
+
* Response for activity logs list
|
|
1123
|
+
*/
|
|
1124
|
+
interface LogsResponse {
|
|
1125
|
+
/** List of log entries */
|
|
1126
|
+
logs: LogEntry[];
|
|
1127
|
+
/** Number of entries returned */
|
|
1128
|
+
count: number;
|
|
1129
|
+
}
|
|
1130
|
+
/**
|
|
1131
|
+
* Activity summary with counts
|
|
1132
|
+
*/
|
|
1133
|
+
interface SummaryResponse {
|
|
1134
|
+
/** Total jobs ever run */
|
|
1135
|
+
totalJobs: number;
|
|
1136
|
+
/** Successfully completed jobs */
|
|
1137
|
+
completed: number;
|
|
1138
|
+
/** Failed jobs */
|
|
1139
|
+
failed: number;
|
|
1140
|
+
/** Breakdown by job type */
|
|
1141
|
+
byType: Record<JobType, {
|
|
1142
|
+
total: number;
|
|
1143
|
+
lastRun?: string;
|
|
1144
|
+
}>;
|
|
1145
|
+
}
|
|
1146
|
+
/**
|
|
1147
|
+
* Parameters for fetching activity logs
|
|
1148
|
+
*/
|
|
1149
|
+
interface GetLogsParams {
|
|
1150
|
+
/** Filter by job type */
|
|
1151
|
+
type?: JobType;
|
|
1152
|
+
/** Filter by status */
|
|
1153
|
+
status?: JobStatus;
|
|
1154
|
+
/** Max entries to return (default: 50, max: 100) */
|
|
1155
|
+
limit?: number;
|
|
1156
|
+
}
|
|
597
1157
|
}
|
|
598
1158
|
|
|
599
1159
|
/**
|
|
@@ -993,6 +1553,301 @@ declare class InsightsModule {
|
|
|
993
1553
|
* GET /v1/insights/youtube/momentum/history
|
|
994
1554
|
*/
|
|
995
1555
|
getYouTubeMomentumHistory(params?: Insights.GetMomentumHistoryParams): Promise<Insights.MomentumHistoryResponse>;
|
|
1556
|
+
/**
|
|
1557
|
+
* Get the best performing video in a time period
|
|
1558
|
+
*
|
|
1559
|
+
* Identifies your top video by views and explains WHY it performed well.
|
|
1560
|
+
*
|
|
1561
|
+
* @param params - Query parameters
|
|
1562
|
+
* @param params.period - Days to analyze (1-90, default: 30)
|
|
1563
|
+
*
|
|
1564
|
+
* @example
|
|
1565
|
+
* ```typescript
|
|
1566
|
+
* const result = await client.insights.getYouTubeBestVideo({ period: 30 });
|
|
1567
|
+
*
|
|
1568
|
+
* if (result.hasData) {
|
|
1569
|
+
* console.log(`🏆 ${result.data.topVideo.title}`);
|
|
1570
|
+
* console.log(`Views: ${result.data.metrics.views}`);
|
|
1571
|
+
* console.log(`${result.data.comparison.vsChannelAverage.description}`);
|
|
1572
|
+
* console.log(result.data.insight);
|
|
1573
|
+
*
|
|
1574
|
+
* // Show how it was calculated
|
|
1575
|
+
* console.log(result._meta.howWeCalculatedThis.method);
|
|
1576
|
+
* } else {
|
|
1577
|
+
* console.log(result.suggestion);
|
|
1578
|
+
* }
|
|
1579
|
+
* ```
|
|
1580
|
+
*
|
|
1581
|
+
* GET /v1/insights/youtube/best-video
|
|
1582
|
+
*/
|
|
1583
|
+
getYouTubeBestVideo(params?: Insights.GetBestVideoParams): Promise<Insights.BestPerformingVideoResponse>;
|
|
1584
|
+
/**
|
|
1585
|
+
* Find videos that are losing momentum
|
|
1586
|
+
*
|
|
1587
|
+
* Compares current period vs previous period to identify declining videos.
|
|
1588
|
+
* Provides actionable suggestions for each decaying video.
|
|
1589
|
+
*
|
|
1590
|
+
* @param params - Query parameters
|
|
1591
|
+
* @param params.period - Days per comparison period (3-14, default: 7)
|
|
1592
|
+
*
|
|
1593
|
+
* @example
|
|
1594
|
+
* ```typescript
|
|
1595
|
+
* const result = await client.insights.getYouTubeContentDecay({ period: 7 });
|
|
1596
|
+
*
|
|
1597
|
+
* if (result.hasData) {
|
|
1598
|
+
* console.log(result.data.insight);
|
|
1599
|
+
* console.log(`${result.data.summary.totalDecaying} videos declining`);
|
|
1600
|
+
*
|
|
1601
|
+
* for (const video of result.data.decayingVideos) {
|
|
1602
|
+
* console.log(`📉 ${video.title}: ${video.decayRate}%`);
|
|
1603
|
+
* console.log(` ${video.suggestion}`);
|
|
1604
|
+
* }
|
|
1605
|
+
* }
|
|
1606
|
+
* ```
|
|
1607
|
+
*
|
|
1608
|
+
* GET /v1/insights/youtube/content-decay
|
|
1609
|
+
*/
|
|
1610
|
+
getYouTubeContentDecay(params?: Insights.GetContentDecayParams): Promise<Insights.ContentDecayResponse>;
|
|
1611
|
+
/**
|
|
1612
|
+
* Get when your audience is most active
|
|
1613
|
+
*
|
|
1614
|
+
* Unlike generic advice, this is based on YOUR audience's behavior.
|
|
1615
|
+
* Analyzes first-day performance by publish day and time to identify
|
|
1616
|
+
* when your audience is most engaged.
|
|
1617
|
+
*
|
|
1618
|
+
* @example
|
|
1619
|
+
* ```typescript
|
|
1620
|
+
* const result = await client.insights.getYouTubeAudienceActivity();
|
|
1621
|
+
*
|
|
1622
|
+
* if (result.hasData) {
|
|
1623
|
+
* console.log(`📅 Most active day: ${result.data.mostActiveDay.day}`);
|
|
1624
|
+
* console.log(`⏰ Peak time: ${result.data.mostActiveTimeSlot.label}`);
|
|
1625
|
+
* console.log(result.data.insight);
|
|
1626
|
+
*
|
|
1627
|
+
* // Show day breakdown
|
|
1628
|
+
* for (const day of result.data.dayBreakdown) {
|
|
1629
|
+
* console.log(`${day.day}: ${day.avgFirstDayViews} avg views`);
|
|
1630
|
+
* }
|
|
1631
|
+
* }
|
|
1632
|
+
* ```
|
|
1633
|
+
*
|
|
1634
|
+
* GET /v1/insights/youtube/audience-activity
|
|
1635
|
+
*/
|
|
1636
|
+
getYouTubeAudienceActivity(): Promise<Insights.AudienceActivityResponse>;
|
|
1637
|
+
/**
|
|
1638
|
+
* @deprecated Use `getYouTubeAudienceActivity()` instead
|
|
1639
|
+
*/
|
|
1640
|
+
getYouTubeBestUploadTime(): Promise<Insights.BestUploadTimeResponse>;
|
|
1641
|
+
/**
|
|
1642
|
+
* Find videos that were hits but are now declining
|
|
1643
|
+
*
|
|
1644
|
+
* Identifies videos that performed above your channel average initially
|
|
1645
|
+
* but have since lost momentum. These are revival opportunities.
|
|
1646
|
+
*
|
|
1647
|
+
* @example
|
|
1648
|
+
* ```typescript
|
|
1649
|
+
* const result = await client.insights.getYouTubeFadingHits();
|
|
1650
|
+
*
|
|
1651
|
+
* if (result.hasData) {
|
|
1652
|
+
* console.log(result.data.insight);
|
|
1653
|
+
* console.log(`${result.data.summary.totalFading} videos could use a boost`);
|
|
1654
|
+
*
|
|
1655
|
+
* for (const video of result.data.fadingHits) {
|
|
1656
|
+
* console.log(`📉 ${video.title}`);
|
|
1657
|
+
* console.log(` Peak: ${video.peakPeriod.avgDailyViews} views/day`);
|
|
1658
|
+
* console.log(` Now: ${video.currentPeriod.avgDailyViews} views/day`);
|
|
1659
|
+
* console.log(` Decline: ${video.decline.percentage}%`);
|
|
1660
|
+
* console.log(` Revival potential: ${video.revivalPotential}`);
|
|
1661
|
+
* console.log(` ${video.whyRevive}`);
|
|
1662
|
+
* for (const suggestion of video.suggestions) {
|
|
1663
|
+
* console.log(` 💡 ${suggestion}`);
|
|
1664
|
+
* }
|
|
1665
|
+
* }
|
|
1666
|
+
* }
|
|
1667
|
+
* ```
|
|
1668
|
+
*
|
|
1669
|
+
* GET /v1/insights/youtube/fading-hits
|
|
1670
|
+
*/
|
|
1671
|
+
getYouTubeFadingHits(): Promise<Insights.FadingHitsResponse>;
|
|
1672
|
+
/**
|
|
1673
|
+
* Measure subscriber quality score (0-100)
|
|
1674
|
+
*
|
|
1675
|
+
* Analyzes whether new subscribers are engaged or just numbers.
|
|
1676
|
+
* Helps identify fake growth or low-quality audiences.
|
|
1677
|
+
*
|
|
1678
|
+
* @param params - Query parameters
|
|
1679
|
+
* @param params.period - Days to analyze (7-90, default: 30)
|
|
1680
|
+
*
|
|
1681
|
+
* @example
|
|
1682
|
+
* ```typescript
|
|
1683
|
+
* const result = await client.insights.getYouTubeSubscriberQuality({ period: 90 });
|
|
1684
|
+
*
|
|
1685
|
+
* if (result.hasData) {
|
|
1686
|
+
* console.log(`Quality Score: ${result.data.qualityScore}/100 (${result.data.scoreLabel})`);
|
|
1687
|
+
* console.log(`Retention: ${result.data.metrics.retentionRate}%`);
|
|
1688
|
+
* console.log(result.data.insight);
|
|
1689
|
+
*
|
|
1690
|
+
* // Show recommendations
|
|
1691
|
+
* for (const rec of result.data.recommendations) {
|
|
1692
|
+
* console.log(`💡 ${rec}`);
|
|
1693
|
+
* }
|
|
1694
|
+
* }
|
|
1695
|
+
* ```
|
|
1696
|
+
*
|
|
1697
|
+
* GET /v1/insights/youtube/subscriber-quality
|
|
1698
|
+
*/
|
|
1699
|
+
getYouTubeSubscriberQuality(params?: Insights.GetSubscriberQualityParams): Promise<Insights.SubscriberQualityResponse>;
|
|
1700
|
+
/**
|
|
1701
|
+
* Detect if your audience is getting tired of your content
|
|
1702
|
+
*
|
|
1703
|
+
* Compares key engagement metrics between recent and previous periods
|
|
1704
|
+
* to identify declining audience interest before it becomes critical.
|
|
1705
|
+
*
|
|
1706
|
+
* @param params - Query parameters
|
|
1707
|
+
* @param params.period - Days per comparison period (14-90, default: 30)
|
|
1708
|
+
*
|
|
1709
|
+
* @example
|
|
1710
|
+
* ```typescript
|
|
1711
|
+
* const result = await client.insights.getYouTubeAudienceFatigue({ period: 30 });
|
|
1712
|
+
*
|
|
1713
|
+
* if (result.hasData) {
|
|
1714
|
+
* console.log(`Fatigue Index: ${result.data.fatigueIndex}/100`);
|
|
1715
|
+
* console.log(`Level: ${result.data.fatigueLevel}`);
|
|
1716
|
+
* console.log(result.data.insight);
|
|
1717
|
+
*
|
|
1718
|
+
* // Check individual signals
|
|
1719
|
+
* if (result.data.signals.watchTimePerView.indicatesFatigue) {
|
|
1720
|
+
* console.log('⚠️ Watch time is declining');
|
|
1721
|
+
* }
|
|
1722
|
+
*
|
|
1723
|
+
* // Get recommendations
|
|
1724
|
+
* for (const rec of result.data.recommendations) {
|
|
1725
|
+
* console.log(`💡 ${rec}`);
|
|
1726
|
+
* }
|
|
1727
|
+
* }
|
|
1728
|
+
* ```
|
|
1729
|
+
*
|
|
1730
|
+
* GET /v1/insights/youtube/audience-fatigue
|
|
1731
|
+
*/
|
|
1732
|
+
getYouTubeAudienceFatigue(params?: Insights.GetAudienceFatigueParams): Promise<Insights.AudienceFatigueResponse>;
|
|
1733
|
+
/**
|
|
1734
|
+
* Find the ideal video length for YOUR audience
|
|
1735
|
+
*
|
|
1736
|
+
* Unlike generic "8-12 minutes is best" advice, this is personalized
|
|
1737
|
+
* based on how YOUR videos perform at different lengths.
|
|
1738
|
+
*
|
|
1739
|
+
* @example
|
|
1740
|
+
* ```typescript
|
|
1741
|
+
* const result = await client.insights.getYouTubeOptimalLength();
|
|
1742
|
+
*
|
|
1743
|
+
* if (result.hasData) {
|
|
1744
|
+
* console.log(`Optimal: ${result.data.optimalLength.bucket}`);
|
|
1745
|
+
* console.log(`Confidence: ${result.data.optimalLength.confidence}`);
|
|
1746
|
+
* console.log(result.data.insight);
|
|
1747
|
+
*
|
|
1748
|
+
* // Show breakdown by length
|
|
1749
|
+
* for (const bucket of result.data.breakdown) {
|
|
1750
|
+
* const marker = bucket.isOptimal ? '🏆' : ' ';
|
|
1751
|
+
* console.log(`${marker} ${bucket.bucket}: ${bucket.avgRetention}% retention, ${bucket.avgEngagement}% engagement`);
|
|
1752
|
+
* }
|
|
1753
|
+
*
|
|
1754
|
+
* // Recommendations
|
|
1755
|
+
* for (const rec of result.data.recommendations) {
|
|
1756
|
+
* console.log(`💡 ${rec}`);
|
|
1757
|
+
* }
|
|
1758
|
+
* }
|
|
1759
|
+
* ```
|
|
1760
|
+
*
|
|
1761
|
+
* GET /v1/insights/youtube/optimal-length
|
|
1762
|
+
*/
|
|
1763
|
+
getYouTubeOptimalLength(): Promise<Insights.OptimalVideoLengthResponse>;
|
|
1764
|
+
/**
|
|
1765
|
+
* Get all YouTube insights in one call
|
|
1766
|
+
*
|
|
1767
|
+
* Efficient for dashboard display - fetches all insights in parallel.
|
|
1768
|
+
* Each insight has `hasData: boolean` to check availability.
|
|
1769
|
+
*
|
|
1770
|
+
* @example
|
|
1771
|
+
* ```typescript
|
|
1772
|
+
* const all = await client.insights.getYouTubeAllInsights();
|
|
1773
|
+
*
|
|
1774
|
+
* // Check which insights are available
|
|
1775
|
+
* console.log('Available:', all._meta.insightsAvailable);
|
|
1776
|
+
*
|
|
1777
|
+
* // Use each insight
|
|
1778
|
+
* if (all.data.bestPerformingVideo.hasData) {
|
|
1779
|
+
* console.log(`Best: ${all.data.bestPerformingVideo.data.topVideo.title}`);
|
|
1780
|
+
* }
|
|
1781
|
+
*
|
|
1782
|
+
* if (all.data.audienceFatigue.hasData) {
|
|
1783
|
+
* console.log(`Fatigue: ${all.data.audienceFatigue.data.fatigueLevel}`);
|
|
1784
|
+
* }
|
|
1785
|
+
*
|
|
1786
|
+
* if (all.data.optimalLength.hasData) {
|
|
1787
|
+
* console.log(`Optimal Length: ${all.data.optimalLength.data.optimalLength.bucket}`);
|
|
1788
|
+
* }
|
|
1789
|
+
* ```
|
|
1790
|
+
*
|
|
1791
|
+
* GET /v1/insights/youtube/all
|
|
1792
|
+
*/
|
|
1793
|
+
getYouTubeAllInsights(): Promise<Insights.AllInsightsResponse>;
|
|
1794
|
+
}
|
|
1795
|
+
|
|
1796
|
+
/**
|
|
1797
|
+
* Activity Module
|
|
1798
|
+
*
|
|
1799
|
+
* View sync job activity and logs
|
|
1800
|
+
*/
|
|
1801
|
+
|
|
1802
|
+
declare class ActivityModule {
|
|
1803
|
+
private client;
|
|
1804
|
+
constructor(client: TrndUpClient);
|
|
1805
|
+
/**
|
|
1806
|
+
* Get recent activity logs
|
|
1807
|
+
*
|
|
1808
|
+
* @param params - Optional filters
|
|
1809
|
+
* @returns List of activity log entries
|
|
1810
|
+
*
|
|
1811
|
+
* @example
|
|
1812
|
+
* ```typescript
|
|
1813
|
+
* // Get all recent logs
|
|
1814
|
+
* const { logs } = await client.activity.getLogs();
|
|
1815
|
+
*
|
|
1816
|
+
* // Get only failed jobs
|
|
1817
|
+
* const { logs } = await client.activity.getLogs({ status: 'failed' });
|
|
1818
|
+
*
|
|
1819
|
+
* // Get video sync jobs only
|
|
1820
|
+
* const { logs } = await client.activity.getLogs({ type: 'videos_sync' });
|
|
1821
|
+
* ```
|
|
1822
|
+
*/
|
|
1823
|
+
getLogs(params?: Activity.GetLogsParams): Promise<Activity.LogsResponse>;
|
|
1824
|
+
/**
|
|
1825
|
+
* Get activity summary with counts by type
|
|
1826
|
+
*
|
|
1827
|
+
* @returns Summary with total/completed/failed counts
|
|
1828
|
+
*
|
|
1829
|
+
* @example
|
|
1830
|
+
* ```typescript
|
|
1831
|
+
* const summary = await client.activity.getSummary();
|
|
1832
|
+
* console.log(`Total: ${summary.totalJobs}, Failed: ${summary.failed}`);
|
|
1833
|
+
* ```
|
|
1834
|
+
*/
|
|
1835
|
+
getSummary(): Promise<Activity.SummaryResponse>;
|
|
1836
|
+
/**
|
|
1837
|
+
* Get the latest log entry for a specific job type
|
|
1838
|
+
*
|
|
1839
|
+
* @param jobType - The type of job to get
|
|
1840
|
+
* @returns Latest log entry or null if none exists
|
|
1841
|
+
*
|
|
1842
|
+
* @example
|
|
1843
|
+
* ```typescript
|
|
1844
|
+
* const latestVideoSync = await client.activity.getLatest('videos_sync');
|
|
1845
|
+
* if (latestVideoSync) {
|
|
1846
|
+
* console.log(`Last sync: ${latestVideoSync.completedAt}`);
|
|
1847
|
+
* }
|
|
1848
|
+
* ```
|
|
1849
|
+
*/
|
|
1850
|
+
getLatest(jobType: Activity.JobType): Promise<Activity.LogEntry | null>;
|
|
996
1851
|
}
|
|
997
1852
|
|
|
998
1853
|
/**
|
|
@@ -1039,9 +1894,10 @@ declare class TrndUpSDK extends TrndUpClient {
|
|
|
1039
1894
|
instagram: InstagramModule;
|
|
1040
1895
|
social: SocialModule;
|
|
1041
1896
|
insights: InsightsModule;
|
|
1897
|
+
activity: ActivityModule;
|
|
1042
1898
|
constructor(config: TrndUpClientConfig);
|
|
1043
1899
|
}
|
|
1044
1900
|
|
|
1045
1901
|
declare const SDK_VERSION = "1.0.0";
|
|
1046
1902
|
|
|
1047
|
-
export { Auth, INSTAGRAM_SCOPES, Insights, Instagram, type RequestOptions, SDK_VERSION, Social, TrndUpApiError, type TrndUpClientConfig, TrndUpNetworkError, TrndUpSDK, YOUTUBE_SCOPES, YouTube };
|
|
1903
|
+
export { Activity, Auth, INSTAGRAM_SCOPES, Insights, Instagram, type RequestOptions, SDK_VERSION, Social, TrndUpApiError, type TrndUpClientConfig, TrndUpNetworkError, TrndUpSDK, YOUTUBE_SCOPES, YouTube };
|