agrs-sequelize-sdk 1.4.59 → 1.4.61
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/migrations/2026-05-17-PIXELS-FOLLOWUP.md +85 -85
- package/migrations/2026-05-17-add-platform-to-ad.js +19 -19
- package/migrations/2026-05-17-add-platform-to-adaccount.js +19 -19
- package/migrations/2026-05-17-add-platform-to-adperformance.js +19 -19
- package/migrations/2026-05-17-add-platform-to-adset.js +19 -19
- package/migrations/2026-05-17-add-platform-to-adsetperformance.js +19 -19
- package/migrations/2026-05-17-add-platform-to-aiarticleretryqueue.js +19 -19
- package/migrations/2026-05-17-add-platform-to-aicampaignqueue.js +19 -19
- package/migrations/2026-05-17-add-platform-to-article.js +19 -19
- package/migrations/2026-05-17-add-platform-to-campaign.js +19 -19
- package/migrations/2026-05-17-add-platform-to-codefuelcampaign.js +19 -19
- package/migrations/2026-05-17-add-platform-to-dynamicfeed.js +19 -19
- package/migrations/2026-05-17-add-platform-to-facebookretryqueue.js +19 -19
- package/migrations/2026-05-17-add-platform-to-pages.js +19 -19
- package/migrations/2026-05-17-add-platform-to-presets.js +19 -19
- package/migrations/2026-05-18-add-group-id-to-ai-campaign-queue.js +18 -18
- package/migrations/2026-05-18-add-platform-code-to-creation-logs.js +65 -65
- package/migrations/2026-05-18-add-platform-code-to-pixels.js +55 -55
- package/migrations/2026-05-18-add-platform-code-to-rsoc-feed-campaigns.js +55 -55
- package/migrations/2026-05-18-add-platform-date-index-to-adperformance.js +16 -16
- package/migrations/2026-05-18-add-platform-date-index-to-adsetperformance.js +16 -16
- package/migrations/2026-05-18-add-review-status-to-ad.js +36 -36
- package/migrations/2026-05-18-create-canonical-insights.js +84 -84
- package/migrations/2026-05-18-create-snapchat-public-profiles.js +68 -68
- package/migrations/2026-05-18-create-tiktok-identities.js +71 -71
- package/migrations/2026-05-18-create-tiktok-snapchat-campaigns.js +143 -143
- package/migrations/2026-05-18-create-tt-snp-adset-ad-tables.js +309 -309
- package/migrations/RUN_ME_MANUALLY_2026-05-17.sql +99 -99
- package/migrations/add-requested-from-dashboard-to-articles.js +17 -17
- package/migrations/change-adset-name-to-text.js +79 -79
- package/models/AICampaignQueue.js +151 -151
- package/models/AIGenerationLog.js +85 -85
- package/models/AIGenerationRequest.js +212 -212
- package/models/AdAccountValues.js +25 -25
- package/models/AdHistory.js +30 -30
- package/models/AdPerformance.js +104 -104
- package/models/AdSet.js +295 -295
- package/models/AdSetHistory.js +30 -30
- package/models/AdsetPerformance.js +137 -137
- package/models/AiArticleRetryQueue.js +157 -157
- package/models/AiCreationRetryQueue.js +134 -134
- package/models/ApiAuditLog.js +127 -127
- package/models/ApiToken.js +67 -67
- package/models/Article.js +222 -222
- package/models/AutomationRule.js +179 -179
- package/models/BannerTemplate.js +129 -129
- package/models/Buyers.js +25 -25
- package/models/Campaign.js +168 -168
- package/models/CampaignActionHistory.js +101 -101
- package/models/CampaignCreationLog.js +340 -340
- package/models/CampaignCreationLogV2.js +392 -392
- package/models/CampaignHistory.js +33 -33
- package/models/CampaignTag.js +46 -46
- package/models/CampaignTagAssignment.js +48 -48
- package/models/CanonicalInsights.js +68 -68
- package/models/Channel.js +55 -55
- package/models/Domain.js +49 -44
- package/models/DynamicFeed.js +218 -218
- package/models/ExplorAdsChannel.js +61 -61
- package/models/FacebookRetryQueue.js +163 -163
- package/models/Feed.js +33 -33
- package/models/FeedArticleConfiguration.js +80 -80
- package/models/FrontStoryChannel.js +59 -59
- package/models/FrontStoryChannelV2.js +60 -60
- package/models/GenericFlowRequest.js +114 -114
- package/models/MidoWebChannel.js +47 -47
- package/models/MineBrandBlocklist.js +56 -56
- package/models/MineBrandConfig.js +26 -26
- package/models/MineChannel.js +47 -47
- package/models/MineRedirectDomain.js +42 -42
- package/models/MineWebhookEvent.js +53 -53
- package/models/Pages.js +117 -117
- package/models/PipelineExecution.js +59 -59
- package/models/PolicyDogsCreativeCache.js +50 -50
- package/models/PolicyDogsImageCache.js +30 -30
- package/models/Presets.js +40 -40
- package/models/PublicApiBatch.js +155 -155
- package/models/PublicApiBatchItem.js +166 -166
- package/models/PublicApiIdempotencyCache.js +135 -135
- package/models/RSOCFeedCampaign.js +387 -387
- package/models/RSOCFeedConfig.js +46 -46
- package/models/RSOCRedirectWsCode.js +22 -22
- package/models/RsocKeywordPerformance.js +110 -110
- package/models/RuleAction.js +90 -90
- package/models/RuleCondition.js +137 -137
- package/models/RuleExecution.js +107 -107
- package/models/RulesValues.js +56 -56
- package/models/SingularChannel.js +31 -31
- package/models/SnapchatAd.js +69 -69
- package/models/SnapchatAdSquad.js +92 -92
- package/models/SnapchatCampaign.js +69 -69
- package/models/SnapchatChannel.js +31 -31
- package/models/SnapchatPublicProfiles.js +67 -67
- package/models/SupportedLocale.js +23 -23
- package/models/SyncHistory.js +249 -249
- package/models/TTQChannel.js +42 -42
- package/models/Team.js +33 -43
- package/models/TemplateMetadata.js +260 -260
- package/models/Tier2_AdAccounts.js +110 -110
- package/models/Tier2_Assets.js +70 -70
- package/models/Tier2_BusinessManagers.js +105 -105
- package/models/Tier2_CreditLines.js +99 -99
- package/models/Tier2_Pages.js +91 -91
- package/models/Tier2_Pixels.js +82 -82
- package/models/Tier2_Tokens.js +64 -64
- package/models/Tier2_UserAdAccounts.js +83 -83
- package/models/TikTokAd.js +71 -71
- package/models/TikTokAdGroup.js +82 -82
- package/models/TikTokCampaign.js +71 -71
- package/models/TiktokChannel.js +31 -31
- package/models/TiktokIdentities.js +65 -65
- package/models/TokenRotationState.js +121 -121
- package/models/TonicRSOCKeywordPerformance.js +122 -122
- package/models/Users.js +204 -204
- package/models/Vertical.js +25 -25
- package/models/newFiles.js +137 -137
- package/package.json +21 -19
- package/run.sh +214 -214
- package/services/sequelizeService.js +110 -110
- package/tarzo-skalio-integration-docs.md +691 -691
|
@@ -1,65 +1,65 @@
|
|
|
1
|
-
module.exports = (sequelize, DataTypes) => {
|
|
2
|
-
const TiktokIdentities = sequelize.define(
|
|
3
|
-
"TiktokIdentities",
|
|
4
|
-
{
|
|
5
|
-
id: {
|
|
6
|
-
type: DataTypes.BIGINT,
|
|
7
|
-
primaryKey: true,
|
|
8
|
-
autoIncrement: true,
|
|
9
|
-
},
|
|
10
|
-
identity_id: {
|
|
11
|
-
type: DataTypes.STRING(64),
|
|
12
|
-
allowNull: false,
|
|
13
|
-
unique: true,
|
|
14
|
-
comment: "TikTok identity_id (CUSTOMIZED_USER) used as creative owner",
|
|
15
|
-
},
|
|
16
|
-
identity_type: {
|
|
17
|
-
type: DataTypes.STRING(32),
|
|
18
|
-
allowNull: false,
|
|
19
|
-
defaultValue: "CUSTOMIZED_USER",
|
|
20
|
-
},
|
|
21
|
-
name: {
|
|
22
|
-
type: DataTypes.STRING(255),
|
|
23
|
-
allowNull: true,
|
|
24
|
-
},
|
|
25
|
-
ad_account_id: {
|
|
26
|
-
type: DataTypes.STRING(64),
|
|
27
|
-
allowNull: false,
|
|
28
|
-
comment:
|
|
29
|
-
"Representative TikTok advertiser_id (legacy). Selection is by " +
|
|
30
|
-
"business_center_id; the resolver ignores this. Kept NOT NULL so the " +
|
|
31
|
-
"column add stays additive.",
|
|
32
|
-
},
|
|
33
|
-
business_center_id: {
|
|
34
|
-
type: DataTypes.STRING(64),
|
|
35
|
-
allowNull: true,
|
|
36
|
-
comment:
|
|
37
|
-
"Business Center this identity is authorized to. Mirrors FB Pages " +
|
|
38
|
-
"(tagged by BM, no ad-account binding). The asset resolver scopes " +
|
|
39
|
-
"identity selection by this, NOT by ad_account_id.",
|
|
40
|
-
},
|
|
41
|
-
status: {
|
|
42
|
-
type: DataTypes.STRING(16),
|
|
43
|
-
allowNull: false,
|
|
44
|
-
defaultValue: "active",
|
|
45
|
-
comment: "active | disabled",
|
|
46
|
-
},
|
|
47
|
-
tier: {
|
|
48
|
-
type: DataTypes.INTEGER,
|
|
49
|
-
allowNull: false,
|
|
50
|
-
defaultValue: 1,
|
|
51
|
-
comment:
|
|
52
|
-
"Rotation weight. Higher tier => higher probability of being picked.",
|
|
53
|
-
},
|
|
54
|
-
},
|
|
55
|
-
{
|
|
56
|
-
tableName: "tiktok_identities",
|
|
57
|
-
indexes: [
|
|
58
|
-
{ fields: ["ad_account_id", "status"] },
|
|
59
|
-
{ fields: ["business_center_id", "status"] },
|
|
60
|
-
],
|
|
61
|
-
}
|
|
62
|
-
);
|
|
63
|
-
|
|
64
|
-
return TiktokIdentities;
|
|
65
|
-
};
|
|
1
|
+
module.exports = (sequelize, DataTypes) => {
|
|
2
|
+
const TiktokIdentities = sequelize.define(
|
|
3
|
+
"TiktokIdentities",
|
|
4
|
+
{
|
|
5
|
+
id: {
|
|
6
|
+
type: DataTypes.BIGINT,
|
|
7
|
+
primaryKey: true,
|
|
8
|
+
autoIncrement: true,
|
|
9
|
+
},
|
|
10
|
+
identity_id: {
|
|
11
|
+
type: DataTypes.STRING(64),
|
|
12
|
+
allowNull: false,
|
|
13
|
+
unique: true,
|
|
14
|
+
comment: "TikTok identity_id (CUSTOMIZED_USER) used as creative owner",
|
|
15
|
+
},
|
|
16
|
+
identity_type: {
|
|
17
|
+
type: DataTypes.STRING(32),
|
|
18
|
+
allowNull: false,
|
|
19
|
+
defaultValue: "CUSTOMIZED_USER",
|
|
20
|
+
},
|
|
21
|
+
name: {
|
|
22
|
+
type: DataTypes.STRING(255),
|
|
23
|
+
allowNull: true,
|
|
24
|
+
},
|
|
25
|
+
ad_account_id: {
|
|
26
|
+
type: DataTypes.STRING(64),
|
|
27
|
+
allowNull: false,
|
|
28
|
+
comment:
|
|
29
|
+
"Representative TikTok advertiser_id (legacy). Selection is by " +
|
|
30
|
+
"business_center_id; the resolver ignores this. Kept NOT NULL so the " +
|
|
31
|
+
"column add stays additive.",
|
|
32
|
+
},
|
|
33
|
+
business_center_id: {
|
|
34
|
+
type: DataTypes.STRING(64),
|
|
35
|
+
allowNull: true,
|
|
36
|
+
comment:
|
|
37
|
+
"Business Center this identity is authorized to. Mirrors FB Pages " +
|
|
38
|
+
"(tagged by BM, no ad-account binding). The asset resolver scopes " +
|
|
39
|
+
"identity selection by this, NOT by ad_account_id.",
|
|
40
|
+
},
|
|
41
|
+
status: {
|
|
42
|
+
type: DataTypes.STRING(16),
|
|
43
|
+
allowNull: false,
|
|
44
|
+
defaultValue: "active",
|
|
45
|
+
comment: "active | disabled",
|
|
46
|
+
},
|
|
47
|
+
tier: {
|
|
48
|
+
type: DataTypes.INTEGER,
|
|
49
|
+
allowNull: false,
|
|
50
|
+
defaultValue: 1,
|
|
51
|
+
comment:
|
|
52
|
+
"Rotation weight. Higher tier => higher probability of being picked.",
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
tableName: "tiktok_identities",
|
|
57
|
+
indexes: [
|
|
58
|
+
{ fields: ["ad_account_id", "status"] },
|
|
59
|
+
{ fields: ["business_center_id", "status"] },
|
|
60
|
+
],
|
|
61
|
+
}
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
return TiktokIdentities;
|
|
65
|
+
};
|
|
@@ -1,121 +1,121 @@
|
|
|
1
|
-
// models/TokenRotationState.js
|
|
2
|
-
module.exports = (sequelize, DataTypes) => {
|
|
3
|
-
const TokenRotationState = sequelize.define(
|
|
4
|
-
"TokenRotationState",
|
|
5
|
-
{
|
|
6
|
-
id: {
|
|
7
|
-
type: DataTypes.INTEGER,
|
|
8
|
-
primaryKey: true,
|
|
9
|
-
autoIncrement: true,
|
|
10
|
-
},
|
|
11
|
-
tokenType: {
|
|
12
|
-
type: DataTypes.STRING,
|
|
13
|
-
allowNull: false,
|
|
14
|
-
unique: true,
|
|
15
|
-
defaultValue: "FACEBOOK_ACCESS_TOKEN",
|
|
16
|
-
comment: "Type of token being rotated (e.g., FACEBOOK_ACCESS_TOKEN)",
|
|
17
|
-
},
|
|
18
|
-
currentIndex: {
|
|
19
|
-
type: DataTypes.INTEGER,
|
|
20
|
-
allowNull: false,
|
|
21
|
-
defaultValue: 0,
|
|
22
|
-
comment: "Current index in the token rotation (0-based)",
|
|
23
|
-
},
|
|
24
|
-
totalTokens: {
|
|
25
|
-
type: DataTypes.INTEGER,
|
|
26
|
-
allowNull: false,
|
|
27
|
-
defaultValue: 10,
|
|
28
|
-
comment: "Total number of tokens in rotation",
|
|
29
|
-
},
|
|
30
|
-
lastUsedAt: {
|
|
31
|
-
type: DataTypes.DATE,
|
|
32
|
-
allowNull: true,
|
|
33
|
-
comment: "Timestamp of last token usage",
|
|
34
|
-
},
|
|
35
|
-
totalUsageCount: {
|
|
36
|
-
type: DataTypes.BIGINT,
|
|
37
|
-
allowNull: false,
|
|
38
|
-
defaultValue: 0,
|
|
39
|
-
comment: "Total number of times tokens have been used",
|
|
40
|
-
},
|
|
41
|
-
rotationStrategy: {
|
|
42
|
-
type: DataTypes.ENUM("round_robin", "least_used", "random"),
|
|
43
|
-
allowNull: false,
|
|
44
|
-
defaultValue: "round_robin",
|
|
45
|
-
comment: "Strategy for token rotation",
|
|
46
|
-
},
|
|
47
|
-
metadata: {
|
|
48
|
-
type: DataTypes.JSONB,
|
|
49
|
-
allowNull: true,
|
|
50
|
-
comment: "Additional metadata (per-token usage stats, health, etc.)",
|
|
51
|
-
},
|
|
52
|
-
},
|
|
53
|
-
{
|
|
54
|
-
tableName: "TokenRotationState",
|
|
55
|
-
timestamps: true, // Adds createdAt and updatedAt
|
|
56
|
-
indexes: [
|
|
57
|
-
{
|
|
58
|
-
fields: ["tokenType"],
|
|
59
|
-
unique: true,
|
|
60
|
-
name: "idx_token_rotation_type",
|
|
61
|
-
},
|
|
62
|
-
{
|
|
63
|
-
fields: ["lastUsedAt"],
|
|
64
|
-
name: "idx_token_rotation_last_used",
|
|
65
|
-
},
|
|
66
|
-
],
|
|
67
|
-
}
|
|
68
|
-
);
|
|
69
|
-
|
|
70
|
-
// Instance methods
|
|
71
|
-
TokenRotationState.prototype.incrementUsage = async function () {
|
|
72
|
-
this.totalUsageCount = (
|
|
73
|
-
BigInt(this.totalUsageCount) + BigInt(1)
|
|
74
|
-
).toString();
|
|
75
|
-
this.lastUsedAt = new Date();
|
|
76
|
-
await this.save();
|
|
77
|
-
};
|
|
78
|
-
|
|
79
|
-
TokenRotationState.prototype.rotateToNext = async function () {
|
|
80
|
-
this.currentIndex = (this.currentIndex + 1) % this.totalTokens;
|
|
81
|
-
await this.save();
|
|
82
|
-
};
|
|
83
|
-
|
|
84
|
-
TokenRotationState.prototype.getCurrentTokenNumber = function () {
|
|
85
|
-
return this.currentIndex + 1; // Return 1-based index
|
|
86
|
-
};
|
|
87
|
-
|
|
88
|
-
// Static methods
|
|
89
|
-
TokenRotationState.getOrCreate = async function (
|
|
90
|
-
tokenType = "FACEBOOK_ACCESS_TOKEN"
|
|
91
|
-
) {
|
|
92
|
-
const [state, created] = await this.findOrCreate({
|
|
93
|
-
where: { tokenType },
|
|
94
|
-
defaults: {
|
|
95
|
-
tokenType,
|
|
96
|
-
currentIndex: 0,
|
|
97
|
-
totalTokens: 10,
|
|
98
|
-
rotationStrategy: "round_robin",
|
|
99
|
-
},
|
|
100
|
-
});
|
|
101
|
-
return state;
|
|
102
|
-
};
|
|
103
|
-
|
|
104
|
-
TokenRotationState.getStats = async function (
|
|
105
|
-
tokenType = "FACEBOOK_ACCESS_TOKEN"
|
|
106
|
-
) {
|
|
107
|
-
const state = await this.findOne({ where: { tokenType } });
|
|
108
|
-
if (!state) return null;
|
|
109
|
-
|
|
110
|
-
return {
|
|
111
|
-
currentTokenNumber: state.getCurrentTokenNumber(),
|
|
112
|
-
totalTokens: state.totalTokens,
|
|
113
|
-
totalUsageCount: state.totalUsageCount.toString(),
|
|
114
|
-
lastUsedAt: state.lastUsedAt,
|
|
115
|
-
rotationStrategy: state.rotationStrategy,
|
|
116
|
-
metadata: state.metadata,
|
|
117
|
-
};
|
|
118
|
-
};
|
|
119
|
-
|
|
120
|
-
return TokenRotationState;
|
|
121
|
-
};
|
|
1
|
+
// models/TokenRotationState.js
|
|
2
|
+
module.exports = (sequelize, DataTypes) => {
|
|
3
|
+
const TokenRotationState = sequelize.define(
|
|
4
|
+
"TokenRotationState",
|
|
5
|
+
{
|
|
6
|
+
id: {
|
|
7
|
+
type: DataTypes.INTEGER,
|
|
8
|
+
primaryKey: true,
|
|
9
|
+
autoIncrement: true,
|
|
10
|
+
},
|
|
11
|
+
tokenType: {
|
|
12
|
+
type: DataTypes.STRING,
|
|
13
|
+
allowNull: false,
|
|
14
|
+
unique: true,
|
|
15
|
+
defaultValue: "FACEBOOK_ACCESS_TOKEN",
|
|
16
|
+
comment: "Type of token being rotated (e.g., FACEBOOK_ACCESS_TOKEN)",
|
|
17
|
+
},
|
|
18
|
+
currentIndex: {
|
|
19
|
+
type: DataTypes.INTEGER,
|
|
20
|
+
allowNull: false,
|
|
21
|
+
defaultValue: 0,
|
|
22
|
+
comment: "Current index in the token rotation (0-based)",
|
|
23
|
+
},
|
|
24
|
+
totalTokens: {
|
|
25
|
+
type: DataTypes.INTEGER,
|
|
26
|
+
allowNull: false,
|
|
27
|
+
defaultValue: 10,
|
|
28
|
+
comment: "Total number of tokens in rotation",
|
|
29
|
+
},
|
|
30
|
+
lastUsedAt: {
|
|
31
|
+
type: DataTypes.DATE,
|
|
32
|
+
allowNull: true,
|
|
33
|
+
comment: "Timestamp of last token usage",
|
|
34
|
+
},
|
|
35
|
+
totalUsageCount: {
|
|
36
|
+
type: DataTypes.BIGINT,
|
|
37
|
+
allowNull: false,
|
|
38
|
+
defaultValue: 0,
|
|
39
|
+
comment: "Total number of times tokens have been used",
|
|
40
|
+
},
|
|
41
|
+
rotationStrategy: {
|
|
42
|
+
type: DataTypes.ENUM("round_robin", "least_used", "random"),
|
|
43
|
+
allowNull: false,
|
|
44
|
+
defaultValue: "round_robin",
|
|
45
|
+
comment: "Strategy for token rotation",
|
|
46
|
+
},
|
|
47
|
+
metadata: {
|
|
48
|
+
type: DataTypes.JSONB,
|
|
49
|
+
allowNull: true,
|
|
50
|
+
comment: "Additional metadata (per-token usage stats, health, etc.)",
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
tableName: "TokenRotationState",
|
|
55
|
+
timestamps: true, // Adds createdAt and updatedAt
|
|
56
|
+
indexes: [
|
|
57
|
+
{
|
|
58
|
+
fields: ["tokenType"],
|
|
59
|
+
unique: true,
|
|
60
|
+
name: "idx_token_rotation_type",
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
fields: ["lastUsedAt"],
|
|
64
|
+
name: "idx_token_rotation_last_used",
|
|
65
|
+
},
|
|
66
|
+
],
|
|
67
|
+
}
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
// Instance methods
|
|
71
|
+
TokenRotationState.prototype.incrementUsage = async function () {
|
|
72
|
+
this.totalUsageCount = (
|
|
73
|
+
BigInt(this.totalUsageCount) + BigInt(1)
|
|
74
|
+
).toString();
|
|
75
|
+
this.lastUsedAt = new Date();
|
|
76
|
+
await this.save();
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
TokenRotationState.prototype.rotateToNext = async function () {
|
|
80
|
+
this.currentIndex = (this.currentIndex + 1) % this.totalTokens;
|
|
81
|
+
await this.save();
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
TokenRotationState.prototype.getCurrentTokenNumber = function () {
|
|
85
|
+
return this.currentIndex + 1; // Return 1-based index
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
// Static methods
|
|
89
|
+
TokenRotationState.getOrCreate = async function (
|
|
90
|
+
tokenType = "FACEBOOK_ACCESS_TOKEN"
|
|
91
|
+
) {
|
|
92
|
+
const [state, created] = await this.findOrCreate({
|
|
93
|
+
where: { tokenType },
|
|
94
|
+
defaults: {
|
|
95
|
+
tokenType,
|
|
96
|
+
currentIndex: 0,
|
|
97
|
+
totalTokens: 10,
|
|
98
|
+
rotationStrategy: "round_robin",
|
|
99
|
+
},
|
|
100
|
+
});
|
|
101
|
+
return state;
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
TokenRotationState.getStats = async function (
|
|
105
|
+
tokenType = "FACEBOOK_ACCESS_TOKEN"
|
|
106
|
+
) {
|
|
107
|
+
const state = await this.findOne({ where: { tokenType } });
|
|
108
|
+
if (!state) return null;
|
|
109
|
+
|
|
110
|
+
return {
|
|
111
|
+
currentTokenNumber: state.getCurrentTokenNumber(),
|
|
112
|
+
totalTokens: state.totalTokens,
|
|
113
|
+
totalUsageCount: state.totalUsageCount.toString(),
|
|
114
|
+
lastUsedAt: state.lastUsedAt,
|
|
115
|
+
rotationStrategy: state.rotationStrategy,
|
|
116
|
+
metadata: state.metadata,
|
|
117
|
+
};
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
return TokenRotationState;
|
|
121
|
+
};
|
|
@@ -1,123 +1,123 @@
|
|
|
1
|
-
module.exports = (sequelize, DataTypes) => {
|
|
2
|
-
const TonicRSOCKeywordPerformance = sequelize.define(
|
|
3
|
-
"TonicRSOCKeywordPerformance",
|
|
4
|
-
{
|
|
5
|
-
Date: {
|
|
6
|
-
type: DataTypes.DATEONLY,
|
|
7
|
-
primaryKey: true,
|
|
8
|
-
},
|
|
9
|
-
adID: {
|
|
10
|
-
type: DataTypes.STRING,
|
|
11
|
-
references: {
|
|
12
|
-
model: "Ad",
|
|
13
|
-
key: "AdID",
|
|
14
|
-
},
|
|
15
|
-
foreignKey: true,
|
|
16
|
-
primaryKey: true,
|
|
17
|
-
},
|
|
18
|
-
Keyword: {
|
|
19
|
-
type: DataTypes.STRING,
|
|
20
|
-
allowNull: false,
|
|
21
|
-
primaryKey: true,
|
|
22
|
-
},
|
|
23
|
-
Country: {
|
|
24
|
-
type: DataTypes.STRING,
|
|
25
|
-
allowNull: false,
|
|
26
|
-
primaryKey: true, // ✅ Country is now part of primary key
|
|
27
|
-
},
|
|
28
|
-
Revenue: {
|
|
29
|
-
type: DataTypes.FLOAT,
|
|
30
|
-
allowNull: false,
|
|
31
|
-
},
|
|
32
|
-
Clicks: {
|
|
33
|
-
type: DataTypes.INTEGER,
|
|
34
|
-
allowNull: false,
|
|
35
|
-
},
|
|
36
|
-
TemplatedKeyword: {
|
|
37
|
-
type: DataTypes.STRING,
|
|
38
|
-
allowNull: true,
|
|
39
|
-
},
|
|
40
|
-
FirstAppearanceDate: {
|
|
41
|
-
type: DataTypes.DATEONLY,
|
|
42
|
-
allowNull: true,
|
|
43
|
-
},
|
|
44
|
-
},
|
|
45
|
-
{
|
|
46
|
-
tableName: "TonicRSOCKeywordPerformance",
|
|
47
|
-
indexes: [
|
|
48
|
-
{
|
|
49
|
-
unique: true,
|
|
50
|
-
fields: ["Date", "adID", "Keyword", "Country"],
|
|
51
|
-
name: "tonic_primary_idx" // ✅ Custom short name
|
|
52
|
-
},
|
|
53
|
-
{
|
|
54
|
-
fields: ["Date"],
|
|
55
|
-
name: "tonic_date_idx"
|
|
56
|
-
},
|
|
57
|
-
{
|
|
58
|
-
fields: ["adID"],
|
|
59
|
-
name: "tonic_adid_idx"
|
|
60
|
-
},
|
|
61
|
-
{
|
|
62
|
-
fields: ["Keyword"],
|
|
63
|
-
name: "tonic_keyword_idx"
|
|
64
|
-
},
|
|
65
|
-
{
|
|
66
|
-
fields: ["Country"],
|
|
67
|
-
name: "tonic_country_idx"
|
|
68
|
-
},
|
|
69
|
-
{
|
|
70
|
-
fields: ["Revenue"],
|
|
71
|
-
name: "tonic_revenue_idx"
|
|
72
|
-
},
|
|
73
|
-
{
|
|
74
|
-
fields: ["Clicks"],
|
|
75
|
-
name: "tonic_clicks_idx"
|
|
76
|
-
},
|
|
77
|
-
{
|
|
78
|
-
fields: ["Country", "Date"],
|
|
79
|
-
name: "tonic_country_date_idx"
|
|
80
|
-
},
|
|
81
|
-
{
|
|
82
|
-
fields: ["Keyword", "Country"],
|
|
83
|
-
name: "tonic_keyword_country_idx"
|
|
84
|
-
},
|
|
85
|
-
{
|
|
86
|
-
fields: ["Date", "Revenue"],
|
|
87
|
-
name: "tonic_date_revenue_idx"
|
|
88
|
-
},
|
|
89
|
-
],
|
|
90
|
-
hooks: {
|
|
91
|
-
beforeCreate: async (record, options) => {
|
|
92
|
-
try {
|
|
93
|
-
const existingKeyword = await sequelize.models.TonicRSOCKeywordPerformance.findOne({
|
|
94
|
-
where: {
|
|
95
|
-
Keyword: sequelize.where(
|
|
96
|
-
sequelize.fn("LOWER", sequelize.col("Keyword")),
|
|
97
|
-
sequelize.fn("LOWER", record.Keyword)
|
|
98
|
-
),
|
|
99
|
-
Country: record.Country,
|
|
100
|
-
},
|
|
101
|
-
attributes: ["FirstAppearanceDate"],
|
|
102
|
-
transaction: options.transaction,
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
record.FirstAppearanceDate =
|
|
106
|
-
existingKeyword?.FirstAppearanceDate || record.Date;
|
|
107
|
-
} catch (error) {
|
|
108
|
-
console.error("Error in TonicRSOCKeywordPerformance FirstAppearanceDate hook:", error);
|
|
109
|
-
throw error;
|
|
110
|
-
}
|
|
111
|
-
},
|
|
112
|
-
},
|
|
113
|
-
}
|
|
114
|
-
);
|
|
115
|
-
|
|
116
|
-
TonicRSOCKeywordPerformance.associate = (models) => {
|
|
117
|
-
TonicRSOCKeywordPerformance.belongsTo(models.Ad, {
|
|
118
|
-
foreignKey: "adID",
|
|
119
|
-
});
|
|
120
|
-
};
|
|
121
|
-
|
|
122
|
-
return TonicRSOCKeywordPerformance;
|
|
1
|
+
module.exports = (sequelize, DataTypes) => {
|
|
2
|
+
const TonicRSOCKeywordPerformance = sequelize.define(
|
|
3
|
+
"TonicRSOCKeywordPerformance",
|
|
4
|
+
{
|
|
5
|
+
Date: {
|
|
6
|
+
type: DataTypes.DATEONLY,
|
|
7
|
+
primaryKey: true,
|
|
8
|
+
},
|
|
9
|
+
adID: {
|
|
10
|
+
type: DataTypes.STRING,
|
|
11
|
+
references: {
|
|
12
|
+
model: "Ad",
|
|
13
|
+
key: "AdID",
|
|
14
|
+
},
|
|
15
|
+
foreignKey: true,
|
|
16
|
+
primaryKey: true,
|
|
17
|
+
},
|
|
18
|
+
Keyword: {
|
|
19
|
+
type: DataTypes.STRING,
|
|
20
|
+
allowNull: false,
|
|
21
|
+
primaryKey: true,
|
|
22
|
+
},
|
|
23
|
+
Country: {
|
|
24
|
+
type: DataTypes.STRING,
|
|
25
|
+
allowNull: false,
|
|
26
|
+
primaryKey: true, // ✅ Country is now part of primary key
|
|
27
|
+
},
|
|
28
|
+
Revenue: {
|
|
29
|
+
type: DataTypes.FLOAT,
|
|
30
|
+
allowNull: false,
|
|
31
|
+
},
|
|
32
|
+
Clicks: {
|
|
33
|
+
type: DataTypes.INTEGER,
|
|
34
|
+
allowNull: false,
|
|
35
|
+
},
|
|
36
|
+
TemplatedKeyword: {
|
|
37
|
+
type: DataTypes.STRING,
|
|
38
|
+
allowNull: true,
|
|
39
|
+
},
|
|
40
|
+
FirstAppearanceDate: {
|
|
41
|
+
type: DataTypes.DATEONLY,
|
|
42
|
+
allowNull: true,
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
tableName: "TonicRSOCKeywordPerformance",
|
|
47
|
+
indexes: [
|
|
48
|
+
{
|
|
49
|
+
unique: true,
|
|
50
|
+
fields: ["Date", "adID", "Keyword", "Country"],
|
|
51
|
+
name: "tonic_primary_idx" // ✅ Custom short name
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
fields: ["Date"],
|
|
55
|
+
name: "tonic_date_idx"
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
fields: ["adID"],
|
|
59
|
+
name: "tonic_adid_idx"
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
fields: ["Keyword"],
|
|
63
|
+
name: "tonic_keyword_idx"
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
fields: ["Country"],
|
|
67
|
+
name: "tonic_country_idx"
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
fields: ["Revenue"],
|
|
71
|
+
name: "tonic_revenue_idx"
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
fields: ["Clicks"],
|
|
75
|
+
name: "tonic_clicks_idx"
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
fields: ["Country", "Date"],
|
|
79
|
+
name: "tonic_country_date_idx"
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
fields: ["Keyword", "Country"],
|
|
83
|
+
name: "tonic_keyword_country_idx"
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
fields: ["Date", "Revenue"],
|
|
87
|
+
name: "tonic_date_revenue_idx"
|
|
88
|
+
},
|
|
89
|
+
],
|
|
90
|
+
hooks: {
|
|
91
|
+
beforeCreate: async (record, options) => {
|
|
92
|
+
try {
|
|
93
|
+
const existingKeyword = await sequelize.models.TonicRSOCKeywordPerformance.findOne({
|
|
94
|
+
where: {
|
|
95
|
+
Keyword: sequelize.where(
|
|
96
|
+
sequelize.fn("LOWER", sequelize.col("Keyword")),
|
|
97
|
+
sequelize.fn("LOWER", record.Keyword)
|
|
98
|
+
),
|
|
99
|
+
Country: record.Country,
|
|
100
|
+
},
|
|
101
|
+
attributes: ["FirstAppearanceDate"],
|
|
102
|
+
transaction: options.transaction,
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
record.FirstAppearanceDate =
|
|
106
|
+
existingKeyword?.FirstAppearanceDate || record.Date;
|
|
107
|
+
} catch (error) {
|
|
108
|
+
console.error("Error in TonicRSOCKeywordPerformance FirstAppearanceDate hook:", error);
|
|
109
|
+
throw error;
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
},
|
|
113
|
+
}
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
TonicRSOCKeywordPerformance.associate = (models) => {
|
|
117
|
+
TonicRSOCKeywordPerformance.belongsTo(models.Ad, {
|
|
118
|
+
foreignKey: "adID",
|
|
119
|
+
});
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
return TonicRSOCKeywordPerformance;
|
|
123
123
|
};
|