vr-models 1.0.57 → 1.0.58

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,71 @@
1
+ import { Model, InferAttributes, InferCreationAttributes, CreationOptional, NonAttribute, ModelStatic } from "vr-migrations";
2
+ import type { User } from "./user.models";
3
+ export declare const CONTACT_TYPES: readonly ["EMAIL", "PHONE", "WHATSAPP"];
4
+ export type ContactType = (typeof CONTACT_TYPES)[number];
5
+ export interface VerificationMetadata {
6
+ lastOtpSentAt?: Date;
7
+ otpAttempts?: number;
8
+ lastFailedAttemptAt?: Date;
9
+ isLocked?: boolean;
10
+ lockedUntil: Date | null;
11
+ carrier?: string;
12
+ countryCode?: string;
13
+ deactivatedAt?: Date | null;
14
+ deactivationReason?: string;
15
+ verificationToken?: string | null;
16
+ tokenExpiresAt?: Date | null;
17
+ }
18
+ export interface ContactAttributes {
19
+ id: string;
20
+ contactValue: string;
21
+ type: ContactType;
22
+ userId: string | null;
23
+ isVerified: boolean;
24
+ verifiedAt: Date | null;
25
+ isPrimary: boolean;
26
+ isActive: boolean;
27
+ otp: string | null;
28
+ otpExpiresAt: Date | null;
29
+ metadata: VerificationMetadata;
30
+ createdAt: Date;
31
+ updatedAt: Date;
32
+ user?: NonAttribute<User>;
33
+ }
34
+ export interface ContactCreationAttributes extends Omit<ContactAttributes, "id" | "createdAt" | "updatedAt" | "metadata"> {
35
+ id?: string;
36
+ metadata?: Partial<VerificationMetadata>;
37
+ }
38
+ export declare class Contact extends Model<InferAttributes<Contact>, InferCreationAttributes<Contact>> implements ContactAttributes {
39
+ id: CreationOptional<string>;
40
+ contactValue: string;
41
+ type: ContactType;
42
+ userId: CreationOptional<string | null>;
43
+ isVerified: CreationOptional<boolean>;
44
+ verifiedAt: CreationOptional<Date | null>;
45
+ isPrimary: CreationOptional<boolean>;
46
+ isActive: CreationOptional<boolean>;
47
+ otp: CreationOptional<string | null>;
48
+ otpExpiresAt: CreationOptional<Date | null>;
49
+ metadata: CreationOptional<VerificationMetadata>;
50
+ readonly createdAt: CreationOptional<Date>;
51
+ readonly updatedAt: CreationOptional<Date>;
52
+ user?: NonAttribute<User>;
53
+ static initialize(sequelize: any): void;
54
+ static associate(models: Record<string, ModelStatic<Model>>): void;
55
+ deactivate(reason?: string): Promise<void>;
56
+ reactivate(): Promise<void>;
57
+ markAsVerified(): Promise<void>;
58
+ isLocked(): boolean;
59
+ getRemainingLockTime(): number | null;
60
+ isExpired(): boolean;
61
+ getRemainingOTPTime(): number | null;
62
+ static findByContactValue(contactValue: string, type: ContactType): Promise<Contact | null>;
63
+ static findVerifiedByContactValue(contactValue: string, type: ContactType): Promise<Contact | null>;
64
+ static getUserContacts(userId: string): Promise<Contact[]>;
65
+ static getUserPrimaryContact(userId: string): Promise<Contact | null>;
66
+ static isContactAvailable(contactValue: string, type: ContactType): Promise<boolean>;
67
+ static cleanupExpiredOTPs(): Promise<void>;
68
+ getDisplayValue(): string;
69
+ getVerificationMethod(): string;
70
+ }
71
+ export type ContactModel = typeof Contact;
@@ -1,8 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.PhoneContact = void 0;
3
+ exports.Contact = exports.CONTACT_TYPES = void 0;
4
+ // src/models/contact.models.ts
4
5
  const vr_migrations_1 = require("vr-migrations");
5
- class PhoneContact extends vr_migrations_1.Model {
6
+ // ==================== CONTACT TYPES ====================
7
+ exports.CONTACT_TYPES = ["EMAIL", "PHONE", "WHATSAPP"];
8
+ class Contact extends vr_migrations_1.Model {
6
9
  // Static initialization method
7
10
  static initialize(sequelize) {
8
11
  this.init({
@@ -12,13 +15,13 @@ class PhoneContact extends vr_migrations_1.Model {
12
15
  primaryKey: true,
13
16
  allowNull: false,
14
17
  },
15
- phoneNumber: {
16
- type: vr_migrations_1.DataTypes.STRING(20),
18
+ contactValue: {
19
+ type: vr_migrations_1.DataTypes.STRING(255),
20
+ allowNull: false,
21
+ },
22
+ type: {
23
+ type: vr_migrations_1.DataTypes.ENUM("EMAIL", "PHONE", "WHATSAPP"),
17
24
  allowNull: false,
18
- unique: true,
19
- validate: {
20
- is: /^\+?[0-9]{10,15}$/,
21
- },
22
25
  },
23
26
  userId: {
24
27
  type: vr_migrations_1.DataTypes.UUID,
@@ -79,27 +82,47 @@ class PhoneContact extends vr_migrations_1.Model {
79
82
  },
80
83
  }, {
81
84
  sequelize,
82
- modelName: "PhoneContact",
83
- tableName: "phone_contacts",
85
+ modelName: "Contact",
86
+ tableName: "contacts",
84
87
  timestamps: true,
85
88
  freezeTableName: true,
89
+ validate: {
90
+ validContactValue() {
91
+ if (this.type === "EMAIL") {
92
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
93
+ if (!emailRegex.test(this.contactValue)) {
94
+ throw new Error("Invalid email address format");
95
+ }
96
+ }
97
+ else if (this.type === "PHONE" || this.type === "WHATSAPP") {
98
+ const phoneRegex = /^\+?[0-9]{10,15}$/;
99
+ if (!phoneRegex.test(this.contactValue)) {
100
+ throw new Error("Invalid phone number format");
101
+ }
102
+ }
103
+ },
104
+ },
86
105
  indexes: [
87
106
  {
88
107
  unique: true,
89
- fields: ["phoneNumber"],
90
- name: "phone_contacts_phone_number_unique",
108
+ fields: ["contactValue", "type"],
109
+ name: "contacts_unique_value_type_idx",
91
110
  },
92
111
  {
93
112
  fields: ["userId"],
94
- name: "phone_contacts_user_id_idx",
113
+ name: "contacts_user_id_idx",
114
+ },
115
+ {
116
+ fields: ["type"],
117
+ name: "contacts_type_idx",
95
118
  },
96
119
  {
97
120
  fields: ["isVerified", "isPrimary"],
98
- name: "phone_contacts_verified_primary_idx",
121
+ name: "contacts_verified_primary_idx",
99
122
  },
100
123
  {
101
124
  fields: ["otpExpiresAt"],
102
- name: "phone_contacts_otp_expiry_idx",
125
+ name: "contacts_otp_expiry_idx",
103
126
  },
104
127
  ],
105
128
  });
@@ -113,6 +136,9 @@ class PhoneContact extends vr_migrations_1.Model {
113
136
  onUpdate: "CASCADE",
114
137
  });
115
138
  }
139
+ // ===========================================================================
140
+ // INSTANCE METHODS
141
+ // ===========================================================================
116
142
  async deactivate(reason) {
117
143
  this.isActive = false;
118
144
  this.metadata = {
@@ -131,6 +157,13 @@ class PhoneContact extends vr_migrations_1.Model {
131
157
  };
132
158
  await this.save();
133
159
  }
160
+ async markAsVerified() {
161
+ this.isVerified = true;
162
+ this.verifiedAt = new Date();
163
+ this.otp = null;
164
+ this.otpExpiresAt = null;
165
+ await this.save();
166
+ }
134
167
  isLocked() {
135
168
  if (!this.metadata.isLocked)
136
169
  return false;
@@ -161,34 +194,37 @@ class PhoneContact extends vr_migrations_1.Model {
161
194
  const remaining = new Date(this.otpExpiresAt).getTime() - new Date().getTime();
162
195
  return Math.max(0, Math.ceil(remaining / 1000));
163
196
  }
164
- // Static methods
165
- static async findByPhoneNumber(phoneNumber) {
166
- return await this.findOne({
167
- where: { phoneNumber },
168
- });
169
- }
170
- static async findVerifiedByPhoneNumber(phoneNumber) {
197
+ // ===========================================================================
198
+ // STATIC METHODS
199
+ // ===========================================================================
200
+ static async findByContactValue(contactValue, type) {
171
201
  return await this.findOne({
172
- where: { phoneNumber, isVerified: true, isActive: true },
202
+ where: { contactValue, type },
173
203
  });
174
204
  }
175
- static async getUserPrimaryPhone(userId) {
205
+ static async findVerifiedByContactValue(contactValue, type) {
176
206
  return await this.findOne({
177
- where: { userId, isPrimary: true, isActive: true },
207
+ where: { contactValue, type, isVerified: true, isActive: true },
178
208
  });
179
209
  }
180
- static async getUserPhones(userId) {
210
+ static async getUserContacts(userId) {
181
211
  return await this.findAll({
182
212
  where: { userId, isActive: true },
183
213
  order: [
184
214
  ["isPrimary", "DESC"],
215
+ ["type", "ASC"],
185
216
  ["createdAt", "ASC"],
186
217
  ],
187
218
  });
188
219
  }
189
- static async isPhoneNumberAvailable(phoneNumber) {
220
+ static async getUserPrimaryContact(userId) {
221
+ return await this.findOne({
222
+ where: { userId, isPrimary: true, isActive: true },
223
+ });
224
+ }
225
+ static async isContactAvailable(contactValue, type) {
190
226
  const existing = await this.findOne({
191
- where: { phoneNumber, isVerified: true },
227
+ where: { contactValue, type, isVerified: true },
192
228
  });
193
229
  return !existing;
194
230
  }
@@ -200,5 +236,33 @@ class PhoneContact extends vr_migrations_1.Model {
200
236
  },
201
237
  });
202
238
  }
239
+ // ===========================================================================
240
+ // TYPE-SPECIFIC HELPERS
241
+ // ===========================================================================
242
+ getDisplayValue() {
243
+ if (this.type === "EMAIL") {
244
+ return this.contactValue;
245
+ }
246
+ else if (this.type === "PHONE" || this.type === "WHATSAPP") {
247
+ // Mask phone number
248
+ const phone = this.contactValue;
249
+ if (phone.length <= 4)
250
+ return phone;
251
+ return phone.slice(0, 3) + "****" + phone.slice(-3);
252
+ }
253
+ return this.contactValue;
254
+ }
255
+ getVerificationMethod() {
256
+ switch (this.type) {
257
+ case "EMAIL":
258
+ return "email";
259
+ case "PHONE":
260
+ return "sms";
261
+ case "WHATSAPP":
262
+ return "whatsapp";
263
+ default:
264
+ return "unknown";
265
+ }
266
+ }
203
267
  }
204
- exports.PhoneContact = PhoneContact;
268
+ exports.Contact = Contact;
@@ -12,5 +12,5 @@ export * from "./installment.models";
12
12
  export * from "./ban.models";
13
13
  export * from "./suspension.models";
14
14
  export * from "./appSpecs.models";
15
- export * from "./phoneContact.models";
16
- export type { UserModel, SecurityClearanceModel, ProductModel, PricingModel, PaymentModel, PaymentEventLogModel, IdempotencyRecordModel, EventLogModel, DevicePaymentPlanModel, DeviceModel, InstallmentModel, BanModel, SuspensionModel, AppSpecsModel, PhoneContactModel, } from "./types";
15
+ export * from "./contact.models";
16
+ export type { UserModel, SecurityClearanceModel, ProductModel, PricingModel, PaymentModel, PaymentEventLogModel, IdempotencyRecordModel, EventLogModel, DevicePaymentPlanModel, DeviceModel, InstallmentModel, BanModel, SuspensionModel, AppSpecsModel, ContactModel, } from "./types";
@@ -28,4 +28,4 @@ __exportStar(require("./installment.models"), exports);
28
28
  __exportStar(require("./ban.models"), exports);
29
29
  __exportStar(require("./suspension.models"), exports);
30
30
  __exportStar(require("./appSpecs.models"), exports);
31
- __exportStar(require("./phoneContact.models"), exports);
31
+ __exportStar(require("./contact.models"), exports);
@@ -11,5 +11,5 @@ export type { InstallmentModel } from "./installment.models";
11
11
  export type { BanModel } from "./ban.models";
12
12
  export type { SuspensionModel } from "./suspension.models";
13
13
  export type { AppSpecsModel } from "./appSpecs.models";
14
- export type { PhoneContactModel } from "./phoneContact.models";
14
+ export type { ContactModel } from "./contact.models";
15
15
  export type { PaymentEventLogModel } from "./paymentEventLog.models";
@@ -1,7 +1,8 @@
1
1
  import { Model, InferAttributes, InferCreationAttributes, CreationOptional, NonAttribute, ModelStatic } from "vr-migrations";
2
+ import type { Device } from "./device.models";
2
3
  import type { Payment } from "./payment.models";
3
4
  import type { SecurityClearance } from "./securityClearance.models";
4
- import type { PhoneContact } from "./phoneContact.models";
5
+ import type { Contact } from "./contact.models";
5
6
  import { Ban } from "./ban.models";
6
7
  import { Suspension } from "./suspension.models";
7
8
  import { DevicePaymentPlan } from "./devicePaymentPlan.models";
@@ -18,7 +19,6 @@ export interface UserAttributes {
18
19
  firstName: string;
19
20
  lastName: string;
20
21
  jacketId?: string | null;
21
- email?: string | null;
22
22
  password?: string | null;
23
23
  securityClearanceId: string;
24
24
  plateNumber?: string | null;
@@ -26,7 +26,7 @@ export interface UserAttributes {
26
26
  birthDate?: number | null;
27
27
  birthMonth?: number | null;
28
28
  birthYear?: number | null;
29
- primaryPhoneId: string | null;
29
+ primaryContactId: string | null;
30
30
  isActive: boolean;
31
31
  forgotPassword: boolean;
32
32
  isDeactivated: boolean;
@@ -37,25 +37,25 @@ export interface UserAttributes {
37
37
  createdAt: Date;
38
38
  payments?: Payment[];
39
39
  securityClearance?: SecurityClearance;
40
- primaryPhone?: PhoneContact;
41
- phones?: PhoneContact[];
40
+ primaryContact?: Contact;
41
+ contacts?: Contact[];
42
42
  bans?: Ban[];
43
43
  suspensions?: Suspension[];
44
+ devices?: Device[];
44
45
  }
45
- export interface UserCreationAttributes extends Omit<UserAttributes, "id" | "createdAt" | "isActive" | "forgotPassword" | "isDeactivated" | "tokenVersion" | "primaryPhoneId"> {
46
+ export interface UserCreationAttributes extends Omit<UserAttributes, "id" | "createdAt" | "isActive" | "forgotPassword" | "isDeactivated" | "tokenVersion" | "primaryContactId"> {
46
47
  id?: string;
47
48
  isActive?: boolean;
48
49
  forgotPassword?: boolean;
49
50
  isDeactivated?: boolean;
50
51
  tokenVersion?: number;
51
- primaryPhoneId?: string | null;
52
+ primaryContactId?: string | null;
52
53
  }
53
54
  export declare class User extends Model<InferAttributes<User>, InferCreationAttributes<User>> implements UserAttributes {
54
55
  id: CreationOptional<string>;
55
56
  firstName: string;
56
57
  lastName: string;
57
58
  jacketId: CreationOptional<string | null>;
58
- email: CreationOptional<string | null>;
59
59
  password: CreationOptional<string | null>;
60
60
  securityClearanceId: string;
61
61
  plateNumber: CreationOptional<string | null>;
@@ -63,7 +63,7 @@ export declare class User extends Model<InferAttributes<User>, InferCreationAttr
63
63
  birthDate: CreationOptional<number | null>;
64
64
  birthMonth: CreationOptional<number | null>;
65
65
  birthYear: CreationOptional<number | null>;
66
- primaryPhoneId: CreationOptional<string | null>;
66
+ primaryContactId: CreationOptional<string | null>;
67
67
  isActive: CreationOptional<boolean>;
68
68
  forgotPassword: CreationOptional<boolean>;
69
69
  isDeactivated: CreationOptional<boolean>;
@@ -75,8 +75,8 @@ export declare class User extends Model<InferAttributes<User>, InferCreationAttr
75
75
  payments?: NonAttribute<Payment[]>;
76
76
  paymentPlans?: NonAttribute<DevicePaymentPlan[]>;
77
77
  securityClearance?: NonAttribute<SecurityClearance>;
78
- primaryPhone?: NonAttribute<PhoneContact>;
79
- phones?: NonAttribute<PhoneContact[]>;
78
+ primaryContact?: NonAttribute<Contact>;
79
+ contacts?: NonAttribute<Contact[]>;
80
80
  bans?: NonAttribute<Ban[]>;
81
81
  suspensions?: NonAttribute<Suspension[]>;
82
82
  static initialize(sequelize: any): void;
@@ -85,7 +85,8 @@ export declare class User extends Model<InferAttributes<User>, InferCreationAttr
85
85
  updateLastLogin(): Promise<void>;
86
86
  deactivate(): Promise<void>;
87
87
  activate(): Promise<void>;
88
- hasVerifiedPhone(): Promise<boolean>;
88
+ getPrimaryVerifiedContact(): Promise<Contact | null>;
89
+ hasVerifiedContactType(type: "EMAIL" | "PHONE" | "WHATSAPP"): Promise<boolean>;
89
90
  getBirthDate(): Date | null;
90
91
  getAge(): number | null;
91
92
  }
@@ -5,8 +5,11 @@ exports.User = exports.GENDER_OPTIONS = void 0;
5
5
  const vr_migrations_1 = require("vr-migrations");
6
6
  // ==================== GENDER OPTIONS ====================
7
7
  exports.GENDER_OPTIONS = ["male", "female"];
8
+ // ==================== USER MODEL ====================
8
9
  class User extends vr_migrations_1.Model {
9
- // Static initialization method
10
+ // ===========================================================================
11
+ // INITIALIZATION
12
+ // ===========================================================================
10
13
  static initialize(sequelize) {
11
14
  this.init({
12
15
  id: {
@@ -27,11 +30,6 @@ class User extends vr_migrations_1.Model {
27
30
  allowNull: true,
28
31
  unique: true,
29
32
  },
30
- email: {
31
- type: vr_migrations_1.DataTypes.STRING(100),
32
- allowNull: true,
33
- unique: true,
34
- },
35
33
  password: {
36
34
  type: vr_migrations_1.DataTypes.STRING,
37
35
  allowNull: true,
@@ -73,7 +71,7 @@ class User extends vr_migrations_1.Model {
73
71
  max: new Date().getFullYear(),
74
72
  },
75
73
  },
76
- primaryPhoneId: {
74
+ primaryContactId: {
77
75
  type: vr_migrations_1.DataTypes.UUID,
78
76
  allowNull: true,
79
77
  },
@@ -125,7 +123,9 @@ class User extends vr_migrations_1.Model {
125
123
  freezeTableName: true,
126
124
  });
127
125
  }
128
- // Static association method
126
+ // ===========================================================================
127
+ // ASSOCIATIONS
128
+ // ===========================================================================
129
129
  static associate(models) {
130
130
  this.belongsTo(models.SecurityClearance, {
131
131
  foreignKey: "securityClearanceId",
@@ -133,15 +133,16 @@ class User extends vr_migrations_1.Model {
133
133
  onDelete: "RESTRICT",
134
134
  onUpdate: "CASCADE",
135
135
  });
136
- this.belongsTo(models.PhoneContact, {
137
- foreignKey: "primaryPhoneId",
138
- as: "primaryPhone",
136
+ // NEW: Contact associations (renamed from PhoneContact)
137
+ this.belongsTo(models.Contact, {
138
+ foreignKey: "primaryContactId",
139
+ as: "primaryContact",
139
140
  onDelete: "SET NULL",
140
141
  onUpdate: "CASCADE",
141
142
  });
142
- this.hasMany(models.PhoneContact, {
143
+ this.hasMany(models.Contact, {
143
144
  foreignKey: "userId",
144
- as: "phones",
145
+ as: "contacts",
145
146
  onDelete: "SET NULL",
146
147
  onUpdate: "CASCADE",
147
148
  });
@@ -170,7 +171,9 @@ class User extends vr_migrations_1.Model {
170
171
  onUpdate: "CASCADE",
171
172
  });
172
173
  }
173
- // Custom instance methods
174
+ // ===========================================================================
175
+ // CUSTOM INSTANCE METHODS
176
+ // ===========================================================================
174
177
  async softDelete(deletedBy, reason) {
175
178
  this.deletion = {
176
179
  deleted: true,
@@ -195,18 +198,25 @@ class User extends vr_migrations_1.Model {
195
198
  this.deactivatedAt = null;
196
199
  await this.save();
197
200
  }
198
- // Helper to check if user has verified phone
199
- async hasVerifiedPhone() {
200
- const PhoneContact = this.constructor.sequelize.models
201
- .PhoneContact;
202
- const verifiedPhone = await PhoneContact.findOne({
203
- where: {
204
- userId: this.id,
205
- isVerified: true,
206
- isActive: true,
207
- },
208
- });
209
- return !!verifiedPhone;
201
+ // Helper to get primary verified contact
202
+ async getPrimaryVerifiedContact() {
203
+ if (this.primaryContactId) {
204
+ const ContactModel = this.constructor.sequelize.models.Contact;
205
+ return await ContactModel.findOne({
206
+ where: {
207
+ id: this.primaryContactId,
208
+ isVerified: true,
209
+ isActive: true,
210
+ },
211
+ });
212
+ }
213
+ return null;
214
+ }
215
+ // Helper to check if user has a verified contact of a specific type
216
+ async hasVerifiedContactType(type) {
217
+ if (!this.contacts)
218
+ return false;
219
+ return this.contacts.some((contact) => contact.type === type && contact.isVerified && contact.isActive);
210
220
  }
211
221
  // Helper to get full birth date as Date object
212
222
  getBirthDate() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vr-models",
3
- "version": "1.0.57",
3
+ "version": "1.0.58",
4
4
  "description": "Shared database models package for VR applications",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -1,71 +0,0 @@
1
- import { Model, InferAttributes, InferCreationAttributes, CreationOptional, NonAttribute, ModelStatic } from "vr-migrations";
2
- import type { User } from "./user.models";
3
- export interface PhoneContactAttributes {
4
- id: string;
5
- phoneNumber: string;
6
- userId: string | null;
7
- isVerified: boolean;
8
- verifiedAt: Date | null;
9
- isPrimary: boolean;
10
- isActive: boolean;
11
- otp: string | null;
12
- otpExpiresAt: Date | null;
13
- metadata: {
14
- lastOtpSentAt?: Date;
15
- otpAttempts?: number;
16
- lastFailedAttemptAt?: Date;
17
- isLocked?: boolean;
18
- lockedUntil: Date | null;
19
- carrier?: string;
20
- countryCode?: string;
21
- deactivatedAt?: Date | null;
22
- deactivationReason?: string;
23
- };
24
- createdAt: Date;
25
- updatedAt: Date;
26
- user?: NonAttribute<User>;
27
- }
28
- export interface PhoneContactCreationAttributes extends Omit<PhoneContactAttributes, "id" | "createdAt" | "updatedAt" | "metadata"> {
29
- id?: string;
30
- metadata?: Record<string, any>;
31
- }
32
- export declare class PhoneContact extends Model<InferAttributes<PhoneContact>, InferCreationAttributes<PhoneContact>> implements PhoneContactAttributes {
33
- id: CreationOptional<string>;
34
- phoneNumber: string;
35
- userId: CreationOptional<string | null>;
36
- isVerified: CreationOptional<boolean>;
37
- verifiedAt: CreationOptional<Date | null>;
38
- isPrimary: CreationOptional<boolean>;
39
- isActive: CreationOptional<boolean>;
40
- otp: CreationOptional<string | null>;
41
- otpExpiresAt: CreationOptional<Date | null>;
42
- metadata: CreationOptional<{
43
- lastOtpSentAt?: Date;
44
- otpAttempts?: number;
45
- lastFailedAttemptAt?: Date;
46
- isLocked?: boolean;
47
- lockedUntil: Date | null;
48
- carrier?: string;
49
- countryCode?: string;
50
- deactivatedAt?: Date | null;
51
- deactivationReason?: string;
52
- }>;
53
- readonly createdAt: CreationOptional<Date>;
54
- readonly updatedAt: CreationOptional<Date>;
55
- user?: NonAttribute<User>;
56
- static initialize(sequelize: any): void;
57
- static associate(models: Record<string, ModelStatic<Model>>): void;
58
- deactivate(reason?: string): Promise<void>;
59
- reactivate(): Promise<void>;
60
- isLocked(): boolean;
61
- getRemainingLockTime(): number | null;
62
- isExpired(): boolean;
63
- getRemainingOTPTime(): number | null;
64
- static findByPhoneNumber(phoneNumber: string): Promise<PhoneContact | null>;
65
- static findVerifiedByPhoneNumber(phoneNumber: string): Promise<PhoneContact | null>;
66
- static getUserPrimaryPhone(userId: string): Promise<PhoneContact | null>;
67
- static getUserPhones(userId: string): Promise<PhoneContact[]>;
68
- static isPhoneNumberAvailable(phoneNumber: string): Promise<boolean>;
69
- static cleanupExpiredOTPs(): Promise<void>;
70
- }
71
- export type PhoneContactModel = typeof PhoneContact;