agrs-sequelize-sdk 1.4.38 → 1.4.40
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.
|
@@ -89,15 +89,33 @@ module.exports = (sequelize, DataTypes) => {
|
|
|
89
89
|
{
|
|
90
90
|
tableName: "PublicApiIdempotencyCache",
|
|
91
91
|
indexes: [
|
|
92
|
-
// Primary lookup: (user_id, key). UNIQUE so
|
|
93
|
-
//
|
|
94
|
-
//
|
|
95
|
-
//
|
|
96
|
-
|
|
92
|
+
// Primary lookup: (user_id, key). UNIQUE so Postgres resolves N
|
|
93
|
+
// concurrent claims atomically — the loser hits a unique violation,
|
|
94
|
+
// Sequelize's findOrCreate catches it, re-finds the winner's row, and
|
|
95
|
+
// returns created=false. That is what makes exactly ONE of the "9
|
|
96
|
+
// concurrent retries" execute the work while the rest get 409.
|
|
97
|
+
//
|
|
98
|
+
// THIS INDEX IS THE ENTIRE FEATURE. Without it every concurrent INSERT
|
|
99
|
+
// succeeds and every retry re-runs the operation. Verified in prod on
|
|
100
|
+
// 2026-07-12: index absent -> a 9-way burst gave 5 executions; index
|
|
101
|
+
// present (local) -> exactly 1.
|
|
102
|
+
//
|
|
103
|
+
// Named explicitly so the migration that backfills it on already-created
|
|
104
|
+
// tables targets the same index. sequelize.sync() runs with alter:false
|
|
105
|
+
// in prod (server.js gates it on DB_COLUMN_TYPE_UPDATE), so it creates
|
|
106
|
+
// the table but does NOT add indexes to a table that already exists.
|
|
107
|
+
{
|
|
108
|
+
name: "PublicApiIdempotencyCache_user_id_key_uniq",
|
|
109
|
+
unique: true,
|
|
110
|
+
fields: ["user_id", "key"],
|
|
111
|
+
},
|
|
97
112
|
// Sweep index — cron does `DELETE WHERE expires_at < NOW()`. Not
|
|
98
113
|
// partial (would need to update after every insert); regular
|
|
99
114
|
// btree is fine for the sweep pattern.
|
|
100
|
-
{
|
|
115
|
+
{
|
|
116
|
+
name: "PublicApiIdempotencyCache_expires_at_idx",
|
|
117
|
+
fields: ["expires_at"],
|
|
118
|
+
},
|
|
101
119
|
],
|
|
102
120
|
}
|
|
103
121
|
);
|
|
@@ -18,10 +18,19 @@ module.exports = (sequelize, DataTypes) => {
|
|
|
18
18
|
type: DataTypes.STRING(255),
|
|
19
19
|
allowNull: true,
|
|
20
20
|
},
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
// 2026-07-12: widened from single STRING → ARRAY(STRING). Snap allows
|
|
22
|
+
// the SAME Public Profile to be linked to MANY ad accounts (per Snap
|
|
23
|
+
// Business Center — one profile can serve multiple advertiser
|
|
24
|
+
// accounts). Storing a single ad_account_id here forced our resolver
|
|
25
|
+
// into cross-account fallback (which Snap rejects with 403 E3002).
|
|
26
|
+
// Now: each row lists every ad account this profile is authorized on.
|
|
27
|
+
ad_account_ids: {
|
|
28
|
+
type: DataTypes.ARRAY(DataTypes.STRING),
|
|
23
29
|
allowNull: false,
|
|
24
|
-
|
|
30
|
+
defaultValue: [],
|
|
31
|
+
comment:
|
|
32
|
+
"Snapchat ad_account_ids this profile can serve. Query with " +
|
|
33
|
+
"'X = ANY(ad_account_ids)'. Empty means unrestricted.",
|
|
25
34
|
},
|
|
26
35
|
status: {
|
|
27
36
|
type: DataTypes.STRING(16),
|
|
@@ -46,7 +55,11 @@ module.exports = (sequelize, DataTypes) => {
|
|
|
46
55
|
},
|
|
47
56
|
{
|
|
48
57
|
tableName: "snapchat_public_profiles",
|
|
49
|
-
|
|
58
|
+
// No index on ad_account_ids directly — Postgres uses GIN on arrays
|
|
59
|
+
// and Sequelize's simple `fields` index syntax doesn't emit GIN. If
|
|
60
|
+
// query performance becomes a concern, add a raw GIN index migration:
|
|
61
|
+
// CREATE INDEX ... ON snapchat_public_profiles USING GIN (ad_account_ids);
|
|
62
|
+
indexes: [{ fields: ["status"] }],
|
|
50
63
|
}
|
|
51
64
|
);
|
|
52
65
|
|