diff --git a/eslint.config.js b/eslint.config.js
index 3ca4b9e3ffc..6f5eae6dd42 100644
--- a/eslint.config.js
+++ b/eslint.config.js
@@ -169,20 +169,13 @@ const config = [
"@typescript-eslint/no-unsafe-call": "off",
},
},
- // Ignore the following files for now.
+ // Next is not running ESLint on root files by default. The only way to
+ // include those would be to explicitly add them one by one. Instead, we
+ // run ESLint directly in addition to next lint on just the root files.
+ // For more info see:
+ // https://nextjs.org/docs/app/api-reference/config/eslint#linting-custom-directories-and-files
{
- files: [
- "src/app/global-error.js",
- "src/db/migrations/*.js",
- "src/scripts/build/*.js",
- "src/scripts/loadtest/*.js",
- // Next is not running ESLint on root files by default. The only way to
- // include those would be to explicitly add them one by one. Instead, we
- // run ESLint directly in addition to next lint on just the root files.
- // For more info see:
- // https://nextjs.org/docs/app/api-reference/config/eslint#linting-custom-directories-and-files
- "*.{js,cjs,ts}",
- ],
+ files: ["*.{js,cjs,ts}"],
languageOptions: {
parserOptions: { project: null },
},
diff --git a/src/app/global-error.js b/src/app/global-error.js
index 58fd89e85de..e05b6c7b290 100644
--- a/src/app/global-error.js
+++ b/src/app/global-error.js
@@ -8,7 +8,12 @@ import * as Sentry from "@sentry/nextjs";
import NextError from "next/error";
import { useEffect } from "react";
-export default function GlobalError({ error }) {
+/**
+ * @param {Object} props
+ * @param {Error} props.error - The error object
+ * @param {number} props.statusCode - HTTP error status code (default: 500)
+ */
+export default function GlobalError({ error, statusCode = 500 }) {
useEffect(() => {
Sentry.captureException(error);
}, [error]);
@@ -17,7 +22,7 @@ export default function GlobalError({ error }) {
{/* This is the default Next.js error component. */}
-
+
);
diff --git a/src/db/migrations/20180418090800_initial_schema.js b/src/db/migrations/20180418090800_initial_schema.js
index 2220e43d80a..4c92dad4d9e 100644
--- a/src/db/migrations/20180418090800_initial_schema.js
+++ b/src/db/migrations/20180418090800_initial_schema.js
@@ -2,6 +2,10 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise }
+ */
export function up(knex) {
return knex.schema.createTable("subscribers", (table) => {
table.increments("id").primary();
@@ -12,6 +16,10 @@ export function up(knex) {
});
}
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise }
+ */
export function down(knex) {
return knex.schema.dropTableIfExists("subscribers");
}
diff --git a/src/db/migrations/20180826102013_add_timestamps_to_subscribers.js b/src/db/migrations/20180826102013_add_timestamps_to_subscribers.js
index 22a892f9050..f9ae802cf76 100644
--- a/src/db/migrations/20180826102013_add_timestamps_to_subscribers.js
+++ b/src/db/migrations/20180826102013_add_timestamps_to_subscribers.js
@@ -2,12 +2,20 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise }
+ */
export function up(knex) {
return knex.schema.table("subscribers", (table) => {
table.timestamps(false, true);
});
}
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise }
+ */
export function down(knex) {
return knex.schema.table("subscribers", (table) => {
table.dropTimestamps();
diff --git a/src/db/migrations/20180829161115_add_fx_newsletter_column.js b/src/db/migrations/20180829161115_add_fx_newsletter_column.js
index 20984121a38..f5cba4e3664 100644
--- a/src/db/migrations/20180829161115_add_fx_newsletter_column.js
+++ b/src/db/migrations/20180829161115_add_fx_newsletter_column.js
@@ -2,12 +2,20 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise }
+ */
export function up(knex) {
return knex.schema.table("subscribers", (table) => {
table.boolean("fx_newsletter").defaultTo(false);
});
}
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise }
+ */
export function down(knex) {
return knex.schema.table("subscribers", (table) => {
table.dropColumn("fx_newsletter");
diff --git a/src/db/migrations/20180930071926_add_signup_language.js b/src/db/migrations/20180930071926_add_signup_language.js
index 7e58823b394..dc98f1c9272 100644
--- a/src/db/migrations/20180930071926_add_signup_language.js
+++ b/src/db/migrations/20180930071926_add_signup_language.js
@@ -2,12 +2,20 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise }
+ */
export function up(knex) {
return knex.schema.table("subscribers", (table) => {
table.string("signup_language");
});
}
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise }
+ */
export function down(knex) {
return knex.schema.table("subscribers", (table) => {
table.dropColumn("signup_language");
diff --git a/src/db/migrations/20181007085241_add_sha1_index.js b/src/db/migrations/20181007085241_add_sha1_index.js
index e809870030e..f8d024e7f2e 100644
--- a/src/db/migrations/20181007085241_add_sha1_index.js
+++ b/src/db/migrations/20181007085241_add_sha1_index.js
@@ -5,12 +5,21 @@
// Note: this index was created on heroku, stage, and prod by hand
// Use this statement to "fake" the migration:
// INSERT INTO knex_migrations (name, batch, migration_time) values ('20181007085241_add_sha1_index.js', 4, '2018-10-07 08:52:42.000-05');
+
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise }
+ */
export function up(knex) {
return knex.schema.table("subscribers", (table) => {
table.index("sha1", "subscribers_sha1_idx");
});
}
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise }
+ */
export function down(knex) {
return knex.schema.table("subscribers", (table) => {
table.dropIndex("sha1", "subscribers_sha1_idx");
diff --git a/src/db/migrations/20181108151941_add_created_at_index.js b/src/db/migrations/20181108151941_add_created_at_index.js
index 938c77cb973..79d876605f9 100644
--- a/src/db/migrations/20181108151941_add_created_at_index.js
+++ b/src/db/migrations/20181108151941_add_created_at_index.js
@@ -2,12 +2,20 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise }
+ */
export function up(knex) {
return knex.schema.table("subscribers", (table) => {
table.index("created_at");
});
}
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise }
+ */
export function down(knex) {
return knex.schema.table("subscribers", (table) => {
table.dropIndex("created_at");
diff --git a/src/db/migrations/20181129152508_add_email_index.js b/src/db/migrations/20181129152508_add_email_index.js
index 3458eceb157..19b272e9290 100644
--- a/src/db/migrations/20181129152508_add_email_index.js
+++ b/src/db/migrations/20181129152508_add_email_index.js
@@ -2,12 +2,20 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise }
+ */
export function up(knex) {
return knex.schema.table("subscribers", (table) => {
table.index("email", "subscribers_email_idx");
});
}
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise }
+ */
export function down(knex) {
return knex.schema.table("subscribers", (table) => {
table.dropIndex("email", "subscribers_email_idx");
diff --git a/src/db/migrations/20181227100332_add_fxa_columns.js b/src/db/migrations/20181227100332_add_fxa_columns.js
index 2eb428660f1..05a6007bb30 100644
--- a/src/db/migrations/20181227100332_add_fxa_columns.js
+++ b/src/db/migrations/20181227100332_add_fxa_columns.js
@@ -2,6 +2,10 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise }
+ */
export function up(knex) {
return knex.schema.table("subscribers", (table) => {
table.string("fxa_refresh_token");
@@ -9,6 +13,10 @@ export function up(knex) {
});
}
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise }
+ */
export function down(knex) {
return knex.schema.table("subscribers", (table) => {
table.dropColumn("fxa_refresh_token");
diff --git a/src/db/migrations/20190117150910_add_verified_index.js b/src/db/migrations/20190117150910_add_verified_index.js
index 86f95e50c59..695b6995657 100644
--- a/src/db/migrations/20190117150910_add_verified_index.js
+++ b/src/db/migrations/20190117150910_add_verified_index.js
@@ -2,12 +2,20 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise }
+ */
export function up(knex) {
return knex.schema.table("subscribers", (table) => {
table.index("verified", "subscribers_verified_idx");
});
}
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise }
+ */
export function down(knex) {
return knex.schema.table("subscribers", (table) => {
table.dropIndex("verified", "subscribers_verified_idx");
diff --git a/src/db/migrations/20190219154519_add_fxa_uid_column.js b/src/db/migrations/20190219154519_add_fxa_uid_column.js
index e27739bfdbb..7f1853e35c4 100644
--- a/src/db/migrations/20190219154519_add_fxa_uid_column.js
+++ b/src/db/migrations/20190219154519_add_fxa_uid_column.js
@@ -2,12 +2,20 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise }
+ */
export function up(knex) {
return knex.schema.table("subscribers", (table) => {
table.string("fxa_uid");
});
}
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise }
+ */
export function down(knex) {
return knex.schema.table("subscribers", (table) => {
table.dropColumn("fxa_uid");
diff --git a/src/db/migrations/20190328111900_add_email_addresses_table.js b/src/db/migrations/20190328111900_add_email_addresses_table.js
index 0c7e310fa44..e78cc9dc039 100644
--- a/src/db/migrations/20190328111900_add_email_addresses_table.js
+++ b/src/db/migrations/20190328111900_add_email_addresses_table.js
@@ -2,6 +2,10 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise<[void, void]> }
+ */
export function up(knex) {
return Promise.all([
knex.schema.createTable("email_addresses", (table) => {
@@ -22,6 +26,10 @@ export function up(knex) {
]);
}
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise<[void, void]> }
+ */
export function down(knex) {
return Promise.all([
knex.schema.dropTableIfExists("email_addresses"),
diff --git a/src/db/migrations/20190422140308_add_subscriber_breaches_shown.js b/src/db/migrations/20190422140308_add_subscriber_breaches_shown.js
index 23ceaa2d403..5f0807d65ab 100644
--- a/src/db/migrations/20190422140308_add_subscriber_breaches_shown.js
+++ b/src/db/migrations/20190422140308_add_subscriber_breaches_shown.js
@@ -2,12 +2,20 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise }
+ */
export function up(knex) {
return knex.schema.table("subscribers", (table) => {
table.timestamp("breaches_last_shown");
});
}
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise }
+ */
export function down(knex) {
return knex.schema.table("subscribers", (table) => {
table.dropColumn("breaches_last_shown");
diff --git a/src/db/migrations/20190510152733_add_timestamps_to_email_addresses.js b/src/db/migrations/20190510152733_add_timestamps_to_email_addresses.js
index 0c57076d17c..359d1e74986 100644
--- a/src/db/migrations/20190510152733_add_timestamps_to_email_addresses.js
+++ b/src/db/migrations/20190510152733_add_timestamps_to_email_addresses.js
@@ -2,12 +2,20 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise }
+ */
export function up(knex) {
return knex.schema.table("email_addresses", (table) => {
table.timestamps(false);
});
}
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise }
+ */
export function down(knex) {
return knex.schema.table("email_addresses", (table) => {
table.dropTimestamps();
diff --git a/src/db/migrations/20190512170106_add_all_emails_to_primary_column.js b/src/db/migrations/20190512170106_add_all_emails_to_primary_column.js
index 362bb6fcb35..70969c20eb9 100644
--- a/src/db/migrations/20190512170106_add_all_emails_to_primary_column.js
+++ b/src/db/migrations/20190512170106_add_all_emails_to_primary_column.js
@@ -2,12 +2,20 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise }
+ */
export function up(knex) {
return knex.schema.table("subscribers", (table) => {
table.boolean("all_emails_to_primary").defaultTo(false);
});
}
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise }
+ */
export function down(knex) {
return knex.schema.table("subscribers", (table) => {
table.dropColumn("all_emails_to_primary");
diff --git a/src/db/migrations/20190523152919_add_fxa_access_token_to_subscribers.js b/src/db/migrations/20190523152919_add_fxa_access_token_to_subscribers.js
index 014dcb308a7..b46c4da8d25 100644
--- a/src/db/migrations/20190523152919_add_fxa_access_token_to_subscribers.js
+++ b/src/db/migrations/20190523152919_add_fxa_access_token_to_subscribers.js
@@ -2,12 +2,20 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise }
+ */
export function up(knex) {
return knex.schema.table("subscribers", (table) => {
table.string("fxa_access_token");
});
}
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise }
+ */
export function down(knex) {
return knex.schema.table("subscribers", (table) => {
table.dropColumn("fxa_access_token");
diff --git a/src/db/migrations/20190713193852_add_email_sha1_index.js b/src/db/migrations/20190713193852_add_email_sha1_index.js
index 37581b429ff..90ccdf91d11 100644
--- a/src/db/migrations/20190713193852_add_email_sha1_index.js
+++ b/src/db/migrations/20190713193852_add_email_sha1_index.js
@@ -5,12 +5,21 @@
// Note: this index was created on heroku, stage, and prod by hand
// Use this statement to "fake" the migration:
// INSERT INTO knex_migrations (name, batch, migration_time) values ('20190713193852_add_email_sha1_index.js', (SELECT max(batch) + 1 FROM knex_migrations), '2019-07-13 19:52:42.000-05');
+
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise }
+ */
export function up(knex) {
return knex.schema.table("email_addresses", (table) => {
table.index("sha1", "email_addresses_sha1_idx");
});
}
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise }
+ */
export function down(knex) {
return knex.schema.table("email_addresses", (table) => {
table.dropIndex("sha1", "email_addresses_sha1_idx");
diff --git a/src/db/migrations/20191118100718_add-fxa-uid-index.js b/src/db/migrations/20191118100718_add-fxa-uid-index.js
index 56bec8bb9c4..35fe648acdb 100644
--- a/src/db/migrations/20191118100718_add-fxa-uid-index.js
+++ b/src/db/migrations/20191118100718_add-fxa-uid-index.js
@@ -6,12 +6,20 @@
// Use this statement to "fake" the migration:
// INSERT INTO knex_migrations (name, batch, migration_time) values ('20191118100718_add-fxa-uid-index.js', (SELECT max(batch) + 1 FROM knex_migrations), '2019-11-18 11:00:00.000-05');
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise }
+ */
export function up(knex) {
return knex.schema.table("subscribers", (table) => {
table.index("fxa_uid", "subscribers_fxa_uid_idx");
});
}
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise }
+ */
export function down(knex) {
return knex.schema.table("subscribers", (table) => {
table.dropIndex("fxa_uid", "subscribers_fxa_uid_idx");
diff --git a/src/db/migrations/20191118170713_add-email_addresses-email-index.js b/src/db/migrations/20191118170713_add-email_addresses-email-index.js
index 597f76190d3..5cf0e06eae4 100644
--- a/src/db/migrations/20191118170713_add-email_addresses-email-index.js
+++ b/src/db/migrations/20191118170713_add-email_addresses-email-index.js
@@ -2,12 +2,20 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise }
+ */
export function up(knex) {
return knex.schema.table("email_addresses", (table) => {
table.index("email", "email_addresses_email_idx");
});
}
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise }
+ */
export function down(knex) {
return knex.schema.table("email_addresses", (table) => {
table.dropIndex("email", "email_addresses_email_idx");
diff --git a/src/db/migrations/20191202161125_add_breaches_resolved_column.js b/src/db/migrations/20191202161125_add_breaches_resolved_column.js
index f2bf666c2bd..2c00ad48ee4 100644
--- a/src/db/migrations/20191202161125_add_breaches_resolved_column.js
+++ b/src/db/migrations/20191202161125_add_breaches_resolved_column.js
@@ -2,12 +2,20 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise }
+ */
export function up(knex) {
return knex.schema.table("subscribers", (table) => {
table.jsonb("breaches_resolved");
});
}
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise }
+ */
export function down(knex) {
return knex.schema.table("subscribers", (table) => {
table.dropColumn("breaches_resolved");
diff --git a/src/db/migrations/20200220143251_add-waitlists-column.js b/src/db/migrations/20200220143251_add-waitlists-column.js
index 82a623bae45..d97d3cf0e68 100644
--- a/src/db/migrations/20200220143251_add-waitlists-column.js
+++ b/src/db/migrations/20200220143251_add-waitlists-column.js
@@ -2,12 +2,20 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise }
+ */
export function up(knex) {
return knex.schema.table("subscribers", (table) => {
table.jsonb("waitlists_joined");
});
}
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise }
+ */
export function down(knex) {
return knex.schema.table("subscribers", (table) => {
table.dropColumn("waitlists_joined");
diff --git a/src/db/migrations/20200708123351_add-subscribers-breaches_last_shown-index.js b/src/db/migrations/20200708123351_add-subscribers-breaches_last_shown-index.js
index f8fda52079f..e5e9e3567a3 100644
--- a/src/db/migrations/20200708123351_add-subscribers-breaches_last_shown-index.js
+++ b/src/db/migrations/20200708123351_add-subscribers-breaches_last_shown-index.js
@@ -2,12 +2,20 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise }
+ */
export function up(knex) {
return knex.schema.table("subscribers", (table) => {
table.index("breaches_last_shown", "subscribers_breaches_last_shown_idx");
});
}
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise }
+ */
export function down(knex) {
return knex.schema.table("email_addresses", (table) => {
table.dropIndex(
diff --git a/src/db/migrations/20200810144851_add_signup_language_index.js.js b/src/db/migrations/20200810144851_add_signup_language_index.js.js
index 5a13d4d3939..d94953a5244 100644
--- a/src/db/migrations/20200810144851_add_signup_language_index.js.js
+++ b/src/db/migrations/20200810144851_add_signup_language_index.js.js
@@ -2,12 +2,20 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise }
+ */
export function up(knex) {
return knex.schema.table("subscribers", (table) => {
table.index("signup_language", "subscribers_signup_language_idx");
});
}
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise }
+ */
export function down(knex) {
return knex.schema.table("email_addresses", (table) => {
table.dropIndex("signup_language", "subscribers_signup_language_idx");
diff --git a/src/db/migrations/20210823152654_add_kid_to_subscribers.js b/src/db/migrations/20210823152654_add_kid_to_subscribers.js
index f18cb5d34a2..d4d61d222e5 100644
--- a/src/db/migrations/20210823152654_add_kid_to_subscribers.js
+++ b/src/db/migrations/20210823152654_add_kid_to_subscribers.js
@@ -2,12 +2,20 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise }
+ */
export function up(knex) {
return knex.schema.table("subscribers", (table) => {
table.integer("kid");
});
}
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise }
+ */
export function down(knex) {
return knex.schema.table("subscribers", (table) => {
table.dropColumn("kid");
diff --git a/src/db/migrations/20211001120114_user_enroll_and_pay_null.js b/src/db/migrations/20211001120114_user_enroll_and_pay_null.js
index 1b170697d43..1bedf4e6c04 100644
--- a/src/db/migrations/20211001120114_user_enroll_and_pay_null.js
+++ b/src/db/migrations/20211001120114_user_enroll_and_pay_null.js
@@ -2,6 +2,10 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise }
+ */
export function up(knex) {
return knex.schema.table("subscribers", (table) => {
table.boolean("removal_would_pay");
@@ -9,6 +13,10 @@ export function up(knex) {
});
}
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise }
+ */
export function down(knex) {
return knex.schema.table("subscribers", (table) => {
table.dropColumn("removal_would_pay");
diff --git a/src/db/migrations/20211001135448_removal_pilot_table.js b/src/db/migrations/20211001135448_removal_pilot_table.js
index a35d3964cda..c35243467ac 100644
--- a/src/db/migrations/20211001135448_removal_pilot_table.js
+++ b/src/db/migrations/20211001135448_removal_pilot_table.js
@@ -2,6 +2,10 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise }
+ */
export function up(knex) {
return knex.schema.createTable("removal_pilot", (table) => {
table.increments("id").primary();
@@ -10,6 +14,10 @@ export function up(knex) {
});
}
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise }
+ */
export function down(knex) {
return knex.schema.dropTableIfExists("removal_pilot");
}
diff --git a/src/db/migrations/20220103145534_initial_removal_pilot_group.js b/src/db/migrations/20220103145534_initial_removal_pilot_group.js
index 2f301789f6c..7c7882cda3b 100644
--- a/src/db/migrations/20220103145534_initial_removal_pilot_group.js
+++ b/src/db/migrations/20220103145534_initial_removal_pilot_group.js
@@ -2,6 +2,10 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise }
+ */
export function up(knex) {
return knex("removal_pilot")
.del()
@@ -13,6 +17,10 @@ export function up(knex) {
});
}
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise }
+ */
export function down(knex) {
return knex("removal_pilot").del();
}
diff --git a/src/db/migrations/20220104095854_add-unenroll-col-to-subscribers.js b/src/db/migrations/20220104095854_add-unenroll-col-to-subscribers.js
index e6444f7982b..393befb0883 100644
--- a/src/db/migrations/20220104095854_add-unenroll-col-to-subscribers.js
+++ b/src/db/migrations/20220104095854_add-unenroll-col-to-subscribers.js
@@ -2,12 +2,20 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise }
+ */
export function up(knex) {
return knex.schema.table("subscribers", (table) => {
table.boolean("removal_optout").defaultTo(false);
});
}
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise }
+ */
export function down(knex) {
return knex.schema.table("subscribers", (table) => {
table.dropColumn("removal_optout");
diff --git a/src/db/migrations/20220607154058_rollback-data-removal-pilot.js b/src/db/migrations/20220607154058_rollback-data-removal-pilot.js
index 4a8b242be28..ba6a460abd5 100644
--- a/src/db/migrations/20220607154058_rollback-data-removal-pilot.js
+++ b/src/db/migrations/20220607154058_rollback-data-removal-pilot.js
@@ -2,6 +2,10 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise }
+ */
export async function up(knex) {
await knex.schema.table("subscribers", (table) => {
table.dropColumns(
@@ -15,6 +19,10 @@ export async function up(knex) {
await knex.schema.dropTableIfExists("removal_pilot");
}
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise }
+ */
export async function down(knex) {
const hasTable = await knex.schema.hasTable("removal_pilot");
diff --git a/src/db/migrations/20220818212858_add-breach-stats.js b/src/db/migrations/20220818212858_add-breach-stats.js
index 60d206a8e94..568a0349758 100644
--- a/src/db/migrations/20220818212858_add-breach-stats.js
+++ b/src/db/migrations/20220818212858_add-breach-stats.js
@@ -2,12 +2,20 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise }
+ */
export function up(knex) {
return knex.schema.table("subscribers", (table) => {
table.jsonb("breach_stats").defaultTo(null);
});
}
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise }
+ */
export function down(knex) {
return knex.schema.table("subscribers", (table) => {
table.dropColumn("breach_stats");
diff --git a/src/db/migrations/20220826220021_add-monthly-email-column.js b/src/db/migrations/20220826220021_add-monthly-email-column.js
index 12f295584fd..3fccfd54147 100644
--- a/src/db/migrations/20220826220021_add-monthly-email-column.js
+++ b/src/db/migrations/20220826220021_add-monthly-email-column.js
@@ -2,12 +2,20 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise }
+ */
export function up(knex) {
return knex.schema.table("subscribers", (table) => {
table.timestamp("monthly_email_at");
});
}
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise }
+ */
export function down(knex) {
return knex.schema.table("subscribers", (table) => {
table.dropColumn("monthly_email_at");
diff --git a/src/db/migrations/20220828233844_add-monthly-email-optout.js b/src/db/migrations/20220828233844_add-monthly-email-optout.js
index efc1dbefa49..2b8b92df524 100644
--- a/src/db/migrations/20220828233844_add-monthly-email-optout.js
+++ b/src/db/migrations/20220828233844_add-monthly-email-optout.js
@@ -2,12 +2,20 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise }
+ */
export function up(knex) {
return knex.schema.table("subscribers", (table) => {
table.boolean("monthly_email_optout");
});
}
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise }
+ */
export function down(knex) {
return knex.schema.table("subscribers", (table) => {
table.dropColumn("monthly_email_optout");
diff --git a/src/db/migrations/20221026215921_add-breach-resolution-column.js b/src/db/migrations/20221026215921_add-breach-resolution-column.js
index de2836281aa..53c55e69bb8 100644
--- a/src/db/migrations/20221026215921_add-breach-resolution-column.js
+++ b/src/db/migrations/20221026215921_add-breach-resolution-column.js
@@ -2,12 +2,20 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise }
+ */
export function up(knex) {
return knex.schema.table("subscribers", (table) => {
table.jsonb("breach_resolution").defaultTo(null);
});
}
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise }
+ */
export function down(knex) {
return knex.schema.table("subscribers", (table) => {
table.dropColumn("breach_resolution");
diff --git a/src/db/migrations/20221026215921_add-breaches-table.js b/src/db/migrations/20221026215921_add-breaches-table.js
index 65699b2d73b..9b933363971 100644
--- a/src/db/migrations/20221026215921_add-breaches-table.js
+++ b/src/db/migrations/20221026215921_add-breaches-table.js
@@ -2,18 +2,22 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise }
+ */
export function up(knex) {
return knex.schema.createTable("breaches", (table) => {
table.increments("id").primary();
- table.string("name").default("").unique();
- table.string("title").default("");
- table.string("domain").default("");
+ table.string("name").defaultTo("").unique();
+ table.string("title").defaultTo("");
+ table.string("domain").defaultTo("");
table.date("breach_date").notNullable();
table.timestamp("added_date");
table.timestamp("modified_date").defaultTo(knex.fn.now());
table.integer("pwn_count").defaultTo(0);
- table.text("description").default("");
- table.string("logo_path").default("");
+ table.text("description").defaultTo("");
+ table.string("logo_path").defaultTo("");
table.specificType("data_classes", "character varying(255)[]");
table.boolean("is_verified").defaultTo(false);
table.boolean("is_fabricated").defaultTo(false);
@@ -24,6 +28,10 @@ export function up(knex) {
});
}
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise }
+ */
export function down(knex) {
return knex.schema.dropTableIfExists("breaches");
}
diff --git a/src/db/migrations/20230322233844_add-db-migration-processing.js b/src/db/migrations/20230322233844_add-db-migration-processing.js
index b1a1d0bd5f0..ddf3eae13d0 100644
--- a/src/db/migrations/20230322233844_add-db-migration-processing.js
+++ b/src/db/migrations/20230322233844_add-db-migration-processing.js
@@ -2,6 +2,10 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise }
+ */
export function up(knex) {
return knex.schema.table("subscribers", (table) => {
table.boolean("db_migration_1");
@@ -9,6 +13,10 @@ export function up(knex) {
});
}
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise }
+ */
export function down(knex) {
return knex.schema.table("subscribers", (table) => {
table.dropColumn("db_migration_1");
diff --git a/src/db/migrations/20230618104332_feature_flags.js b/src/db/migrations/20230618104332_feature_flags.js
index 28f1cc9ba56..fc413ebe635 100644
--- a/src/db/migrations/20230618104332_feature_flags.js
+++ b/src/db/migrations/20230618104332_feature_flags.js
@@ -2,11 +2,15 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise }
+ */
export function up(knex) {
return knex.schema.createTable("feature_flags", (table) => {
table.string("name").primary().unique();
table.boolean("is_enabled").defaultTo(false);
- table.text("description").default("");
+ table.text("description").defaultTo("");
table.specificType("dependencies", "character varying(255)[]");
table.specificType("allow_list", "character varying(255)[]");
table.specificType("wait_list", "character varying(255)[]");
@@ -17,7 +21,10 @@ export function up(knex) {
table.string("owner");
});
}
-
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise }
+ */
export function down(knex) {
return knex.schema.dropTableIfExists("feature_flags");
}
diff --git a/src/db/migrations/20230623072741_add_unique_constraint_onerep_profile_id.js b/src/db/migrations/20230623072741_add_unique_constraint_onerep_profile_id.js
index ece57f0121c..018b6461aff 100644
--- a/src/db/migrations/20230623072741_add_unique_constraint_onerep_profile_id.js
+++ b/src/db/migrations/20230623072741_add_unique_constraint_onerep_profile_id.js
@@ -18,6 +18,6 @@ export function up(knex) {
*/
export function down(knex) {
return knex.schema.table("subscribers", (table) => {
- table.dropUnique("onerep_profile_id");
+ table.dropUnique(["onerep_profile_id"]);
});
}
diff --git a/src/db/migrations/20230703010356_add-onerep-profiles-table.js b/src/db/migrations/20230703010356_add-onerep-profiles-table.js
index 50c779cbeb2..41486da7b0f 100644
--- a/src/db/migrations/20230703010356_add-onerep-profiles-table.js
+++ b/src/db/migrations/20230703010356_add-onerep-profiles-table.js
@@ -2,6 +2,10 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise }
+ */
export function up(knex) {
return knex.schema.createTable("onerep_profiles", (table) => {
table.increments("id").primary();
@@ -9,9 +13,21 @@ export function up(knex) {
.integer("onerep_profile_id")
.references("subscribers.onerep_profile_id")
.nullable();
+ // @ts-ignore TODO: The type Knex.CreateTableBuilder is missing `varchar`:
+ // https://github.com/knex/knex/blob/master/types/index.d.ts#L2420
+ // The method is implemented, but the method `string` is recommended.
table.varchar("first_name");
+ // @ts-ignore TODO: The type Knex.CreateTableBuilder is missing `varchar`:
+ // https://github.com/knex/knex/blob/master/types/index.d.ts#L2420
+ // The method is implemented, but the method `string` is recommended.
table.varchar("last_name");
+ // @ts-ignore TODO: The type Knex.CreateTableBuilder is missing `varchar`:
+ // https://github.com/knex/knex/blob/master/types/index.d.ts#L2420
+ // The method is implemented, but the method `string` is recommended.
table.varchar("city_name");
+ // @ts-ignore TODO: The type Knex.CreateTableBuilder is missing `varchar`:
+ // https://github.com/knex/knex/blob/master/types/index.d.ts#L2420
+ // The method is implemented, but the method `string` is recommended.
table.varchar("state_code");
table.date("date_of_birth");
table.timestamp("created_at").defaultTo(knex.fn.now());
diff --git a/src/db/migrations/20230711034311_remove_temp_migration_col.js b/src/db/migrations/20230711034311_remove_temp_migration_col.js
index cda60093b7c..1b34fb6fdec 100644
--- a/src/db/migrations/20230711034311_remove_temp_migration_col.js
+++ b/src/db/migrations/20230711034311_remove_temp_migration_col.js
@@ -6,7 +6,6 @@
* @param { import("knex").Knex } knex
* @returns { Promise }
*/
-
export async function up(knex) {
if (await knex.schema.hasColumn("subscribers", "db_migration_1")) {
await knex.schema.alterTable("subscribers", (table) => {
@@ -21,6 +20,10 @@ export async function up(knex) {
}
}
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise }
+ */
export async function down(knex) {
if (true === (await knex.schema.hasColumn("subscribers", "db_migration_1"))) {
console.log("do nothing for db_migration_1");
diff --git a/src/db/migrations/20230811154502_add_onerep_scan_reason.js b/src/db/migrations/20230811154502_add_onerep_scan_reason.js
index 5f3d99c455a..2f11f0d5dc7 100644
--- a/src/db/migrations/20230811154502_add_onerep_scan_reason.js
+++ b/src/db/migrations/20230811154502_add_onerep_scan_reason.js
@@ -12,6 +12,10 @@ export function up(knex) {
});
}
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise }
+ */
export function down(knex) {
return knex.schema.table("onerep_scans", (table) => {
table.dropColumn("onerep_scan_reason");
diff --git a/src/db/migrations/20230907143204_add_onerep_scanresults_table.js b/src/db/migrations/20230907143204_add_onerep_scanresults_table.js
index 8c7c4acd67d..93e3fceb125 100644
--- a/src/db/migrations/20230907143204_add_onerep_scanresults_table.js
+++ b/src/db/migrations/20230907143204_add_onerep_scanresults_table.js
@@ -55,28 +55,32 @@ export async function up(knex) {
const scanResultRows = scanRows
.map((scan) => {
return (
- scan.onerep_scan_results?.data.map((scanResult) => {
- const rowToInsert = {
- onerep_scan_result_id: scanResult.id,
- onerep_scan_id: scan.onerep_scan_id,
- link: scanResult.link,
- age:
- typeof scanResult.age === "string"
- ? Number.parseInt(scanResult.age, 10)
- : null,
- data_broker: scanResult.data_broker,
- data_broker_id: scanResult.data_broker_id,
- emails: JSON.stringify(scanResult.emails),
- phones: JSON.stringify(scanResult.phones),
- addresses: JSON.stringify(scanResult.addresses),
- relatives: JSON.stringify(scanResult.relatives),
- first_name: scanResult.first_name,
- middle_name: scanResult.middle_name,
- last_name: scanResult.last_name,
- status: scanResult.status,
- };
- return rowToInsert;
- }) ?? []
+ scan.onerep_scan_results?.data.map(
+ (
+ /** @type {import("knex/types/tables").OnerepScanResultRow} */ scanResult,
+ ) => {
+ const rowToInsert = {
+ onerep_scan_result_id: scanResult.id,
+ onerep_scan_id: scan.onerep_scan_id,
+ link: scanResult.link,
+ age:
+ typeof scanResult.age === "string"
+ ? Number.parseInt(scanResult.age, 10)
+ : null,
+ data_broker: scanResult.data_broker,
+ data_broker_id: scanResult.data_broker_id,
+ emails: JSON.stringify(scanResult.emails),
+ phones: JSON.stringify(scanResult.phones),
+ addresses: JSON.stringify(scanResult.addresses),
+ relatives: JSON.stringify(scanResult.relatives),
+ first_name: scanResult.first_name,
+ middle_name: scanResult.middle_name,
+ last_name: scanResult.last_name,
+ status: scanResult.status,
+ };
+ return rowToInsert;
+ },
+ ) ?? []
);
})
.flat();
@@ -100,6 +104,6 @@ export async function down(knex) {
});
await knex.schema.dropTable("onerep_scan_results");
await knex.schema.alterTable("onerep_scans", (table) => {
- table.dropUnique("onerep_scan_id");
+ table.dropUnique(["onerep_scan_id"]);
});
}
diff --git a/src/db/migrations/20230921132056_add_status_column.js b/src/db/migrations/20230921132056_add_status_column.js
index 773b3e85fc4..58e80b72237 100644
--- a/src/db/migrations/20230921132056_add_status_column.js
+++ b/src/db/migrations/20230921132056_add_status_column.js
@@ -10,6 +10,7 @@ export async function up(knex) {
await knex.schema.alterTable("onerep_scans", (table) => {
table.string("onerep_scan_status");
});
+ // @ts-ignore TODO: Fix type error.
await knex("onerep_scans").update({ onerep_scan_status: "finished" });
await knex.schema.alterTable("onerep_scans", (table) => {
table.dropNullable("onerep_scan_status");
diff --git a/src/db/migrations/20231102024624_add_unique_index_to_scan_results_id.js b/src/db/migrations/20231102024624_add_unique_index_to_scan_results_id.js
index 513ae82c739..be5a115b3e9 100644
--- a/src/db/migrations/20231102024624_add_unique_index_to_scan_results_id.js
+++ b/src/db/migrations/20231102024624_add_unique_index_to_scan_results_id.js
@@ -24,6 +24,6 @@ export async function up(knex) {
*/
export function down(knex) {
return knex.schema.table("onerep_scan_results", (table) => {
- table.dropUnique("onerep_scan_result_id");
+ table.dropUnique(["onerep_scan_result_id"]);
});
}
diff --git a/src/db/migrations/20231220015816_onerep_stats.js b/src/db/migrations/20231220015816_onerep_stats.js
index 65261c454a0..a7c57885ec3 100644
--- a/src/db/migrations/20231220015816_onerep_stats.js
+++ b/src/db/migrations/20231220015816_onerep_stats.js
@@ -2,6 +2,10 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise }
+ */
export async function up(knex) {
return knex.schema.createTable("stats", (table) => {
table.increments("id").primary();
diff --git a/src/db/migrations/20240108008813_marketing_attributions.js b/src/db/migrations/20240108008813_marketing_attributions.js
index e4d6bfc321f..a7f0c474985 100644
--- a/src/db/migrations/20240108008813_marketing_attributions.js
+++ b/src/db/migrations/20240108008813_marketing_attributions.js
@@ -2,6 +2,10 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise }
+ */
export async function up(knex) {
return knex.schema.createTable("attributions", (table) => {
table.increments("id").primary();
diff --git a/src/db/migrations/20240408161125_add_monthly_report_column.js b/src/db/migrations/20240408161125_add_monthly_report_column.js
index a07cfe85bc2..a7e7d6997b8 100644
--- a/src/db/migrations/20240408161125_add_monthly_report_column.js
+++ b/src/db/migrations/20240408161125_add_monthly_report_column.js
@@ -2,6 +2,10 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise }
+ */
export function up(knex) {
return knex.schema.table("subscribers", (table) => {
table.dropColumn("monthly_email_optout");
@@ -11,6 +15,10 @@ export function up(knex) {
});
}
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise }
+ */
export function down(knex) {
return knex.schema.table("subscribers", (table) => {
table.boolean("monthly_email_optout");
diff --git a/src/db/migrations/20240423150332_add_suffix_and_middle_name_to_onerep_profile_table.js b/src/db/migrations/20240423150332_add_suffix_and_middle_name_to_onerep_profile_table.js
index 1560a51c864..276af364f50 100644
--- a/src/db/migrations/20240423150332_add_suffix_and_middle_name_to_onerep_profile_table.js
+++ b/src/db/migrations/20240423150332_add_suffix_and_middle_name_to_onerep_profile_table.js
@@ -2,9 +2,19 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise }
+ */
export function up(knex) {
return knex.schema.table("onerep_profiles", (table) => {
+ // @ts-ignore TODO: The type Knex.CreateTableBuilder is missing `varchar`:
+ // https://github.com/knex/knex/blob/master/types/index.d.ts#L2420
+ // The method is implemented, but the method `string` is recommended.
table.varchar("name_suffix").after("onerep_profile_id");
+ // @ts-ignore TODO: The type Knex.CreateTableBuilder is missing `varchar`:
+ // https://github.com/knex/knex/blob/master/types/index.d.ts#L2420
+ // The method is implemented, but the method `string` is recommended.
table.varchar("middle_name").after("first_name");
});
}
diff --git a/src/db/migrations/20240604053111_subscriber_coupons.js b/src/db/migrations/20240604053111_subscriber_coupons.js
index f83918d7444..90ed098a153 100644
--- a/src/db/migrations/20240604053111_subscriber_coupons.js
+++ b/src/db/migrations/20240604053111_subscriber_coupons.js
@@ -2,6 +2,10 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise }
+ */
export async function up(knex) {
return knex.schema.createTable("subscriber_coupons", (table) => {
table.increments("id").primary();
diff --git a/src/db/migrations/20240606111238_add_subscriber_sign_in_count.js b/src/db/migrations/20240606111238_add_subscriber_sign_in_count.js
index be17be36e1a..57ffbbc151d 100644
--- a/src/db/migrations/20240606111238_add_subscriber_sign_in_count.js
+++ b/src/db/migrations/20240606111238_add_subscriber_sign_in_count.js
@@ -2,12 +2,20 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise }
+ */
export function up(knex) {
return knex.schema.table("subscribers", (table) => {
table.integer("sign_in_count").defaultTo(0);
});
}
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise }
+ */
export function down(knex) {
return knex.schema.table("subscribers", (table) => {
table.dropColumn("sign_in_count");
diff --git a/src/db/migrations/20240610150332_add_optout_attempts_to_onerep_scan_results_table.js b/src/db/migrations/20240610150332_add_optout_attempts_to_onerep_scan_results_table.js
index 1e5302329c2..cb2757e9368 100644
--- a/src/db/migrations/20240610150332_add_optout_attempts_to_onerep_scan_results_table.js
+++ b/src/db/migrations/20240610150332_add_optout_attempts_to_onerep_scan_results_table.js
@@ -2,6 +2,10 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise }
+ */
export function up(knex) {
return knex.schema.table("onerep_scan_results", (table) => {
table.integer("optout_attempts").after("status").nullable();
diff --git a/src/db/migrations/20240702102931_add_fxa_expiry_to_subscribers.js b/src/db/migrations/20240702102931_add_fxa_expiry_to_subscribers.js
index 780e7b5cb62..48bd044546b 100644
--- a/src/db/migrations/20240702102931_add_fxa_expiry_to_subscribers.js
+++ b/src/db/migrations/20240702102931_add_fxa_expiry_to_subscribers.js
@@ -2,6 +2,10 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise }
+ */
export function up(knex) {
return knex.schema.table("subscribers", (table) => {
table.timestamp("fxa_session_expiry").after("fxa_access_token").nullable();
diff --git a/src/db/migrations/20240715115031_qa_custom_breaches.js b/src/db/migrations/20240715115031_qa_custom_breaches.js
index c097b280bff..2bf419ac9c1 100644
--- a/src/db/migrations/20240715115031_qa_custom_breaches.js
+++ b/src/db/migrations/20240715115031_qa_custom_breaches.js
@@ -2,6 +2,10 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise }
+ */
export function up(knex) {
// camel case for easier insertion into table
return knex.schema.createTable("qa_custom_breaches", (table) => {
diff --git a/src/db/migrations/20240822032133_subscriber_email_preferences.js b/src/db/migrations/20240822032133_subscriber_email_preferences.js
index 4c575c2684d..3d14bff92d2 100644
--- a/src/db/migrations/20240822032133_subscriber_email_preferences.js
+++ b/src/db/migrations/20240822032133_subscriber_email_preferences.js
@@ -2,6 +2,10 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise }
+ */
export async function up(knex) {
await knex.schema.createTable(
"subscriber_email_preferences",
diff --git a/src/db/migrations/20241105115743_add_data_brokers.js b/src/db/migrations/20241105115743_add_data_brokers.js
index 0b5d050b262..28105e24da3 100644
--- a/src/db/migrations/20241105115743_add_data_brokers.js
+++ b/src/db/migrations/20241105115743_add_data_brokers.js
@@ -2,6 +2,10 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise }
+ */
export async function up(knex) {
return knex.schema.createTable("onerep_data_brokers", (table) => {
table.increments("id").primary();
@@ -13,6 +17,10 @@ export async function up(knex) {
});
}
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise }
+ */
export async function down(knex) {
return knex.schema.dropTable("onerep_data_brokers");
}
diff --git a/src/db/migrations/20250115032133_subscriber_churns.js b/src/db/migrations/20250115032133_subscriber_churns.js
index 561314f4e88..3914d2736ff 100644
--- a/src/db/migrations/20250115032133_subscriber_churns.js
+++ b/src/db/migrations/20250115032133_subscriber_churns.js
@@ -2,6 +2,10 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise }
+ */
export async function up(knex) {
await knex.schema.createTable("subscriber_churns", function (table) {
table.increments("id").primary();
diff --git a/src/db/migrations/20250204102945_add_last_optout_at.js b/src/db/migrations/20250204102945_add_last_optout_at.js
index 8429cc2f5ee..5e64e0611ae 100644
--- a/src/db/migrations/20250204102945_add_last_optout_at.js
+++ b/src/db/migrations/20250204102945_add_last_optout_at.js
@@ -2,6 +2,10 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise }
+ */
export async function up(knex) {
await knex.schema.table("onerep_scan_results", (table) => {
table.timestamp("last_optout_at").after("optout_attempts").nullable();
diff --git a/src/scripts/build/checkNodeVersionAlignment.js b/src/scripts/build/checkNodeVersionAlignment.js
index e41237796a2..5a106e6d543 100644
--- a/src/scripts/build/checkNodeVersionAlignment.js
+++ b/src/scripts/build/checkNodeVersionAlignment.js
@@ -17,26 +17,38 @@ import { fileURLToPath } from "node:url";
*/
const __dirname = dirname(fileURLToPath(import.meta.url));
+/**
+ * @param {string} path - File path
+ * @returns {Promise} File content
+ */
const load = (path) => readFile(resolve(__dirname, "../../../", path), "utf-8");
const packageJson = JSON.parse(await load("package.json"));
const lockFile = JSON.parse(await load("package-lock.json"));
-const dockerFileNodeVersion = (await load("Dockerfile"))
- .split("\n")
- .find((line) => line.startsWith("FROM node:"))
- .split("FROM node:")[1]
- .split("-alpine")[0];
+const dockerFileNodeVersion =
+ (
+ (await load("Dockerfile"))
+ .split("\n")
+ .find((line) => line.startsWith("FROM node:")) ?? ""
+ )
+ .split("FROM node:")[1]
+ ?.split("-alpine")[0] ?? "default-value"; // Provide a safe fallback value
+
// Yes, we're assuming `netlify.toml` to contain a line in exactly this format:
// environment = { NODE_VERSION = "20.12.0", NPM_VERSION = "10.2.4" }
-const netlifyNodeVersion = (await load("netlify.toml"))
- .split("\n")
- .find((line) => line.includes('NODE_VERSION = "'))
+const netlifyNodeVersion = (
+ (await load("netlify.toml"))
+ .split("\n")
+ .find((line) => line.includes('NODE_VERSION = "')) ?? ""
+)
.split('NODE_VERSION = "')[1]
.split('", NPM_VERSION')[0];
-const esbuildVersion = (await load("esbuild.cronjobs.js"))
- .split("\n")
- .find((line) => line.includes("target:"))
+const esbuildVersion = (
+ (await load("esbuild.cronjobs.js"))
+ .split("\n")
+ .find((line) => line.includes("target:")) ?? ""
+)
.split('"node')[1]
.split('",')[0];
@@ -59,10 +71,19 @@ const ghaVersions = ghaWorkflows.flatMap(([filename, contents]) => {
]);
});
+/**
+ * @param {string} version - The full version string
+ * @returns {string} The minor version
+ */
const getMinorOnly = (version) => {
const versionParts = version.split(".");
return `${versionParts[0]}.${versionParts[1]}`;
};
+
+/**
+ * @param {string} source - The file to check.
+ * @param {string} version - The reference Node version.
+ */
const checkVersion = (source, version) => {
const voltaVersion = packageJson.volta.node;
if (getMinorOnly(voltaVersion) !== getMinorOnly(version)) {
diff --git a/src/scripts/build/getAutoCompleteLocations.js b/src/scripts/build/getAutoCompleteLocations.js
index efc19301bfe..7c4e36498ab 100644
--- a/src/scripts/build/getAutoCompleteLocations.js
+++ b/src/scripts/build/getAutoCompleteLocations.js
@@ -15,6 +15,10 @@ if (!existsSync(dataPath)) {
const fetchUrl = `https://s3.amazonaws.com/${process.env.S3_BUCKET}/autocomplete/locationAutocompleteData.json`;
console.debug({ fetchUrl });
const { body } = await fetch(fetchUrl);
+ if (!body) {
+ throw new Error(`Failed to fetch: ${fetchUrl}`);
+ }
+ // @ts-ignore If body is `null` we are already throwing an error above.
await finished(Readable.fromWeb(body).pipe(stream));
} catch (e) {
console.error(e);
diff --git a/src/scripts/build/gleanTypes.js b/src/scripts/build/gleanTypes.js
index 8b46a9e43d2..5a7db3d7102 100644
--- a/src/scripts/build/gleanTypes.js
+++ b/src/scripts/build/gleanTypes.js
@@ -27,6 +27,7 @@ async function generateTypeMap() {
(filename) => filename.endsWith(".ts") && filename !== MAP_FILE_NAME,
)
.map((filename) => filename.replace(".ts", ""));
+ /** @type {Array<[string, Array<[string, string]>]>} */
const typeMapByModule = await Promise.all(
moduleNames.map(async (moduleName) => [
moduleName,
@@ -64,9 +65,9 @@ async function generateTypeMap() {
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// AUTOGENERATED BY the \`build-glean-types\` script. DO NOT EDIT. DO NOT COMMIT.
-
+
${eventTypeDefsString}
-
+
export type GleanMetricMap = {\n${typeMapString}\n};
`;
@@ -75,13 +76,13 @@ export type GleanMetricMap = {\n${typeMapString}\n};
/**
* @param {string} moduleName
+ * @return {Promise>}
*/
async function getTypeMap(moduleName) {
const filePath = resolve(GLEAN_GENERATED_DIR, `${moduleName}.ts`);
const fileContents = await fs.readFile(filePath, "utf-8");
const eventNameAndTypeRegex =
/export const (.+?) = new EventMetricType<(.+?)>/gs;
- /** @type {Array<[string, string, string]>} */
const matches = Array.from(fileContents.matchAll(eventNameAndTypeRegex));
return matches.map(([_match, eventName, eventTypeDef]) => [
eventName,
diff --git a/src/scripts/build/nimbusTypes.js b/src/scripts/build/nimbusTypes.js
index ef920bd783b..0e8f1918d71 100644
--- a/src/scripts/build/nimbusTypes.js
+++ b/src/scripts/build/nimbusTypes.js
@@ -11,7 +11,8 @@ run();
/**
* See https://experimenter.info/fml-spec/#additional-types
*
- * @typedef {"String" | "Boolean" | "Int" | "Text" | "Image" | `Option<${Type}>` | `List<${Type}>` | `Map<${Type}, ${Type}>`} Type
+ * @typedef { "String" | "Boolean" | "Int" | "Text" | "Image" } BaseType
+ * @typedef { BaseType | `Option<${BaseType}>` | `List<${BaseType}>` | `Map<${BaseType}, ${BaseType}>` } Type
*/
/**
* @typedef {"local" | "staging" | "production"} Channel
@@ -23,7 +24,7 @@ run();
* description: string;
* type: Type;
* default: unknown;
- * string-alias?: string;
+ * "string-alias"?: string;
* }
* >} Variables
*/
@@ -36,7 +37,7 @@ run();
* variables: Variables;
* defaults?: Array<{
* channel: Channel;
- * values: Record;
+ * value: Record;
* }>;
* }>;
* enums?: Record {
- return ` "${variableName}": ${getType(nimbusConfig.features[featureId].variables[variableName].type)};\n`;
+ return ` "${variableName}": ${getTypeScriptType(nimbusConfig.features[featureId].variables[variableName].type)};\n`;
});
return ` "${featureId}": {\n${variableDefs.join("")} };\n`;
});
@@ -208,15 +209,15 @@ function getStringAliases(nimbusConfig) {
/**
* @param {NimbusConfig} nimbusConfig
- * @returns string
+ * @returns {string}
*/
function getTypeAliases(nimbusConfig) {
const objects = nimbusConfig.objects ?? {};
const objectDefs = Object.keys(objects).map((typeAlias) => {
- const propertyNames = Object.keys(nimbusConfig.objects[typeAlias].fields);
+ const propertyNames = Object.keys(objects[typeAlias].fields);
const propertyDefs = propertyNames.map((propertyName) => {
// TODO: Add descriptions as TSDoc comment?
- return ` "${propertyName}": ${getType(nimbusConfig.objects[typeAlias].fields[propertyName].type)};\n`;
+ return ` "${propertyName}": ${getTypeScriptType(objects[typeAlias].fields[propertyName].type)};\n`;
});
// TODO: Add description as TSDoc comment?
return `type ${typeAlias} = {\n${propertyDefs.join("")}};\n`;
@@ -225,7 +226,7 @@ function getTypeAliases(nimbusConfig) {
const enums = nimbusConfig.enums ?? {};
const enumDefs = Object.keys(enums).map((typeAlias) => {
// TODO: Add values as TSDoc comment?
- const unionOfStrings = Object.keys(nimbusConfig.enums[typeAlias].variants)
+ const unionOfStrings = Object.keys(enums[typeAlias].variants)
.map((variant) => `"${variant}"`)
.join(" | ");
return `type ${typeAlias} = ${unionOfStrings};`;
@@ -241,9 +242,9 @@ function getTypeAliases(nimbusConfig) {
/**
* @param {string} type
- * @returns string
+ * @returns {string} type
*/
-function getType(type) {
+function getTypeScriptType(type) {
if (type === "String") {
return "string";
}
@@ -258,16 +259,16 @@ function getType(type) {
}
if (type.startsWith("Option<")) {
const t = type.substring("Option<".length, type.length - 1).trim();
- return `null | ${getType(t)}`;
+ return `null | ${getTypeScriptType(t)}`;
}
if (type.startsWith("List<")) {
const t = type.substring("List<".length, type.length - 1).trim();
- return `Array<${getType(t)}>`;
+ return `Array<${getTypeScriptType(t)}>`;
}
if (type.startsWith("Map<")) {
const kv = type.substring("Map<".length, type.length - 1).trim();
const [k, v] = kv.split(",").map((part) => part.trim());
- return `Record<${getType(k)}, ${getType(v)}>`;
+ return `Record<${getTypeScriptType(k)}, ${getTypeScriptType(v)}>`;
}
return type;
diff --git a/src/scripts/build/uploadAutoCompleteLocations.js b/src/scripts/build/uploadAutoCompleteLocations.js
index ad215599064..76508fd98e2 100644
--- a/src/scripts/build/uploadAutoCompleteLocations.js
+++ b/src/scripts/build/uploadAutoCompleteLocations.js
@@ -25,7 +25,6 @@ import {
import Sentry from "@sentry/nextjs";
import os from "os";
import path from "path";
-import fs from "fs";
import AdmZip from "adm-zip";
import { uploadToS3 } from "../../utils/s3.js";
@@ -61,6 +60,12 @@ const allowedFeatureCodes = [
"PPLL",
];
+/**
+ * Logs the progress of a task.
+ *
+ * @param {number} currentCount - The current count.
+ * @param {number} totalCount - The total count.
+ */
function logProgress(currentCount, totalCount) {
const progress = Math.round(((currentCount + 1) / totalCount) * 100);
process.stdout.write(
@@ -68,6 +73,14 @@ function logProgress(currentCount, totalCount) {
);
}
+/**
+ * Writes the content of a remote file to a local write stream.
+ *
+ * @param {Object} param - The parameters for the function.
+ * @param {string} param.url - The URL of the remote file.
+ * @param {import("fs").WriteStream} param.writeStream - The write stream the file content is written to.
+ * @returns {Promise} Resolves when the file has been written.
+ */
function writeFromRemoteFile({ url, writeStream }) {
return new Promise((resolve, reject) => {
https.get(url, (res) => {
@@ -82,6 +95,15 @@ function writeFromRemoteFile({ url, writeStream }) {
});
}
+/**
+ * Fetches the remote archive.
+ *
+ * @param {Object} param - The parameters for the function.
+ * @param {string} param.remoteArchiveUrl - The URL of the remote archive.
+ * @param {string} param.localDownloadPath - The local path where the file will be downloaded.
+ * @param {string} param.localExtractionPath - The local path where the archive will be extracted.
+ * @returns {Promise} Resolves when the extraction is complete.
+ */
async function fetchRemoteArchive({
remoteArchiveUrl,
localDownloadPath,
@@ -100,7 +122,7 @@ async function fetchRemoteArchive({
const zip = new AdmZip(localDownloadPath);
await new Promise((resolve, reject) => {
zip.extractAllToAsync(localExtractionPath, true, false, (error) =>
- error ? reject(error) : resolve(),
+ error ? reject(error) : resolve(localExtractionPath),
);
});
}
@@ -185,7 +207,7 @@ try {
return null;
})
- .filter((alternateName) => alternateName);
+ .filter((alternateName) => alternateName !== null);
console.info("Reading file: Hierarchy");
const hierachyData = readFileSync(
@@ -211,7 +233,12 @@ try {
const locationDataRows = locationData.split("\n");
const locationRowCount = locationDataRows.length;
const locationDataPopulated = locationDataRows.reduce(
- (relevantLocations, location, rowIndex) => {
+ (
+ /** @type {Array} */
+ relevantLocations,
+ location,
+ rowIndex,
+ ) => {
logProgress(rowIndex, locationRowCount);
const [
@@ -293,10 +320,30 @@ try {
return false;
}
- return locationDataPopulated.some((location) => {
+ return locationDataRows.some((location) => {
+ const [
+ geonameId,
+ _name,
+ _asciiname,
+ _alternatenames,
+ _latitude,
+ _longitude,
+ featureClass,
+ _featureCode,
+ _countryCode,
+ _cc2,
+ _admin1Code,
+ _admin2Code,
+ _admin3Code,
+ _admin4Code,
+ _population,
+ _elevation,
+ _dem,
+ _timezone,
+ _modificationDate,
+ ] = location.split("\t"); // lines are tab delimited
return (
- location.id === parentId &&
- location.featureClass === allowedFeatureClass
+ geonameId === parentId && featureClass === allowedFeatureClass
);
});
},
@@ -324,12 +371,12 @@ try {
};
writeFileSync(LOCATIONS_DATA_FILE, JSON.stringify(locationDataFinal));
- let readStream = fs.createReadStream(LOCATIONS_DATA_FILE);
+ const fileBuffer = readFileSync(LOCATIONS_DATA_FILE);
if (process.argv.includes("--skip-upload")) {
console.debug("Skipping S3 upload");
} else {
- await uploadToS3(`autocomplete/${LOCATIONS_DATA_FILE}`, readStream);
+ await uploadToS3(`autocomplete/${LOCATIONS_DATA_FILE}`, fileBuffer);
}
if (CLEANUP_TMP_DATA_AFTER_FINISHED) {
diff --git a/src/scripts/loadtest/hibp.js b/src/scripts/loadtest/hibp.js
index 98e65c09b7a..4ed7be27f9c 100644
--- a/src/scripts/loadtest/hibp.js
+++ b/src/scripts/loadtest/hibp.js
@@ -14,9 +14,8 @@
import { post } from "k6/http";
import crypto from "k6/crypto";
-// k6 exposes environment variables via the __ENV variable:
+// @ts-ignore: k6 exposes environment variables via the __ENV variable:
// https://grafana.com/docs/k6/latest/using-k6/environment-variables/
-/** @type {typeof process.env} */
const envVars = __ENV;
const HIBP_NOTIFY_TOKEN = envVars.HIBP_NOTIFY_TOKEN;
@@ -48,7 +47,7 @@ const mockedBreachedEmailHash =
export const run = () => {
/** @type {import("../../app/api/v1/hibp/notify/route").PostHibpNotificationRequestBody} */
- let data = {
+ const data = {
breachName: "ApexSMS",
// NOTE: modify this hash range if you want to receive email to specific test account(s).
// This example should only email an address that is a sha1 hash for 1c48923da9f6f17165711712d11bc104087444cc.
@@ -58,7 +57,7 @@ export const run = () => {
};
// Using a JSON string as body
- let res = post(url, JSON.stringify(data), {
+ const res = post(url, JSON.stringify(data), {
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${HIBP_NOTIFY_TOKEN}`,
@@ -67,10 +66,12 @@ export const run = () => {
try {
const result = res.json();
+ // @ts-ignore TODO: Add `PostHibpNotificationResponseBody` type to `src/app/api/v1/hibp/notify/route`, and use it.
if (result.success !== true) {
throw new Error(`Non-success result: ${JSON.stringify(result)}`);
}
} catch {
+ // @ts-ignore TODO: Add type correct type for res.
throw new Error(`Failed to parse result: ${res.status}, ${res.text}`);
}
};
diff --git a/tsconfig.json b/tsconfig.json
index c7cdf9e58d7..0fa2f058886 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,10 +1,13 @@
{
"include": [
- "next-env.d.ts",
"**/*.ts",
"**/*.tsx",
".next/types/**/*.ts",
- "jest.setup.ts"
+ // JS files that are not yet migrated to TS.
+ "src/app/global-error.js",
+ "src/db/migrations/*.js",
+ "src/scripts/build/*.js",
+ "src/scripts/loadtest/hibp.js"
],
"compilerOptions": {
/* Visit https://aka.ms/tsconfig to read more about this file */
@@ -99,8 +102,5 @@
"skipLibCheck": true /* Skip type checking all .d.ts files. */,
"lib": ["dom", "dom.iterable", "esnext"]
},
- "exclude": [
- "node_modules/",
- "sentry.*.config.ts",
- ]
+ "exclude": ["node_modules"]
}